iconv 0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/iconv/iconv.c CHANGED
@@ -4,7 +4,6 @@
4
4
  iconv.c -
5
5
 
6
6
  $Author$
7
- $Date$
8
7
  created at: Wed Dec 1 20:28:09 JST 1999
9
8
 
10
9
  All the files in this distribution are covered under the Ruby's
@@ -14,12 +13,12 @@
14
13
 
15
14
  **********************************************************************/
16
15
 
17
- #include "ruby.h"
16
+ #include "ruby/ruby.h"
18
17
  #include <errno.h>
19
18
  #include <iconv.h>
20
19
  #include <assert.h>
21
- #include "st.h"
22
- #include "intern.h"
20
+ #include "ruby/st.h"
21
+ #include "ruby/encoding.h"
23
22
 
24
23
  /*
25
24
  * Document-class: Iconv
@@ -27,20 +26,20 @@
27
26
  * == Summary
28
27
  *
29
28
  * Ruby extension for charset conversion.
30
- *
29
+ *
31
30
  * == Abstract
32
31
  *
33
32
  * Iconv is a wrapper class for the UNIX 95 <tt>iconv()</tt> function family,
34
33
  * which translates string between various encoding systems.
35
- *
34
+ *
36
35
  * See Open Group's on-line documents for more details.
37
36
  * * <tt>iconv.h</tt>: http://www.opengroup.org/onlinepubs/007908799/xsh/iconv.h.html
38
37
  * * <tt>iconv_open()</tt>: http://www.opengroup.org/onlinepubs/007908799/xsh/iconv_open.html
39
38
  * * <tt>iconv()</tt>: http://www.opengroup.org/onlinepubs/007908799/xsh/iconv.html
40
39
  * * <tt>iconv_close()</tt>: http://www.opengroup.org/onlinepubs/007908799/xsh/iconv_close.html
41
- *
40
+ *
42
41
  * Which coding systems are available is platform-dependent.
43
- *
42
+ *
44
43
  * == Examples
45
44
  *
46
45
  * 1. Simple conversion between two charsets.
@@ -67,6 +66,12 @@
67
66
  * 4. Shorthand for (3).
68
67
  *
69
68
  * Iconv.iconv(to, from, *input.to_a)
69
+ *
70
+ * == Attentions
71
+ *
72
+ * Even if some extentions of implementation dependent are useful,
73
+ * DON'T USE those extentions in libraries and scripts to widely distribute.
74
+ * If you want to use those feature, use String#encode.
70
75
  */
71
76
 
72
77
  /* Invalid value for iconv_t is -1 but 0 for VALUE, I hope VALUE is
@@ -80,9 +85,18 @@ struct iconv_env_t
80
85
  int argc;
81
86
  VALUE *argv;
82
87
  VALUE ret;
88
+ int toidx;
83
89
  VALUE (*append)_((VALUE, VALUE));
84
90
  };
85
91
 
92
+ struct rb_iconv_opt_t
93
+ {
94
+ VALUE transliterate;
95
+ VALUE discard_ilseq;
96
+ };
97
+
98
+ static ID id_transliterate, id_discard_ilseq;
99
+
86
100
  static VALUE rb_eIconvInvalidEncoding;
87
101
  static VALUE rb_eIconvFailure;
88
102
  static VALUE rb_eIconvIllegalSeq;
@@ -91,26 +105,28 @@ static VALUE rb_eIconvOutOfRange;
91
105
  static VALUE rb_eIconvBrokenLibrary;
92
106
 
93
107
  static ID rb_success, rb_failed;
94
- static VALUE iconv_fail _((VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, const char *mesg));
95
- static VALUE iconv_fail_retry _((VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, const char *mesg));
108
+ static VALUE iconv_fail _((VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, VALUE mesg));
109
+ static VALUE iconv_fail_retry _((VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, VALUE mesg));
96
110
  static VALUE iconv_failure_initialize _((VALUE error, VALUE mesg, VALUE success, VALUE failed));
97
111
  static VALUE iconv_failure_success _((VALUE self));
98
112
  static VALUE iconv_failure_failed _((VALUE self));
99
113
 
100
- static iconv_t iconv_create _((VALUE to, VALUE from));
114
+ static iconv_t iconv_create _((VALUE to, VALUE from, struct rb_iconv_opt_t *opt, int *idx));
101
115
  static void iconv_dfree _((void *cd));
102
116
  static VALUE iconv_free _((VALUE cd));
103
117
  static VALUE iconv_try _((iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen));
104
- static VALUE rb_str_derive _((VALUE str, const char* ptr, int len));
105
- static VALUE iconv_convert _((iconv_t cd, VALUE str, long start, long length, struct iconv_env_t* env));
118
+ static VALUE rb_str_derive _((VALUE str, const char* ptr, long len));
119
+ static VALUE iconv_convert _((iconv_t cd, VALUE str, long start, long length, int toidx,
120
+ struct iconv_env_t* env));
106
121
  static VALUE iconv_s_allocate _((VALUE klass));
107
- static VALUE iconv_initialize _((VALUE self, VALUE to, VALUE from));
108
- static VALUE iconv_s_open _((VALUE self, VALUE to, VALUE from));
122
+ static VALUE iconv_initialize _((int argc, VALUE *argv, VALUE self));
123
+ static VALUE iconv_s_open _((int argc, VALUE *argv, VALUE self));
109
124
  static VALUE iconv_s_convert _((struct iconv_env_t* env));
110
125
  static VALUE iconv_s_iconv _((int argc, VALUE *argv, VALUE self));
111
126
  static VALUE iconv_init_state _((VALUE cd));
112
127
  static VALUE iconv_finish _((VALUE self));
113
128
  static VALUE iconv_iconv _((int argc, VALUE *argv, VALUE self));
129
+ static VALUE iconv_conv _((int argc, VALUE *argv, VALUE self));
114
130
 
115
131
  static VALUE charset_map;
116
132
 
@@ -120,94 +136,162 @@ static VALUE charset_map;
120
136
  *
121
137
  * Returns the map from canonical name to system dependent name.
122
138
  */
123
- static VALUE charset_map_get _((void))
139
+ static VALUE
140
+ charset_map_get(void)
124
141
  {
125
142
  return charset_map;
126
143
  }
127
144
 
145
+ static VALUE
146
+ strip_glibc_option(VALUE *code)
147
+ {
148
+ VALUE val = StringValue(*code);
149
+ const char *ptr = RSTRING_PTR(val), *pend = RSTRING_END(val);
150
+ const char *slash = memchr(ptr, '/', pend - ptr);
151
+
152
+ if (slash && slash < pend - 1 && slash[1] == '/') {
153
+ VALUE opt = rb_str_subseq(val, slash - ptr, pend - slash);
154
+ val = rb_str_subseq(val, 0, slash - ptr);
155
+ *code = val;
156
+ return opt;
157
+ }
158
+ return 0;
159
+ }
160
+
128
161
  static char *
