DEFINITIONS
This source file includes following functions.
- _
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 #include <errno.h>
36 #include <iconv.h>
37 #include <assert.h>
38 #include "ruby.h"
39 #include "intern.h"
40
41
42
43 #define VALUE2ICONV(v) ((iconv_t)((VALUE)(v) ^ -1))
44 #define ICONV2VALUE(c) ((VALUE)(c) ^ -1)
45
46 struct iconv_env_t
47 {
48 iconv_t cd;
49 int argc;
50 VALUE *argv;
51 VALUE ret;
52 };
53
54 static VALUE rb_eIconvFailure;
55 static VALUE rb_eIconvIllegalSeq;
56 static VALUE rb_eIconvInvalidChar;
57 static VALUE rb_eIconvOutOfRange;
58 static ID rb_inserter;
59
60 static ID rb_success, rb_failed, rb_mesg;
61 static VALUE iconv_failure_initialize _((VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env));
62 static VALUE iconv_failure_success _((VALUE self));
63 static VALUE iconv_failure_failed _((VALUE self));
64
65 static iconv_t iconv_create _((VALUE to, VALUE from));
66 static VALUE iconv_free _((VALUE cd));
67 static VALUE iconv_try _((iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen));
68 static VALUE rb_str_derive _((VALUE str, const char* ptr, int len));
69 static VALUE iconv_convert _((iconv_t cd, VALUE str, int start, int length, struct iconv_env_t* env));
70 static VALUE iconv_s_allocate _((VALUE klass));
71 static VALUE iconv_initialize _((VALUE self, VALUE to, VALUE from));
72 static VALUE iconv_s_open _((VALUE self, VALUE to, VALUE from));
73 static VALUE iconv_s_convert _((struct iconv_env_t* env));
74 static VALUE iconv_s_iconv _((int argc, VALUE *argv, VALUE self));
75 static VALUE iconv_init_state _((VALUE cd));
76 static VALUE iconv_finish _((VALUE self));
77 static VALUE iconv_iconv _((int argc, VALUE *argv, VALUE self));
78
79
80
81
82
83
84
85
86
87
88
89
90
91 static iconv_t
92 iconv_create
93 #ifdef HAVE_PROTOTYPES
94 (VALUE to, VALUE from)
95 #else
96 (to, from)
97 VALUE to;
98 VALUE from;
99 #endif
100 {
101 const char* tocode = StringValuePtr(to);
102 const char* fromcode = StringValuePtr(from);
103
104 iconv_t cd = iconv_open(tocode, fromcode);
105
106 if (cd == (iconv_t)-1) {
107 switch (errno) {
108 case EMFILE:
109 case ENFILE:
110 case ENOMEM:
111 rb_gc();
112 cd = iconv_open(tocode, fromcode);
113 }
114 if (cd == (iconv_t)-1) {
115 volatile VALUE msg = rb_str_new2("iconv(\"");
116 rb_str_buf_cat2(rb_str_buf_append(msg, to), "\", \"");
117 rb_str_buf_cat2(rb_str_buf_append(msg, from), "\")");
118 rb_sys_fail(StringValuePtr(msg));
119 }
120 }
121
122 return cd;
123 }
124
125 static VALUE
126 iconv_free
127 #ifdef HAVE_PROTOTYPES
128 (VALUE cd)
129 #else
130 (cd)
131 VALUE cd;
132 #endif
133 {
134 if (cd && iconv_close(VALUE2ICONV(cd)) == -1)
135 rb_sys_fail("iconv_close");
136 return Qnil;
137 }
138
139 #define ICONV_FREE (RUBY_DATA_FUNC)iconv_free
140
141 static VALUE
142 iconv_try
143 #ifdef HAVE_PROTOTYPES
144 (iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen)
145 #else
146 (cd, inptr, inlen, outptr, outlen)
147 iconv_t cd;
148 const char **inptr;
149 size_t *inlen;
150 char **outptr;
151 size_t *outlen;
152 #endif
153 {
154 if (iconv(cd, (char **)inptr, inlen, outptr, outlen) == (size_t)-1) {
155 if (!*inlen)
156 return Qfalse;
157 switch (errno) {
158 case E2BIG:
159
160 break;
161 case EILSEQ:
162 return rb_class_new_instance(0, 0, rb_eIconvIllegalSeq);
163 case EINVAL:
164 return rb_class_new_instance(0, 0, rb_eIconvInvalidChar);
165 default:
166 rb_sys_fail("iconv");
167 }
168 }
169 else if (*inlen > 0) {
170
171 return rb_class_new_instance(0, 0, rb_eIconvIllegalSeq);
172 }
173 return Qfalse;
174 }
175
176 #define iconv_fail(error, success, failed, env) \
177 rb_exc_raise(iconv_failure_initialize(error, success, failed, env))
178
179 static VALUE
180 iconv_failure_initialize
181 #ifdef HAVE_PROTOTYPES
182 (VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env)
183 #else
184 (error, success, failed, env)
185 VALUE error;
186 VALUE success;
187 VALUE failed;
188 struct iconv_env_t *env;
189 #endif
190 {
191 if (!rb_ivar_defined(error, rb_mesg) || NIL_P(rb_ivar_get(error, rb_mesg)))
192 rb_ivar_set(error, rb_mesg, rb_inspect(failed));
193 if (env) {
194 success = rb_funcall3(env->ret, rb_inserter, 1, &success);
195 if (env->argc > 0) {
196 *(env->argv) = failed;
197 failed = rb_ary_new4(env->argc, env->argv);
198 }
199 }
200 rb_ivar_set(error, rb_success, success);
201 rb_ivar_set(error, rb_failed, failed);
202 return error;
203 }
204
205 static VALUE
206 rb_str_derive
207 #ifdef HAVE_PROTOTYPES
208 (VALUE str, const char* ptr, int len)
209 #else
210 (str, ptr, len)
211 VALUE str;
212 const char *ptr;
213 int len;
214 #endif
215 {
216 VALUE ret;
217
218 if (NIL_P(str))
219 return rb_str_new(ptr, len);
220 if (RSTRING(str)->ptr == ptr && RSTRING(str)->len == len)
221 return str;
222 ret = rb_str_new(ptr, len);
223 OBJ_INFECT(ret, str);
224 return ret;
225 }
226
227 static VALUE
228 iconv_convert
229 #ifdef HAVE_PROTOTYPES
230 (iconv_t cd, VALUE str, int start, int length, struct iconv_env_t* env)
231 #else
232 (cd, str, start, length, env)
233 iconv_t cd;
234 VALUE str;
235 int start;
236 int length;
237 struct iconv_env_t *env;
238 #endif
239 {
240 VALUE ret = Qfalse;
241 VALUE error = Qfalse;
242 const char *inptr, *instart;
243 size_t inlen;
244
245 char buffer[BUFSIZ];
246 char *outptr;
247 size_t outlen;
248
249 if (cd == (iconv_t)-1)
250 rb_raise(rb_eArgError, "closed iconv");
251
252 if (NIL_P(str)) {
253
254 inptr = "";
255 inlen = 0;
256 outptr = buffer;
257 outlen = sizeof(buffer);
258 error = iconv_try(cd, &inptr, &inlen, &outptr, &outlen);
259 if (error)
260 iconv_fail(error, Qnil, Qnil, env);
261
262 inptr = NULL;
263 length = 0;
264 }
265 else {
266 int slen;
267
268 Check_Type(str, T_STRING);
269 slen = RSTRING(str)->len;
270 inptr = RSTRING(str)->ptr;
271
272 if (start < 0 ? (start += slen) < 0 : start >= slen)
273 length = 0;
274 else if (length < 0 && (length += slen + 1) < 0)
275 length = 0;
276 else if ((length -= start) < 0)
277 length = 0;
278 else
279 inptr += start;
280 }
281 instart = inptr;
282 inlen = length;
283
284 do {
285 const char *tmpstart = inptr;
286 outptr = buffer;
287 outlen = sizeof(buffer);
288
289 error = iconv_try(cd, &inptr, &inlen, &outptr, &outlen);
290
291 if (0 <= outlen && outlen <= sizeof(buffer)) {
292 outlen = sizeof(buffer) - outlen;
293 if (outlen > inptr - tmpstart ||
294 (outlen < inptr - tmpstart && inlen > 0) ||
295 memcmp(buffer, tmpstart, outlen))
296 {
297 if (NIL_P(str)) {
298 ret = rb_str_new(buffer, outlen);
299 }
300 else {
301 if (ret) {
302 ret = rb_str_buf_cat(ret, instart, tmpstart - instart);
303 }
304 else {
305 ret = rb_str_new(instart, tmpstart - instart);
306 OBJ_INFECT(ret, str);
307 }
308 ret = rb_str_buf_cat(ret, buffer, outlen);
309 instart = inptr;
310 }
311 }
312 else if (!inlen) {
313 inptr = tmpstart + outlen;
314 }
315 }
316 else {
317
318 char errmsg[50];
319 sprintf(errmsg, "bug?(output length = %d)", sizeof(buffer) - outlen);
320 error = rb_exc_new2(rb_eIconvOutOfRange, errmsg);
321 }
322
323 if (error) {
324 if (!ret)
325 ret = rb_str_derive(str, instart, inptr - instart);
326 str = rb_str_derive(str, inptr, inlen);
327 iconv_fail(error, ret, str, env);
328 }
329 } while (inlen > 0);
330
331 if (!ret)
332 ret = rb_str_derive(str, instart, inptr - instart);
333 return ret;
334 }
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366 static VALUE
367 iconv_s_allocate
368 #ifdef HAVE_PROTOTYPES
369 (VALUE klass)
370 #else
371 (klass)
372 VALUE klass;
373 #endif
374 {
375 return Data_Wrap_Struct(klass, 0, ICONV_FREE, 0);
376 }
377
378 static VALUE
379 iconv_initialize
380 #ifdef HAVE_PROTOTYPES
381 (VALUE self, VALUE to, VALUE from)
382 #else
383 (self, to, from)
384 VALUE self;
385 VALUE to;
386 VALUE from;
387 #endif
388 {
389 iconv_free((VALUE)(DATA_PTR(self)));
390 DATA_PTR(self) = NULL;
391 DATA_PTR(self) = (void *)ICONV2VALUE(iconv_create(to, from));
392 return self;
393 }
394
395 static VALUE
396 iconv_s_open
397 #ifdef HAVE_PROTOTYPES
398 (VALUE self, VALUE to, VALUE from)
399 #else
400 (self, to, from)
401 VALUE self;
402 VALUE to;
403 VALUE from;
404 #endif
405 {
406 VALUE cd = ICONV2VALUE(iconv_create(to, from));
407
408 if (rb_block_given_p()) {
409 self = Data_Wrap_Struct(self, NULL, NULL, (void *)cd);
410 return rb_ensure(rb_yield, self, (VALUE(*)())iconv_finish, self);
411 }
412 else {
413 return Data_Wrap_Struct(self, NULL, ICONV_FREE, (void *)cd);
414 }
415 }
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433 static VALUE
434 iconv_s_convert
435 #ifdef HAVE_PROTOTYPES
436 (struct iconv_env_t* env)
437 #else
438 (env)
439 struct iconv_env_t *env;
440 #endif
441 {
442 VALUE last = 0;
443
444 for (; env->argc > 0; --env->argc, ++env->argv) {
445 VALUE s = iconv_convert(env->cd, last = *(env->argv), 0, -1, env);
446 rb_funcall3(env->ret, rb_inserter, 1, &s);
447 }
448
449 if (!NIL_P(last)) {
450 VALUE s = iconv_convert(env->cd, Qnil, 0, 0, env);
451 if (RSTRING(s)->len)
452 rb_funcall3(env->ret, rb_inserter, 1, &s);
453 }
454
455 return env->ret;
456 }
457
458 static VALUE
459 iconv_s_iconv
460 #ifdef HAVE_PROTOTYPES
461 (int argc, VALUE *argv, VALUE self)
462 #else
463 (argc, argv, self)
464 int argc;
465 VALUE *argv;
466 VALUE self;
467 #endif
468 {
469 struct iconv_env_t arg;
470
471 if (argc < 2)
472 rb_raise(rb_eArgError, "wrong # of arguments (%d for %d)", argc, 2);
473
474 arg.argc = argc -= 2;
475 arg.argv = argv + 2;
476 arg.ret = rb_ary_new2(argc);
477 arg.cd = iconv_create(argv[0], argv[1]);
478 return rb_ensure(iconv_s_convert, (VALUE)&arg, iconv_free, ICONV2VALUE(arg.cd));
479 }
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498 static VALUE
499 iconv_init_state
500 #ifdef HAVE_PROTOTYPES
501 (VALUE cd)
502 #else
503 (cd)
504 VALUE cd;
505 #endif
506 {
507 return iconv_convert(VALUE2ICONV(cd), Qnil, 0, 0, NULL);
508 }
509
510 static VALUE
511 iconv_finish
512 #ifdef HAVE_PROTOTYPES
513 (VALUE self)
514 #else
515 (self)
516 VALUE self;
517 #endif
518 {
519 VALUE cd;
520
521 Check_Type(self, T_DATA);
522
523 cd = (VALUE)DATA_PTR(self);
524 if (!cd) return Qnil;
525 DATA_PTR(self) = NULL;
526
527 return rb_ensure(iconv_init_state, cd, iconv_free, cd);
528 }
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555 static VALUE
556 iconv_iconv
557 #ifdef HAVE_PROTOTYPES
558 (int argc, VALUE *argv, VALUE self)
559 #else
560 (argc, argv, self)
561 int argc;
562 VALUE *argv;
563 VALUE self;
564 #endif
565 {
566 VALUE str, n1, n2;
567
568 Check_Type(self, T_DATA);
569
570 n1 = n2 = Qnil;
571 rb_scan_args(argc, argv, "12", &str, &n1, &n2);
572
573 return iconv_convert(VALUE2ICONV(DATA_PTR(self)), str,
574 NIL_P(n1) ? 0 : NUM2INT(n1),
575 NIL_P(n2) ? -1 : NUM2INT(n1),
576 NULL);
577 }
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602 static VALUE
603 iconv_failure_success
604 #ifdef HAVE_PROTOTYPES
605 (VALUE self)
606 #else
607 (self)
608 VALUE self;
609 #endif
610 {
611 return rb_ivar_get(self, rb_success);
612 }
613
614
615
616
617
618
619
620
621 static VALUE
622 iconv_failure_failed
623 #ifdef HAVE_PROTOTYPES
624 (VALUE self)
625 #else
626 (self)
627 VALUE self;
628 #endif
629 {
630 return rb_ivar_get(self, rb_failed);
631 }
632
633
634
635
636
637
638
639 static VALUE
640 iconv_failure_inspect
641 #ifdef HAVE_PROTOTYPES
642 (VALUE self)
643 #else
644 (self)
645 VALUE self;
646 #endif
647 {
648 char *cname = rb_class2name(CLASS_OF(self));
649 VALUE success = iconv_failure_success(self);
650 VALUE failed = iconv_failure_failed(self);
651 VALUE str = rb_str_buf_cat2(rb_str_new2("#<"), cname);
652 str = rb_str_buf_cat(str, ": ", 2);
653 str = rb_str_buf_append(str, rb_inspect(success));
654 str = rb_str_buf_cat(str, ", ", 2);
655 str = rb_str_buf_append(str, rb_inspect(failed));
656 return rb_str_buf_cat(str, ">", 1);
657 }
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689 void
690 Init_iconv _((void))
691 {
692 VALUE rb_cIconv = rb_define_class("Iconv", rb_cData);
693 rb_define_singleton_method(rb_cIconv, "allocate", iconv_s_allocate, 0);
694 rb_define_singleton_method(rb_cIconv, "open", iconv_s_open, 2);
695 rb_define_singleton_method(rb_cIconv, "iconv", iconv_s_iconv, -1);
696 rb_define_method(rb_cIconv, "initialize", iconv_initialize, 2);
697 rb_define_method(rb_cIconv, "close", iconv_finish, 0);
698 rb_define_method(rb_cIconv, "iconv", iconv_iconv, -1);
699
700 rb_eIconvFailure = rb_define_module_under(rb_cIconv, "Failure");
701 rb_define_method(rb_eIconvFailure, "success", iconv_failure_success, 0);
702 rb_define_method(rb_eIconvFailure, "failed", iconv_failure_failed, 0);
703 rb_define_method(rb_eIconvFailure, "inspect", iconv_failure_inspect, 0);
704
705 rb_eIconvIllegalSeq = rb_define_class_under(rb_cIconv, "IllegalSequence", rb_eArgError);
706 rb_eIconvInvalidChar = rb_define_class_under(rb_cIconv, "InvalidCharacter", rb_eArgError);
707 rb_eIconvOutOfRange = rb_define_class_under(rb_cIconv, "OutOfRange", rb_eRuntimeError);
708 rb_include_module(rb_eIconvIllegalSeq, rb_eIconvFailure);
709 rb_include_module(rb_eIconvInvalidChar, rb_eIconvFailure);
710 rb_include_module(rb_eIconvOutOfRange, rb_eIconvFailure);
711
712 rb_inserter = rb_intern("<<");
713 rb_success = rb_intern("success");
714 rb_failed = rb_intern("failed");
715 rb_mesg = rb_intern("mesg");
716 }
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738