aboutsummaryrefslogtreecommitdiffstats
path: root/transcode.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-18 12:06:42 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-18 12:06:42 +0000
commit035d4816c3782eca70464fa553b968dc46adee53 (patch)
tree6d4afdf333976a87b4f0de7ef667c8e4603277f9 /transcode.c
parent89b4f06a596e993a82630913f085a82265cb499c (diff)
downloadruby-035d4816c3782eca70464fa553b968dc46adee53.tar.gz
* include/ruby/io.h (rb_io_t): new fields: writeconv,
writeconv_stateless and writeconv_initialized. (MakeOpenFile): initialize them. * include/ruby/encoding.h (rb_econv_stateless_encoding): declared. (rb_econv_string): declared. * io.c (make_writeconv): new function. (io_fwrite): use econv. (make_readconv): fix error message. (finish_writeconv): new function. (fptr_finalize): call finish_writeconv. (clear_writeconv): new function. (clear_codeconv): new function to call both clear_readconv and clear_writeconv. (rb_io_fptr_finalize): call clear_codeconv instead of clear_readconv. (mode_enc): ditto. (io_set_encoding): ditto. (argf_next_argv): ditto. (io_encoding_set): ditto. * gc.c (gc_mark_children): mark writeconv_stateless in T_FILE. * transcode.c (stateless_encoding_i): new function. (rb_econv_stateless_encoding): ditto. (rb_econv_string): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18691 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'transcode.c')
-rw-r--r--transcode.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/transcode.c b/transcode.c
index 33b1c7fc96..6ef4e84040 100644
--- a/transcode.c
+++ b/transcode.c
@@ -1219,6 +1219,78 @@ rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
tc->readagain_len -= n;
}
+struct stateless_encoding_t {
+ const char *stateless_enc;
+ const char *stateful_enc;
+};
+
+static int
+stateless_encoding_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ struct stateless_encoding_t *data = (struct stateless_encoding_t *)arg;
+ st_table *table2 = (st_table *)val;
+ st_data_t v;
+
+ if (st_lookup(table2, (st_data_t)data->stateful_enc, &v)) {
+ transcoder_entry_t *entry = (transcoder_entry_t *)v;
+ const rb_transcoder *tr = load_transcoder_entry(entry);
+ if (tr && tr->stateful_type == stateful_encoder) {
+ data->stateless_enc = tr->from_encoding;
+ return ST_STOP;
+ }
+ }
+ return ST_CONTINUE;
+}
+
+const char *
+rb_econv_stateless_encoding(const char *stateful_enc)
+{
+ struct stateless_encoding_t data;
+ data.stateful_enc = stateful_enc;
+ data.stateless_enc = NULL;
+ st_foreach(transcoder_table, stateless_encoding_i, (st_data_t)&data);
+ if (data.stateless_enc)
+ return data.stateless_enc;
+ return NULL;
+}
+
+VALUE
+rb_econv_string(rb_econv_t *ec, VALUE src, long off, long len, VALUE dst, int flags)
+{
+ unsigned const char *ss, *sp, *se;
+ unsigned char *ds, *dp, *de;
+ rb_econv_result_t res;
+
+ if (NIL_P(dst)) {
+ dst = rb_str_buf_new(len);
+ }
+
+ res = econv_destination_buffer_full;
+ while (res == econv_destination_buffer_full) {
+ long dlen = RSTRING_LEN(dst);
+ int max_output = ec->last_tc->transcoder->max_output;
+ if (rb_str_capacity(dst) - dlen < (size_t)len + max_output) {
+ unsigned long new_capa = (unsigned long)dlen + len + max_output;
+ if (LONG_MAX < new_capa)
+ rb_raise(rb_eArgError, "too long string");
+ rb_str_resize(dst, new_capa);
+ rb_str_set_len(dst, dlen);
+ }
+ ss = sp = (const unsigned char *)RSTRING_PTR(src) + off;
+ se = ss + len;
+ ds = dp = (unsigned char *)RSTRING_PTR(dst) + dlen;
+ de = ds + rb_str_capacity(dst);
+ res = rb_econv_convert(ec, &sp, se, &dp, de, flags);
+ off += sp - ss;
+ len -= sp - ss;
+ rb_str_set_len(dst, dlen + (dp - ds));
+ rb_econv_check_error(ec);
+ }
+
+ return dst;
+}
+
+
static VALUE
make_econv_exception(rb_econv_t *ec)
{