129
- map_charset
130
- #ifdef HAVE_PROTOTYPES
131
- (VALUE *code)
132
- #else /* HAVE_PROTOTYPES */
133
- (code)
134
- VALUE *code;
135
- #endif /* HAVE_PROTOTYPES */
162
+ map_charset(VALUE *code)
136
163
  {
137
- VALUE val = *code;
164
+ VALUE val = StringValue(*code);
138
165
 
139
- if (RHASH(charset_map)->tbl && RHASH(charset_map)->tbl->num_entries) {
166
+ if (RHASH_SIZE(charset_map)) {
167
+ st_data_t data;
140
168
  VALUE key = rb_funcall2(val, rb_intern("downcase"), 0, 0);
141
169
  StringValuePtr(key);
142
- if (st_lookup(RHASH(charset_map)->tbl, key, &val)) {
143
- *code = val;
170
+ if (st_lookup(RHASH_TBL(charset_map), key, &data)) {
171
+ *code = (VALUE)data;
144
172
  }
145
173
  }
146
174
  return StringValuePtr(*code);
147
175
  }
148
176
 
149
- NORETURN(static void rb_iconv_sys_fail(const char *s));
177
+ NORETURN(static void rb_iconv_sys_fail_str(VALUE msg));
150
178
  static void
151
- rb_iconv_sys_fail(const char *s)
179
+ rb_iconv_sys_fail_str(VALUE msg)
152
180
  {
153
181
  if (errno == 0) {
154
- rb_exc_raise(iconv_fail(rb_eIconvBrokenLibrary, Qnil, Qnil, NULL, s));
182
+ rb_exc_raise(iconv_fail(rb_eIconvBrokenLibrary, Qnil, Qnil, NULL, msg));
155
183
  }
156
- rb_sys_fail(s);
184
+ rb_sys_fail_str(msg);
185
+ }
186
+
187
+ #define rb_sys_fail_str(s) rb_iconv_sys_fail_str(s)
188
+
189
+ NORETURN(static void rb_iconv_sys_fail(const char *s));
190
+ static void
191
+ rb_iconv_sys_fail(const char *s)
192
+ {
193
+ rb_iconv_sys_fail_str(rb_str_new_cstr(s));
157
194
  }
158
195
 
159
196
  #define rb_sys_fail(s) rb_iconv_sys_fail(s)
160
197
 
161
198
  static iconv_t
162
- iconv_create
163
- #ifdef HAVE_PROTOTYPES
164
- (VALUE to, VALUE from)
165
- #else /* HAVE_PROTOTYPES */
166
- (to, from)
167
- VALUE to;
168
- VALUE from;
169
- #endif /* HAVE_PROTOTYPES */
199
+ iconv_create(VALUE to, VALUE from, struct rb_iconv_opt_t *opt, int *idx)
170
200
  {
201
+ VALUE toopt = strip_glibc_option(&to);
202
+ VALUE fromopt = strip_glibc_option(&from);
203
+ VALUE toenc = 0, fromenc = 0;
171
204
  const char* tocode = map_charset(&to);
172
205
  const char* fromcode = map_charset(&from);
206
+ iconv_t cd;
207
+ int retry = 0;
173
208
 
174
- iconv_t cd = iconv_open(tocode, fromcode);
209
+ *idx = rb_enc_find_index(tocode);
175
210
 
176
- if (cd == (iconv_t)-1) {
211
+ if (toopt) {
212
+ toenc = rb_str_plus(to, toopt);
213
+ tocode = RSTRING_PTR(toenc);
214
+ }
215
+ if (fromopt) {
216
+ fromenc = rb_str_plus(from, fromopt);
217
+ fromcode = RSTRING_PTR(fromenc);
218
+ }
219
+ while ((cd = iconv_open(tocode, fromcode)) == (iconv_t)-1) {
220
+ int inval = 0;
177
221
  switch (errno) {
178
222
  case EMFILE:
179
223
  case ENFILE:
180
224
  case ENOMEM:
181
- rb_gc();
182
- cd = iconv_open(tocode, fromcode);
225
+ if (!retry++) {
226
+ rb_gc();
227
+ continue;
228
+ }
229
+ break;
230
+ case EINVAL:
231
+ retry = 0;
232
+ inval = 1;
233
+ if (toenc) {
234
+ tocode = RSTRING_PTR(to);
235
+ rb_str_resize(toenc, 0);
236
+ toenc = 0;
237
+ continue;
238
+ }
239
+ if (fromenc) {
240
+ fromcode = RSTRING_PTR(from);
241
+ rb_str_resize(fromenc, 0);
242
+ fromenc = 0;
243
+ continue;
244
+ }
245
+ break;
183
246
  }
184
- if (cd == (iconv_t)-1) {
185
- int inval = errno == EINVAL;
247
+ {
186
248
  const char *s = inval ? "invalid encoding " : "iconv";
187
- volatile VALUE msg = rb_str_new(0, strlen(s) + RSTRING(to)->len +
188
- RSTRING(from)->len + 8);
189
-
190
- sprintf(RSTRING(msg)->ptr, "%s(\"%s\", \"%s\")",
191
- s, RSTRING(to)->ptr, RSTRING(from)->ptr);
192
- s = RSTRING(msg)->ptr;
193
- RSTRING(msg)->len = strlen(s);
194
- if (!inval) rb_sys_fail(s);
249
+ VALUE msg = rb_sprintf("%s(\"%s\", \"%s\")",
250
+ s, RSTRING_PTR(to), RSTRING_PTR(from));
251
+ if (!inval) rb_sys_fail_str(msg);
195
252
  rb_exc_raise(iconv_fail(rb_eIconvInvalidEncoding, Qnil,
196
- rb_ary_new3(2, to, from), NULL, s));
253
+ rb_ary_new3(2, to, from), NULL, msg));
254
+ }
255
+ }
256
+
257
+ if (toopt || fromopt) {
258
+ if (toopt && fromopt && RTEST(rb_str_equal(toopt, fromopt))) {
259
+ fromopt = 0;
260
+ }
261
+ if (toopt && fromopt) {
262
+ rb_warning("encoding option isn't portable: %s, %s",
263
+ RSTRING_PTR(toopt) + 2, RSTRING_PTR(fromopt) + 2);
264
+ }
265
+ else {
266
+ rb_warning("encoding option isn't portable: %s",
267
+ (toopt ? RSTRING_PTR(toopt) : RSTRING_PTR(fromopt)) + 2);
268
+ }
269
+ }
270
+
271
+ if (opt) {
272
+ #ifdef ICONV_SET_TRANSLITERATE
273
+ if (opt->transliterate != Qundef) {
274
+ int flag = RTEST(opt->transliterate);
275
+ rb_warning("encoding option isn't portable: transliterate");
276
+ if (iconvctl(cd, ICONV_SET_TRANSLITERATE, (void *)&flag))
277
+ rb_sys_fail("ICONV_SET_TRANSLITERATE");
197
278
  }
279
+ #endif
280
+ #ifdef ICONV_SET_DISCARD_ILSEQ
281
+ if (opt->discard_ilseq != Qundef) {
282
+ int flag = RTEST(opt->discard_ilseq);
283
+ rb_warning("encoding option isn't portable: discard_ilseq");
284
+ if (iconvctl(cd, ICONV_SET_DISCARD_ILSEQ, (void *)&flag))
285
+ rb_sys_fail("ICONV_SET_DISCARD_ILSEQ");
286
+ }
287
+ #endif
198
288
  }
199
289
 
200
290
  return cd;
201
291
  }
202
292
 
203
293
  static void
204
- iconv_dfree
205
- #ifdef HAVE_PROTOTYPES
206
- (void *cd)
207
- #else /* HAVE_PROTOTYPES */
208
- (cd)
209
- void *cd;
210
- #endif /* HAVE_PROTOTYPES */
294
+ iconv_dfree(void *cd)
211
295
  {
212
296
  iconv_close(VALUE2ICONV(cd));
213
297
  }
@@ -215,13 +299,7 @@ iconv_dfree
215
299
  #define ICONV_FREE iconv_dfree
216
300
 
217
301
  static VALUE
218
- iconv_free
219
- #ifdef HAVE_PROTOTYPES
220
- (VALUE cd)
221
- #else /* HAVE_PROTOTYPES */
222
- (cd)
223
- VALUE cd;
224
- #endif /* HAVE_PROTOTYPES */
302
+ iconv_free(VALUE cd)
225
303
  {
226
304
  if (cd && iconv_close(VALUE2ICONV(cd)) == -1)
227
305
  rb_sys_fail("iconv_close");
@@ -229,13 +307,7 @@ iconv_free
229
307
  }
230
308
 
231
309
  static VALUE
232
- check_iconv
233
- #ifdef HAVE_PROTOTYPES
234
- (VALUE obj)
235
- #else /* HAVE_PROTOTYPES */
236
- (obj)
237
- VALUE obj;
238
- #endif /* HAVE_PROTOTYPES */
310
+ check_iconv(VALUE obj)
239
311
  {
240
312
  Check_Type(obj, T_DATA);
241
313
  if (RDATA(obj)->dfree != ICONV_FREE) {
@@ -245,17 +317,7 @@ check_iconv
245
317
  }
246
318
 
247
319
  static VALUE
248
- iconv_try
249
- #ifdef HAVE_PROTOTYPES
250
- (iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen)
251
- #else /* HAVE_PROTOTYPES */
252
- (cd, inptr, inlen, outptr, outlen)
253
- iconv_t cd;
254
- const char **inptr;
255
- size_t *inlen;
256
- char **outptr;
257
- size_t *outlen;
258
- #endif /* HAVE_PROTOTYPES */
320
+ iconv_try(iconv_t cd, const char **inptr, size_t *inlen, char **outptr, size_t *outlen)
259
321
  {
260
322
  #ifdef ICONV_INPTR_CONST
261
323
  #define ICONV_INPTR_CAST
@@ -295,13 +357,8 @@ iconv_try
295
357
 
296
358
  #define FAILED_MAXLEN 16
297
359
 
298
- static VALUE iconv_failure_initialize
299
- #ifdef HAVE_PROTOTYPES
300
- (VALUE error, VALUE mesg, VALUE success, VALUE failed)
301
- #else /* HAVE_PROTOTYPES */
302
- (error, mesg, success, failed)
303
- VALUE error, mesg, success, failed;
304
- #endif /* HAVE_PROTOTYPES */
360
+ static VALUE
361
+ iconv_failure_initialize(VALUE error, VALUE mesg, VALUE success, VALUE failed)
305
362
  {
306
363
  rb_call_super(1, &mesg);
307
364
  rb_ivar_set(error, rb_success, success);
@@ -310,22 +367,14 @@ static VALUE iconv_failure_initialize
310
367
  }
311
368
 
312
369
  static VALUE
313
- iconv_fail
314
- #ifdef HAVE_PROTOTYPES
315
- (VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, const char *mesg)
316
- #else /* HAVE_PROTOTYPES */
317
- (error, success, failed, env, mesg)
318
- VALUE error, success, failed;
319
- struct iconv_env_t *env;
320
- const char *mesg;
321
- #endif /* HAVE_PROTOTYPES */
370
+ iconv_fail(VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, VALUE mesg)
322
371
  {
323
372
  VALUE args[3];
324
373
 
325
- if (mesg && *mesg) {
326
- args[0] = rb_str_new2(mesg);
374
+ if (!NIL_P(mesg)) {
375
+ args[0] = mesg;
327
376
  }
328
- else if (TYPE(failed) != T_STRING || RSTRING(failed)->len < FAILED_MAXLEN) {
377
+ else if (TYPE(failed) != T_STRING || RSTRING_LEN(failed) < FAILED_MAXLEN) {
329
378
  args[0] = rb_inspect(failed);
330
379
  }
331
380
  else {
@@ -345,33 +394,23 @@ iconv_fail
345
394
  }
346
395
 
347
396
  static VALUE
348
- iconv_fail_retry(VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, const char *mesg)
397
+ iconv_fail_retry(VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, VALUE mesg)
349
398
  {
350
399
  error = iconv_fail(error, success, failed, env, mesg);
351
400
  if (!rb_block_given_p()) rb_exc_raise(error);
352
- ruby_errinfo = error;
401
+ rb_set_errinfo(error);
353
402
  return rb_yield(failed);
354
403
  }
355
404
 
356
405
  static VALUE
357
- rb_str_derive
358
- #ifdef HAVE_PROTOTYPES
359
- (VALUE str, const char* ptr, int len)
360
- #else /* HAVE_PROTOTYPES */
361
- (str, ptr, len)
362
- VALUE str;
363
- const char *ptr;
364
- int len;
365
- #endif /* HAVE_PROTOTYPES */
406
+ rb_str_derive(VALUE str, const char* ptr, long len)
366
407
  {
367
408
  VALUE ret;
368
409
 
369
410
  if (NIL_P(str))
370
411
  return rb_str_new(ptr, len);
371
- if (RSTRING(str)->ptr == ptr && RSTRING(str)->len == len)
372
- return str;
373
- if (RSTRING(str)->ptr + RSTRING(str)->len == ptr + len)
374
- ret = rb_str_substr(str, ptr - RSTRING(str)->ptr, len);
412
+ if (RSTRING_PTR(str) + RSTRING_LEN(str) == ptr + len)
413
+ ret = rb_str_subseq(str, ptr - RSTRING_PTR(str), len);
375
414
  else
376
415
  ret = rb_str_new(ptr, len);
377
416
  OBJ_INFECT(ret, str);
@@ -379,17 +418,7 @@ rb_str_derive
379
418
  }
380
419
 
381
420
  static VALUE
382
- iconv_convert
383
- #ifdef HAVE_PROTOTYPES
384
- (iconv_t cd, VALUE str, long start, long length, struct iconv_env_t* env)
385
- #else /* HAVE_PROTOTYPES */
386
- (cd, str, start, length, env)
387
- iconv_t cd;
388
- VALUE str;
389
- long start;
390
- long length;
391
- struct iconv_env_t *env;
392
- #endif /* HAVE_PROTOTYPES */
421
+ iconv_convert(iconv_t cd, VALUE str, long start, long length, int toidx, struct iconv_env_t* env)
393
422
  {
394
423
  VALUE ret = Qfalse;
395
424
  VALUE error = Qfalse;
@@ -413,9 +442,9 @@ iconv_convert
413
442
  error = iconv_try(cd, &inptr, &inlen, &outptr, &outlen);
414
443
  if (RTEST(error)) {
415
444
  unsigned int i;
416
- rescue = iconv_fail_retry(error, Qnil, Qnil, env, 0);
445
+ rescue = iconv_fail_retry(error, Qnil, Qnil, env, Qnil);
417
446
  if (TYPE(rescue) == T_ARRAY) {
418
- str = RARRAY(rescue)->len > 0 ? RARRAY(rescue)->ptr[0] : Qnil;
447
+ str = RARRAY_LEN(rescue) > 0 ? RARRAY_PTR(rescue)[0] : Qnil;
419
448
  }
420
449
  if (FIXNUM_P(str) && (i = FIX2INT(str)) <= 0xff) {
421
450
  char c = i;
@@ -430,11 +459,11 @@ iconv_convert
430
459
  length = 0;
431
460
  }
432
461
  else {
433
- int slen;
462
+ long slen;
434
463
 
435
464
  StringValue(str);
436
- slen = RSTRING(str)->len;
437
- inptr = RSTRING(str)->ptr;
465
+ slen = RSTRING_LEN(str);
466
+ inptr = RSTRING_PTR(str);
438
467
 
439
468
  inptr += start;
440
469
  if (length < 0 || length > start + slen)
@@ -444,23 +473,27 @@ iconv_convert
444
473
  inlen = length;
445
474
 
446
475
  do {
447
- char errmsg[50];
476
+ VALUE errmsg = Qnil;
448
477
  const char *tmpstart = inptr;
449
478
  outptr = buffer;
450
479
  outlen = sizeof(buffer);
451
480
 
452
- errmsg[0] = 0;
453
481
  error = iconv_try(cd, &inptr, &inlen, &outptr, &outlen);
454
482
 
455
- if (0 <= outlen && outlen <= sizeof(buffer)) {
483
+ if (
484
+ #if SIGNEDNESS_OF_SIZE_T < 0
485
+ 0 <= outlen &&
486
+ #endif
487
+ outlen <= sizeof(buffer)) {
456
488
  outlen = sizeof(buffer) - outlen;
457
489
  if (NIL_P(error) || /* something converted */
458
- outlen > inptr - tmpstart || /* input can't contain output */
459
- (outlen < inptr - tmpstart && inlen > 0) || /* something skipped */
490
+ outlen > (size_t)(inptr - tmpstart) || /* input can't contain output */
491
+ (outlen < (size_t)(inptr - tmpstart) && inlen > 0) || /* something skipped */
460
492
  memcmp(buffer, tmpstart, outlen)) /* something differs */
461
493
  {
462
494
  if (NIL_P(str)) {
463
495
  ret = rb_str_new(buffer, outlen);
496
+ if (toidx >= 0) rb_enc_associate_index(ret, toidx);
464
497
  }
465
498
  else {
466
499
  if (ret) {
@@ -468,6 +501,7 @@ iconv_convert
468
501
  }
469
502
  else {
470
503
  ret = rb_str_new(instart, tmpstart - instart);
504
+ if (toidx >= 0) rb_enc_associate_index(ret, toidx);
471
505
  OBJ_INFECT(ret, str);
472
506
  }
473
507
  ret = rb_str_buf_cat(ret, buffer, outlen);
@@ -480,26 +514,29 @@ iconv_convert
480
514
  }
481
515
  else {
482
516
  /* Some iconv() have a bug, return *outlen out of range */
483
- sprintf(errmsg, "bug?(output length = %ld)", (long)(sizeof(buffer) - outlen));
517
+ errmsg = rb_sprintf("bug?(output length = %ld)", (long)(sizeof(buffer) - outlen));
484
518
  error = rb_eIconvOutOfRange;
485
519
  }
486
520
 
487
521
  if (RTEST(error)) {
488
522
  long len = 0;
489
523
 
490
- if (!ret)
524
+ if (!ret) {
491
525
  ret = rb_str_derive(str, instart, inptr - instart);
492
- else if (inptr > instart)
526
+ if (toidx >= 0) rb_enc_associate_index(ret, toidx);
527
+ }
528
+ else if (inptr > instart) {
493
529
  rb_str_cat(ret, instart, inptr - instart);
530
+ }
494
531
  str = rb_str_derive(str, inptr, inlen);
495
532
  rescue = iconv_fail_retry(error, ret, str, env, errmsg);
496
533
  if (TYPE(rescue) == T_ARRAY) {
497
- if ((len = RARRAY(rescue)->len) > 0)
498
- rb_str_concat(ret, RARRAY(rescue)->ptr[0]);
499
- if (len > 1 && !NIL_P(str = RARRAY(rescue)->ptr[1])) {
534
+ if ((len = RARRAY_LEN(rescue)) > 0)
535
+ rb_str_concat(ret, RARRAY_PTR(rescue)[0]);
536
+ if (len > 1 && !NIL_P(str = RARRAY_PTR(rescue)[1])) {
500
537
  StringValue(str);
501
- inlen = length = RSTRING(str)->len;
502
- instart = inptr = RSTRING(str)->ptr;
538
+ inlen = length = RSTRING_LEN(str);
539
+ instart = inptr = RSTRING_PTR(str);
503
540
  continue;
504
541
  }
505
542
  }
@@ -510,36 +547,107 @@ iconv_convert
510
547
  }
511
548
  } while (inlen > 0);
512
549
 
513
- if (!ret)
550
+ if (!ret) {
514
551
  ret = rb_str_derive(str, instart, inptr - instart);
515
- else if (inptr > instart)
552
+ if (toidx >= 0) rb_enc_associate_index(ret, toidx);
553
+ }
554
+ else if (inptr > instart) {
516
555
  rb_str_cat(ret, instart, inptr - instart);
556
+ }
517
557
  return ret;
518
558
  }
519
559
 
520
560
  static VALUE
521
- iconv_s_allocate
522
- #ifdef HAVE_PROTOTYPES
523
- (VALUE klass)
524
- #else /* HAVE_PROTOTYPES */
525
- (klass)
526
- VALUE klass;
527
- #endif /* HAVE_PROTOTYPES */
561
+ iconv_s_allocate(VALUE klass)
528
562
  {
529
563
  return Data_Wrap_Struct(klass, 0, ICONV_FREE, 0);
530
564
  }
531
565
 
566
+ static VALUE
567
+ get_iconv_opt_i(VALUE i, VALUE arg)
568
+ {
569
+ VALUE name;
570
+ #if defined ICONV_SET_TRANSLITERATE || defined ICONV_SET_DISCARD_ILSEQ
571
+ VALUE val;
572
+ struct rb_iconv_opt_t *opt = (struct rb_iconv_opt_t *)arg;
573
+ #endif
574
+
575
+ i = rb_Array(i);
576
+ name = rb_ary_entry(i, 0);
577
+ #if defined ICONV_SET_TRANSLITERATE || defined ICONV_SET_DISCARD_ILSEQ
578
+ val = rb_ary_entry(i, 1);
579
+ #endif
580
+ do {
581
+ if (SYMBOL_P(name)) {
582
+ ID id = SYM2ID(name);
583
+ if (id == id_transliterate) {
584
+ #ifdef ICONV_SET_TRANSLITERATE
585
+ opt->transliterate = val;
586
+ #else
587
+ rb_notimplement();
588
+ #endif
589
+ break;
590
+ }
591
+ if (id == id_discard_ilseq) {
592
+ #ifdef ICONV_SET_DISCARD_ILSEQ
593
+ opt->discard_ilseq = val;
594
+ #else
595
+ rb_notimplement();
596
+ #endif
597
+ break;
598
+ }
599
+ }
600
+ else {
601
+ const char *s = StringValueCStr(name);
602
+ if (strcmp(s, "transliterate") == 0) {
603
+ #ifdef ICONV_SET_TRANSLITERATE
604
+ opt->transliterate = val;
605
+ #else
606
+ rb_notimplement();
607
+ #endif
608
+ break;
609
+ }
610
+ if (strcmp(s, "discard_ilseq") == 0) {
611
+ #ifdef ICONV_SET_DISCARD_ILSEQ
612
+ opt->discard_ilseq = val;
613
+ #else
614
+ rb_notimplement();
615
+ #endif
616
+ break;
617
+ }
618
+ }
619
+ name = rb_inspect(name);
620
+ rb_raise(rb_eArgError, "unknown option - %s", StringValueCStr(name));
621
+ } while (0);
622
+ return Qnil;
623
+ }
624
+
625
+ static void
626
+ get_iconv_opt(struct rb_iconv_opt_t *opt, VALUE options)
627
+ {
628
+ opt->transliterate = Qundef;
629
+ opt->discard_ilseq = Qundef;
630
+ if (!NIL_P(options)) {
631
+ rb_block_call(options, rb_intern("each"), 0, 0, get_iconv_opt_i, (VALUE)opt);
632
+ }
633
+ }
634
+
635
+ #define iconv_ctl(self, func, val) (\
636
+ iconvctl(VALUE2ICONV(check_iconv(self)), func, (void *)&(val)) ? \
637
+ rb_sys_fail(#func) : (void)0)
638
+
532
639
  /*
533
640
  * Document-method: new
534
- * call-seq: Iconv.new(to, from)
641
+ * call-seq: Iconv.new(to, from, [options])
535
642
  *
536
643
  * Creates new code converter from a coding-system designated with +from+
537
644
  * to another one designated with +to+.
538
- *
645
+ *
539
646
  * === Parameters
540
647
  *
541
648
  * +to+:: encoding name for destination
542
649
  * +from+:: encoding name for source
650
+ * +options+:: options for converter
543
651
  *
544
652
  * === Exceptions
545
653
  *
@@ -548,19 +656,18 @@ iconv_s_allocate
548
656
  * SystemCallError:: if <tt>iconv_open(3)</tt> fails
549
657
  */
550
658
  static VALUE
551
- iconv_initialize
552
- #ifdef HAVE_PROTOTYPES
553
- (VALUE self, VALUE to, VALUE from)
554
- #else /* HAVE_PROTOTYPES */
555
- (self, to, from)
556
- VALUE self;
557
- VALUE to;
558
- VALUE from;
559
- #endif /* HAVE_PROTOTYPES */
659
+ iconv_initialize(int argc, VALUE *argv, VALUE self)
560
660
  {
661
+ VALUE to, from, options;
662
+ struct rb_iconv_opt_t opt;
663
+ int idx;
664
+
665
+ rb_scan_args(argc, argv, "21", &to, &from, &options);
666
+ get_iconv_opt(&opt, options);
561
667
  iconv_free(check_iconv(self));
562
668
  DATA_PTR(self) = NULL;
563
- DATA_PTR(self) = (void *)ICONV2VALUE(iconv_create(to, from));
669
+ DATA_PTR(self) = (void *)ICONV2VALUE(iconv_create(to, from, &opt, &idx));
670
+ if (idx >= 0) ENCODING_SET(self, idx);
564
671
  return self;
565
672
  }
566
673
 
@@ -573,19 +680,19 @@ iconv_initialize
573
680
  * returned from the block.
574
681
  */
575
682
  static VALUE
576
- iconv_s_open
577
- #ifdef HAVE_PROTOTYPES
578
- (VALUE self, VALUE to, VALUE from)
579
- #else /* HAVE_PROTOTYPES */
580
- (self, to, from)
581
- VALUE self;
582
- VALUE to;
583
- VALUE from;
584
- #endif /* HAVE_PROTOTYPES */
683
+ iconv_s_open(int argc, VALUE *argv, VALUE self)
585
684
  {
586
- VALUE cd = ICONV2VALUE(iconv_create(to, from));
685
+ VALUE to, from, options, cd;
686
+ struct rb_iconv_opt_t opt;
687
+ int idx;
688
+
689
+ rb_scan_args(argc, argv, "21", &to, &from, &options);
690
+ get_iconv_opt(&opt, options);
691
+ cd = ICONV2VALUE(iconv_create(to, from, &opt, &idx));
587
692
 
588
693
  self = Data_Wrap_Struct(self, NULL, ICONV_FREE, (void *)cd);
694
+ if (idx >= 0) ENCODING_SET(self, idx);
695
+
589
696
  if (rb_block_given_p()) {
590
697
  return rb_ensure(rb_yield, self, (VALUE(*)())iconv_finish, self);
591
698
  }
@@ -595,24 +702,19 @@ iconv_s_open
595
702
  }
596
703
 
597
704
  static VALUE
598
- iconv_s_convert
599
- #ifdef HAVE_PROTOTYPES
600
- (struct iconv_env_t* env)
601
- #else /* HAVE_PROTOTYPES */
602
- (env)
603
- struct iconv_env_t *env;
604
- #endif /* HAVE_PROTOTYPES */
705
+ iconv_s_convert(struct iconv_env_t* env)
605
706
  {
606
707
  VALUE last = 0;
607
708
 
608
709
  for (; env->argc > 0; --env->argc, ++env->argv) {
609
- VALUE s = iconv_convert(env->cd, last = *(env->argv), 0, -1, env);
710
+ VALUE s = iconv_convert(env->cd, last = *(env->argv),
711
+ 0, -1, env->toidx, env);
610
712
  env->append(env->ret, s);
611
713
  }
612
714
 
613
715
  if (!NIL_P(last)) {
614
- VALUE s = iconv_convert(env->cd, Qnil, 0, 0, env);
615
- if (RSTRING(s)->len)
716
+ VALUE s = iconv_convert(env->cd, Qnil, 0, 0, env->toidx, env);
717
+ if (RSTRING_LEN(s))
616
718
  env->append(env->ret, s);
617
719
  }
618
720
 
@@ -638,15 +740,7 @@ iconv_s_convert
638
740
  * Exceptions thrown by Iconv.new, Iconv.open and Iconv#iconv.
639
741
  */
640
742
  static VALUE
641
- iconv_s_iconv
642
- #ifdef HAVE_PROTOTYPES
643
- (int argc, VALUE *argv, VALUE self)
644
- #else /* HAVE_PROTOTYPES */
645
- (argc, argv, self)
646
- int argc;
647
- VALUE *argv;
648
- VALUE self;
649
- #endif /* HAVE_PROTOTYPES */
743
+ iconv_s_iconv(int argc, VALUE *argv, VALUE self)
650
744
  {
651
745
  struct iconv_env_t arg;
652
746
 
@@ -657,7 +751,7 @@ iconv_s_iconv
657
751
  arg.argv = argv + 2;
658
752
  arg.append = rb_ary_push;
659
753
  arg.ret = rb_ary_new2(argc);
660
- arg.cd = iconv_create(argv[0], argv[1]);
754
+ arg.cd = iconv_create(argv[0], argv[1], NULL, &arg.toidx);
661
755
  return rb_ensure(iconv_s_convert, (VALUE)&arg, iconv_free, ICONV2VALUE(arg.cd));
662
756
  }
663
757
 
@@ -670,13 +764,7 @@ iconv_s_iconv
670
764
  * See Iconv.iconv.
671
765
  */
672
766
  static VALUE
673
- iconv_s_conv
674
- #ifdef HAVE_PROTOTYPES
675
- (VALUE self, VALUE to, VALUE from, VALUE str)
676
- #else /* HAVE_PROTOTYPES */
677
- (self, to, from, str)
678
- VALUE self, to, from, str;
679
- #endif /* HAVE_PROTOTYPES */
767
+ iconv_s_conv(VALUE self, VALUE to, VALUE from, VALUE str)
680
768
  {
681
769
  struct iconv_env_t arg;
682
770
 
@@ -684,10 +772,94 @@ iconv_s_conv
684
772
  arg.argv = &str;
685
773
  arg.append = rb_str_append;
686
774
  arg.ret = rb_str_new(0, 0);
687
- arg.cd = iconv_create(to, from);
775
+ arg.cd = iconv_create(to, from, NULL, &arg.toidx);
688
776
  return rb_ensure(iconv_s_convert, (VALUE)&arg, iconv_free, ICONV2VALUE(arg.cd));
689
777
  }
690
778
 
779
+ /*
780
+ * Document-method: list
781
+ * call-seq: Iconv.list {|*aliases| ... }
782
+ *
783
+ * Iterates each alias sets.
784
+ */
785
+
786
+ #ifdef HAVE_ICONVLIST
787
+ struct iconv_name_list
788
+ {
789
+ unsigned int namescount;
790
+ const char *const *names;
791
+ VALUE array;
792
+ };
793
+
794
+ static VALUE
795
+ list_iconv_i(VALUE ptr)
796
+ {
797
+ struct iconv_name_list *p = (struct iconv_name_list *)ptr;
798
+ unsigned int i, namescount = p->namescount;
799
+ const char *const *names = p->names;
800
+ VALUE ary = rb_ary_new2(namescount);
801
+
802
+ for (i = 0; i < namescount; i++) {
803
+ rb_ary_push(ary, rb_str_new2(names[i]));
804
+ }
805
+ if (p->array) {
806
+ return rb_ary_push(p->array, ary);
807
+ }
808
+ return rb_yield(ary);
809
+ }
810
+
811
+ static int
812
+ list_iconv(unsigned int namescount, const char *const *names, void *data)
813
+ {
814
+ int *state = data;
815
+ struct iconv_name_list list;
816
+
817
+ list.namescount = namescount;
818
+ list.names = names;
819
+ list.array = ((VALUE *)data)[1];
820
+ rb_protect(list_iconv_i, (VALUE)&list, state);
821
+ return *state;
822
+ }
823
+ #endif
824
+
825
+ #if defined(HAVE_ICONVLIST) || defined(HAVE___ICONV_FREE_LIST)
826
+ static VALUE
827
+ iconv_s_list(void)
828
+ {
829
+ #ifdef HAVE_ICONVLIST
830
+ int state;
831
+ VALUE args[2];
832
+
833
+ args[1] = rb_block_given_p() ? 0 : rb_ary_new();
834
+ iconvlist(list_iconv, args);
835
+ state = *(int *)args;
836
+ if (state) rb_jump_tag(state);
837
+ if (args[1]) return args[1];
838
+ #elif defined(HAVE___ICONV_FREE_LIST)
839
+ char **list;
840
+ size_t sz, i;
841
+ VALUE ary;
842
+
843
+ if (__iconv_get_list(&list, &sz)) return Qnil;
844
+
845
+ ary = rb_ary_new2(sz);
846
+ for (i = 0; i < sz; i++) {
847
+ rb_ary_push(ary, rb_str_new2(list[i]));
848
+ }
849
+ __iconv_free_list(list, sz);
850
+
851
+ if (!rb_block_given_p())
852
+ return ary;
853
+ for (i = 0; i < RARRAY_LEN(ary); i++) {
854
+ rb_yield(RARRAY_PTR(ary)[i]);
855
+ }
856
+ #endif
857
+ return Qnil;
858
+ }
859
+ #else
860
+ #define iconv_s_list rb_f_notimplement
861
+ #endif
862
+
691
863
  /*
692
864
  * Document-method: close
693
865
  *
@@ -700,32 +872,20 @@ iconv_s_conv
700
872
  * its initial shift state.
701
873
  */
702
874
  static VALUE
703
- iconv_init_state
704
- #ifdef HAVE_PROTOTYPES
705
- (VALUE cd)
706
- #else /* HAVE_PROTOTYPES */
707
- (cd)
708
- VALUE cd;
709
- #endif /* HAVE_PROTOTYPES */
875
+ iconv_init_state(VALUE self)
710
876
  {
711
- return iconv_convert(VALUE2ICONV(cd), Qnil, 0, 0, NULL);
877
+ iconv_t cd = VALUE2ICONV((VALUE)DATA_PTR(self));
878
+ DATA_PTR(self) = NULL;
879
+ return iconv_convert(cd, Qnil, 0, 0, ENCODING_GET(self), NULL);
712
880
  }
713
881
 
714
882
  static VALUE
715
- iconv_finish
716
- #ifdef HAVE_PROTOTYPES
717
- (VALUE self)
718
- #else /* HAVE_PROTOTYPES */
719
- (self)
720
- VALUE self;
721
- #endif /* HAVE_PROTOTYPES */
883
+ iconv_finish(VALUE self)
722
884
  {
723
885
  VALUE cd = check_iconv(self);
724
886
 
725
887
  if (!cd) return Qnil;
726
- DATA_PTR(self) = NULL;
727
-
728
- return rb_ensure(iconv_init_state, cd, iconv_free, cd);
888
+ return rb_ensure(iconv_init_state, self, iconv_free, cd);
729
889
  }
730
890
 
731
891
  /*
@@ -756,34 +916,186 @@ iconv_finish
756
916
  * See the Iconv documentation.
757
917
  */
758
918
  static VALUE
759
- iconv_iconv
760
- #ifdef HAVE_PROTOTYPES
761
- (int argc, VALUE *argv, VALUE self)
762
- #else /* HAVE_PROTOTYPES */
763
- (argc, argv, self)
764
- int argc;
765
- VALUE *argv;
766
- VALUE self;
767
- #endif /* HAVE_PROTOTYPES */
919
+ iconv_iconv(int argc, VALUE *argv, VALUE self)
768
920
  {
769
921
  VALUE str, n1, n2;
770
922
  VALUE cd = check_iconv(self);
771
923
  long start = 0, length = 0, slen = 0;
772
924
 
773
925
  rb_scan_args(argc, argv, "12", &str, &n1, &n2);
774
- if (!NIL_P(str)) slen = RSTRING_LEN(StringValue(str));
926
+ if (!NIL_P(str)) {
927
+ VALUE n = rb_str_length(StringValue(str));
928
+ slen = NUM2LONG(n);
929
+ }
775
930
  if (argc != 2 || !RTEST(rb_range_beg_len(n1, &start, &length, slen, 0))) {
776
931
  if (NIL_P(n1) || ((start = NUM2LONG(n1)) < 0 ? (start += slen) >= 0 : start < slen)) {
777
- if (NIL_P(n2)) {
778
- length = -1;
779
- }
780
- else if ((length = NUM2LONG(n2)) >= slen - start) {
781
- length = slen - start;
782
- }
932
+ length = NIL_P(n2) ? -1 : NUM2LONG(n2);
933
+ }
934
+ }
935
+ if (start > 0 || length > 0) {
936
+ rb_encoding *enc = rb_enc_get(str);
937
+ const char *s = RSTRING_PTR(str), *e = s + RSTRING_LEN(str);
938
+ const char *ps = s;
939
+ if (start > 0) {
940
+ start = (ps = rb_enc_nth(s, e, start, enc)) - s;
941
+ }
942
+ if (length > 0) {
943
+ length = rb_enc_nth(ps, e, length, enc) - ps;
783
944
  }
784
945
  }
785
946
 
786
- return iconv_convert(VALUE2ICONV(cd), str, start, length, NULL);
947
+ return iconv_convert(VALUE2ICONV(cd), str, start, length, ENCODING_GET(self), NULL);
948
+ }
949
+
950
+ /*
951
+ * Document-method: conv
952
+ * call-seq: conv(str...)
953
+ *
954
+ * Equivalent to
955
+ *
956
+ * iconv(nil, str..., nil).join
957
+ */
958
+ static VALUE
959
+ iconv_conv(int argc, VALUE *argv, VALUE self)
960
+ {
961
+ iconv_t cd = VALUE2ICONV(check_iconv(self));
962
+ VALUE str, s;
963
+ int toidx = ENCODING_GET(self);
964
+
965
+ str = iconv_convert(cd, Qnil, 0, 0, toidx, NULL);
966
+ if (argc > 0) {
967
+ do {
968
+ s = iconv_convert(cd, *argv++, 0, -1, toidx, NULL);
969
+ if (RSTRING_LEN(s))
970
+ rb_str_buf_append(str, s);
971
+ } while (--argc);
972
+ s = iconv_convert(cd, Qnil, 0, 0, toidx, NULL);
973
+ if (RSTRING_LEN(s))
974
+ rb_str_buf_append(str, s);
975
+ }
976
+
977
+ return str;
978
+ }
979
+
980
+ #ifdef ICONV_TRIVIALP
981
+ /*
982
+ * Document-method: trivial?
983
+ * call-seq: trivial?
984
+ *
985
+ * Returns trivial flag.
986
+ */
987
+ static VALUE
988
+ iconv_trivialp(VALUE self)
989
+ {
990
+ int trivial = 0;
991
+ iconv_ctl(self, ICONV_TRIVIALP, trivial);
992
+ if (trivial) return Qtrue;
993
+ return Qfalse;
994
+ }
995
+ #else
996
+ #define iconv_trivialp rb_f_notimplement
997
+ #endif
998
+
999
+ #ifdef ICONV_GET_TRANSLITERATE
1000
+ /*
1001
+ * Document-method: transliterate?
1002
+ * call-seq: transliterate?
1003
+ *
1004
+ * Returns transliterate flag.
1005
+ */
1006
+ static VALUE
1007
+ iconv_get_transliterate(VALUE self)
1008
+ {
1009
+ int trans = 0;
1010
+ iconv_ctl(self, ICONV_GET_TRANSLITERATE, trans);
1011
+ if (trans) return Qtrue;
1012
+ return Qfalse;
1013
+ }
1014
+ #else
1015
+ #define iconv_get_transliterate rb_f_notimplement
1016
+ #endif
1017
+
1018
+ #ifdef ICONV_SET_TRANSLITERATE
1019
+ /*
1020
+ * Document-method: transliterate=
1021
+ * call-seq: cd.transliterate = flag
1022
+ *
1023
+ * Sets transliterate flag.
1024
+ */
1025
+ static VALUE
1026
+ iconv_set_transliterate(VALUE self, VALUE transliterate)
1027
+ {
1028
+ int trans = RTEST(transliterate);
1029
+ iconv_ctl(self, ICONV_SET_TRANSLITERATE, trans);
1030
+ return self;
1031
+ }
1032
+ #else
1033
+ #define iconv_set_transliterate rb_f_notimplement
1034
+ #endif
1035
+
1036
+ #ifdef ICONV_GET_DISCARD_ILSEQ
1037
+ /*
1038
+ * Document-method: discard_ilseq?
1039
+ * call-seq: discard_ilseq?
1040
+ *
1041
+ * Returns discard_ilseq flag.
1042
+ */
1043
+ static VALUE
1044
+ iconv_get_discard_ilseq(VALUE self)
1045
+ {
1046
+ int dis = 0;
1047
+ iconv_ctl(self, ICONV_GET_DISCARD_ILSEQ, dis);
1048
+ if (dis) return Qtrue;
1049
+ return Qfalse;
1050
+ }
1051
+ #else
1052
+ #define iconv_get_discard_ilseq rb_f_notimplement
1053
+ #endif
1054
+
1055
+ #ifdef ICONV_SET_DISCARD_ILSEQ
1056
+ /*
1057
+ * Document-method: discard_ilseq=
1058
+ * call-seq: cd.discard_ilseq = flag
1059
+ *
1060
+ * Sets discard_ilseq flag.
1061
+ */
1062
+ static VALUE
1063
+ iconv_set_discard_ilseq(VALUE self, VALUE discard_ilseq)
1064
+ {
1065
+ int dis = RTEST(discard_ilseq);
1066
+ iconv_ctl(self, ICONV_SET_DISCARD_ILSEQ, dis);
1067
+ return self;
1068
+ }
1069
+ #else
1070
+ #define iconv_set_discard_ilseq rb_f_notimplement
1071
+ #endif
1072
+
1073
+ /*
1074
+ * Document-method: ctlmethods
1075
+ * call-seq: Iconv.ctlmethods => array
1076
+ *
1077
+ * Returns available iconvctl() method list.
1078
+ */
1079
+ static VALUE
1080
+ iconv_s_ctlmethods(VALUE klass)
1081
+ {
1082
+ VALUE ary = rb_ary_new();
1083
+ #ifdef ICONV_TRIVIALP
1084
+ rb_ary_push(ary, ID2SYM(rb_intern("trivial?")));
1085
+ #endif
1086
+ #ifdef ICONV_GET_TRANSLITERATE
1087
+ rb_ary_push(ary, ID2SYM(rb_intern("transliterate?")));
1088
+ #endif
1089
+ #ifdef ICONV_SET_TRANSLITERATE
1090
+ rb_ary_push(ary, ID2SYM(rb_intern("transliterate=")));
1091
+ #endif
1092
+ #ifdef ICONV_GET_DISCARD_ILSEQ
1093
+ rb_ary_push(ary, ID2SYM(rb_intern("discard_ilseq?")));
1094
+ #endif
1095
+ #ifdef ICONV_SET_DISCARD_ILSEQ
1096
+ rb_ary_push(ary, ID2SYM(rb_intern("discard_ilseq=")));
1097
+ #endif
1098
+ return ary;
787
1099
  }
788
1100
 
789
1101
  /*
@@ -802,13 +1114,7 @@ iconv_iconv
802
1114
  * failure and the last element is string on the way.
803
1115
  */
804
1116
  static VALUE
805
- iconv_failure_success
806
- #ifdef HAVE_PROTOTYPES
807
- (VALUE self)
808
- #else /* HAVE_PROTOTYPES */
809
- (self)
810
- VALUE self;
811
- #endif /* HAVE_PROTOTYPES */
1117
+ iconv_failure_success(VALUE self)
812
1118
  {
813
1119
  return rb_attr_get(self, rb_success);
814
1120
  }
@@ -818,16 +1124,10 @@ iconv_failure_success
818
1124
  * call-seq: failed
819
1125
  *
820
1126
  * Returns substring of the original string passed to Iconv that starts at the
821
- * character caused the exception.
1127
+ * character caused the exception.
822
1128
  */
823
1129
  static VALUE
824
- iconv_failure_failed
825
- #ifdef HAVE_PROTOTYPES
826
- (VALUE self)
827
- #else /* HAVE_PROTOTYPES */
828
- (self)
829
- VALUE self;
830
- #endif /* HAVE_PROTOTYPES */
1130
+ iconv_failure_failed(VALUE self)
831
1131
  {
832
1132
  return rb_attr_get(self, rb_failed);
833
1133
  }
@@ -839,13 +1139,7 @@ iconv_failure_failed
839
1139
  * Returns inspected string like as: #<_class_: _success_, _failed_>
840
1140
  */
841
1141
  static VALUE
842
- iconv_failure_inspect
843
- #ifdef HAVE_PROTOTYPES
844
- (VALUE self)
845
- #else /* HAVE_PROTOTYPES */
846
- (self)
847
- VALUE self;
848
- #endif /* HAVE_PROTOTYPES */
1142
+ iconv_failure_inspect(VALUE self)
849
1143
  {
850
1144
  const char *cname = rb_class2name(CLASS_OF(self));
851
1145
  VALUE success = rb_attr_get(self, rb_success);
@@ -860,13 +1154,13 @@ iconv_failure_inspect
860
1154
 
861
1155
  /*
862
1156
  * Document-class: Iconv::InvalidEncoding
863
- *
1157
+ *
864
1158
  * Requested coding-system is not available on this system.
865
1159
  */
866
1160
 
867
1161
  /*
868
1162
  * Document-class: Iconv::IllegalSequence
869
- *
1163
+ *
870
1164
  * Input conversion stopped due to an input byte that does not belong to
871
1165
  * the input codeset, or the output codeset does not contain the
872
1166
  * character.
@@ -874,36 +1168,44 @@ iconv_failure_inspect
874
1168
 
875
1169
  /*
876
1170
  * Document-class: Iconv::InvalidCharacter
877
- *
1171
+ *
878
1172
  * Input conversion stopped due to an incomplete character or shift
879
1173
  * sequence at the end of the input buffer.
880
1174
  */
881
1175
 
882
1176
  /*
883
1177
  * Document-class: Iconv::OutOfRange
884
- *
1178
+ *
885
1179
  * Iconv library internal error. Must not occur.
886
1180
  */
887
1181
 
888
1182
  /*
889
1183
  * Document-class: Iconv::BrokenLibrary
890
- *
1184
+ *
891
1185
  * Detected a bug of underlying iconv(3) libray.
892
1186
  * * returns an error without setting errno properly
893
1187
  */
894
1188
 
895
1189
  void
896
- Init_iconv _((void))
1190
+ Init_iconv(void)
897
1191
  {
898
1192
  VALUE rb_cIconv = rb_define_class("Iconv", rb_cData);
899
1193
 
900
1194
  rb_define_alloc_func(rb_cIconv, iconv_s_allocate);
901
- rb_define_singleton_method(rb_cIconv, "open", iconv_s_open, 2);
1195
+ rb_define_singleton_method(rb_cIconv, "open", iconv_s_open, -1);
902
1196
  rb_define_singleton_method(rb_cIconv, "iconv", iconv_s_iconv, -1);
903
1197
  rb_define_singleton_method(rb_cIconv, "conv", iconv_s_conv, 3);
904
- rb_define_method(rb_cIconv, "initialize", iconv_initialize, 2);
1198
+ rb_define_singleton_method(rb_cIconv, "list", iconv_s_list, 0);
1199
+ rb_define_singleton_method(rb_cIconv, "ctlmethods", iconv_s_ctlmethods, 0);
1200
+ rb_define_method(rb_cIconv, "initialize", iconv_initialize, -1);
905
1201
  rb_define_method(rb_cIconv, "close", iconv_finish, 0);
906
1202
  rb_define_method(rb_cIconv, "iconv", iconv_iconv, -1);
1203
+ rb_define_method(rb_cIconv, "conv", iconv_conv, -1);
1204
+ rb_define_method(rb_cIconv, "trivial?", iconv_trivialp, 0);
1205
+ rb_define_method(rb_cIconv, "transliterate?", iconv_get_transliterate, 0);
1206
+ rb_define_method(rb_cIconv, "transliterate=", iconv_set_transliterate, 1);
1207
+ rb_define_method(rb_cIconv, "discard_ilseq?", iconv_get_discard_ilseq, 0);
1208
+ rb_define_method(rb_cIconv, "discard_ilseq=", iconv_set_discard_ilseq, 1);
907
1209
 
908
1210
  rb_eIconvFailure = rb_define_module_under(rb_cIconv, "Failure");
909
1211
  rb_define_method(rb_eIconvFailure, "initialize", iconv_failure_initialize, 3);
@@ -924,8 +1226,11 @@ Init_iconv _((void))
924
1226
 
925
1227
  rb_success = rb_intern("success");
926
1228
  rb_failed = rb_intern("failed");
1229
+ id_transliterate = rb_intern("transliterate");
1230
+ id_discard_ilseq = rb_intern("discard_ilseq");
927
1231
 
928
1232
  rb_gc_register_address(&charset_map);
929
1233
  charset_map = rb_hash_new();
930
1234
  rb_define_singleton_method(rb_cIconv, "charset_map", charset_map_get, 0);
931
1235
  }
1236
+