static VALUE bubblebabble_str_new(VALUE str_digest) { char *digest; size_t digest_len; VALUE str; char *p; size_t i, j, seed = 1; static const char vowels[] = { 'a', 'e', 'i', 'o', 'u', 'y' }; static const char consonants[] = { 'b', 'c', 'd', 'f', 'g', 'h', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'v', 'z', 'x' }; StringValue(str_digest); digest = RSTRING_PTR(str_digest); digest_len = RSTRING_LEN(str_digest); if ((LONG_MAX - 2) / 3 < (digest_len | 1)) { rb_raise(rb_eRuntimeError, "digest string too long"); } str = rb_str_new(0, (digest_len | 1) * 3 + 2); p = RSTRING_PTR(str); i = j = 0; p[j++] = 'x'; for (;;) { unsigned char byte1, byte2; if (i >= digest_len) { p[j++] = vowels[seed % 6]; p[j++] = consonants[16]; p[j++] = vowels[seed / 6]; break; } byte1 = digest[i++]; p[j++] = vowels[(((byte1 >> 6) & 3) + seed) % 6]; p[j++] = consonants[(byte1 >> 2) & 15]; p[j++] = vowels[((byte1 & 3) + (seed / 6)) % 6]; if (i >= digest_len) { break; } byte2 = digest[i++]; p[j++] = consonants[(byte2 >> 4) & 15]; p[j++] = '-'; p[j++] = consonants[byte2 & 15]; seed = (seed * 5 + byte1 * 7 + byte2) % 36; } p[j] = 'x'; return str; }
static int rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn) { VALUE features, this_feature_index = Qnil, v, p, load_path = 0; const char *f, *e; long i, len, elen, n; st_table *loading_tbl, *features_index; st_data_t data; int type; if (fn) *fn = 0; if (ext) { elen = strlen(ext); len = strlen(feature) - elen; type = rb ? 'r' : 's'; } else { len = strlen(feature); elen = 0; type = 0; } features = get_loaded_features(); features_index = get_loaded_features_index(); st_lookup(features_index, (st_data_t)feature, (st_data_t *)&this_feature_index); /* We search `features` for an entry such that either "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}" for some j, or "#{features[i]}" == "#{feature}#{e}" Here `e` is an "allowed" extension -- either empty or one of the extensions accepted by IS_RBEXT, IS_SOEXT, or IS_DLEXT. Further, if `ext && rb` then `IS_RBEXT(e)`, and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`. If `expanded`, then only the latter form (without load_path[j]) is accepted. Otherwise either form is accepted, *unless* `ext` is false and an otherwise-matching entry of the first form is preceded by an entry of the form "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}" where `e2` matches %r{^\.[^./]*$} but is not an allowed extension. After a "distractor" entry of this form, only entries of the form "#{feature}#{e}" are accepted. In `rb_provide_feature()` and `get_loaded_features_index()` we maintain an invariant that the array `this_feature_index` will point to every entry in `features` which has the form "#{prefix}#{feature}#{e}" where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty or ends in '/'. This includes both match forms above, as well as any distractors, so we may ignore all other entries in `features`. */ if (!NIL_P(this_feature_index)) { for (i = 0; ; i++) { VALUE entry; long index; if (RB_TYPE_P(this_feature_index, T_ARRAY)) { if (i >= RARRAY_LEN(this_feature_index)) break; entry = RARRAY_AREF(this_feature_index, i); } else { if (i > 0) break; entry = this_feature_index; } index = FIX2LONG(entry); v = RARRAY_AREF(features, index); f = StringValuePtr(v); if ((n = RSTRING_LEN(v)) < len) continue; if (strncmp(f, feature, len) != 0) { if (expanded) continue; if (!load_path) load_path = rb_get_expanded_load_path(); if (!(p = loaded_feature_path(f, n, feature, len, type, load_path))) continue; expanded = 1; f += RSTRING_LEN(p) + 1; } if (!*(e = f + len)) { if (ext) continue; return 'u'; } if (*e != '.') continue; if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) { return 's'; } if ((rb || !ext) && (IS_RBEXT(e))) { return 'r'; } } } loading_tbl = get_loading_table(); if (loading_tbl) { f = 0; if (!expanded) { struct loaded_feature_searching fs; fs.name = feature; fs.len = len; fs.type = type; fs.load_path = load_path ? load_path : rb_get_expanded_load_path(); fs.result = 0; st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs); if ((f = fs.result) != 0) { if (fn) *fn = f; goto loading; } } if (st_get_key(loading_tbl, (st_data_t)feature, &data)) { if (fn) *fn = (const char*)data; loading: if (!ext) return 'u'; return !IS_RBEXT(ext) ? 's' : 'r'; } else { VALUE bufstr; char *buf; static const char so_ext[][4] = { ".so", ".o", }; if (ext && *ext) return 0; bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN); buf = RSTRING_PTR(bufstr); MEMCPY(buf, feature, char, len); for (i = 0; (e = loadable_ext[i]) != 0; i++) { strlcpy(buf + len, e, DLEXT_MAXLEN + 1); if (st_get_key(loading_tbl, (st_data_t)buf, &data)) { rb_str_resize(bufstr, 0); if (fn) *fn = (const char*)data; return i ? 's' : 'r'; } } for (i = 0; i < numberof(so_ext); i++) { strlcpy(buf + len, so_ext[i], DLEXT_MAXLEN + 1); if (st_get_key(loading_tbl, (st_data_t)buf, &data)) { rb_str_resize(bufstr, 0); if (fn) *fn = (const char*)data; return 's'; } } rb_str_resize(bufstr, 0); } } return 0; }
mrb_value mrb_check_intern_str(mrb_state *mrb, mrb_value str) { return mrb_check_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); }
VALUE string_spec_RSTRING_LEN(VALUE self, VALUE str) { return INT2FIX(RSTRING_LEN(str)); }
VALUE rb_thrift_memory_buffer_write(VALUE self, VALUE str) { VALUE buf = GET_BUF(self); rb_str_buf_cat(buf, RSTRING_PTR(str), RSTRING_LEN(str)); return Qnil; }
static grn_table_cursor * rb_grn_patricia_trie_open_grn_prefix_cursor (int argc, VALUE *argv, VALUE self, grn_ctx **context) { grn_obj *table; grn_table_cursor *cursor; void *prefix = NULL; unsigned prefix_size = 0; int offset = 0, limit = -1; int flags = GRN_CURSOR_PREFIX; VALUE options, rb_prefix, rb_key_bytes, rb_key_bits; VALUE rb_order, rb_order_by; VALUE rb_greater_than, rb_less_than, rb_offset, rb_limit; rb_grn_table_deconstruct((RbGrnTable *)SELF(self), &table, context, NULL, NULL, NULL, NULL, NULL, NULL); rb_scan_args(argc, argv, "11", &rb_prefix, &options); rb_grn_scan_options(options, "key_bytes", &rb_key_bytes, "key_bites", &rb_key_bits, "offset", &rb_offset, "limit", &rb_limit, "order", &rb_order, "order_by", &rb_order_by, "greater_than", &rb_greater_than, "less_than", &rb_less_than, NULL); prefix = StringValuePtr(rb_prefix); if (!NIL_P(rb_key_bytes) && !NIL_P(rb_key_bits)) { rb_raise(rb_eArgError, "should not specify both :key_bytes and :key_bits once: %s", rb_grn_inspect(rb_ary_new4(argc, argv))); } else if (!NIL_P(rb_key_bytes)) { prefix_size = NUM2UINT(rb_key_bytes); } else if (!NIL_P(rb_key_bits)) { prefix_size = NUM2UINT(rb_key_bits); flags |= GRN_CURSOR_SIZE_BY_BIT; } else { prefix_size = RSTRING_LEN(rb_prefix); } if (!NIL_P(rb_offset)) offset = NUM2INT(rb_offset); if (!NIL_P(rb_limit)) limit = NUM2INT(rb_limit); if (NIL_P(rb_order)) { } else if (rb_grn_equal_option(rb_order, "asc") || rb_grn_equal_option(rb_order, "ascending")) { flags |= GRN_CURSOR_ASCENDING; } else if (rb_grn_equal_option(rb_order, "desc") || rb_grn_equal_option(rb_order, "descending")) { flags |= GRN_CURSOR_DESCENDING; } else { rb_raise(rb_eArgError, "order should be one of " "[:asc, :ascending, :desc, :descending]: %s", rb_grn_inspect(rb_order)); } if (NIL_P(rb_order_by)) { } else if (rb_grn_equal_option(rb_order_by, "id")) { flags |= GRN_CURSOR_BY_ID; } else if (rb_grn_equal_option(rb_order_by, "key")) { if (table->header.type != GRN_TABLE_PAT_KEY) { rb_raise(rb_eArgError, "order_by => :key is available " "only for Groonga::PatriciaTrie: %s", rb_grn_inspect(self)); } flags |= GRN_CURSOR_BY_KEY; } else { rb_raise(rb_eArgError, "order_by should be one of [:id%s]: %s", table->header.type == GRN_TABLE_PAT_KEY ? ", :key" : "", rb_grn_inspect(rb_order_by)); } if (RVAL2CBOOL(rb_greater_than)) flags |= GRN_CURSOR_GT; if (RVAL2CBOOL(rb_less_than)) flags |= GRN_CURSOR_LT; cursor = grn_table_cursor_open(*context, table, prefix, prefix_size, NULL, 0, offset, limit, flags); rb_grn_context_check(*context, self); return cursor; }
VALUE string_spec_rb_external_str_new(VALUE self, VALUE str) { return rb_external_str_new(RSTRING_PTR(str), RSTRING_LEN(str)); }
/** * RubyWatchman.query(query, socket) * * Converts `query`, a Watchman query comprising Ruby objects, into the Watchman * binary protocol format, transmits it over socket, and unserializes and * returns the result. */ VALUE RubyWatchman_query(VALUE self, VALUE query, VALUE socket) { VALUE error = Qnil; VALUE errorClass = Qnil; VALUE loaded = Qnil; void *buffer = NULL; int fileno = NUM2INT(rb_funcall(socket, rb_intern("fileno"), 0)); // do blocking I/O to simplify the following logic int flags = fcntl(fileno, F_GETFL); if ( !(flags & O_NONBLOCK) && fcntl(fileno, F_SETFL, flags & ~O_NONBLOCK) == -1 ) { error = rb_str_new2("unable to clear O_NONBLOCK flag"); goto cleanup; } // send the message VALUE serialized = RubyWatchman_dump(self, query); long query_len = RSTRING_LEN(serialized); ssize_t sent = send(fileno, RSTRING_PTR(serialized), query_len, 0); if (sent == -1) { goto system_call_fail; } else if (sent != query_len) { error = rb_str_new2("sent byte count mismatch"); goto cleanup; } // sniff to see how large the header is int8_t peek[WATCHMAN_PEEK_BUFFER_SIZE]; ssize_t received = recv(fileno, peek, WATCHMAN_SNIFF_BUFFER_SIZE, MSG_PEEK | MSG_WAITALL); if (received == -1) { goto system_call_fail; } else if (received != WATCHMAN_SNIFF_BUFFER_SIZE) { error = rb_str_new2("failed to sniff PDU header"); goto cleanup; } // peek at size of PDU int8_t sizes[] = { 0, 0, 0, 1, 2, 4, 8 }; int8_t sizes_idx = peek[sizeof(WATCHMAN_BINARY_MARKER) - 1]; if (sizes_idx < WATCHMAN_INT8_MARKER || sizes_idx > WATCHMAN_INT64_MARKER) { error = rb_str_new2("bad PDU size marker"); goto cleanup; } ssize_t peek_size = sizeof(WATCHMAN_BINARY_MARKER) - 1 + sizeof(int8_t) + sizes[sizes_idx]; received = recv(fileno, peek, peek_size, MSG_PEEK); if (received == -1) { goto system_call_fail; } else if (received != peek_size) { error = rb_str_new2("failed to peek at PDU header"); goto cleanup; } int8_t *pdu_size_ptr = peek + sizeof(WATCHMAN_BINARY_MARKER) - sizeof(int8_t); int64_t payload_size = peek_size + watchman_load_int((char **)&pdu_size_ptr, (char *)peek + peek_size); // actually read the PDU buffer = xmalloc(payload_size); if (!buffer) { errorClass = rb_eNoMemError; error = rb_str_new2("failed to allocate"); goto cleanup; } received = recv(fileno, buffer, payload_size, MSG_WAITALL); if (received == -1) { goto system_call_fail; } else if (received != payload_size) { error = rb_str_new2("failed to load PDU"); goto cleanup; } if (!(flags & O_NONBLOCK) && fcntl(fileno, F_SETFL, flags) == -1) { error = rb_str_new2("unable to restore fnctl flags"); goto cleanup; } char *payload = buffer + peek_size; loaded = watchman_load(&payload, payload + payload_size); goto cleanup; system_call_fail: errorClass = rb_eSystemCallError; error = INT2FIX(errno); cleanup: if (buffer) { xfree(buffer); } if (!(flags & O_NONBLOCK) && fcntl(fileno, F_SETFL, flags) == -1) { rb_raise(rb_eRuntimeError, "unable to restore fnctl flags"); } if (NIL_P(errorClass)) { errorClass = rb_eRuntimeError; } if (!NIL_P(error)) { rb_exc_raise(rb_class_new_instance(1, &error, errorClass)); } return loaded; }
// based on https://gist.github.com/3066997 static mrb_value migrate_simple_value(mrb_state *mrb, mrb_value v, mrb_state *mrb2) { mrb_value nv = mrb_nil_value(); nv.tt = v.tt; switch (mrb_type(v)) { case MRB_TT_OBJECT: nv.value.p = v.value.p; break; case MRB_TT_FALSE: case MRB_TT_TRUE: case MRB_TT_FIXNUM: nv.value.i = v.value.i; break; case MRB_TT_SYMBOL: nv = mrb_symbol_value(mrb_intern_str(mrb2, v)); break; case MRB_TT_FLOAT: nv.value.f = v.value.f; break; case MRB_TT_STRING: nv = mrb_str_new(mrb2, RSTRING_PTR(v), RSTRING_LEN(v)); break; case MRB_TT_ARRAY: { struct RArray *a0, *a1; int i; a0 = mrb_ary_ptr(v); nv = mrb_ary_new_capa(mrb2, a0->len); a1 = mrb_ary_ptr(nv); for (i=0; i<a0->len; i++) { int ai = mrb_gc_arena_save(mrb2); a1->ptr[i] = migrate_simple_value(mrb, a0->ptr[i], mrb2); a1->len++; mrb_gc_arena_restore(mrb2, ai); } } break; case MRB_TT_HASH: { mrb_value ka; int i, l; nv = mrb_hash_new(mrb2); ka = mrb_hash_keys(mrb, v); l = RARRAY_LEN(ka); for (i = 0; i < l; i++) { int ai = mrb_gc_arena_save(mrb2); mrb_value k = migrate_simple_value(mrb, mrb_ary_entry(ka, i), mrb2); mrb_value o = migrate_simple_value(mrb, mrb_hash_get(mrb, v, k), mrb2); mrb_hash_set(mrb2, nv, k, o); mrb_gc_arena_restore(mrb2, ai); } } break; default: mrb_raise(mrb, E_TYPE_ERROR, "cannot migrate object"); break; } return nv; }
static void codedump(mrb_state *mrb, mrb_irep *irep) { int ai; mrb_code *pc, *pcend; mrb_code ins; const char *file = NULL, *next_file; if (!irep) return; printf("irep %p nregs=%d nlocals=%d pools=%d syms=%d reps=%d iseq=%d\n", (void*)irep, irep->nregs, irep->nlocals, (int)irep->plen, (int)irep->slen, (int)irep->rlen, (int)irep->ilen); if (irep->lv) { int i; printf("local variable names:\n"); for (i = 1; i < irep->nlocals; ++i) { char const *s = mrb_sym2name(mrb, irep->lv[i - 1].name); int n = irep->lv[i - 1].r ? irep->lv[i - 1].r : i; printf(" R%d:%s\n", n, s ? s : ""); } } pc = irep->iseq; pcend = pc + irep->ilen; while (pc < pcend) { ptrdiff_t i; uint32_t a; uint16_t b; uint8_t c; ai = mrb_gc_arena_save(mrb); i = pc - irep->iseq; next_file = mrb_debug_get_filename(mrb, irep, i); if (next_file && file != next_file) { printf("file: %s\n", next_file); file = next_file; } print_header(mrb, irep, i); ins = READ_B(); switch (ins) { CASE(OP_NOP, Z): printf("OP_NOP\n"); break; CASE(OP_MOVE, BB): printf("OP_MOVE\tR%d\tR%d\t", a, b); print_lv_ab(mrb, irep, a, b); break; CASE(OP_LOADL, BB): { mrb_value v = irep->pool[b]; mrb_value s = mrb_inspect(mrb, v); printf("OP_LOADL\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); } print_lv_a(mrb, irep, a); break; CASE(OP_LOADI, BB): printf("OP_LOADI\tR%d\t%d\t", a, b); print_lv_a(mrb, irep, a); break; CASE(OP_LOADINEG, BB): printf("OP_LOADI\tR%d\t-%d\t", a, b); print_lv_a(mrb, irep, a); break; CASE(OP_LOADI__1, B): printf("OP_LOADI__1\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_LOADI_0, B): goto L_LOADI; CASE(OP_LOADI_1, B): goto L_LOADI; CASE(OP_LOADI_2, B): goto L_LOADI; CASE(OP_LOADI_3, B): goto L_LOADI; CASE(OP_LOADI_4, B): goto L_LOADI; CASE(OP_LOADI_5, B): goto L_LOADI; CASE(OP_LOADI_6, B): goto L_LOADI; CASE(OP_LOADI_7, B): L_LOADI: printf("OP_LOADI_%d\tR%d\t\t", ins-(int)OP_LOADI_0, a); print_lv_a(mrb, irep, a); break; CASE(OP_LOADSYM, BB): printf("OP_LOADSYM\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_LOADNIL, B): printf("OP_LOADNIL\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_LOADSELF, B): printf("OP_LOADSELF\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_LOADT, B): printf("OP_LOADT\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_LOADF, B): printf("OP_LOADF\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_GETGV, BB): printf("OP_GETGV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETGV, BB): printf("OP_SETGV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_GETSV, BB): printf("OP_GETSV\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETSV, BB): printf("OP_SETSV\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_GETCONST, BB): printf("OP_GETCONST\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETCONST, BB): printf("OP_SETCONST\t:%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_GETMCNST, BB): printf("OP_GETMCNST\tR%d\tR%d::%s", a, a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETMCNST, BB): printf("OP_SETMCNST\tR%d::%s\tR%d", a+1, mrb_sym2name(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_GETIV, BB): printf("OP_GETIV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETIV, BB): printf("OP_SETIV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_GETUPVAR, BBB): printf("OP_GETUPVAR\tR%d\t%d\t%d", a, b, c); print_lv_a(mrb, irep, a); break; CASE(OP_SETUPVAR, BBB): printf("OP_SETUPVAR\tR%d\t%d\t%d", a, b, c); print_lv_a(mrb, irep, a); break; CASE(OP_GETCV, BB): printf("OP_GETCV\tR%d\t%s", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_SETCV, BB): printf("OP_SETCV\t%s\tR%d", mrb_sym2name(mrb, irep->syms[b]), a); print_lv_a(mrb, irep, a); break; CASE(OP_JMP, S): printf("OP_JMP\t\t%03d\n", a); break; CASE(OP_JMPIF, BS): printf("OP_JMPIF\tR%d\t%03d\t", a, b); print_lv_a(mrb, irep, a); break; CASE(OP_JMPNOT, BS): printf("OP_JMPNOT\tR%d\t%03d\t", a, b); print_lv_a(mrb, irep, a); break; CASE(OP_JMPNIL, BS): printf("OP_JMPNIL\tR%d\t%03d\t", a, b); print_lv_a(mrb, irep, a); break; CASE(OP_SENDV, BB): printf("OP_SENDV\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); break; CASE(OP_SENDVB, BB): printf("OP_SENDVB\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); break; CASE(OP_SEND, BBB): printf("OP_SEND\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); break; CASE(OP_SENDB, BBB): printf("OP_SENDB\tR%d\t:%s\t%d\n", a, mrb_sym2name(mrb, irep->syms[b]), c); break; CASE(OP_CALL, Z): printf("OP_CALL\n"); break; CASE(OP_SUPER, BB): printf("OP_SUPER\tR%d\t%d\n", a, b); break; CASE(OP_ARGARY, BS): printf("OP_ARGARY\tR%d\t%d:%d:%d:%d (%d)", a, (b>>11)&0x3f, (b>>10)&0x1, (b>>5)&0x1f, (b>>4)&0x1, (b>>0)&0xf); print_lv_a(mrb, irep, a); break; CASE(OP_ENTER, W): printf("OP_ENTER\t%d:%d:%d:%d:%d:%d:%d\n", (a>>18)&0x1f, (a>>13)&0x1f, (a>>12)&0x1, (a>>7)&0x1f, (a>>2)&0x1f, (a>>1)&0x1, a & 0x1); break; CASE(OP_KEY_P, BB): printf("OP_KEY_P\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_KEYEND, Z): printf("OP_KEYEND\n"); break; CASE(OP_KARG, BB): printf("OP_KARG\tR%d\t:%s\t", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_RETURN, B): printf("OP_RETURN\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_RETURN_BLK, B): printf("OP_RETURN_BLK\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_BREAK, B): printf("OP_BREAK\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_BLKPUSH, BS): printf("OP_BLKPUSH\tR%d\t%d:%d:%d:%d (%d)", a, (b>>11)&0x3f, (b>>10)&0x1, (b>>5)&0x1f, (b>>4)&0x1, (b>>0)&0xf); print_lv_a(mrb, irep, a); break; CASE(OP_LAMBDA, BB): printf("OP_LAMBDA\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); break; CASE(OP_BLOCK, BB): printf("OP_BLOCK\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); break; CASE(OP_METHOD, BB): printf("OP_METHOD\tR%d\tI(%d:%p)\n", a, b, irep->reps[b]); break; CASE(OP_RANGE_INC, B): printf("OP_RANGE_INC\tR%d\n", a); break; CASE(OP_RANGE_EXC, B): printf("OP_RANGE_EXC\tR%d\n", a); break; CASE(OP_DEF, BB): printf("OP_DEF\tR%d\t:%s\n", a, mrb_sym2name(mrb, irep->syms[b])); break; CASE(OP_UNDEF, B): printf("OP_UNDEF\t:%s\n", mrb_sym2name(mrb, irep->syms[a])); break; CASE(OP_ALIAS, BB): printf("OP_ALIAS\t:%s\t%s\n", mrb_sym2name(mrb, irep->syms[a]), mrb_sym2name(mrb, irep->syms[b])); break; CASE(OP_ADD, B): printf("OP_ADD\tR%d\t\n", a); break; CASE(OP_ADDI, BB): printf("OP_ADDI\tR%d\t%d\n", a, b); break; CASE(OP_SUB, B): printf("OP_SUB\tR%d\t\n", a); break; CASE(OP_SUBI, BB): printf("OP_SUBI\tR%d\t%d\n", a, b); break; CASE(OP_MUL, B): printf("OP_MUL\tR%d\t\n", a); break; CASE(OP_DIV, B): printf("OP_DIV\tR%d\t\n", a); break; CASE(OP_LT, B): printf("OP_LT\t\tR%d\t\n", a); break; CASE(OP_LE, B): printf("OP_LE\t\tR%d\t\n", a); break; CASE(OP_GT, B): printf("OP_GT\t\tR%d\t\n", a); break; CASE(OP_GE, B): printf("OP_GE\t\tR%d\t\n", a); break; CASE(OP_EQ, B): printf("OP_EQ\t\tR%d\t\n", a); break; CASE(OP_ARRAY, BB): printf("OP_ARRAY\tR%d\t%d\t", a, b); print_lv_a(mrb, irep, a); break; CASE(OP_ARRAY2, BBB): printf("OP_ARRAY\tR%d\tR%d\t%d\t", a, b, c); print_lv_ab(mrb, irep, a, b); break; CASE(OP_ARYCAT, B): printf("OP_ARYCAT\tR%d\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_ARYPUSH, B): printf("OP_ARYPUSH\tR%d\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_ARYDUP, B): printf("OP_ARYDUP\tR%d\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_AREF, BBB): printf("OP_AREF\tR%d\tR%d\t%d", a, b, c); print_lv_ab(mrb, irep, a, b); break; CASE(OP_ASET, BBB): printf("OP_ASET\tR%d\tR%d\t%d", a, b, c); print_lv_ab(mrb, irep, a, b); break; CASE(OP_APOST, BBB): printf("OP_APOST\tR%d\t%d\t%d", a, b, c); print_lv_a(mrb, irep, a); break; CASE(OP_INTERN, B): printf("OP_INTERN\tR%d", a); print_lv_a(mrb, irep, a); break; CASE(OP_STRING, BB): { mrb_value v = irep->pool[b]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); } print_lv_a(mrb, irep, a); break; CASE(OP_STRCAT, B): printf("OP_STRCAT\tR%d\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_HASH, BB): printf("OP_HASH\tR%d\t%d\t", a, b); print_lv_a(mrb, irep, a); break; CASE(OP_HASHADD, BB): printf("OP_HASHADD\tR%d\t%d\t", a, b); print_lv_a(mrb, irep, a); break; CASE(OP_HASHCAT, B): printf("OP_HASHCAT\tR%d\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_OCLASS, B): printf("OP_OCLASS\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_CLASS, BB): printf("OP_CLASS\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_MODULE, BB): printf("OP_MODULE\tR%d\t:%s", a, mrb_sym2name(mrb, irep->syms[b])); print_lv_a(mrb, irep, a); break; CASE(OP_EXEC, BB): printf("OP_EXEC\tR%d\tI(%d:%p)", a, b, irep->reps[b]); print_lv_a(mrb, irep, a); break; CASE(OP_SCLASS, B): printf("OP_SCLASS\tR%d\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_TCLASS, B): printf("OP_TCLASS\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_ERR, B): { mrb_value v = irep->pool[a]; mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); printf("OP_ERR\t%s\n", RSTRING_PTR(s)); } break; CASE(OP_EPUSH, B): printf("OP_EPUSH\t\t:I(%d:%p)\n", a, irep->reps[a]); break; CASE(OP_ONERR, S): printf("OP_ONERR\t%03d\n", a); break; CASE(OP_EXCEPT, B): printf("OP_EXCEPT\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_RESCUE, BB): printf("OP_RESCUE\tR%d\tR%d", a, b); print_lv_ab(mrb, irep, a, b); break; CASE(OP_RAISE, B): printf("OP_RAISE\tR%d\t\t", a); print_lv_a(mrb, irep, a); break; CASE(OP_POPERR, B): printf("OP_POPERR\t%d\t\t\n", a); break; CASE(OP_EPOP, B): printf("OP_EPOP\t%d\n", a); break; CASE(OP_DEBUG, BBB): printf("OP_DEBUG\t%d\t%d\t%d\n", a, b, c); break; CASE(OP_STOP, Z): printf("OP_STOP\n"); break; CASE(OP_EXT1, Z): ins = READ_B(); printf("OP_EXT1\n"); print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _1 (); goto L_OP_ ## i; #include "mruby/ops.h" #undef OPCODE } break; CASE(OP_EXT2, Z): ins = READ_B(); printf("OP_EXT2\n"); print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _2 (); goto L_OP_ ## i; #include "mruby/ops.h" #undef OPCODE } break; CASE(OP_EXT3, Z): ins = READ_B(); printf("OP_EXT3\n"); print_header(mrb, irep, pc-irep->iseq-2); switch (ins) { #define OPCODE(i,x) case OP_ ## i: FETCH_ ## x ## _3 (); goto L_OP_ ## i; #include "mruby/ops.h" #undef OPCODE } break; default: printf("OP_unknown (0x%x)\n", ins); break; } mrb_gc_arena_restore(mrb, ai); } printf("\n"); }
/** * Encodes and appends the string `string` to `w` */ void watchman_dump_string(watchman_t *w, VALUE string) { watchman_append(w, &watchman_string_marker, sizeof(watchman_string_marker)); watchman_dump_int(w, RSTRING_LEN(string)); watchman_append(w, RSTRING_PTR(string), RSTRING_LEN(string)); }
static void error_print(void) { volatile VALUE errat = Qnil; /* OK */ rb_thread_t *th = GET_THREAD(); VALUE errinfo = th->errinfo; int raised_flag = th->raised_flag; volatile VALUE eclass, e; const char *volatile einfo; volatile long elen; if (NIL_P(errinfo)) return; rb_thread_raised_clear(th); PUSH_TAG(); if (EXEC_TAG() == 0) { errat = get_backtrace(errinfo); } else { errat = Qnil; } if (EXEC_TAG()) goto error; if (NIL_P(errat)) { const char *file = rb_sourcefile(); int line = rb_sourceline(); if (!file) warn_printf("%d", line); else if (!line) warn_printf("%s", file); else warn_printf("%s:%d", file, line); } else if (RARRAY_LEN(errat) == 0) { error_pos(); } else { VALUE mesg = RARRAY_PTR(errat)[0]; if (NIL_P(mesg)) error_pos(); else { warn_print2(RSTRING_PTR(mesg), RSTRING_LEN(mesg)); } } eclass = CLASS_OF(errinfo); if (EXEC_TAG() == 0) { e = rb_funcall(errinfo, rb_intern("message"), 0, 0); StringValue(e); einfo = RSTRING_PTR(e); elen = RSTRING_LEN(e); } else { einfo = ""; elen = 0; } if (EXEC_TAG()) goto error; if (eclass == rb_eRuntimeError && elen == 0) { warn_print(": unhandled exception\n"); } else { VALUE epath; epath = rb_class_name(eclass); if (elen == 0) { warn_print(": "); warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath)); warn_print("\n"); } else { char *tail = 0; long len = elen; if (RSTRING_PTR(epath)[0] == '#') epath = 0; if ((tail = memchr(einfo, '\n', elen)) != 0) { len = tail - einfo; tail++; /* skip newline */ } warn_print(": "); warn_print2(einfo, len); if (epath) { warn_print(" ("); warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath)); warn_print(")\n"); } if (tail) { warn_print2(tail, elen - len - 1); if (einfo[elen-1] != '\n') warn_print2("\n", 1); } } } if (!NIL_P(errat)) { long i; long len = RARRAY_LEN(errat); VALUE *ptr = RARRAY_PTR(errat); int skip = eclass == rb_eSysStackError; #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5) #define TRACE_HEAD 8 #define TRACE_TAIL 5 for (i = 1; i < len; i++) { if (RB_TYPE_P(ptr[i], T_STRING)) { warn_printf("\tfrom %s\n", RSTRING_PTR(ptr[i])); } if (skip && i == TRACE_HEAD && len > TRACE_MAX) { warn_printf("\t ... %ld levels...\n", len - TRACE_HEAD - TRACE_TAIL); i = len - TRACE_TAIL; } } } error: POP_TAG(); rb_thread_raised_set(th, raised_flag); }
/* * call-seq: * ctx.setup => Qtrue # first time * ctx.setup => nil # thereafter * * This method is called automatically when a new SSLSocket is created. * Normally you do not need to call this method (unless you are writing an extension in C). */ static VALUE ossl_sslctx_setup(VALUE self) { SSL_CTX *ctx; X509 *cert = NULL, *client_ca = NULL; X509_STORE *store; EVP_PKEY *key = NULL; char *ca_path = NULL, *ca_file = NULL; int i, verify_mode; VALUE val; if(OBJ_FROZEN(self)) return Qnil; Data_Get_Struct(self, SSL_CTX, ctx); #if !defined(OPENSSL_NO_DH) if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){ SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback); } else{ SSL_CTX_set_tmp_dh_callback(ctx, ossl_default_tmp_dh_callback); } #endif SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)self); val = ossl_sslctx_get_cert_store(self); if(!NIL_P(val)){ /* * WORKAROUND: * X509_STORE can count references, but * X509_STORE_free() doesn't care it. * So we won't increment it but mark it by ex_data. */ store = GetX509StorePtr(val); /* NO NEED TO DUP */ SSL_CTX_set_cert_store(ctx, store); SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1); } val = ossl_sslctx_get_extra_cert(self); if(!NIL_P(val)){ rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self); } /* private key may be bundled in certificate file. */ val = ossl_sslctx_get_cert(self); cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */ val = ossl_sslctx_get_key(self); key = NIL_P(val) ? NULL : GetPKeyPtr(val); /* NO DUP NEEDED */ if (cert && key) { if (!SSL_CTX_use_certificate(ctx, cert)) { /* Adds a ref => Safe to FREE */ ossl_raise(eSSLError, "SSL_CTX_use_certificate:"); } if (!SSL_CTX_use_PrivateKey(ctx, key)) { /* Adds a ref => Safe to FREE */ ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey:"); } if (!SSL_CTX_check_private_key(ctx)) { ossl_raise(eSSLError, "SSL_CTX_check_private_key:"); } } val = ossl_sslctx_get_client_ca(self); if(!NIL_P(val)){ if(TYPE(val) == T_ARRAY){ for(i = 0; i < RARRAY_LEN(val); i++){ client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]); if (!SSL_CTX_add_client_CA(ctx, client_ca)){ /* Copies X509_NAME => FREE it. */ ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); } } } else{ client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */ if (!SSL_CTX_add_client_CA(ctx, client_ca)){ /* Copies X509_NAME => FREE it. */ ossl_raise(eSSLError, "SSL_CTX_add_client_CA"); } } } val = ossl_sslctx_get_ca_file(self); ca_file = NIL_P(val) ? NULL : StringValuePtr(val); val = ossl_sslctx_get_ca_path(self); ca_path = NIL_P(val) ? NULL : StringValuePtr(val); if(ca_file || ca_path){ if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path)) rb_warning("can't set verify locations"); } val = ossl_sslctx_get_verify_mode(self); verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val); SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback); if (RTEST(ossl_sslctx_get_client_cert_cb(self))) SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb); val = ossl_sslctx_get_timeout(self); if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val)); val = ossl_sslctx_get_verify_dep(self); if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2LONG(val)); val = ossl_sslctx_get_options(self); if(!NIL_P(val)) { SSL_CTX_set_options(ctx, NUM2LONG(val)); } else { SSL_CTX_set_options(ctx, SSL_OP_ALL); } rb_obj_freeze(self); val = ossl_sslctx_get_sess_id_ctx(self); if (!NIL_P(val)){ StringValue(val); if (!SSL_CTX_set_session_id_context(ctx, RSTRING_PTR(val), RSTRING_LEN(val))){ ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:"); } } if (RTEST(rb_iv_get(self, "@session_get_cb"))) { SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb); OSSL_Debug("SSL SESSION get callback added"); } if (RTEST(rb_iv_get(self, "@session_new_cb"))) { SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb); OSSL_Debug("SSL SESSION new callback added"); } if (RTEST(rb_iv_get(self, "@session_remove_cb"))) { SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb); OSSL_Debug("SSL SESSION remove callback added"); } return Qtrue; }
static VALUE string_to_c_internal(VALUE self) { VALUE s; s = self; if (RSTRING_LEN(s) == 0) return rb_assoc_new(Qnil, self); { VALUE m, sr, si, re, r, i; int po; m = f_match(comp_pat0, s); if (!NIL_P(m)) { sr = f_aref(m, INT2FIX(1)); si = f_aref(m, INT2FIX(2)); re = f_post_match(m); po = 1; } if (NIL_P(m)) { m = f_match(comp_pat1, s); if (!NIL_P(m)) { sr = Qnil; si = f_aref(m, INT2FIX(1)); if (NIL_P(si)) si = rb_usascii_str_new2(""); { VALUE t; t = f_aref(m, INT2FIX(2)); if (NIL_P(t)) t = rb_usascii_str_new2("1"); rb_str_concat(si, t); } re = f_post_match(m); po = 0; } } if (NIL_P(m)) { m = f_match(comp_pat2, s); if (NIL_P(m)) return rb_assoc_new(Qnil, self); sr = f_aref(m, INT2FIX(1)); if (NIL_P(f_aref(m, INT2FIX(2)))) si = Qnil; else { VALUE t; si = f_aref(m, INT2FIX(3)); t = f_aref(m, INT2FIX(4)); if (NIL_P(t)) t = rb_usascii_str_new2("1"); rb_str_concat(si, t); } re = f_post_match(m); po = 0; } r = INT2FIX(0); i = INT2FIX(0); if (!NIL_P(sr)) { if (f_include_p(sr, a_slash)) r = f_to_r(sr); else if (f_gt_p(f_count(sr, a_dot_and_an_e), INT2FIX(0))) r = f_to_f(sr); else r = f_to_i(sr); } if (!NIL_P(si)) { if (f_include_p(si, a_slash)) i = f_to_r(si); else if (f_gt_p(f_count(si, a_dot_and_an_e), INT2FIX(0))) i = f_to_f(si); else i = f_to_i(si); } if (po) return rb_assoc_new(rb_complex_polar(r, i), re); else return rb_assoc_new(rb_complex_new2(r, i), re); } }
static int rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn) { VALUE v, features, p, load_path = 0; const char *f, *e; long i, len, elen, n; st_table *loading_tbl; st_data_t data; int type; if (fn) *fn = 0; if (ext) { elen = strlen(ext); len = strlen(feature) - elen; type = rb ? 'r' : 's'; } else { len = strlen(feature); elen = 0; type = 0; } features = get_loaded_features(); for (i = 0; i < RARRAY_LEN(features); ++i) { v = RARRAY_PTR(features)[i]; f = StringValuePtr(v); if ((n = RSTRING_LEN(v)) < len) continue; if (strncmp(f, feature, len) != 0) { if (expanded) continue; if (!load_path) load_path = rb_get_expanded_load_path(); if (!(p = loaded_feature_path(f, n, feature, len, type, load_path))) continue; expanded = 1; f += RSTRING_LEN(p) + 1; } if (!*(e = f + len)) { if (ext) continue; return 'u'; } if (*e != '.') continue; if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) { return 's'; } if ((rb || !ext) && (IS_RBEXT(e))) { return 'r'; } } loading_tbl = get_loading_table(); if (loading_tbl) { f = 0; if (!expanded) { struct loaded_feature_searching fs; fs.name = feature; fs.len = len; fs.type = type; fs.load_path = load_path ? load_path : rb_get_load_path(); fs.result = 0; st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs); if ((f = fs.result) != 0) { if (fn) *fn = f; goto loading; } } if (st_get_key(loading_tbl, (st_data_t)feature, &data)) { if (fn) *fn = (const char*)data; loading: if (!ext) return 'u'; return !IS_RBEXT(ext) ? 's' : 'r'; } else { VALUE bufstr; char *buf; if (ext && *ext) return 0; bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN); buf = RSTRING_PTR(bufstr); MEMCPY(buf, feature, char, len); for (i = 0; (e = loadable_ext[i]) != 0; i++) { strlcpy(buf + len, e, DLEXT_MAXLEN + 1); if (st_get_key(loading_tbl, (st_data_t)buf, &data)) { rb_str_resize(bufstr, 0); if (fn) *fn = (const char*)data; return i ? 's' : 'r'; } } rb_str_resize(bufstr, 0); } } return 0; }
static mrb_value http_request_method(mrb_state *mrb, mrb_value self) { h2o_mruby_generator_t *generator; struct st_h2o_mruby_http_request_context_t *ctx; const char *arg_url; mrb_int arg_url_len; mrb_value arg_hash; h2o_iovec_t method; h2o_url_t url; /* parse args */ arg_hash = mrb_nil_value(); mrb_get_args(mrb, "s|H", &arg_url, &arg_url_len, &arg_hash); /* precond check */ if ((generator = h2o_mruby_current_generator) == NULL || generator->req == NULL) mrb_exc_raise(mrb, create_downstream_closed_exception(mrb)); /* allocate context and initialize */ ctx = h2o_mem_alloc_shared(&generator->req->pool, sizeof(*ctx), on_dispose); memset(ctx, 0, sizeof(*ctx)); ctx->generator = generator; ctx->receiver = mrb_nil_value(); h2o_buffer_init(&ctx->req.buf, &h2o_socket_buffer_prototype); h2o_buffer_init(&ctx->resp.after_closed, &h2o_socket_buffer_prototype); ctx->refs.request = mrb_nil_value(); ctx->refs.input_stream = mrb_nil_value(); /* uri */ if (h2o_url_parse(arg_url, arg_url_len, &url) != 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "invaild URL"); /* method */ method = h2o_iovec_init(H2O_STRLIT("GET")); if (mrb_hash_p(arg_hash)) { mrb_value t = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->shared->symbols.sym_method)); if (!mrb_nil_p(t)) { t = mrb_str_to_str(mrb, t); method = h2o_iovec_init(RSTRING_PTR(t), RSTRING_LEN(t)); } } /* start building the request */ h2o_buffer_reserve(&ctx->req.buf, method.len + 1); append_to_buffer(&ctx->req.buf, method.base, method.len); append_to_buffer(&ctx->req.buf, H2O_STRLIT(" ")); h2o_buffer_reserve(&ctx->req.buf, url.path.len + url.authority.len + sizeof(" HTTP/1.1\r\nConnection: close\r\nHost: \r\n") - 1); append_to_buffer(&ctx->req.buf, url.path.base, url.path.len); append_to_buffer(&ctx->req.buf, H2O_STRLIT(" HTTP/1.1\r\nConnection: close\r\nHost: ")); append_to_buffer(&ctx->req.buf, url.authority.base, url.authority.len); append_to_buffer(&ctx->req.buf, H2O_STRLIT("\r\n")); /* headers */ if (mrb_hash_p(arg_hash)) { mrb_value headers = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->shared->symbols.sym_headers)); if (!mrb_nil_p(headers)) { if (h2o_mruby_iterate_headers(generator->ctx, headers, flatten_request_header, ctx) != 0) { mrb_value exc = mrb_obj_value(mrb->exc); mrb->exc = NULL; mrb_exc_raise(mrb, exc); } } } /* body */ if (mrb_hash_p(arg_hash)) { mrb_value body = mrb_hash_get(mrb, arg_hash, mrb_symbol_value(generator->ctx->shared->symbols.sym_body)); if (!mrb_nil_p(body)) { if (mrb_obj_eq(mrb, body, generator->rack_input)) { /* fast path */ mrb_int pos; mrb_input_stream_get_data(mrb, body, NULL, NULL, &pos, NULL, NULL); ctx->req.body = generator->req->entity; ctx->req.body.base += pos; ctx->req.body.len -= pos; } else { if (!mrb_string_p(body)) { body = mrb_funcall(mrb, body, "read", 0); if (!mrb_string_p(body)) mrb_raise(mrb, E_ARGUMENT_ERROR, "body.read did not return string"); } ctx->req.body = h2o_strdup(&ctx->generator->req->pool, RSTRING_PTR(body), RSTRING_LEN(body)); } if (!ctx->req.has_transfer_encoding) { char buf[64]; size_t l = (size_t)sprintf(buf, "content-length: %zu\r\n", ctx->req.body.len); h2o_buffer_reserve(&ctx->req.buf, l); append_to_buffer(&ctx->req.buf, buf, l); } } } h2o_buffer_reserve(&ctx->req.buf, 2); append_to_buffer(&ctx->req.buf, H2O_STRLIT("\r\n")); /* build request and connect */ h2o_http1client_connect(&ctx->client, ctx, &generator->req->conn->ctx->proxy.client_ctx, url.host, h2o_url_get_port(&url), url.scheme == &H2O_URL_SCHEME_HTTPS, on_connect); ctx->refs.request = h2o_mruby_create_data_instance( mrb, mrb_ary_entry(generator->ctx->shared->constants, H2O_MRUBY_HTTP_REQUEST_CLASS), ctx, &request_type); return ctx->refs.request; }
/* * call-seq: * Groonga::PatriciaTrie.create(options={}) -> Groonga::PatriciaTrie * Groonga::PatriciaTrie.create(options={}) {|table| ... } * * 各レコードをパトリシアトライで管理するテーブルを生成する。 * ブロックを指定すると、そのブロックに生成したテーブルが渡さ * れ、ブロックを抜けると自動的にテーブルが破棄される。 * * _options_に指定可能な値は以下の通り。 * * [+:context+] * テーブルが利用するGroonga::Context。省略すると * Groonga::Context.defaultを用いる。 * * [+:name+] * テーブルの名前。名前をつけると、Groonga::Context#[]に名 * 前を指定してテーブルを取得することができる。省略すると * 無名テーブルになり、テーブルIDでのみ取得できる。 * * [+:path+] * テーブルを保存するパス。パスを指定すると永続テーブルとな * り、プロセス終了後もレコードは保持される。次回起動時に * Groonga::Context#[]で保存されたレコードを利用する * ことができる。省略すると一時テーブルになり、プロセスが終 * 了するとレコードは破棄される。 * * [+:persistent+] * +true+を指定すると永続テーブルとなる。+path+を省略した * 場合は自動的にパスが付加される。+:context+で指定した * Groonga::Contextに結びついているデータベースが一時デー * タベースの場合は例外が発生する。 * * [+:key_normalize+] * +true+を指定するとキーを正規化する。 * * [+:key_with_sis+] * +true+を指定するとキーの文字列の全suffixが自動的に登 * 録される。 * * [+:key_type+] * キーの種類を示すオブジェクトを指定する。キーの種類には型 * 名("Int32"や"ShortText"など)またはGroonga::Typeまたは * テーブル(Groonga::Array、Groonga::Hash、 * Groonga::PatriciaTrieのどれか)を指定する。 * * Groonga::Typeを指定した場合は、その型が示す範囲の値をキー * として使用する。ただし、キーの最大サイズは4096バイトで * あるため、Groonga::Type::TEXTやGroonga::Type::LONG_TEXT * は使用できない。 * * テーブルを指定した場合はレコードIDをキーとして使用する。 * 指定したテーブルのGroonga::Recordをキーとして使用するこ * ともでき、その場合は自動的にGroonga::Recordからレコード * IDを取得する。 * * 省略した場合はShortText型をキーとして使用する。この場合、 * 4096バイトまで使用可能である。 * * [+:value_type+] * 値の型を指定する。省略すると値のための領域を確保しない。 * 値を保存したい場合は必ず指定すること。 * * 参考: Groonga::Type.new * * [+:default_tokenizer+] * Groonga::IndexColumnで使用するトークナイザを指定する。 * デフォルトでは何も設定されていないので、テーブルに * Groonga::IndexColumnを定義する場合は * <tt>"TokenBigram"</tt>などを指定する必要がある。 * * [+:sub_records+] * +true+を指定すると#groupでグループ化したときに、 * Groonga::Record#n_sub_recordsでグループに含まれるレコー * ドの件数を取得できる。 * * 使用例: * * 無名一時テーブルを生成する。 * Groonga::PatriciaTrie.create * * 無名永続テーブルを生成する。 * Groonga::PatriciaTrie.create(:path => "/tmp/hash.grn") * * 名前付き永続テーブルを生成する。ただし、ファイル名は気に * しない。 * Groonga::PatriciaTrie.create(:name => "Bookmarks", * :persistent => true) * * それぞれのレコードに512バイトの値を格納できる無名一時テー * ブルを生成する。 * Groonga::PatriciaTrie.create(:value => 512) * * キーとして文字列を使用する無名一時テーブルを生成する。 * Groonga::PatriciaTrie.create(:key_type => Groonga::Type::SHORT_TEXT) * * キーとして文字列を使用する無名一時テーブルを生成する。 * (キーの種類を表すオブジェクトは文字列で指定。) * Groonga::PatriciaTrie.create(:key_type => "ShortText") * * キーとして<tt>Bookmarks</tt>テーブルのレコードを使用す * る無名一時テーブルを生成する。 * bookmarks = Groonga::PatriciaTrie.create(:name => "Bookmarks") * Groonga::PatriciaTrie.create(:key_type => bookmarks) * * キーとして<tt>Bookmarks</tt>テーブルのレコードを使用す * る無名一時テーブルを生成する。 * (テーブルは文字列で指定。) * Groonga::PatriciaTrie.create(:name => "Bookmarks") * Groonga::PatriciaTrie.create(:key_type => "Bookmarks") * * 全文検索用のトークンをバイグラムで切り出す無名一時テーブ * ルを生成する。 * bookmarks = Groonga::PatriciaTrie.create(:name => "Bookmarks") * bookmarks.define_column("comment", "Text") * terms = Groonga::PatriciaTrie.create(:name => "Terms", * :default_tokenizer => "TokenBigram") * terms.define_index_column("content", bookmarks, * :source => "Bookmarks.comment") */ static VALUE rb_grn_patricia_trie_s_create (int argc, VALUE *argv, VALUE klass) { grn_ctx *context; grn_obj *key_type = NULL, *value_type = NULL, *table; const char *name = NULL, *path = NULL; unsigned name_size = 0; grn_obj_flags flags = GRN_OBJ_TABLE_PAT_KEY; VALUE rb_table; VALUE options, rb_context, rb_name, rb_path, rb_persistent; VALUE rb_key_normalize, rb_key_with_sis, rb_key_type; VALUE rb_value_type; VALUE rb_default_tokenizer, rb_sub_records; rb_scan_args(argc, argv, "01", &options); rb_grn_scan_options(options, "context", &rb_context, "name", &rb_name, "path", &rb_path, "persistent", &rb_persistent, "key_normalize", &rb_key_normalize, "key_with_sis", &rb_key_with_sis, "key_type", &rb_key_type, "value_type", &rb_value_type, "default_tokenizer", &rb_default_tokenizer, "sub_records", &rb_sub_records, NULL); context = rb_grn_context_ensure(&rb_context); if (!NIL_P(rb_name)) { name = StringValuePtr(rb_name); name_size = RSTRING_LEN(rb_name); flags |= GRN_OBJ_PERSISTENT; } if (!NIL_P(rb_path)) { path = StringValueCStr(rb_path); flags |= GRN_OBJ_PERSISTENT; } if (RVAL2CBOOL(rb_persistent)) flags |= GRN_OBJ_PERSISTENT; if (RVAL2CBOOL(rb_key_normalize)) flags |= GRN_OBJ_KEY_NORMALIZE; if (RVAL2CBOOL(rb_key_with_sis)) flags |= GRN_OBJ_KEY_WITH_SIS; if (NIL_P(rb_key_type)) { key_type = grn_ctx_at(context, GRN_DB_SHORT_TEXT); } else { key_type = RVAL2GRNOBJECT(rb_key_type, &context); } if (!NIL_P(rb_value_type)) value_type = RVAL2GRNOBJECT(rb_value_type, &context); if (RVAL2CBOOL(rb_sub_records)) flags |= GRN_OBJ_WITH_SUBREC; table = grn_table_create(context, name, name_size, path, flags, key_type, value_type); if (!table) rb_grn_context_check(context, rb_ary_new4(argc, argv)); rb_table = GRNOBJECT2RVAL(klass, context, table, GRN_TRUE); if (!NIL_P(rb_default_tokenizer)) rb_funcall(rb_table, rb_intern("default_tokenizer="), 1, rb_default_tokenizer); if (rb_block_given_p()) return rb_ensure(rb_yield, rb_table, rb_grn_object_close, rb_table); else return rb_table; }
static void write_name_and_type(bson_buffer* buffer, VALUE name, char type) { buffer_write_bytes(buffer, &type, 1); buffer_write_bytes(buffer, RSTRING_PTR(name), RSTRING_LEN(name)); buffer_write_bytes(buffer, &zero, 1); }
static void putmsg(VALUE msg_rb, const Descriptor* desc, upb_sink *sink, int depth) { MessageHeader* msg; upb_msg_field_iter i; upb_status status; upb_sink_startmsg(sink); // Protect against cycles (possible because users may freely reassign message // and repeated fields) by imposing a maximum recursion depth. if (depth > ENCODE_MAX_NESTING) { rb_raise(rb_eRuntimeError, "Maximum recursion depth exceeded during encoding."); } TypedData_Get_Struct(msg_rb, MessageHeader, &Message_type, msg); for (upb_msg_field_begin(&i, desc->msgdef); !upb_msg_field_done(&i); upb_msg_field_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); bool is_matching_oneof = false; uint32_t offset = desc->layout->fields[upb_fielddef_index(f)].offset + sizeof(MessageHeader); if (upb_fielddef_containingoneof(f)) { uint32_t oneof_case_offset = desc->layout->fields[upb_fielddef_index(f)].case_offset + sizeof(MessageHeader); // For a oneof, check that this field is actually present -- skip all the // below if not. if (DEREF(msg, oneof_case_offset, uint32_t) != upb_fielddef_number(f)) { continue; } // Otherwise, fall through to the appropriate singular-field handler // below. is_matching_oneof = true; } if (is_map_field(f)) { VALUE map = DEREF(msg, offset, VALUE); if (map != Qnil) { putmap(map, f, sink, depth); } } else if (upb_fielddef_isseq(f)) { VALUE ary = DEREF(msg, offset, VALUE); if (ary != Qnil) { putary(ary, f, sink, depth); } } else if (upb_fielddef_isstring(f)) { VALUE str = DEREF(msg, offset, VALUE); if (is_matching_oneof || RSTRING_LEN(str) > 0) { putstr(str, f, sink); } } else if (upb_fielddef_issubmsg(f)) { putsubmsg(DEREF(msg, offset, VALUE), f, sink, depth); } else { upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); #define T(upbtypeconst, upbtype, ctype, default_value) \ case upbtypeconst: { \ ctype value = DEREF(msg, offset, ctype); \ if (is_matching_oneof || value != default_value) { \ upb_sink_put##upbtype(sink, sel, value); \ } \ } \ break; switch (upb_fielddef_type(f)) { T(UPB_TYPE_FLOAT, float, float, 0.0) T(UPB_TYPE_DOUBLE, double, double, 0.0) T(UPB_TYPE_BOOL, bool, uint8_t, 0) case UPB_TYPE_ENUM: T(UPB_TYPE_INT32, int32, int32_t, 0) T(UPB_TYPE_UINT32, uint32, uint32_t, 0) T(UPB_TYPE_INT64, int64, int64_t, 0) T(UPB_TYPE_UINT64, uint64, uint64_t, 0) case UPB_TYPE_STRING: case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: rb_raise(rb_eRuntimeError, "Internal error."); } #undef T } } upb_sink_endmsg(sink, &status); }
static int write_element_allow_id(VALUE key, VALUE value, VALUE extra, int allow_id) { bson_buffer* buffer = (bson_buffer*)NUM2LL(rb_ary_entry(extra, 0)); VALUE check_keys = rb_ary_entry(extra, 1); if (TYPE(key) == T_SYMBOL) { // TODO better way to do this... ? key = rb_str_new2(rb_id2name(SYM2ID(key))); } if (TYPE(key) != T_STRING) { rb_raise(rb_eTypeError, "keys must be strings or symbols"); } if (!allow_id && strcmp("_id", RSTRING_PTR(key)) == 0) { return ST_CONTINUE; } if (check_keys == Qtrue) { int i; if (RSTRING_LEN(key) > 0 && RSTRING_PTR(key)[0] == '$') { rb_raise(InvalidName, "key must not start with '$'"); } for (i = 0; i < RSTRING_LEN(key); i++) { if (RSTRING_PTR(key)[i] == '.') { rb_raise(InvalidName, "key must not contain '.'"); } } } switch(TYPE(value)) { case T_BIGNUM: case T_FIXNUM: { if (rb_funcall(value, rb_intern(">"), 1, LL2NUM(9223372036854775807LL)) == Qtrue || rb_funcall(value, rb_intern("<"), 1, LL2NUM(-9223372036854775808LL)) == Qtrue) { rb_raise(rb_eRangeError, "MongoDB can only handle 8-byte ints"); } if (rb_funcall(value, rb_intern(">"), 1, INT2NUM(2147483647L)) == Qtrue || rb_funcall(value, rb_intern("<"), 1, INT2NUM(-2147483648L)) == Qtrue) { long long ll_value; write_name_and_type(buffer, key, 0x12); ll_value = NUM2LL(value); buffer_write_bytes(buffer, (char*)&ll_value, 8); } else { int int_value; write_name_and_type(buffer, key, 0x10); int_value = NUM2LL(value); buffer_write_bytes(buffer, (char*)&int_value, 4); } break; } case T_TRUE: { write_name_and_type(buffer, key, 0x08); buffer_write_bytes(buffer, &one, 1); break; } case T_FALSE: { write_name_and_type(buffer, key, 0x08); buffer_write_bytes(buffer, &zero, 1); break; } case T_FLOAT: { double d = NUM2DBL(value); write_name_and_type(buffer, key, 0x01); buffer_write_bytes(buffer, (char*)&d, 8); break; } case T_NIL: { write_name_and_type(buffer, key, 0x0A); break; } case T_HASH: { write_name_and_type(buffer, key, 0x03); write_doc(buffer, value, check_keys); break; } case T_ARRAY: { int start_position, length_location, items, i, obj_length; VALUE* values; write_name_and_type(buffer, key, 0x04); start_position = buffer->position; // save space for length length_location = buffer_save_bytes(buffer, 4); items = RARRAY_LEN(value); values = RARRAY_PTR(value); for(i = 0; i < items; i++) { char* name; VALUE key; INT2STRING(&name, i); key = rb_str_new2(name); write_element(key, values[i], pack_extra(buffer, check_keys)); free(name); } // write null byte and fill in length buffer_write_bytes(buffer, &zero, 1); obj_length = buffer->position - start_position; memcpy(buffer->buffer + length_location, &obj_length, 4); break; } case T_STRING: { if (strcmp(rb_class2name(RBASIC(value)->klass), "Mongo::Code") == 0) { int start_position, length_location, length, total_length; write_name_and_type(buffer, key, 0x0F); start_position = buffer->position; length_location = buffer_save_bytes(buffer, 4); length = RSTRING_LEN(value) + 1; buffer_write_bytes(buffer, (char*)&length, 4); buffer_write_bytes(buffer, RSTRING_PTR(value), length - 1); buffer_write_bytes(buffer, &zero, 1); write_doc(buffer, rb_funcall(value, rb_intern("scope"), 0), Qfalse); total_length = buffer->position - start_position; memcpy(buffer->buffer + length_location, &total_length, 4); break; } else { int length = RSTRING_LEN(value) + 1; write_name_and_type(buffer, key, 0x02); buffer_write_bytes(buffer, (char*)&length, 4); buffer_write_bytes(buffer, RSTRING_PTR(value), length - 1); buffer_write_bytes(buffer, &zero, 1); break; } } case T_SYMBOL: { const char* str_value = rb_id2name(SYM2ID(value)); int length = strlen(str_value) + 1; write_name_and_type(buffer, key, 0x0E); buffer_write_bytes(buffer, (char*)&length, 4); buffer_write_bytes(buffer, str_value, length); break; } case T_OBJECT: { // TODO there has to be a better way to do these checks... const char* cls = rb_class2name(RBASIC(value)->klass); if (strcmp(cls, "Mongo::Binary") == 0 || strcmp(cls, "ByteBuffer") == 0) { const char subtype = strcmp(cls, "ByteBuffer") ? (const char)FIX2INT(rb_funcall(value, rb_intern("subtype"), 0)) : 2; VALUE string_data = rb_funcall(value, rb_intern("to_s"), 0); int length = RSTRING_LEN(string_data); write_name_and_type(buffer, key, 0x05); if (subtype == 2) { const int other_length = length + 4; buffer_write_bytes(buffer, (const char*)&other_length, 4); buffer_write_bytes(buffer, &subtype, 1); } buffer_write_bytes(buffer, (const char*)&length, 4); if (subtype != 2) { buffer_write_bytes(buffer, &subtype, 1); } buffer_write_bytes(buffer, RSTRING_PTR(string_data), length); break; } if (strcmp(cls, "Mongo::ObjectID") == 0) { VALUE as_array = rb_funcall(value, rb_intern("to_a"), 0); int i; write_name_and_type(buffer, key, 0x07); for (i = 0; i < 12; i++) { char byte = (char)FIX2INT(RARRAY_PTR(as_array)[i]); buffer_write_bytes(buffer, &byte, 1); } break; } if (strcmp(cls, "Mongo::DBRef") == 0) { int start_position, length_location, obj_length; VALUE ns, oid; write_name_and_type(buffer, key, 0x03); start_position = buffer->position; // save space for length length_location = buffer_save_bytes(buffer, 4); ns = rb_funcall(value, rb_intern("namespace"), 0); write_element(rb_str_new2("$ref"), ns, pack_extra(buffer, Qfalse)); oid = rb_funcall(value, rb_intern("object_id"), 0); write_element(rb_str_new2("$id"), oid, pack_extra(buffer, Qfalse)); // write null byte and fill in length buffer_write_bytes(buffer, &zero, 1); obj_length = buffer->position - start_position; memcpy(buffer->buffer + length_location, &obj_length, 4); break; } } case T_DATA: { // TODO again, is this really the only way to do this? const char* cls = rb_class2name(RBASIC(value)->klass); if (strcmp(cls, "Time") == 0) { double t = NUM2DBL(rb_funcall(value, rb_intern("to_f"), 0)); long long time_since_epoch = (long long)round(t * 1000); write_name_and_type(buffer, key, 0x09); buffer_write_bytes(buffer, (const char*)&time_since_epoch, 8); break; } } case T_REGEXP: { int length = RREGEXP_SRC_LEN(value); char* pattern = (char*)RREGEXP_SRC_PTR(value); long flags = RREGEXP(value)->ptr->options; VALUE has_extra; write_name_and_type(buffer, key, 0x0B); buffer_write_bytes(buffer, pattern, length); buffer_write_bytes(buffer, &zero, 1); if (flags & IGNORECASE) { char ignorecase = 'i'; buffer_write_bytes(buffer, &ignorecase, 1); } if (flags & MULTILINE) { char multiline = 'm'; buffer_write_bytes(buffer, &multiline, 1); } if (flags & EXTENDED) { char extended = 'x'; buffer_write_bytes(buffer, &extended, 1); } has_extra = rb_funcall(value, rb_intern("respond_to?"), 1, rb_str_new2("extra_options_str")); if (TYPE(has_extra) == T_TRUE) { VALUE extra = rb_funcall(value, rb_intern("extra_options_str"), 0); int old_position = buffer->position; buffer_write_bytes(buffer, RSTRING_PTR(extra), RSTRING_LEN(extra)); qsort(buffer->buffer + old_position, RSTRING_LEN(extra), sizeof(char), cmp_char); } buffer_write_bytes(buffer, &zero, 1); break; } default: { rb_raise(rb_eTypeError, "no c encoder for this type yet (%d)", TYPE(value)); break; } } return ST_CONTINUE; }
VALUE string_spec_rb_str_resize_RSTRING_LEN(VALUE self, VALUE str, VALUE size) { VALUE modified = rb_str_resize(str, FIX2INT(size)); return INT2FIX(RSTRING_LEN(modified)); }
// int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); // http://man7.org/linux/man-pages/man2/msgsnd.2.html // // Sends a message to the message queue. VALUE sysvmq_send(int argc, VALUE *argv, VALUE self) { VALUE message; VALUE priority = INT2FIX(1); VALUE flags = INT2FIX(0); sysvmq_blocking_call_t blocking; sysvmq_t* sysv; if (argc > 3 || argc == 0) { rb_raise(rb_eArgError, "Wrong number of arguments (1..3)"); } message = argv[0]; if (argc >= 2) priority = argv[1]; if (argc == 3) flags = argv[2]; message = rb_funcall(message, rb_intern("to_s"), 0); TypedData_Get_Struct(self, sysvmq_t, &sysvmq_type, sysv); Check_Type(flags, T_FIXNUM); Check_Type(priority, T_FIXNUM); // TODO: Call to_s on message if it responds to // Attach blocking call parameters to the struct passed to the blocking // function wrapper. blocking.flags = FIX2INT(flags); blocking.size = RSTRING_LEN(message); blocking.sysv = sysv; // See msgrcv(2) wrapper blocking.error = UNINITIALIZED_ERROR; blocking.length = UNINITIALIZED_ERROR; // The buffer can be obtained from `sysvmq_maybe_blocking_send`, instead of // passing it, set it directly on the instance struct. sysv->msgbuf->mtype = FIX2INT(priority); if (blocking.size > sysv->buffer_size) { rb_raise(rb_eArgError, "Size of message is bigger than buffer size."); } // TODO: Can a string copy be avoided? memcpy(sysv->msgbuf->mtext, RSTRING_PTR(message), blocking.size); // Non-blocking call, skip the expensive GVL release/acquire if ((blocking.flags & IPC_NOWAIT) == IPC_NOWAIT) { while(sysvmq_maybe_blocking_send(&blocking) == NULL && blocking.error < 0) { if (errno == EINTR) { continue; } rb_sys_fail("Failed sending message to queue"); } } else { // msgsnd(2) can block waiting for a message, if IPC_NOWAIT is not passed. // We unlock the GVL waiting for the call so other threads (e.g. signal // handling) can continue to work. while (WITHOUT_GVL(sysvmq_maybe_blocking_send, &blocking, RUBY_UBF_IO, NULL) == NULL && blocking.error < 0) { if (errno == EINTR || blocking.error == UNINITIALIZED_ERROR) { continue; } rb_sys_fail("Failed sending message to queue"); } } return message; }
VALUE string_spec_rb_str_set_len_RSTRING_LEN(VALUE self, VALUE str, VALUE len) { rb_str_set_len(str, NUM2LONG(len)); return INT2FIX(RSTRING_LEN(str)); }
static void setup_send_buffer(struct rw_args *x, VALUE buffer) { buffer = rb_obj_as_string(buffer); x->msg_ptr = RSTRING_PTR(buffer); x->msg_len = (size_t)RSTRING_LEN(buffer); }
MRB_API mrb_sym mrb_intern_str(mrb_state *mrb, mrb_value str) { return mrb_intern(mrb, RSTRING_PTR(str), RSTRING_LEN(str)); }
void yajl_encode_part(void * wrapper, VALUE obj, VALUE io) { VALUE str, outBuff, otherObj; yajl_encoder_wrapper * w = wrapper; yajl_gen_status status; int idx = 0; const unsigned char * buffer; const char * cptr; unsigned int len; if (io != Qnil || w->on_progress_callback != Qnil) { status = yajl_gen_get_buf(w->encoder, &buffer, &len); if (len >= WRITE_BUFSIZE) { outBuff = rb_str_new((const char *)buffer, len); if (io != Qnil) { rb_io_write(io, outBuff); } else if (w->on_progress_callback != Qnil) { rb_funcall(w->on_progress_callback, intern_call, 1, outBuff); } yajl_gen_clear(w->encoder); } } switch (TYPE(obj)) { case T_HASH: status = yajl_gen_map_open(w->encoder); /* TODO: itterate through keys in the hash */ VALUE keys = rb_funcall(obj, intern_keys, 0); VALUE entry, keyStr; for(idx=0; idx<RARRAY_LEN(keys); idx++) { entry = rb_ary_entry(keys, idx); keyStr = rb_funcall(entry, intern_to_s, 0); /* key must be a string */ /* the key */ yajl_encode_part(w, keyStr, io); /* the value */ yajl_encode_part(w, rb_hash_aref(obj, entry), io); } status = yajl_gen_map_close(w->encoder); break; case T_ARRAY: status = yajl_gen_array_open(w->encoder); for(idx=0; idx<RARRAY_LEN(obj); idx++) { otherObj = rb_ary_entry(obj, idx); yajl_encode_part(w, otherObj, io); } status = yajl_gen_array_close(w->encoder); break; case T_NIL: status = yajl_gen_null(w->encoder); break; case T_TRUE: status = yajl_gen_bool(w->encoder, 1); break; case T_FALSE: status = yajl_gen_bool(w->encoder, 0); break; case T_FIXNUM: case T_FLOAT: case T_BIGNUM: str = rb_funcall(obj, intern_to_s, 0); cptr = RSTRING_PTR(str); len = RSTRING_LEN(str); if (memcmp(cptr, "NaN", 3) == 0 || memcmp(cptr, "Infinity", 8) == 0 || memcmp(cptr, "-Infinity", 9) == 0) { rb_raise(cEncodeError, "'%s' is an invalid number", cptr); } status = yajl_gen_number(w->encoder, cptr, len); break; default: if (rb_respond_to(obj, intern_to_json)) { str = rb_funcall(obj, intern_to_json, 0); cptr = RSTRING_PTR(str); len = RSTRING_LEN(str); status = yajl_gen_number(w->encoder, cptr, len); } else { if (TYPE(obj) != T_STRING) { str = rb_funcall(obj, intern_to_s, 0); }else { str = obj; } cptr = RSTRING_PTR(str); len = RSTRING_LEN(str); status = yajl_gen_string(w->encoder, (const unsigned char *)cptr, len); } break; } }