Exemplo n.º 1
0
static mrb_value
mrb_mod_to_s(mrb_state *mrb, mrb_value klass)
{
  mrb_value str;

  if (mrb_type(klass) == MRB_TT_SCLASS) {
    mrb_value v = mrb_iv_get(mrb, klass, mrb_intern2(mrb, "__attached__", 12));

    str = mrb_str_new(mrb, "#<Class:", 8);

    switch (mrb_type(v)) {
      case MRB_TT_CLASS:
      case MRB_TT_MODULE:
      case MRB_TT_SCLASS:
        mrb_str_append(mrb, str, mrb_inspect(mrb, v));
        break;
      default:
        mrb_str_append(mrb, str, mrb_any_to_s(mrb, v));
        break;
    }
    mrb_str_cat(mrb, str, ">", 1);
  }
  else {
    struct RClass *c;
    mrb_value path;

    str = mrb_str_buf_new(mrb, 32);
    c = mrb_class_ptr(klass);
    path = mrb_class_path(mrb, c);

    if (mrb_nil_p(path)) {
      switch (mrb_type(klass)) {
        case MRB_TT_CLASS:
          mrb_str_cat(mrb, str, "#<Class:", 8);
          break;

        case MRB_TT_MODULE:
          mrb_str_cat(mrb, str, "#<Module:", 9);
          break;

        default:
          /* Shouldn't be happened? */
          mrb_str_cat(mrb, str, "#<??????:", 9);
          break;
      }
      mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, c));
      mrb_str_cat(mrb, str, ">", 1);
    }
    else {
      str = path;
    }
  }

  return str;
}
Exemplo n.º 2
0
Arquivo: vm.c Projeto: mrbrdo/mruby_cc
static void
localjump_error(mrb_state *mrb, localjump_error_kind kind)
{
  char kind_str[3][7] = { "return", "break", "yield" };
  char kind_str_len[] = { 6, 5, 5 };
  static const char lead[] = "unexpected ";
  mrb_value msg;
  mrb_value exc;

  msg = mrb_str_buf_new(mrb, sizeof(lead) + 7);
  mrb_str_cat(mrb, msg, lead, sizeof(lead) - 1);
  mrb_str_cat(mrb, msg, kind_str[kind], kind_str_len[kind]);
  exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
  mrb->exc = mrb_obj_ptr(exc);
}
Exemplo n.º 3
0
mrb_value
mrb_class_find_path(mrb_state *mrb, struct RClass *c)
{
  mrb_value outer, path;
  mrb_sym name;
  const char *str;
  mrb_int len;
  mrb_sym osym = mrb_intern_lit(mrb, "__outer__");

  outer = mrb_obj_iv_get(mrb, (struct RObject*)c, osym);
  if (mrb_nil_p(outer)) return outer;
  name = find_class_sym(mrb, mrb_class_ptr(outer), c);
  if (name == 0) return mrb_nil_value();
  str = mrb_class_name(mrb, mrb_class_ptr(outer));
  path = mrb_str_new_capa(mrb, 40);
  mrb_str_cat_cstr(mrb, path, str);
  mrb_str_cat_cstr(mrb, path, "::");

  str = mrb_sym2name_len(mrb, name, &len);
  mrb_str_cat(mrb, path, str, len);
  iv_del(mrb, c->iv, osym, NULL);
  iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path);
  mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path);
  return path;
}
Exemplo n.º 4
0
mrb_value
mrb_class_find_path(mrb_state *mrb, struct RClass *c)
{
  struct RClass *outer;
  mrb_value path;
  mrb_sym name;
  const char *str;
  mrb_int len;

  if (detect_outer_loop(mrb, c)) return mrb_nil_value();
  outer = outer_class(mrb, c);
  if (outer == NULL) return mrb_nil_value();
  name = find_class_sym(mrb, outer, c);
  if (name == 0) return mrb_nil_value();
  str = mrb_class_name(mrb, outer);
  path = mrb_str_new_capa(mrb, 40);
  mrb_str_cat_cstr(mrb, path, str);
  mrb_str_cat_cstr(mrb, path, "::");

  str = mrb_sym2name_len(mrb, name, &len);
  mrb_str_cat(mrb, path, str, len);
  if (RSTRING_PTR(path)[0] != '#') {
    iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL);
    iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path);
    mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path);
  }
  return path;
}
Exemplo n.º 5
0
static void
get_backtrace_i(mrb_state *mrb, struct backtrace_location *loc, void *data)
{
  mrb_value ary, str;
  char buf[32];
  int ai = mrb_gc_arena_save(mrb);

  ary = mrb_obj_value((struct RArray*)data);

  str = mrb_str_new_cstr(mrb, loc->filename);
  snprintf(buf, sizeof(buf), ":%d", loc->lineno);
  mrb_str_cat_cstr(mrb, str, buf);

  if (loc->method) {
    mrb_str_cat_lit(mrb, str, ":in ");

    if (loc->class_name) {
      mrb_str_cat_cstr(mrb, str, loc->class_name);
      mrb_str_cat(mrb, str, &loc->sep, 1);
    }

    mrb_str_cat_cstr(mrb, str, loc->method);
  }

  mrb_ary_push(mrb, ary, str);
  mrb_gc_arena_restore(mrb, ai);
}
Exemplo n.º 6
0
static mrb_value
inspect_hash(mrb_state *mrb, mrb_value hash, int recur)
{
  mrb_value str, str2;
  khash_t(ht) *h = RHASH_TBL(hash);
  khiter_t k;

  if (recur) return mrb_str_new_lit(mrb, "{...}");

  str = mrb_str_new_lit(mrb, "{");
  if (h && kh_size(h) > 0) {
    for (k = kh_begin(h); k != kh_end(h); k++) {
      int ai;

      if (!kh_exist(h,k)) continue;

      ai = mrb_gc_arena_save(mrb);

      if (RSTRING_LEN(str) > 1) mrb_str_cat(mrb, str, ", ", 2);

      str2 = mrb_inspect(mrb, kh_key(h,k));
      mrb_str_append(mrb, str, str2);
      mrb_str_buf_cat(mrb, str, "=>", 2);
      str2 = mrb_inspect(mrb, kh_value(h,k));
      mrb_str_append(mrb, str, str2);

      mrb_gc_arena_restore(mrb, ai);
    }
  }
  mrb_str_buf_cat(mrb, str, "}", 1);

  return str;
}
Exemplo n.º 7
0
static int
inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
  mrb_value str = *(mrb_value*)p;
  const char *s;
  mrb_int len;
  mrb_value ins;
  char *sp = RSTRING_PTR(str);

  /* need not to show internal data */
  if (sp[0] == '-') { /* first element */
    sp[0] = '#';
    mrb_str_cat_lit(mrb, str, " ");
  }
  else {
    mrb_str_cat_lit(mrb, str, ", ");
  }
  s = mrb_sym2name_len(mrb, sym, &len);
  mrb_str_cat(mrb, str, s, len);
  mrb_str_cat_lit(mrb, str, "=");
  if (mrb_type(v) == MRB_TT_OBJECT) {
    ins = mrb_any_to_s(mrb, v);
  }
  else {
    ins = mrb_inspect(mrb, v);
  }
  mrb_str_cat_str(mrb, str, ins);
  return 0;
}
Exemplo n.º 8
0
Arquivo: hash.c Projeto: Zyxwvu/mruby
static khint_t
mrb_hash_ht_hash_func(mrb_state *mrb, mrb_value key)
{
  char type = mrb_type(key);
  mrb_value s1 = mrb_str_new(mrb, &type, 1);
  mrb_value s2 = mrb_inspect(mrb, key);
  s1 = mrb_str_cat(mrb, s1, RSTRING_PTR(s2), RSTRING_LEN(s2));
  return kh_str_hash_func(mrb, RSTRING_PTR(s1));
}
Exemplo n.º 9
0
const char*
mrb_class_name(mrb_state *mrb, struct RClass* c)
{
  mrb_value path = mrb_class_path(mrb, c);
  if (mrb_nil_p(path)) {
    path = mrb_str_new(mrb, "#<Class:", 8);
    mrb_str_concat(mrb, path, mrb_ptr_to_str(mrb, c));
    mrb_str_cat(mrb, path, ">", 1);
  }
  return mrb_str_ptr(path)->ptr;
}
Exemplo n.º 10
0
mrb_value
mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
{
    iv_tbl *t = obj->iv;
    size_t len = iv_size(mrb, t);

    if (len > 0) {
        const char *cn = mrb_obj_classname(mrb, mrb_obj_value(obj));
        mrb_value str = mrb_str_buf_new(mrb, 30);

        mrb_str_buf_cat(mrb, str, "-<", 2);
        mrb_str_cat2(mrb, str, cn);
        mrb_str_cat(mrb, str, ":", 1);
        mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, obj));

        iv_foreach(mrb, t, inspect_i, &str);
        mrb_str_cat(mrb, str, ">", 1);
        return str;
    }
    return mrb_any_to_s(mrb, mrb_obj_value(obj));
}
Exemplo n.º 11
0
static int
inspect_i(mrb_state *mrb, mrb_sym sym, mrb_value v, void *p)
{
    mrb_value str = *(mrb_value*)p;
    const char *s;
    size_t len;

    /* need not to show internal data */
    if (RSTRING_PTR(str)[0] == '-') { /* first element */
        RSTRING_PTR(str)[0] = '#';
        mrb_str_cat(mrb, str, " ", 1);
    }
    else {
        mrb_str_cat(mrb, str, ", ", 2);
    }
    s = mrb_sym2name_len(mrb, sym, &len);
    mrb_str_cat(mrb, str, s, len);
    mrb_str_cat(mrb, str, "=", 1);
    mrb_str_append(mrb, str, mrb_inspect(mrb, v));
    return 0;
}
Exemplo n.º 12
0
Arquivo: error.c Projeto: koie/mruby
static mrb_value
exc_inspect(mrb_state *mrb, mrb_value exc)
{
  mrb_value str, mesg, file, line;

  mesg = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "mesg", 4));
  file = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "file", 4));
  line = mrb_attr_get(mrb, exc, mrb_intern2(mrb, "line", 4));

  if (!mrb_nil_p(file) && !mrb_nil_p(line)) {
    str = file;
    mrb_str_cat(mrb, str, ":", 1);
    mrb_str_append(mrb, str, line);
    mrb_str_cat(mrb, str, ": ", 2);
    if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
      mrb_str_append(mrb, str, mesg);
      mrb_str_cat(mrb, str, " (", 2);
    }
    mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
    if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
      mrb_str_cat(mrb, str, ")", 1);
    }
  }
  else {
    str = mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
    if (!mrb_nil_p(mesg) && RSTRING_LEN(mesg) > 0) {
      mrb_str_cat(mrb, str, ": ", 2);
      mrb_str_append(mrb, str, mesg);
    } else {
      mrb_str_cat(mrb, str, ": ", 2);
      mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
    }
  }
  return str;
}
Exemplo n.º 13
0
static void post_response(struct st_h2o_mruby_http_request_context_t *ctx, int status,
                          const h2o_http1client_header_t *headers_sorted, size_t num_headers)
{
    mrb_state *mrb = ctx->generator->ctx->shared->mrb;
    int gc_arena = mrb_gc_arena_save(mrb);
    size_t i;

    mrb_value resp = mrb_ary_new_capa(mrb, 3);

    /* set status */
    mrb_ary_set(mrb, resp, 0, mrb_fixnum_value(status));

    /* set headers */
    mrb_value headers_hash = mrb_hash_new_capa(mrb, (int)num_headers);
    for (i = 0; i < num_headers; ++i) {
        /* skip the headers, we determine the eos! */
        if (h2o_memis(headers_sorted[i].name, headers_sorted[i].name_len, H2O_STRLIT("content-length")) ||
            h2o_memis(headers_sorted[i].name, headers_sorted[i].name_len, H2O_STRLIT("transfer-encoding")))
            continue;
        /* build and set the hash entry */
        mrb_value k = mrb_str_new(mrb, headers_sorted[i].name, headers_sorted[i].name_len);
        mrb_value v = mrb_str_new(mrb, headers_sorted[i].value, headers_sorted[i].value_len);
        while (i + 1 < num_headers && h2o_memis(headers_sorted[i].name, headers_sorted[i].name_len, headers_sorted[i + 1].name,
                                                headers_sorted[i + 1].name_len)) {
            ++i;
            v = mrb_str_cat_lit(mrb, v, "\n");
            v = mrb_str_cat(mrb, v, headers_sorted[i].value, headers_sorted[i].value_len);
        }
        mrb_hash_set(mrb, headers_hash, k, v);
    }
    mrb_ary_set(mrb, resp, 1, headers_hash);

    /* set input stream */
    assert(mrb_nil_p(ctx->refs.input_stream));
    ctx->refs.input_stream = h2o_mruby_create_data_instance(
        mrb, mrb_ary_entry(ctx->generator->ctx->shared->constants, H2O_MRUBY_HTTP_INPUT_STREAM_CLASS), ctx, &input_stream_type);
    mrb_ary_set(mrb, resp, 2, ctx->refs.input_stream);

    if (mrb_nil_p(ctx->receiver)) {
        /* is async */
        mrb_funcall(mrb, ctx->refs.request, "_set_response", 1, resp);
        if (mrb->exc != NULL) {
            fprintf(stderr, "_set_response failed\n");
            abort();
        }
    } else {
        /* send response to the waiting receiver */
        h2o_mruby_run_fiber(ctx->generator, detach_receiver(ctx), resp, NULL);
    }

    mrb_gc_arena_restore(mrb, gc_arena);
}
Exemplo n.º 14
0
static mrb_value
range_to_s(mrb_state *mrb, mrb_value range)
{
  mrb_value str, str2;
  struct RRange *r = mrb_range_ptr(range);

  str  = mrb_obj_as_string(mrb, r->edges->beg);
  str2 = mrb_obj_as_string(mrb, r->edges->end);
  str  = mrb_str_dup(mrb, str);
  mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
  mrb_str_append(mrb, str, str2);

  return str;
}
Exemplo n.º 15
0
mrb_value
mrb_any_to_s(mrb_state *mrb, mrb_value obj)
{
  mrb_value str = mrb_str_buf_new(mrb, 20);
  const char *cname = mrb_obj_classname(mrb, obj);

  mrb_str_buf_cat(mrb, str, "#<", 2);
  mrb_str_cat2(mrb, str, cname);
  mrb_str_cat(mrb, str, ":", 1);
  mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(obj)));
  mrb_str_buf_cat(mrb, str, ">", 1);

  return str;
}
Exemplo n.º 16
0
mrb_value
mrb_obj_iv_inspect(mrb_state *mrb, struct RObject *obj)
{
  iv_tbl *t = obj->iv;
  int len = iv_size(mrb, t);

  if (len > 0) {
    const char *cn = mrb_obj_classname(mrb, mrb_obj_value(obj));
    mrb_value str = mrb_sprintf(mrb, "-<%s:%p", cn, (void*)obj);

    iv_foreach(mrb, t, inspect_i, &str);
    mrb_str_cat(mrb, str, ">", 1);
    return str;
  }
  return mrb_any_to_s(mrb, mrb_obj_value(obj));
}
Exemplo n.º 17
0
static mrb_value
inspect_range(mrb_state *mrb, mrb_value range, mrb_value dummy, int recur)
{
  mrb_value str, str2;
  struct RRange *r = mrb_range_ptr(range);

  if (recur) {
    return mrb_str_new2(mrb, r->excl ? "(... ... ...)" : "(... .. ...)");
  }
  str  = mrb_inspect(mrb, r->edges->beg);
  str2 = mrb_inspect(mrb, r->edges->end);
  str  = mrb_str_dup(mrb, str);
  mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
  mrb_str_append(mrb, str, str2);

  return str;
}
Exemplo n.º 18
0
Arquivo: range.c Projeto: jjue/mruby
static mrb_value
inspect_range(mrb_state *mrb, mrb_value range, mrb_value dummy, int recur)
{
  mrb_value str, str2;
  struct RRange *r = mrb_range_ptr(range);

  if (recur) {
    static const char s[2][14] = { "(... ... ...)", "(... .. ...)" };
    static const int n[] = { 13, 12 };
    int idx;

    idx = (r->excl) ? 0 : 1;
    return mrb_str_new(mrb, s[idx], n[idx]);
  }
  str  = mrb_inspect(mrb, r->edges->beg);
  str2 = mrb_inspect(mrb, r->edges->end);
  str  = mrb_str_dup(mrb, str);
  mrb_str_cat(mrb, str, "...", r->excl ? 3 : 2);
  mrb_str_append(mrb, str, str2);

  return str;
}
Exemplo n.º 19
0
mrb_value
mrb_restore_backtrace(mrb_state *mrb)
{
  int i;
  mrb_value backtrace;

  backtrace = mrb_ary_new(mrb);
  for (i = 0; i < mrb->backtrace.n; i++) {
    int ai;
    mrb_backtrace_entry *entry;
    mrb_value mrb_entry;
    char buf[32];

    ai = mrb_gc_arena_save(mrb);
    entry = &(mrb->backtrace.entries[i]);

    mrb_entry = mrb_str_new_cstr(mrb, entry->filename);
    snprintf(buf, sizeof(buf), ":%d", entry->lineno);
    mrb_str_cat_cstr(mrb, mrb_entry, buf);
    if (entry->method_id != 0) {
      mrb_str_cat_lit(mrb, mrb_entry, ":in ");

      if (entry->klass) {
        mrb_str_cat_cstr(mrb, mrb_entry, mrb_class_name(mrb, entry->klass));
        mrb_str_cat(mrb, mrb_entry, &entry->sep, 1);
      }

      mrb_str_cat_cstr(mrb, mrb_entry, mrb_sym2name(mrb, entry->method_id));
    }

    mrb_ary_push(mrb, backtrace, mrb_entry);

    mrb_gc_arena_restore(mrb, ai);
  }

  return backtrace;
}
Exemplo n.º 20
0
/*********************************************************
 * main
 *********************************************************/
