void ngx_mrb_raise_error(mrb_state *mrb, mrb_value obj, ngx_http_request_t *r) { struct RString *str; char *err_out; obj = mrb_funcall(mrb, obj, "inspect", 0); if (mrb_type(obj) == MRB_TT_STRING) { str = mrb_str_ptr(obj); err_out = str->as.heap.ptr; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "mrb_run failed: return 500 HTTP status code to client: error: %s", err_out); } }
void ngx_mrb_raise_conf_error(mrb_state *mrb, mrb_value obj, ngx_conf_t *cf) { struct RString *str; char *err_out; obj = mrb_funcall(mrb, obj, "inspect", 0); if (mrb_type(obj) == MRB_TT_STRING) { str = mrb_str_ptr(obj); err_out = str->as.heap.ptr; ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "mrb_run failed. error: %s", err_out); } }
static void printstr(mrb_state *mrb, mrb_value obj) { struct RString *str; char *s; int len; if (mrb_string_p(obj)) { str = mrb_str_ptr(obj); s = str->ptr; len = str->len; fwrite(s, len, 1, stdout); } }
mrb_value mrb_str_pool(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); struct RString *ns; char *ptr; mrb_int len; ns = (struct RString *)mrb_malloc(mrb, sizeof(struct RString)); ns->tt = MRB_TT_STRING; ns->c = mrb->string_class; if (RSTR_NOFREE_P(s)) { ns->flags = MRB_STR_NOFREE; ns->as.heap.ptr = s->as.heap.ptr; ns->as.heap.len = s->as.heap.len; ns->as.heap.aux.capa = 0; } else { ns->flags = 0; if (RSTR_EMBED_P(s)) { ptr = s->as.ary; len = RSTR_EMBED_LEN(s); } else { ptr = s->as.heap.ptr; len = s->as.heap.len; } if (len < RSTRING_EMBED_LEN_MAX) { RSTR_SET_EMBED_FLAG(ns); RSTR_SET_EMBED_LEN(ns, len); if (ptr) { memcpy(ns->as.ary, ptr, len); } ns->as.ary[len] = '\0'; } else { ns->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1); ns->as.heap.len = len; ns->as.heap.aux.capa = len; if (ptr) { memcpy(ns->as.heap.ptr, ptr, len); } ns->as.heap.ptr[len] = '\0'; } } return mrb_obj_value(ns); }
void mrb_print_error(mrb_state *mrb) { #ifdef ENABLE_STDIO mrb_value s; mrb_print_backtrace(mrb); s = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); if (mrb_string_p(s)) { struct RString *str = mrb_str_ptr(s); fwrite(str->ptr, str->len, 1, stderr); putc('\n', stderr); } #endif }
mrb_value mrb_any_to_s(mrb_state *mrb, mrb_value obj) { const char *cname = mrb_obj_classname(mrb, obj); size_t len; mrb_value str; struct RString *s; len = strlen(cname)+6+16; str = mrb_str_new(mrb, 0, len); /* 6:tags 16:addr */ s = mrb_str_ptr(str); s->len = sprintf(s->ptr, "#<%s:0x%lx>", cname, (unsigned long)(obj.value.p)); return str; }
mrb_value mrb_str_pool(mrb_state *mrb, mrb_value str) { struct RString *s = mrb_str_ptr(str); struct RString *ns; char *ptr; mrb_int len; ns = (struct RString *)mrb_malloc(mrb, sizeof(struct RString)); ns->tt = MRB_TT_STRING; ns->c = mrb->string_class; if (s->flags & MRB_STR_EMBED) len = (mrb_int)((s->flags & MRB_STR_EMBED_LEN_MASK) >> MRB_STR_EMBED_LEN_SHIFT); else
mrb_value cfunc_pointer_to_s(mrb_state *mrb, mrb_value self) { struct cfunc_type_data *data = DATA_PTR(self); size_t len; mrb_value str; struct RString *s; const char* p = (const char*)get_cfunc_pointer_data(data); len = strlen(p); str = mrb_str_new(mrb, 0, len); s = mrb_str_ptr(str); strcpy(s->ptr, p); s->len = strlen(s->ptr); return str; }
void mrb_irep_free(mrb_state *mrb, mrb_irep *irep) { size_t i; if (!(irep->flags & MRB_ISEQ_NO_FREE)) mrb_free(mrb, irep->iseq); for (i=0; i<irep->plen; i++) { if (mrb_type(irep->pool[i]) == MRB_TT_STRING) { if ((mrb_str_ptr(irep->pool[i])->flags & (MRB_STR_NOFREE|MRB_STR_EMBED)) == 0) { mrb_free(mrb, RSTRING_PTR(irep->pool[i])); } mrb_free(mrb, mrb_obj_ptr(irep->pool[i])); } #ifdef MRB_WORD_BOXING else if (mrb_type(irep->pool[i]) == MRB_TT_FLOAT) { mrb_free(mrb, mrb_obj_ptr(irep->pool[i])); } #endif } mrb_free(mrb, irep->pool); mrb_free(mrb, irep->syms); for (i=0; i<irep->rlen; i++) { mrb_irep_decref(mrb, irep->reps[i]); } mrb_free(mrb, irep->reps); mrb_free(mrb, (void *)irep->filename); mrb_free(mrb, irep->lines); mrb_free(mrb, irep->prof_info); if (irep->jit_entry_tab) { int i; int j; for (i = 0; i < irep->ilen; i++) { for (j = 0; j < irep->jit_entry_tab[i].size; j++) { if (irep->jit_entry_tab[i].body[j].reginfo) { mrb_free(mrb, irep->jit_entry_tab[i].body[j].reginfo); } } } mrb_free(mrb, irep->jit_entry_tab->body); mrb_free(mrb, irep->jit_entry_tab); } mrb_debug_info_free(mrb, irep->debug_info); mrb_free(mrb, irep); }
static mrb_value mrb_str_setbyte(mrb_state *mrb, mrb_value str) { mrb_int pos, byte; long len = RSTRING_LEN(str); mrb_get_args(mrb, "ii", &pos, &byte); if (pos < -len || len <= pos) mrb_raisef(mrb, E_INDEX_ERROR, "index %S is out of array", mrb_fixnum_value(pos)); if (pos < 0) pos += len; mrb_str_modify(mrb, mrb_str_ptr(str)); byte &= 0xff; RSTRING_PTR(str)[pos] = byte; return mrb_fixnum_value((unsigned char)byte); }
static void ngx_mrb_raise_file_error(mrb_state *mrb, mrb_value obj, ngx_http_request_t *r, char *code_file) { struct RString *str; char *err_out; obj = mrb_funcall(mrb, obj, "inspect", 0); if (mrb_type(obj) == MRB_TT_STRING) { str = mrb_str_ptr(obj); err_out = str->ptr; ngx_log_error(NGX_LOG_ERR , r->connection->log , 0 , "mrb_run failed. file: %s error: %s" , code_file , err_out ); } }
mrb_value mrb_any_to_s(mrb_state *mrb, mrb_value obj) { const char *cname = mrb_obj_classname(mrb, obj); size_t len; mrb_value str; struct RString *s; len = strlen(cname)+6+16; str = mrb_str_new(mrb, 0, len); /* 6:tags 16:addr */ s = mrb_str_ptr(str); // snprintf(RSTRING(str)->ptr, len+1, "#<%s:0x%lx>", cname, obj); sprintf(s->buf, "#<%s:0x%lx>", cname, (unsigned long)(obj.value.p)); s->len = strlen(s->buf); /*if (OBJ_TAINTED(obj)) OBJ_TAINT(str);*/ return str; }
mrb_value printstr(mrb_state *mrb, mrb_value obj) { struct RString *str; char *s; size_t len; if (mrb_type(obj) == MRB_TT_STRING) { str = mrb_str_ptr(obj); s = str->buf; len = str->len; while (len--) { putc(*s, stdout); s++; } } return obj; }
void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) { const struct types *type = builtin_types; struct RString *s; int xt; /*if (x == Qundef) { //mrb_bug("undef leaked to the Ruby space"); printf ("undef leaked to the Ruby space\n"); }*/ xt = mrb_type(x); if ((xt != t) || (xt == MRB_TT_DATA)) { while (type->type < MRB_TT_MAXDEFINE) { if (type->type == t) { const char *etype; if (mrb_nil_p(x)) { etype = "nil"; } else if (mrb_type(x) == MRB_TT_FIXNUM) { etype = "Fixnum"; } else if (mrb_type(x) == MRB_TT_SYMBOL) { etype = "Symbol"; } else if (mrb_special_const_p(x)) { s = mrb_str_ptr(mrb_obj_as_string(mrb, x)); etype = s->buf; } else { etype = mrb_obj_classname(mrb, x); } mrb_raise(mrb, E_TYPE_ERROR, "wrong argument type %s (expected %s)", etype, type->name); } type++; } /*mrb_bug("unknown type 0x%x", t);*/ printf ("unknown type 0x%x (0x%x given)", t, mrb_type(x)); } }
void ap_mrb_raise_error(mrb_state *mrb, mrb_value obj, request_rec *r) { struct RString *str; char *err_out; obj = mrb_funcall(mrb, obj, "inspect", 0); if (mrb_type(obj) == MRB_TT_STRING) { str = mrb_str_ptr(obj); err_out = str->ptr; ap_log_rerror(APLOG_MARK , APLOG_ERR , 0 , r , "%s ERROR %s: mrb_run failed. error: %s" , MODULE_NAME , __func__ , err_out ); } }
void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) { const struct types *type = builtin_types; struct RString *s; enum mrb_vtype xt; xt = mrb_type(x); if ((xt != t) || (xt == MRB_TT_DATA)) { while (type->type < MRB_TT_MAXDEFINE) { if (type->type == t) { const char *etype; if (mrb_nil_p(x)) { etype = "nil"; } else if (mrb_fixnum_p(x)) { etype = "Fixnum"; } else if (mrb_type(x) == MRB_TT_SYMBOL) { etype = "Symbol"; } else if (mrb_special_const_p(x)) { s = mrb_str_ptr(mrb_obj_as_string(mrb, x)); etype = s->ptr; } else { etype = mrb_obj_classname(mrb, x); } mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected %S)", mrb_str_new_cstr(mrb, etype), mrb_str_new_cstr(mrb, type->name)); } type++; } mrb_raisef(mrb, E_TYPE_ERROR, "unknown type %S (%S given)", mrb_fixnum_value(t), mrb_fixnum_value(mrb_type(x))); } }
int mrb_cloexec_open(mrb_state *mrb, const char *pathname, mrb_int flags, mrb_int mode) { mrb_value emsg; int fd, retry = FALSE; char* fname = mrb_locale_from_utf8(pathname, -1); #ifdef O_CLOEXEC /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */ flags |= O_CLOEXEC; #elif defined O_NOINHERIT flags |= O_NOINHERIT; #endif reopen: fd = open(fname, (int)flags, (fmode_t)mode); if (fd == -1) { if (!retry) { switch (errno) { case ENFILE: case EMFILE: mrb_garbage_collect(mrb); retry = TRUE; goto reopen; } } emsg = mrb_format(mrb, "open %S", mrb_str_new_cstr(mrb, pathname)); mrb_str_modify(mrb, mrb_str_ptr(emsg)); mrb_sys_fail(mrb, RSTRING_PTR(emsg)); } mrb_locale_free(fname); if (fd <= 2) { mrb_fd_cloexec(mrb, fd); } return fd; }
/* retrieve arguments from mrb_state. mrb_get_args(mrb, format, ...) returns number of arguments parsed. fortmat specifiers: o: Object [mrb_value] S: String [mrb_value] A: Array [mrb_value] H: Hash [mrb_value] s: String [char*,int] z: String [char*] a: Array [mrb_value*,int] f: Float [mrb_float] i: Integer [mrb_int] n: Symbol [mrb_sym] &: Block [mrb_value] *: rest argument [mrb_value*,int] |: optional */ int mrb_get_args(mrb_state *mrb, const char *format, ...) { char c; int i = 0; mrb_value *sp = mrb->stack + 1; va_list ap; int argc = mrb->ci->argc; int opt = 0; va_start(ap, format); if (argc < 0) { struct RArray *a = mrb_ary_ptr(mrb->stack[1]); argc = a->len; sp = a->ptr; } while ((c = *format++)) { switch (c) { case '|': case '*': case '&': break; default: if (argc <= i && !opt) { mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); } } switch (c) { case 'o': { mrb_value *p; p = va_arg(ap, mrb_value*); if (i < argc) { *p = *sp++; i++; } } break; case 'S': { mrb_value *p; p = va_arg(ap, mrb_value*); if (i < argc) { *p = to_str(mrb, *sp++); i++; } } break; case 'A': { mrb_value *p; p = va_arg(ap, mrb_value*); if (i < argc) { *p = to_ary(mrb, *sp++); i++; } } break; case 'H': { mrb_value *p; p = va_arg(ap, mrb_value*); if (i < argc) { *p = to_hash(mrb, *sp++); i++; } } break; case 's': { mrb_value ss; struct RString *s; char **ps = 0; int *pl = 0; ps = va_arg(ap, char**); pl = va_arg(ap, int*); if (i < argc) { ss = to_str(mrb, *sp++); s = mrb_str_ptr(ss); *ps = s->ptr; *pl = s->len; i++; } } break; case 'z': { mrb_value ss; struct RString *s; char **ps; ps = va_arg(ap, char**); if (i < argc) { ss = to_str(mrb, *sp++); s = mrb_str_ptr(ss); if (strlen(s->ptr) != s->len) { mrb_raise(mrb, E_ARGUMENT_ERROR, "String contains NUL"); } *ps = s->ptr; i++; } } break; case 'a': { mrb_value aa; struct RArray *a; mrb_value **pb; int *pl; pb = va_arg(ap, mrb_value**); pl = va_arg(ap, int*); if (i < argc) { aa = to_ary(mrb, *sp++); a = mrb_ary_ptr(aa); *pb = a->ptr; *pl = a->len; i++; } } break; case 'f': { mrb_float *p; p = va_arg(ap, mrb_float*); if (i < argc) { switch (mrb_type(*sp)) { case MRB_TT_FLOAT: *p = mrb_float(*sp); break; case MRB_TT_FIXNUM: *p = (mrb_float)mrb_fixnum(*sp); break; case MRB_TT_STRING: mrb_raise(mrb, E_TYPE_ERROR, "String can't be coerced into Float"); break; default: { mrb_value tmp; tmp = mrb_convert_type(mrb, *sp, MRB_TT_FLOAT, "Float", "to_f"); *p = mrb_float(tmp); } break; } sp++; i++; } } break; case 'i': { mrb_int *p; p = va_arg(ap, mrb_int*); if (i < argc) { switch (mrb_type(*sp)) { case MRB_TT_FIXNUM: *p = mrb_fixnum(*sp); break; case MRB_TT_FLOAT: { mrb_float f = mrb_float(*sp); if (!FIXABLE(f)) { mrb_raise(mrb, E_RANGE_ERROR, "float too big for int"); } *p = (mrb_int)f; } break; case MRB_TT_FALSE: *p = 0; break; default: { mrb_value tmp; tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int"); *p = mrb_fixnum(tmp); } break; } sp++; i++; } } break; case 'n': { mrb_sym *symp; symp = va_arg(ap, mrb_sym*); if (i < argc) { mrb_value ss; ss = *sp++; if (mrb_type(ss) == MRB_TT_SYMBOL) { *symp = mrb_symbol(ss); } else { *symp = mrb_intern_str(mrb, to_str(mrb, ss)); } i++; } } break; case '&': { mrb_value *p, *bp; p = va_arg(ap, mrb_value*); if (mrb->ci->argc < 0) { bp = mrb->stack + 2; } else { bp = mrb->stack + mrb->ci->argc + 1; } *p = *bp; } break; case '|': opt = 1; break; case '*': { mrb_value **var; int *pl; var = va_arg(ap, mrb_value**); pl = va_arg(ap, int*); if (argc > i) { *pl = argc-i; if (*pl > 0) { *var = sp; i = argc; } i = argc; sp += *pl; } else { *pl = 0; *var = NULL; } } break; default: mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid argument specifier %c", c); break; } } if (!c && argc > i) { mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); } va_end(ap); return i; }
int mrb_get_args(mrb_state *mrb, const char *format, ...) { char c; int i=0; mrb_value *sp = mrb->stack + 1; va_list ap; int argc = mrb->ci->argc; int *argcp; va_start(ap, format); if (argc < 0) { struct RArray *a = mrb_ary_ptr(mrb->stack[1]); argc = a->len; sp = a->buf; } while ((c = *format++)) { switch (c) { case 'o': { mrb_value *p; p = va_arg(ap, mrb_value*); *p = *sp; i++; sp++; } break; case 'i': { mrb_int *p; p = va_arg(ap, mrb_int*); switch (sp->tt) { case MRB_TT_FIXNUM: *p = mrb_fixnum(*sp); break; case MRB_TT_FLOAT: *p = (mrb_int)mrb_float(*sp); break; case MRB_TT_FALSE: *p = 0; break; default: { mrb_value tmp; tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int"); *p = mrb_fixnum(tmp); } break; } i++; sp++; } break; case 'f': { mrb_float *p; p = va_arg(ap, mrb_float*); switch (sp->tt) { case MRB_TT_FLOAT: *p = mrb_float(*sp); break; case MRB_TT_FIXNUM: *p = (mrb_float)mrb_fixnum(*sp); break; case MRB_TT_FALSE: *p = 0.0; break; default: { mrb_value tmp; tmp = mrb_convert_type(mrb, *sp, MRB_TT_FLOAT, "Float", "to_f"); *p = mrb_float(tmp); } break; } i++; sp++; } break; case 's': { char **ps = 0; size_t *pl = 0; struct RString *s; if (argc > i) { s = mrb_str_ptr(*sp); ps = va_arg(ap, char**); *ps = s->buf; pl = va_arg(ap, size_t*); *pl = s->len; } i++; sp++; } break; case 'a': { mrb_value *var; var = va_arg(ap, mrb_value*); if (argc > i) { if (var) { memcpy(var, sp, sizeof(mrb_value)*(argc-i)); } //i = mrb->argc; } else { if (var) *var = mrb_ary_new(mrb); } argcp = va_arg(ap, int*); *argcp = argc-i; goto last_var; } break; case 'b': { struct RProc **p; mrb_value *bp = mrb->stack + 1; p = va_arg(ap, struct RProc**); if (mrb->ci->argc > 0) { bp += mrb->ci->argc; } if (mrb_nil_p(*bp)) *p = 0; else *p = mrb_proc_ptr(*bp); } break; case '&': { mrb_value *p, *bp = mrb->stack + 1; p = va_arg(ap, mrb_value*); if (mrb->ci->argc > 0) { bp += mrb->ci->argc; } *p = *bp; } break; case '*': { mrb_value **var; var = va_arg(ap, mrb_value**); argcp = va_arg(ap, int*); if (argc > i) { *argcp = argc-i; if (*argcp > 0) { if (var) { *var = sp; } i += *argcp; } } else { *argcp = 0; *var = NULL; } goto last_var; } break; } }
/* retrieve arguments from mrb_state. mrb_get_args(mrb, format, ...) returns number of arguments parsed. fortmat specifiers: o: Object [mrb_value] S: String [mrb_value] A: Array [mrb_value] H: Hash [mrb_value] s: String [char*,int] z: String [char*] a: Array [mrb_value*,int] f: Float [mrb_float] i: Integer [mrb_int] &: Block [mrb_value] *: rest argument [mrb_value*,int] |: optional */ int mrb_get_args(mrb_state *mrb, const char *format, ...) { char c; int i = 0; mrb_value *sp = mrb->stack + 1; va_list ap; int argc = mrb->ci->argc; int opt = 0; va_start(ap, format); if (argc < 0) { struct RArray *a = mrb_ary_ptr(mrb->stack[1]); argc = a->len; sp = a->buf; } while ((c = *format++)) { switch (c) { case '|': case '*': case '&': break; default: if (argc <= i) { if (opt) continue; mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); } } switch (c) { case 'o': { mrb_value *p; p = va_arg(ap, mrb_value*); *p = *sp; i++; sp++; } break; case 'S': { mrb_value *p; p = va_arg(ap, mrb_value*); *p = to_str(mrb, *sp); i++; sp++; } break; case 'A': { mrb_value *p; p = va_arg(ap, mrb_value*); *p = to_ary(mrb, *sp); i++; sp++; } break; case 'H': { mrb_value *p; p = va_arg(ap, mrb_value*); *p = to_hash(mrb, *sp); i++; sp++; } break; case 's': { mrb_value ss; struct RString *s; char **ps = 0; int *pl = 0; ss = to_str(mrb, *sp); s = mrb_str_ptr(ss); ps = va_arg(ap, char**); *ps = s->buf; pl = va_arg(ap, int*); *pl = s->len; i++; sp++; } break; case 'z': { mrb_value ss; struct RString *s; char **ps; ss = to_str(mrb, *sp); s = mrb_str_ptr(ss); if (strlen(s->buf) != s->len) { mrb_raise(mrb, E_ARGUMENT_ERROR, "String contains NUL"); } ps = va_arg(ap, char**); *ps = s->buf; i++; sp++; } break; case 'a': { mrb_value aa; struct RArray *a; mrb_value **pb; int *pl; aa = to_ary(mrb, *sp); a = mrb_ary_ptr(aa); pb = va_arg(ap, mrb_value**); *pb = a->buf; pl = va_arg(ap, int*); *pl = a->len; i++; sp++; } break; case 'f': { mrb_float *p; p = va_arg(ap, mrb_float*); switch (sp->tt) { case MRB_TT_FLOAT: *p = mrb_float(*sp); break; case MRB_TT_FIXNUM: *p = (mrb_float)mrb_fixnum(*sp); break; case MRB_TT_FALSE: *p = 0.0; break; default: { mrb_value tmp; tmp = mrb_convert_type(mrb, *sp, MRB_TT_FLOAT, "Float", "to_f"); *p = mrb_float(tmp); } break; } i++; sp++; } break; case 'i': { mrb_int *p; p = va_arg(ap, mrb_int*); switch (sp->tt) { case MRB_TT_FIXNUM: *p = mrb_fixnum(*sp); break; case MRB_TT_FLOAT: *p = (mrb_int)mrb_float(*sp); break; case MRB_TT_FALSE: *p = 0; break; default: { mrb_value tmp; tmp = mrb_convert_type(mrb, *sp, MRB_TT_FIXNUM, "Integer", "to_int"); *p = mrb_fixnum(tmp); } break; } i++; sp++; } break; case '&': { mrb_value *p, *bp = mrb->stack + 1; p = va_arg(ap, mrb_value*); if (mrb->ci->argc > 0) { bp += mrb->ci->argc; } *p = *bp; } break; case '|': opt = 1; break; case '*': { mrb_value **var; int *pl; var = va_arg(ap, mrb_value**); pl = va_arg(ap, int*); if (argc > i) { *pl = argc-i; if (*pl > 0) { *var = sp; i = argc; } i = argc; sp += *pl; } else { *pl = 0; *var = NULL; } } break; } } if (!c && argc > i) { mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments"); } va_end(ap); return i; }
/* * call-seq: * string.succ -> string * * Returns next sequence of the string; * * a = "abc" * a.succ #=> "abd" */ static mrb_value mrb_str_succ_bang(mrb_state *mrb, mrb_value self) { mrb_value result; unsigned char *p, *e, *b, *t; const char *prepend; struct RString *s = mrb_str_ptr(self); size_t l; if (RSTRING_LEN(self) == 0) return self; mrb_str_modify(mrb, s); l = RSTRING_LEN(self); b = p = (unsigned char*) RSTRING_PTR(self); t = e = p + l; *(e--) = 0; // find trailing ascii/number while (e >= b) { if (ISALNUM(*e)) break; e--; } if (e < b) { e = p + l - 1; result = mrb_str_new_lit(mrb, ""); } else { // find leading letter of the ascii/number b = e; while (b > p) { if (!ISALNUM(*b) || (ISALNUM(*b) && *b != '9' && *b != 'z' && *b != 'Z')) break; b--; } if (!ISALNUM(*b)) b++; result = mrb_str_new(mrb, (char*) p, b - p); } while (e >= b) { if (!ISALNUM(*e)) { if (*e == 0xff) { mrb_str_cat_lit(mrb, result, "\x01"); (*e) = 0; } else (*e)++; break; } prepend = NULL; if (*e == '9') { if (e == b) prepend = "1"; *e = '0'; } else if (*e == 'z') { if (e == b) prepend = "a"; *e = 'a'; } else if (*e == 'Z') { if (e == b) prepend = "A"; *e = 'A'; } else { (*e)++; break; } if (prepend) mrb_str_cat_cstr(mrb, result, prepend); e--; } result = mrb_str_cat(mrb, result, (char*) b, t - b); l = RSTRING_LEN(result); mrb_str_resize(mrb, self, l); memcpy(RSTRING_PTR(self), RSTRING_PTR(result), l); return self; }