static VALUE decode(VALUE self, VALUE str) { int rc; punycode_uint *ustr; size_t len; char *buf = NULL; VALUE retv; str = rb_check_convert_type(str, T_STRING, "String", "to_s"); len = RSTRING_LEN(str); ustr = malloc(len * sizeof(punycode_uint)); if (ustr == NULL) { rb_raise(rb_eNoMemError, "cannot allocate memory (%d bytes)", (uint32_t)len); return Qnil; } rc = punycode_decode(RSTRING_LEN(str), RSTRING_PTR(str), &len, ustr, NULL); if (rc != PUNYCODE_SUCCESS) { xfree(ustr); rb_raise(ePunycodeError, "%s (%d)", punycode_strerror(rc), rc); return Qnil; } buf = stringprep_ucs4_to_utf8(ustr, len, NULL, &len); retv = rb_enc_str_new(buf, len, rb_utf8_encoding()); xfree(ustr); xfree(buf); return retv; }
/* @overload write_plist(hash, path) * * Writes the serialized contents of a property list to the specified path. * * @note This does not yet support all possible types that can exist in a valid property list. * * @note This currently only assumes to be given an Xcode project document. * This means that it only accepts dictionaries, arrays, and strings in * the document. * * @param [Hash] hash The property list to serialize. * @param [String] path The path to the property list file. * @return [true, false] Wether or not saving was successful. */ static VALUE write_plist(VALUE self, VALUE hash, VALUE path) { VALUE h = rb_check_convert_type(hash, T_HASH, "Hash", "to_hash"); if (NIL_P(h)) { rb_raise(rb_eTypeError, "%s can't be coerced to Hash", rb_obj_classname(hash)); } CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); rb_hash_foreach(h, dictionary_set, (st_data_t)dict); CFURLRef fileURL = str_to_url(path); CFWriteStreamRef stream = CFWriteStreamCreateWithFile(NULL, fileURL); CFRelease(fileURL); CFIndex success = 0; if (CFWriteStreamOpen(stream)) { CFStringRef errorString; success = CFPropertyListWriteToStream(dict, stream, kCFPropertyListXMLFormat_v1_0, &errorString); if (!success) { CFShow(errorString); } } else { printf("Unable to open stream!\n"); } CFRelease(dict); return success ? Qtrue : Qfalse; }
PRIMITIVE VALUE vm_to_ary(VALUE obj) { VALUE ary = rb_check_convert_type(obj, T_ARRAY, "Array", "to_ary"); if (NIL_P(ary)) { ary = rb_ary_new4(1, &obj); } return ary; }
static void vm_caller_setup_arg_block(const rb_thread_t *th, rb_control_frame_t *reg_cfp, struct rb_calling_info *calling, const struct rb_call_info *ci, rb_iseq_t *blockiseq, const int is_super) { if (ci->flag & VM_CALL_ARGS_BLOCKARG) { rb_proc_t *po; VALUE proc; proc = *(--reg_cfp->sp); if (NIL_P(proc)) { calling->blockptr = NULL; } else if (SYMBOL_P(proc) && rb_method_basic_definition_p(rb_cSymbol, idTo_proc)) { calling->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp); calling->blockptr->iseq = (rb_iseq_t *)proc; calling->blockptr->proc = proc; } else if (RUBY_VM_IFUNC_P(proc)) { calling->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp); calling->blockptr->iseq = (rb_iseq_t *)proc; calling->blockptr->proc = proc; } else { if (!rb_obj_is_proc(proc)) { VALUE b; b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); if (NIL_P(b) || !rb_obj_is_proc(b)) { rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)", rb_obj_classname(proc)); } proc = b; } GetProcPtr(proc, po); calling->blockptr = &po->block; RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp)->proc = proc; } } else if (blockiseq != 0) { /* likely */ rb_block_t *blockptr = calling->blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(reg_cfp); blockptr->iseq = blockiseq; blockptr->proc = 0; } else { if (is_super) { calling->blockptr = GET_BLOCK_PTR(); } else { calling->blockptr = NULL; } } }
PRIMITIVE VALUE vm_ary_cat(VALUE ary, VALUE obj) { VALUE ary2 = rb_check_convert_type(obj, T_ARRAY, "Array", "to_a"); if (!NIL_P(ary2)) { rb_ary_concat(ary, ary2); } else { rb_ary_push(ary, obj); } return ary; }
PRIMITIVE VALUE vm_ary_check(VALUE obj, int size) { VALUE ary = rb_check_convert_type(obj, T_ARRAY, "Array", "to_ary"); if (NIL_P(ary)) { rb_raise(rb_eTypeError, "expected Array"); } if (RARRAY_LEN(ary) != size) { rb_raise(rb_eArgError, "expected Array of size %d, got %ld", size, RARRAY_LEN(ary)); } return ary; }
vm_resolve_args(VALUE **pargv, size_t argv_size, int *pargc, VALUE *args) { unsigned int i, argc = *pargc, real_argc = 0, j = 0; VALUE *argv = *pargv; bool splat_arg_follows = false; for (i = 0; i < argc; i++) { VALUE arg = args[j++]; if (arg == SPLAT_ARG_FOLLOWS) { splat_arg_follows = true; i--; } else { if (splat_arg_follows) { VALUE ary = rb_check_convert_type(arg, T_ARRAY, "Array", "to_a"); if (NIL_P(ary)) { ary = rb_ary_new4(1, &arg); } int count = RARRAY_LEN(ary); if (real_argc + count >= argv_size) { const size_t new_argv_size = real_argc + count + 100; VALUE *new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE) * new_argv_size); memcpy(new_argv, argv, sizeof(VALUE) * argv_size); argv = new_argv; argv_size = new_argv_size; } int j; for (j = 0; j < count; j++) { argv[real_argc++] = RARRAY_AT(ary, j); } splat_arg_follows = false; } else { if (real_argc >= argv_size) { const size_t new_argv_size = real_argc + 100; VALUE *new_argv = (VALUE *)xmalloc_ptrs(sizeof(VALUE) * new_argv_size); memcpy(new_argv, argv, sizeof(VALUE) * argv_size); argv = new_argv; argv_size = new_argv_size; } argv[real_argc++] = arg; } } } *pargv = argv; *pargc = real_argc; }
PRIMITIVE void * vm_get_block(VALUE obj) { if (obj == Qnil) { return NULL; } VALUE proc = rb_check_convert_type(obj, T_DATA, "Proc", "to_proc"); if (NIL_P(proc)) { rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)", rb_obj_classname(obj)); } return rb_proc_get_block(proc); }
static VALUE get_hash(volatile VALUE *hash, int argc, const VALUE *argv) { VALUE tmp; if (*hash != Qundef) return *hash; if (argc != 2) { rb_raise(rb_eArgError, "one hash required"); } tmp = rb_check_convert_type(argv[1], T_HASH, "Hash", "to_hash"); if (NIL_P(tmp)) { rb_raise(rb_eArgError, "one hash required"); } return (*hash = tmp); }
PRIMITIVE VALUE vm_when_splat(unsigned char overriden, VALUE comparedTo, VALUE splat) { VALUE ary = rb_check_convert_type(splat, T_ARRAY, "Array", "to_a"); if (NIL_P(ary)) { ary = rb_ary_new4(1, &splat); } long i, count = RARRAY_LEN(ary); for (i = 0; i < count; i++) { VALUE o = RARRAY_AT(ary, i); if (RTEST(vm_fast_eqq(o, comparedTo, overriden))) { return Qtrue; } } return Qfalse; }
static VALUE rhash_set_default_proc(VALUE hash, SEL sel, VALUE proc) { rhash_modify(hash); VALUE tmp = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); if (NIL_P(tmp)) { rb_raise(rb_eTypeError, "wrong default_proc type %s (expected Proc)", rb_obj_classname(proc)); } proc = tmp; default_proc_arity_check(proc); GC_WB(&RHASH(hash)->ifnone, proc); RHASH(hash)->has_proc_default = true; return proc; }
VALUE rb_proc_check_and_call(VALUE proc, int argc, VALUE *argv) { VALUE tmp = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); if (NIL_P(tmp)) { rb_raise(rb_eTypeError, "wrong type %s (expected Proc)", rb_obj_classname(proc)); } proc = tmp; const int arity = rb_proc_arity(proc); if (arity != argc) { rb_raise(rb_eArgError, "expected Proc with %d arguments (got %d)", argc, arity); } return proc_call(proc, 0, argc, argv); }
static VALUE encode(VALUE self, VALUE str) { int rc; punycode_uint *ustr; size_t len; size_t buflen = 0x100; char *buf = NULL; VALUE retv; str = rb_check_convert_type(str, T_STRING, "String", "to_s"); ustr = stringprep_utf8_to_ucs4(RSTRING_PTR(str), RSTRING_LEN(str), &len); while (1) { buf = realloc(buf, buflen); if (buf == NULL) { xfree(ustr); rb_raise(rb_eNoMemError, "cannot allocate memory (%d bytes)", (uint32_t)buflen); return Qnil; } rc = punycode_encode(len, ustr, NULL, &buflen, buf); if (rc == PUNYCODE_SUCCESS) { break; } else if (rc == PUNYCODE_BIG_OUTPUT) { buflen += 0x100; } else { xfree(ustr); xfree(buf); rb_raise(ePunycodeError, "%s (%d)", punycode_strerror(rc), rc); return Qnil; } } retv = rb_str_new(buf, buflen); xfree(ustr); xfree(buf); return retv; }
void rb_grn_scan_options (VALUE options, ...) { VALUE original_options = options; VALUE available_keys; const char *key; VALUE *value; va_list args; options = rb_check_convert_type(options, T_HASH, "Hash", "to_hash"); if (NIL_P(options)) { options = rb_hash_new(); } else if (options == original_options) { options = rb_funcall(options, rb_intern("dup"), 0); } available_keys = rb_ary_new(); va_start(args, options); key = va_arg(args, const char *); while (key) { VALUE rb_key; value = va_arg(args, VALUE *); rb_key = RB_GRN_INTERN(key); rb_ary_push(available_keys, rb_key); *value = rb_funcall(options, rb_intern("delete"), 1, rb_key); key = va_arg(args, const char *); } va_end(args); if (RVAL2CBOOL(rb_funcall(options, rb_intern("empty?"), 0))) return; rb_raise(rb_eArgError, "unexpected key(s) exist: %s: available keys: %s", rb_grn_inspect(rb_funcall(options, rb_intern("keys"), 0)), rb_grn_inspect(available_keys)); }
VALUE rb_grn_check_convert_to_hash (VALUE object) { return rb_check_convert_type(object, RUBY_T_HASH, "Hash", "to_hash"); }
/* * call-seq: configure(opts) * * Configure this State instance with the Hash _opts_, and return * itself. */ static VALUE cState_configure(VALUE self, VALUE opts) { VALUE tmp; GET_STATE(self); tmp = rb_check_convert_type(opts, T_HASH, "Hash", "to_hash"); if (NIL_P(tmp)) tmp = rb_convert_type(opts, T_HASH, "Hash", "to_h"); opts = tmp; tmp = rb_hash_aref(opts, ID2SYM(i_indent)); if (RTEST(tmp)) { unsigned long len; Check_Type(tmp, T_STRING); len = RSTRING_LEN(tmp); state->indent = fstrndup(RSTRING_PTR(tmp), len + 1); state->indent_len = len; } tmp = rb_hash_aref(opts, ID2SYM(i_space)); if (RTEST(tmp)) { unsigned long len; Check_Type(tmp, T_STRING); len = RSTRING_LEN(tmp); state->space = fstrndup(RSTRING_PTR(tmp), len + 1); state->space_len = len; } tmp = rb_hash_aref(opts, ID2SYM(i_space_before)); if (RTEST(tmp)) { unsigned long len; Check_Type(tmp, T_STRING); len = RSTRING_LEN(tmp); state->space_before = fstrndup(RSTRING_PTR(tmp), len + 1); state->space_before_len = len; } tmp = rb_hash_aref(opts, ID2SYM(i_array_nl)); if (RTEST(tmp)) { unsigned long len; Check_Type(tmp, T_STRING); len = RSTRING_LEN(tmp); state->array_nl = fstrndup(RSTRING_PTR(tmp), len + 1); state->array_nl_len = len; } tmp = rb_hash_aref(opts, ID2SYM(i_object_nl)); if (RTEST(tmp)) { unsigned long len; Check_Type(tmp, T_STRING); len = RSTRING_LEN(tmp); state->object_nl = fstrndup(RSTRING_PTR(tmp), len + 1); state->object_nl_len = len; } tmp = ID2SYM(i_max_nesting); state->max_nesting = 100; if (option_given_p(opts, tmp)) { VALUE max_nesting = rb_hash_aref(opts, tmp); if (RTEST(max_nesting)) { Check_Type(max_nesting, T_FIXNUM); state->max_nesting = FIX2LONG(max_nesting); } else { state->max_nesting = 0; } } tmp = ID2SYM(i_depth); state->depth = 0; if (option_given_p(opts, tmp)) { VALUE depth = rb_hash_aref(opts, tmp); if (RTEST(depth)) { Check_Type(depth, T_FIXNUM); state->depth = FIX2LONG(depth); } else { state->depth = 0; } } tmp = ID2SYM(i_buffer_initial_length); if (option_given_p(opts, tmp)) { VALUE buffer_initial_length = rb_hash_aref(opts, tmp); if (RTEST(buffer_initial_length)) { long initial_length; Check_Type(buffer_initial_length, T_FIXNUM); initial_length = FIX2LONG(buffer_initial_length); if (initial_length > 0) state->buffer_initial_length = initial_length; } } tmp = rb_hash_aref(opts, ID2SYM(i_allow_nan)); state->allow_nan = RTEST(tmp); tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only)); state->ascii_only = RTEST(tmp); tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode)); state->quirks_mode = RTEST(tmp); return self; }
int rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...) { int i; const char *p = fmt; VALUE *var; va_list vargs; int f_var = 0, f_hash = 0, f_block = 0; int n_lead = 0, n_opt = 0, n_trail = 0, n_mand; int argi = 0; VALUE hash = Qnil; if (ISDIGIT(*p)) { n_lead = *p - '0'; p++; if (ISDIGIT(*p)) { n_opt = *p - '0'; p++; if (ISDIGIT(*p)) { n_trail = *p - '0'; p++; goto block_arg; } } } if (*p == '*') { f_var = 1; p++; if (ISDIGIT(*p)) { n_trail = *p - '0'; p++; } } block_arg: if (*p == ':') { f_hash = 1; p++; } if (*p == '&') { f_block = 1; p++; } if (*p != '\0') { rb_fatal("bad scan arg format: %s", fmt); } n_mand = n_lead + n_trail; if (argc < n_mand) goto argc_error; va_start(vargs, fmt); /* capture an option hash - phase 1: pop */ if (f_hash && n_mand < argc) { VALUE last = argv[argc - 1]; if (NIL_P(last)) { /* nil is taken as an empty option hash only if it is not ambiguous; i.e. '*' is not specified and arguments are given more than sufficient */ if (!f_var && n_mand + n_opt < argc) argc--; } else { hash = rb_check_convert_type(last, T_HASH, "Hash", "to_hash"); if (!NIL_P(hash)) argc--; } } /* capture leading mandatory arguments */ for (i = n_lead; i-- > 0; ) { var = va_arg(vargs, VALUE *); if (var) *var = argv[argi]; argi++; } /* capture optional arguments */ for (i = n_opt; i-- > 0; ) { var = va_arg(vargs, VALUE *); if (argi < argc - n_trail) { if (var) *var = argv[argi]; argi++; } else { if (var) *var = Qnil; } } /* capture variable length arguments */ if (f_var) { int n_var = argc - argi - n_trail; var = va_arg(vargs, VALUE *); if (0 < n_var) { if (var) *var = rb_ary_new4(n_var, &argv[argi]); argi += n_var; } else { if (var) *var = rb_ary_new(); } } /* capture trailing mandatory arguments */ for (i = n_trail; i-- > 0; ) { var = va_arg(vargs, VALUE *); if (var) *var = argv[argi]; argi++; } /* capture an option hash - phase 2: assignment */ if (f_hash) { var = va_arg(vargs, VALUE *); if (var) *var = hash; } /* capture iterator block */ if (f_block) { var = va_arg(vargs, VALUE *); if (rb_block_given_p()) { *var = rb_block_proc(); } else { *var = Qnil; } } va_end(vargs); if (argi < argc) goto argc_error; return argc; argc_error: if (0 < n_opt) rb_raise(rb_eArgError, "wrong number of arguments (%d for %d..%d%s)", argc, n_mand, n_mand + n_opt, f_var ? "+" : ""); else rb_raise(rb_eArgError, "wrong number of arguments (%d for %d%s)", argc, n_mand, f_var ? "+" : ""); }
/* * call-seq: * Dir.new( string ) -> aDir * * Returns a new directory object for the named directory. */ static VALUE dir_initialize(int argc, VALUE *argv, VALUE dir) { struct dir_data *dp; static rb_encoding *fs_encoding; rb_encoding *intencoding, *extencoding; VALUE dirname, opt; static VALUE sym_intenc, sym_extenc; if (!sym_intenc) { sym_intenc = ID2SYM(rb_intern("internal_encoding")); sym_extenc = ID2SYM(rb_intern("external_encoding")); fs_encoding = rb_filesystem_encoding(); } intencoding = NULL; extencoding = fs_encoding; rb_scan_args(argc, argv, "11", &dirname, &opt); if (!NIL_P(opt)) { VALUE v, extenc=Qnil, intenc=Qnil; opt = rb_check_convert_type(opt, T_HASH, "Hash", "to_hash"); v = rb_hash_aref(opt, sym_intenc); if (!NIL_P(v)) intenc = v; v = rb_hash_aref(opt, sym_extenc); if (!NIL_P(v)) extenc = v; if (!NIL_P(extenc)) { extencoding = rb_to_encoding(extenc); if (!NIL_P(intenc)) { intencoding = rb_to_encoding(intenc); if (extencoding == intencoding) { rb_warn("Ignoring internal encoding '%s': it is identical to external encoding '%s'", RSTRING_PTR(rb_inspect(intenc)), RSTRING_PTR(rb_inspect(extenc))); intencoding = NULL; } } } else if (!NIL_P(intenc)) { rb_raise(rb_eArgError, "External encoding must be specified when internal encoding is given"); } } { rb_encoding *dirname_encoding = rb_enc_get(dirname); if (rb_usascii_encoding() != dirname_encoding && rb_ascii8bit_encoding() != dirname_encoding #if defined __APPLE__ && rb_utf8_encoding() != dirname_encoding #endif && extencoding != dirname_encoding) { if (!intencoding) intencoding = dirname_encoding; dirname = rb_str_transcode(dirname, rb_enc_from_encoding(extencoding)); } } FilePathValue(dirname); Data_Get_Struct(dir, struct dir_data, dp); if (dp->dir) closedir(dp->dir); if (dp->path) xfree(dp->path); dp->dir = NULL; dp->path = NULL; dp->intenc = intencoding; dp->extenc = extencoding; dp->dir = opendir(RSTRING_PTR(dirname)); if (dp->dir == NULL) { if (errno == EMFILE || errno == ENFILE) { rb_gc(); dp->dir = opendir(RSTRING_PTR(dirname)); } if (dp->dir == NULL) { rb_sys_fail(RSTRING_PTR(dirname)); } } dp->path = strdup(RSTRING_PTR(dirname)); return dir; }
static VALUE so_check_convert_type(VALUE self, VALUE obj) { return rb_check_convert_type(obj, T_ARRAY, "Array", "to_ary"); }
static VALUE rhash_try_convert(VALUE dummy, SEL sel, VALUE hash) { return rb_check_convert_type(hash, T_HASH, "Hash", "to_hash"); }
static VALUE rb_io_check_io(VALUE io) { return rb_check_convert_type(io, T_FILE, "IO", "to_io"); }
static inline int caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, VALUE flag, int argc, rb_iseq_t *blockiseq, rb_block_t **block) { rb_block_t *blockptr = 0; if (block) { if (flag & VM_CALL_ARGS_BLOCKARG_BIT) { rb_proc_t *po; VALUE proc; proc = *(--cfp->sp); if (proc != Qnil) { if (!rb_obj_is_proc(proc)) { VALUE b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); if (NIL_P(b) || !rb_obj_is_proc(b)) { rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc)", rb_obj_classname(proc)); } proc = b; } GetProcPtr(proc, po); blockptr = &po->block; RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc; *block = blockptr; } } else if (blockiseq) { blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); blockptr->iseq = blockiseq; blockptr->proc = 0; *block = blockptr; } } /* expand top of stack? */ if (flag & VM_CALL_ARGS_SPLAT_BIT) { VALUE ary = *(cfp->sp - 1); VALUE *ptr; int i; VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"); if (NIL_P(tmp)) { /* do nothing */ } else { long len = RARRAY_LEN(tmp); ptr = RARRAY_PTR(tmp); cfp->sp -= 1; CHECK_STACK_OVERFLOW(cfp, len); for (i = 0; i < len; i++) { *cfp->sp++ = ptr[i]; } argc += i-1; } } return argc; }
/* @overload gsub(pattern, replacement) * * Returns the receiver with all matches of PATTERN replaced by REPLACEMENT, * inheriting any taint and untrust from the receiver and from REPLACEMENT. * * The REPLACEMENT is used as a specification for what to replace matches * with: * * <table> * <thead> * <tr><th>Specification</th><th>Replacement</th></tr> * </thead> * <tbody> * <tr> * <td><code>\1</code>, <code>\2</code>, …, <code>\</code><em>n</em></td> * <td>Numbered sub-match <em>n</em></td> * </tr> * <tr> * <td><code>\k<</code><em>name</em><code>></code></td> * <td>Named sub-match <em>name</em></td> * </tr> * </tbody> * </table> * * The Regexp special variables `$&`, `$'`, <code>$\`</code>, `$1`, `$2`, …, * `$`_n_ are updated accordingly. * * @param [Regexp, #to_str] pattern * @param [#to_str] replacement * @return [U::String] * * @overload gsub(pattern, replacements) * * Returns the receiver with all matches of PATTERN replaced by * REPLACEMENTS#[_match_], where _match_ is the matched substring, inheriting * any taint and untrust from the receiver and from the * REPLACEMENTS#[_match_]es, as well as any taint on REPLACEMENTS. * * The Regexp special variables `$&`, `$'`, <code>$\`</code>, `$1`, `$2`, …, * `$`_n_ are updated accordingly. * * @param [Regexp, #to_str] pattern * @param [#to_hash] replacements * @raise [RuntimeError] If any replacement is the result being constructed * @raise [Exception] Any error raised by REPLACEMENTS#default, if it gets * called * @return [U::String] * * @overload gsub(pattern){ |match| … } * * Returns the receiver with all matches of PATTERN replaced by the results * of the given block, inheriting any taint and untrust from the receiver and * from the results of the given block. * * The Regexp special variables `$&`, `$'`, <code>$\`</code>, `$1`, `$2`, …, * `$`_n_ are updated accordingly. * * @param [Regexp, #to_str] pattern * @yieldparam [U::String] match * @yieldreturn [#to_str] * @return [U::String] * * @overload gsub(pattern) * * Returns an Enumerator over the matches of PATTERN in the receiver. * * The Regexp special variables `$&`, `$'`, <code>$\`</code>, `$1`, `$2`, …, * `$`_n_ will be updated accordingly. * * @param [Regexp, #to_str] pattern * @return [Enumerator] */ VALUE rb_u_string_gsub(int argc, VALUE *argv, VALUE self) { VALUE pattern, replacement; VALUE replacements = Qnil; bool use_block = false; bool tainted = false; if (argc == 1) { RETURN_ENUMERATOR(self, argc, argv); use_block = true; } if (rb_scan_args(argc, argv, "11", &pattern, &replacement) == 2) { replacements = rb_check_convert_type(replacement, T_HASH, "Hash", "to_hash"); if (NIL_P(replacements)) StringValue(replacement); if (OBJ_TAINTED(replacement)) tainted = true; } pattern = rb_u_pattern_argument(pattern, true); VALUE str = rb_str_to_str(self); long begin = rb_reg_search(pattern, str, 0, 0); if (begin < 0) return self; const char *base = RSTRING_PTR(str); const char *p = base; const char *end = RSTRING_END(str); VALUE substituted = rb_u_str_buf_new(RSTRING_LEN(str) + 30); do { VALUE match = rb_backref_get(); struct re_registers *registers = RMATCH_REGS(match); VALUE result; if (use_block || !NIL_P(replacements)) { if (use_block) { VALUE ustr = rb_u_string_new_rb(rb_reg_nth_match(0, match)); result = rb_u_string_object_as_string(rb_yield(ustr)); } else { VALUE ustr = rb_u_string_new_c(self, base + registers->beg[0], registers->end[0] - registers->beg[0]); result = rb_u_string_object_as_string(rb_hash_aref(replacements, ustr)); } if (result == substituted) rb_u_raise(rb_eRuntimeError, "result of block is string being built; please try not to cheat"); } else result = #ifdef HAVE_RB_REG_REGSUB4 rb_reg_regsub(replacement, str, registers, pattern); #else rb_reg_regsub(replacement, str, registers); #endif if (OBJ_TAINTED(result)) tainted = true; const struct rb_u_string *value = RVAL2USTRING_ANY(result); rb_str_buf_cat(substituted, p, registers->beg[0] - (p - base)); rb_str_buf_cat(substituted, USTRING_STR(value), USTRING_LENGTH(value)); OBJ_INFECT(substituted, result); p = base + registers->end[0]; if (registers->beg[0] == registers->end[0]) p = u_next(p); if (p >= end) break; begin = rb_reg_search(pattern, str, registers->end[0], 0); } while (begin >= 0); if (p < end) rb_str_buf_cat(substituted, p, end - p); rb_reg_search(pattern, str, end - p, 0); RBASIC(substituted)->klass = rb_obj_class(str); OBJ_INFECT(substituted, str); if (tainted) OBJ_TAINT(substituted); return rb_u_string_new_rb(substituted); }
static int str_transcode(int argc, VALUE *argv, VALUE *self) { VALUE dest; VALUE str = *self; long blen, slen; unsigned char *buf, *bp, *sp, *fromp; rb_encoding *from_enc, *to_enc; const char *from_e, *to_e; int from_encidx, to_encidx; VALUE from_encval, to_encval; const rb_transcoder *my_transcoder; rb_transcoding my_transcoding; int final_encoding = 0; VALUE opt; int options = 0; opt = rb_check_convert_type(argv[argc-1], T_HASH, "Hash", "to_hash"); if (!NIL_P(opt)) { VALUE v; argc--; v = rb_hash_aref(opt, sym_invalid); if (NIL_P(v)) { rb_raise(rb_eArgError, "unknown value for invalid: setting"); } else if (v==sym_ignore) { options |= INVALID_IGNORE; } } if (argc < 1 || argc > 2) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..2)", argc); } if ((to_encidx = rb_to_encoding_index(to_encval = argv[0])) < 0) { to_enc = 0; to_encidx = 0; to_e = StringValueCStr(to_encval); } else { to_enc = rb_enc_from_index(to_encidx); to_e = rb_enc_name(to_enc); } if (argc==1) { from_encidx = rb_enc_get_index(str); from_enc = rb_enc_from_index(from_encidx); from_e = rb_enc_name(from_enc); } else if ((from_encidx = rb_to_encoding_index(from_encval = argv[1])) < 0) { from_enc = 0; from_e = StringValueCStr(from_encval); } else { from_enc = rb_enc_from_index(from_encidx); from_e = rb_enc_name(from_enc); } if (from_enc && from_enc == to_enc) { return -1; } if (from_enc && to_enc && rb_enc_asciicompat(from_enc) && rb_enc_asciicompat(to_enc)) { if (ENC_CODERANGE(str) == ENC_CODERANGE_7BIT) { return to_encidx; } } if (encoding_equal(from_e, to_e)) { return -1; } do { /* loop for multistep transcoding */ /* later, maybe use smaller intermediate strings for very long strings */ if (!(my_transcoder = transcode_dispatch(from_e, to_e))) { rb_raise(rb_eArgError, "transcoding not supported (from %s to %s)", from_e, to_e); } my_transcoding.transcoder = my_transcoder; if (my_transcoder->preprocessor) { fromp = sp = (unsigned char *)RSTRING_PTR(str); slen = RSTRING_LEN(str); blen = slen + 30; /* len + margin */ dest = rb_str_tmp_new(blen); bp = (unsigned char *)RSTRING_PTR(dest); my_transcoding.ruby_string_dest = dest; (*my_transcoder->preprocessor)(&fromp, &bp, (sp+slen), (bp+blen), &my_transcoding); if (fromp != sp+slen) { rb_raise(rb_eArgError, "not fully converted, %td bytes left", sp+slen-fromp); } buf = (unsigned char *)RSTRING_PTR(dest); *bp = '\0'; rb_str_set_len(dest, bp - buf); str = dest; } fromp = sp = (unsigned char *)RSTRING_PTR(str); slen = RSTRING_LEN(str); blen = slen + 30; /* len + margin */ dest = rb_str_tmp_new(blen); bp = (unsigned char *)RSTRING_PTR(dest); my_transcoding.ruby_string_dest = dest; my_transcoding.flush_func = str_transcoding_resize; transcode_loop(&fromp, &bp, (sp+slen), (bp+blen), my_transcoder, &my_transcoding, options); if (fromp != sp+slen) { rb_raise(rb_eArgError, "not fully converted, %td bytes left", sp+slen-fromp); } buf = (unsigned char *)RSTRING_PTR(dest); *bp = '\0'; rb_str_set_len(dest, bp - buf); if (my_transcoder->postprocessor) { str = dest; fromp = sp = (unsigned char *)RSTRING_PTR(str); slen = RSTRING_LEN(str); blen = slen + 30; /* len + margin */ dest = rb_str_tmp_new(blen); bp = (unsigned char *)RSTRING_PTR(dest); my_transcoding.ruby_string_dest = dest; (*my_transcoder->postprocessor)(&fromp, &bp, (sp+slen), (bp+blen), &my_transcoding); if (fromp != sp+slen) { rb_raise(rb_eArgError, "not fully converted, %td bytes left", sp+slen-fromp); } buf = (unsigned char *)RSTRING_PTR(dest); *bp = '\0'; rb_str_set_len(dest, bp - buf); } if (encoding_equal(my_transcoder->to_encoding, to_e)) { final_encoding = 1; } else { from_e = my_transcoder->to_encoding; str = dest; } } while (!final_encoding); /* set encoding */ if (!to_enc) { to_encidx = rb_define_dummy_encoding(to_e); } *self = dest; return to_encidx; }