static mrb_value
mrb_value_to_string(mrb_state* mrb, mrb_value value) {
  mrb_value str;

  if (mrb_nil_p(value)) {
    return mrb_str_new_cstr(mrb, "null");
  }

  switch (mrb_type(value)) {
  case MRB_TT_FIXNUM:
  case MRB_TT_FLOAT:
  case MRB_TT_TRUE:
  case MRB_TT_FALSE:
  case MRB_TT_UNDEF:
    str = mrb_funcall(mrb, value, "to_s", 0, NULL);
    break;
  case MRB_TT_SYMBOL:
    value = mrb_funcall(mrb, value, "to_s", 0, NULL);
    /* FALLTHROUGH */
  case MRB_TT_STRING:
    {
      int ai = mrb_gc_arena_save(mrb);
      char* ptr = RSTRING_PTR(value);
      char* end = RSTRING_END(value);
      str = mrb_str_new_cstr(mrb, "\""); 
      while (ptr < end && *ptr) {
        switch (*ptr) {
        case '\\':
          str = mrb_str_cat_cstr(mrb, str, "\\\\");
          break;
        case '"':
          str = mrb_str_cat_cstr(mrb, str, "\\\"");
          break;
        case '\b':
          str = mrb_str_cat_cstr(mrb, str, "\\b");
          break;
        case '\f':
          str = mrb_str_cat_cstr(mrb, str, "\\f");
          break;
        case '\n':
          str = mrb_str_cat_cstr(mrb, str, "\\n");
          break;
        case '\r':
          str = mrb_str_cat_cstr(mrb, str, "\\r");
          break;
        case '\t':
          str = mrb_str_cat_cstr(mrb, str, "\\t");
          break;
        default:
          // TODO: handle unicode
          str = mrb_str_cat(mrb, str, ptr, 1);
        }
        ptr++;
      }
      mrb_str_cat_cstr(mrb, str, "\""); 
      mrb_gc_arena_restore(mrb, ai);
    }
    break;
  case MRB_TT_HASH:
    {
      mrb_value keys;
      int n, l;
      str = mrb_str_new_cstr(mrb, "{");
      keys = mrb_hash_keys(mrb, value);
      l = RARRAY_LEN(keys);
      for (n = 0; n < l; n++) {
        mrb_value obj;
        int ai = mrb_gc_arena_save(mrb);
        mrb_value key = mrb_ary_entry(keys, n);
        mrb_value enckey = mrb_funcall(mrb, key, "to_s", 0, NULL);
        enckey = mrb_funcall(mrb, enckey, "inspect", 0, NULL);
        mrb_str_concat(mrb, str, enckey);
        mrb_str_cat_cstr(mrb, str, ":");
        obj = mrb_hash_get(mrb, value, key);
        mrb_str_concat(mrb, str, mrb_value_to_string(mrb, obj));
        if (n != l - 1) {
          mrb_str_cat_cstr(mrb, str, ",");
        }
        mrb_gc_arena_restore(mrb, ai);
      }
      mrb_str_cat_cstr(mrb, str, "}");
      break;
    }
  case MRB_TT_ARRAY:
    {
      int n, l;
      str = mrb_str_new_cstr(mrb, "[");
      l = RARRAY_LEN(value);
      for (n = 0; n < l; n++) {
        int ai = mrb_gc_arena_save(mrb);
        mrb_value obj = mrb_ary_entry(value, n);
        mrb_str_concat(mrb, str, mrb_value_to_string(mrb, obj));
        if (n != l - 1) {
          mrb_str_cat_cstr(mrb, str, ",");
        }
        mrb_gc_arena_restore(mrb, ai);
      }
      mrb_str_cat_cstr(mrb, str, "]");
      break;
    }
  default:
    mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument");
  }
  return str;
}
Exemplo n.º 21
0
/*
 *  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;
}