Example #1
0
static mrb_value mrb_memcached_set(mrb_state *mrb, mrb_value self)
{
  mrb_value key, val;
  mrb_int expr = 0;
  mrb_memcached_data *data = DATA_PTR(self);
  memcached_return mrt;

  mrb_get_args(mrb, "oo|i", &key, &val, &expr);
  switch (mrb_type(key)) {
    case MRB_TT_STRING:
      break;
    case MRB_TT_SYMBOL:
      key = mrb_obj_as_string(mrb, key);
      break;
    default:
      mrb_raise(mrb, E_RUNTIME_ERROR, "memcached key type is string or symbol");
  }
  val = mrb_obj_as_string(mrb, val);

  mrt = memcached_set(data->mst, RSTRING_PTR(key), RSTRING_LEN(key), RSTRING_PTR(val), RSTRING_LEN(val), (time_t)expr, (uint32_t)0);
  if (mrt != MEMCACHED_SUCCESS && mrt != MEMCACHED_BUFFERED) {
    // set failed
    return mrb_nil_value();
  }
  return mrb_fixnum_value(mrt);
}
Example #2
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;
}
Example #3
0
static mrb_value mrb_vedis_set(mrb_state *mrb, mrb_value self)
{
    int ret;
    vedis *vstore = DATA_PTR(self);
    mrb_value key_obj, val_obj;
    const char *key = NULL;

    mrb_get_args(mrb, "oo", &key_obj, &val_obj);
    switch (mrb_type(key_obj)) {
        case MRB_TT_STRING:
            key = RSTRING_PTR(key_obj);
            break;
        case MRB_TT_SYMBOL:
            key = mrb_sym2name(mrb, mrb_obj_to_sym(mrb, key_obj));
            break;
        default:
            mrb_raise(mrb, E_RUNTIME_ERROR, "vedis key type is string or symbol");
    }
    val_obj = mrb_obj_as_string(mrb, val_obj);
    ret = vedis_kv_store(vstore, key, strlen(key), RSTRING_PTR(val_obj), RSTRING_LEN(val_obj));
    if (ret != VEDIS_OK) {
        mrb_vedis_error(mrb, vstore, 0);
    }

    return val_obj;
}
Example #4
0
static mrb_value mrb_vedis_append_s(mrb_state *mrb, mrb_value key_obj, mrb_value val_obj, vedis *vstore)
{
    int ret;
    const char *key = NULL;
    size_t key_len;

    switch (mrb_type(key_obj)) {
        case MRB_TT_STRING:
            key = RSTRING_PTR(key_obj);
            key_len = RSTRING_LEN(key_obj);
            break;
        case MRB_TT_SYMBOL:
            key = mrb_sym2name(mrb, mrb_obj_to_sym(mrb, key_obj));
            key_len = strlen(key);
            break;
        default:
            mrb_raise(mrb, E_RUNTIME_ERROR, "vedis key type is string or symbol");
    }
    val_obj = mrb_obj_as_string(mrb, val_obj);
    ret = vedis_kv_append(vstore, key, key_len, RSTRING_PTR(val_obj), RSTRING_LEN(val_obj));
    if (ret != VEDIS_OK) {
        mrb_vedis_error(mrb, vstore, 0);
    }
    return mrb_true_value();
}
Example #5
0
static mrb_value mrb_memcached_get(mrb_state *mrb, mrb_value self)
{
  mrb_value key;
  char *val;
  size_t len;
  uint32_t flags;
  memcached_return mrt;
  mrb_memcached_data *data = DATA_PTR(self);

  mrb_get_args(mrb, "o", &key);
  switch (mrb_type(key)) {
    case MRB_TT_STRING:
      break;
    case MRB_TT_SYMBOL:
      key = mrb_obj_as_string(mrb, key);
      break;
    default:
      mrb_raise(mrb, E_RUNTIME_ERROR, "memcached key type is string or symbol");
  }
  val = memcached_get(data->mst, RSTRING_PTR(key), RSTRING_LEN(key), &len, &flags, &(mrt));
  if (mrt != MEMCACHED_SUCCESS && mrt != MEMCACHED_BUFFERED) {
    free(val);
    // value not found
    return mrb_nil_value();
  }
  return mrb_str_new(mrb, val, len);
}
Example #6
0
static mrb_value exc_inspect(mrb_state *mrb, mrb_value exc)
{
    RString *str;
    mrb_value mesg = mrb_attr_get(exc, mrb->intern2("mesg", 4));
    mrb_value file = mrb_attr_get(exc, mrb->intern2("file", 4));
    mrb_value line = mrb_attr_get(exc, mrb->intern2("line", 4));
    RString *mesg_ptr = mesg.is_nil() ? nullptr : mesg.ptr<RString>();
    if (!file.is_nil() && !line.is_nil()) {
        assert(file.is_string());
        str = file.ptr<RString>()->dup();
        str->str_buf_cat(":",1);
        str->str_cat(mrb_obj_as_string(mrb,line));
        str->str_buf_cat(": ",2);
        if (mesg_ptr && mesg_ptr->len > 0) {
            str->str_cat(mesg_ptr);
            str->str_buf_cat(" (",2);
        }
        str->str_buf_cat(mrb_obj_classname(mrb, exc));
        if (mesg_ptr && mesg_ptr->len > 0) {
            str->str_buf_cat(")",1);
        }
    }
    else {
        str = RString::create(mrb,mrb_obj_classname(mrb, exc));
        str->str_buf_cat(": ",2);
        if (mesg_ptr && mesg_ptr->len > 0) {
            str->str_cat(mesg_ptr);
        } else {
            str->str_buf_cat(mrb_obj_classname(mrb, exc));
        }
    }
    return str->wrap();
}
Example #7
0
MRB_API mrb_value
mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep)
{
  if (!mrb_nil_p(sep)) {
    sep = mrb_obj_as_string(mrb, sep);
  }
  return join_ary(mrb, ary, sep, mrb_ary_new(mrb));
}
static mrb_value ngx_http_mruby_rputs(mrb_state *mrb, mrb_value self)
{
    mrb_value                   argv;
    ngx_buf_t                  *b;
    ngx_http_mruby_rputs_chain_list_t *chain;
    u_char                     *str;
    ngx_str_t                   ns;
    ngx_http_request_t         *r;
    ngx_http_mruby_ctx_t       *ctx;

    r   = ngx_http_mruby_get_request();
    ctx = ngx_http_get_module_ctx(r, ngx_http_mruby_module);

    mrb_get_args(mrb, "o", &argv);
    argv = mrb_obj_as_string(mrb, argv);

    ns.data = (u_char *)RSTRING_PTR(argv);
    ns.len  = RSTRING_LEN(argv);

    if (ns.len == 0) {
        return self;
    }

    if (ctx->rputs_chain == NULL) {
        chain       = ngx_pcalloc(r->pool, sizeof(ngx_http_mruby_rputs_chain_list_t));
        chain->out  = ngx_alloc_chain_link(r->pool);
        chain->last = &chain->out;
    } else {
        chain = ctx->rputs_chain;
        (*chain->last)->next = ngx_alloc_chain_link(r->pool);
        chain->last = &(*chain->last)->next;
    }

    b = ngx_calloc_buf(r->pool);
    (*chain->last)->buf = b;
    (*chain->last)->next = NULL;

    if ((str = ngx_pnalloc(r->pool, ns.len + 1)) == NULL) {
        return self;
    }

    ngx_memcpy(str, ns.data, ns.len);
    str[ns.len] = '\0';
    (*chain->last)->buf->pos    = str;
    (*chain->last)->buf->last   = str + ns.len;
    (*chain->last)->buf->memory = 1;
    ctx->rputs_chain = chain;

    if (r->headers_out.content_length_n == -1) {
        r->headers_out.content_length_n += ns.len + 1;
    } else {
        r->headers_out.content_length_n += ns.len;
    }

    return self;
}
Example #9
0
static mrb_value
join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list)
{
  mrb_int i;
  mrb_value result, val, tmp;

  /* check recursive */
  for (i=0; i<RARRAY_LEN(list); i++) {
    if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) {
      mrb_raise(mrb, E_ARGUMENT_ERROR, "recursive array join");
    }
  }

  mrb_ary_push(mrb, list, ary);

  result = mrb_str_buf_new(mrb, 64);

  for (i=0; i<RARRAY_LEN(ary); i++) {
    if (i > 0 && !mrb_nil_p(sep)) {
      mrb_str_cat_str(mrb, result, sep);
    }

    val = RARRAY_PTR(ary)[i];
    switch (mrb_type(val)) {
    case MRB_TT_ARRAY:
    ary_join:
      val = join_ary(mrb, val, sep, list);
      /* fall through */

    case MRB_TT_STRING:
    str_join:
      mrb_str_cat_str(mrb, result, val);
      break;

    default:
      if (!mrb_immediate_p(val)) {
        tmp = mrb_check_string_type(mrb, val);
        if (!mrb_nil_p(tmp)) {
          val = tmp;
          goto str_join;
        }
        tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary");
        if (!mrb_nil_p(tmp)) {
          val = tmp;
          goto ary_join;
        }
      }
      val = mrb_obj_as_string(mrb, val);
      goto str_join;
    }
  }

  mrb_ary_pop(mrb, list);

  return result;
}
static mrb_value ngx_http_mruby_variable_set(mrb_state *mrb, mrb_value self)
{
    char      *k;
    mrb_value  o;

    mrb_get_args(mrb, "zo", &k, &o);
    o = mrb_obj_as_string(mrb, o);

    return ngx_http_mruby_variable_set_internal(mrb, self, k, o);
}
Example #11
0
VCL_STRING vmod_exec(VRT_CTX, struct vmod_priv *priv, VCL_STRING code)
{
    mrb_state *mrb = (mrb_state*)priv->priv;
    mrb_value v = mrb_code_exec(mrb, code);
    if(!mrb_string_p(v))
    {
        v = mrb_obj_as_string(mrb,v);
    }

    return RSTRING_PTR(v);
}
static mrb_value ngx_http_mruby_log(mrb_state *mrb, mrb_value self)
{   
    mrb_value          *argv;
    mrb_value           msg;
    mrb_int             argc;
    mrb_int             log_level;
    ngx_http_request_t *r;

    r = ngx_http_mruby_get_request();

    mrb_get_args(mrb, "*", &argv, &argc);

    if (argc != 2) {
        ngx_log_error(NGX_LOG_ERR
            , r->connection->log
            , 0
            , "%s ERROR %s: argument is not 2"
            , MODULE_NAME
            , __FUNCTION__
        );
        return self;
    }

    if (mrb_type(argv[0]) != MRB_TT_FIXNUM) {
        ngx_log_error(NGX_LOG_ERR
            , r->connection->log
            , 0
            , "%s ERROR %s: argv[0] is not integer"
            , MODULE_NAME
            , __FUNCTION__
        );
        return self;
    }

    log_level = mrb_fixnum(argv[0]);

    if (log_level < 0) {
        ngx_log_error(NGX_LOG_ERR
            , r->connection->log
            , 0
            , "%s ERROR %s: log level is not positive number"
            , MODULE_NAME
            , __FUNCTION__
        );
        return self;
    }

    msg = mrb_obj_as_string(mrb, argv[1]);

    ngx_log_error((ngx_uint_t)log_level, r->connection->log, 0, "%s", RSTRING_PTR(msg));

    return self;
}
Example #13
0
static void
p(mrb_state *mrb, mrb_value obj)
{
  mrb_value val;

  val = mrb_funcall(mrb, obj, "inspect", 0);
  if (!mrb_string_p(val)) {
    val = mrb_obj_as_string(mrb, obj);
  }
  fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout);
  putc('\n', stdout);
}
static mrb_value ngx_http_mruby_parse_http_time(mrb_state *mrb, mrb_value self)
{
    mrb_value mrb_http_time;
    ngx_str_t http_time;

    mrb_get_args(mrb, "o", &mrb_http_time);
    mrb_http_time = mrb_obj_as_string(mrb, mrb_http_time);

    http_time.data = (u_char *)RSTRING_PTR(mrb_http_time);
    http_time.len  = RSTRING_LEN(mrb_http_time);

    return mrb_fixnum_value(ngx_http_parse_time(http_time.data, http_time.len));
}
Example #15
0
static mrb_value
exc_inspect(mrb_state *mrb, mrb_value exc)
{
  mrb_value str;

  str = mrb_str_new2(mrb, mrb_obj_classname(mrb, exc));
  exc = mrb_obj_as_string(mrb, exc);

  if (RSTRING_LEN(exc) > 0) {
    mrb_str_cat2(mrb, str, ": ");
    mrb_str_append(mrb, str, exc);
  }
  return str;
}
ngx_int_t ngx_http_mruby_run_body_filter(ngx_http_request_t *r, ngx_http_mruby_state_t *state, ngx_http_mruby_code_t *code, ngx_flag_t cached)
{
    ngx_http_mruby_ctx_t *ctx;
    mrb_value ARGV, mrb_result;
    size_t body_length;

    ctx  = ngx_http_get_module_ctx(r, ngx_http_mruby_module);

    ngx_http_mruby_push_request(r);

    state->ai = mrb_gc_arena_save(state->mrb);

    ARGV = mrb_ary_new_capa(state->mrb, 1);

    mrb_ary_push(state->mrb, ARGV, mrb_str_new(state->mrb, (char *)ctx->filter_ctx.body, ctx->filter_ctx.body_length));
    mrb_define_global_const(state->mrb, "ARGV", ARGV);

    mrb_result = mrb_run(state->mrb, code->proc, mrb_top_self(state->mrb));
    if (state->mrb->exc) {
        ngx_http_mruby_raise_error(state, code, r);
        mrb_gc_arena_restore(state->mrb, state->ai);
        //mrb_gc_protect(state->mrb, ctx->table);
        if (!cached) {
            ngx_http_mruby_irep_clean(state, code);
        }
        return NGX_ERROR;
    }
    
    mrb_result = mrb_obj_as_string(state->mrb, mrb_result);

    body_length = RSTRING_LEN(mrb_result);

    if (body_length != 0) {
        ctx->filter_ctx.body        = (u_char *)RSTRING_PTR(mrb_result);
        ctx->filter_ctx.body_length = body_length;
    }

    mrb_gc_arena_restore(state->mrb, state->ai);
    //mrb_gc_protect(state->mrb, ctx->table);

    if (!cached) {
        ngx_http_mruby_irep_clean(state, code);
    }

    return NGX_OK;
}
static mrb_value ngx_http_mruby_base64_encode(mrb_state *mrb, mrb_value self)
{
    mrb_value mrb_src;
    ngx_str_t src, dst;

    mrb_get_args(mrb, "o", &mrb_src);
    mrb_src = mrb_obj_as_string(mrb, mrb_src);

    src.data = (u_char *)RSTRING_PTR(mrb_src);
    src.len  = RSTRING_LEN(mrb_src);

    dst.len  = ngx_base64_encoded_length(src.len);
    dst.data = mrb_malloc(mrb, dst.len + 1);

    ngx_encode_base64(&dst, &src);

    return mrb_str_new(mrb, (char *)dst.data, dst.len);
}
Example #18
0
File: error.c Project: Zyxwvu/mruby
static mrb_value
exc_inspect(mrb_state *mrb, mrb_value exc)
{
  mrb_value str, klass;

  klass = mrb_str_new2(mrb, mrb_obj_classname(mrb, exc));
  exc = mrb_obj_as_string(mrb, exc);
  if (RSTRING_LEN(exc) == 0) {
    return klass;
  }

  str = mrb_str_new2(mrb, "#<");
  mrb_str_append(mrb, str, klass);
  mrb_str_cat2(mrb, str, ": ");
  mrb_str_append(mrb, str, exc);
  mrb_str_cat2(mrb, str, ">");

  return str;
}
Example #19
0
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));
  }
}
Example #20
0
File: error.c Project: deweerdt/h2o
static mrb_value
exc_inspect(mrb_state *mrb, mrb_value exc)
{
  mrb_value str, mesg, file, line;
  mrb_bool append_mesg;

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

  append_mesg = !mrb_nil_p(mesg);
  if (append_mesg) {
    mesg = mrb_obj_as_string(mrb, mesg);
    append_mesg = RSTRING_LEN(mesg) > 0;
  }

  if (!mrb_nil_p(file) && !mrb_nil_p(line)) {
    str = mrb_str_dup(mrb, file);
    mrb_str_cat_lit(mrb, str, ":");
    mrb_str_append(mrb, str, line);
    mrb_str_cat_lit(mrb, str, ": ");
    if (append_mesg) {
      mrb_str_cat_str(mrb, str, mesg);
      mrb_str_cat_lit(mrb, str, " (");
    }
    mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
    if (append_mesg) {
      mrb_str_cat_lit(mrb, str, ")");
    }
  }
  else {
    const char *cname = mrb_obj_classname(mrb, exc);
    str = mrb_str_new_cstr(mrb, cname);
    mrb_str_cat_lit(mrb, str, ": ");
    if (append_mesg) {
      mrb_str_cat_str(mrb, str, mesg);
    }
    else {
      mrb_str_cat_cstr(mrb, str, cname);
    }
  }
  return str;
}
ngx_int_t ngx_http_mruby_run_args(ngx_http_request_t *r, ngx_http_mruby_state_t *state, ngx_http_mruby_code_t *code, ngx_flag_t cached,
                           ngx_http_variable_value_t *args, size_t nargs, ngx_str_t *result)
{
    ngx_uint_t i;
    mrb_value ARGV, mrb_result;

    state->ai = mrb_gc_arena_save(state->mrb);

    ARGV = mrb_ary_new_capa(state->mrb, nargs);

    for (i = 0; i < nargs; i++) {
        mrb_ary_push(state->mrb, ARGV, mrb_str_new(state->mrb, (char *)args[i].data, args[i].len));
    }

    mrb_define_global_const(state->mrb, "ARGV", ARGV);

    ngx_http_mruby_push_request(r);
    mrb_result = mrb_run(state->mrb, code->proc, mrb_top_self(state->mrb));
    if (state->mrb->exc) {
        ngx_http_mruby_raise_error(state, code, r);
        mrb_gc_arena_restore(state->mrb, state->ai);
        //mrb_gc_protect(state->mrb, ctx->table);
        if (!cached) {
            ngx_http_mruby_irep_clean(state, code);
        }
        return NGX_ERROR;
    }
    
    mrb_result = mrb_obj_as_string(state->mrb, mrb_result);

    result->data = (u_char *)RSTRING_PTR(mrb_result);
    result->len  = RSTRING_LEN(mrb_result);

    mrb_gc_arena_restore(state->mrb, state->ai);
    //mrb_gc_protect(state->mrb, ctx->table);

    if (!cached) {
        ngx_http_mruby_irep_clean(state, code);
    }

    return NGX_OK;
}
Example #22
0
static void
p(mrb_state *mrb, mrb_value obj, int prompt)
{
  mrb_value val;

  val = mrb_funcall(mrb, obj, "inspect", 0); 
  if (prompt) {
    if (!mrb->exc) {
      fputs(" => ", stdout);
    }   
    else {
      val = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0); 
    }   
  }
  if (!mrb_string_p(val)) {
    val = mrb_obj_as_string(mrb, obj);
  }
  fwrite(RSTRING_PTR(val), RSTRING_LEN(val), 1, stdout);
  putc('\n', stdout);
}
static mrb_value ngx_http_mruby_variable_method_missing(mrb_state *mrb, mrb_value self)
{
    mrb_value  name, *a;
    int        alen, len;
    mrb_value  s_name;
    char      *c_name;

    mrb_get_args(mrb, "n*", &name, &a, &alen);

    s_name = mrb_sym2str(mrb, mrb_symbol(name));
    c_name = mrb_str_to_cstr(mrb, s_name);
    len    = ngx_strlen(c_name);

    if (c_name[len - 1] == '=') {
        a[0] = mrb_obj_as_string(mrb, a[0]);
        return ngx_http_mruby_variable_set_internal(mrb, self, strtok(c_name, "="), a[0]);
    }

    return ngx_http_mruby_variable_get(mrb, self, c_name);
}
Example #24
0
static mrb_value ngx_stream_mrb_errlogger(mrb_state *mrb, mrb_value self)
{
  mrb_value msg;
  mrb_int log_level;
  ngx_stream_mruby_internal_ctx_t *ictx = mrb->ud;
  ngx_stream_session_t *s = ictx->s;

  if (s == NULL) {
    mrb_raise(mrb, E_RUNTIME_ERROR, "can't use logger at this phase. only use at session stream phase");
  }

  mrb_get_args(mrb, "io", &log_level, &msg);
  if (log_level < 0) {
    ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "%s ERROR %s: log level is not positive number", MODULE_NAME,
                  __func__);
    return self;
  }
  msg = mrb_obj_as_string(mrb, msg);
  ngx_log_error((ngx_uint_t)log_level, s->connection->log, 0, "%s", mrb_str_to_cstr(mrb, msg));

  return self;
}
Example #25
0
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)));
  }
}
Example #26
0
mrb_value
mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep)
{
  sep = mrb_obj_as_string(mrb, sep);
  return join_ary(mrb, ary, sep, mrb_ary_new(mrb));
}
Example #27
0
mrb_value
mrb_str_format(mrb_state *mrb, int argc, const mrb_value *argv, mrb_value fmt)
{
  const char *p, *end;
  char *buf;
  mrb_int blen;
  mrb_int bsiz;
  mrb_value result;
  mrb_int n;
  mrb_int width;
  mrb_int prec;
  int flags = FNONE;
  int nextarg = 1;
  int posarg = 0;
  mrb_value nextvalue;
  mrb_value tmp;
  mrb_value str;
  mrb_value hash = mrb_undef_value();

#define CHECK_FOR_WIDTH(f)                                                  \
  if ((f) & FWIDTH) {                                                       \
    mrb_raise(mrb, E_ARGUMENT_ERROR, "width given twice");         \
  }                                                                         \
  if ((f) & FPREC0) {                                                       \
    mrb_raise(mrb, E_ARGUMENT_ERROR, "width after precision");     \
  }
#define CHECK_FOR_FLAGS(f)                                                  \
  if ((f) & FWIDTH) {                                                       \
    mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after width");          \
  }                                                                         \
  if ((f) & FPREC0) {                                                       \
    mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after precision");      \
  }

  ++argc;
  --argv;
  mrb_string_value(mrb, &fmt);
  p = RSTRING_PTR(fmt);
  end = p + RSTRING_LEN(fmt);
  blen = 0;
  bsiz = 120;
  result = mrb_str_buf_new(mrb, bsiz);
  buf = RSTRING_PTR(result);
  memset(buf, 0, bsiz);

  for (; p < end; p++) {
    const char *t;
    mrb_sym id = 0;

    for (t = p; t < end && *t != '%'; t++) ;
    PUSH(p, t - p);
    if (t >= end)
      goto sprint_exit; /* end of fmt string */

    p = t + 1;    /* skip `%' */

    width = prec = -1;
    nextvalue = mrb_undef_value();

retry:
    switch (*p) {
      default:
        mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - \\%%S", mrb_str_new(mrb, p, 1));
        break;

      case ' ':
        CHECK_FOR_FLAGS(flags);
        flags |= FSPACE;
        p++;
        goto retry;

      case '#':
        CHECK_FOR_FLAGS(flags);
        flags |= FSHARP;
        p++;
        goto retry;

      case '+':
        CHECK_FOR_FLAGS(flags);
        flags |= FPLUS;
        p++;
        goto retry;

      case '-':
        CHECK_FOR_FLAGS(flags);
        flags |= FMINUS;
        p++;
        goto retry;

      case '0':
        CHECK_FOR_FLAGS(flags);
        flags |= FZERO;
        p++;
        goto retry;

      case '1': case '2': case '3': case '4':
      case '5': case '6': case '7': case '8': case '9':
        n = 0;
        GETNUM(n, width);
        if (*p == '$') {
          if (!mrb_undef_p(nextvalue)) {
            mrb_raisef(mrb, E_ARGUMENT_ERROR, "value given twice - %S$", mrb_fixnum_value(n));
          }
          nextvalue = GETPOSARG(n);
          p++;
          goto retry;
        }
        CHECK_FOR_WIDTH(flags);
        width = n;
        flags |= FWIDTH;
        goto retry;

      case '<':
      case '{': {
        const char *start = p;
        char term = (*p == '<') ? '>' : '}';
        mrb_value symname;

        for (; p < end && *p != term; )
          p++;
        if (id) {
          mrb_raisef(mrb, E_ARGUMENT_ERROR, "name%S after <%S>",
                     mrb_str_new(mrb, start, p - start + 1), mrb_sym2str(mrb, id));
        }
        symname = mrb_str_new(mrb, start + 1, p - start - 1);
        id = mrb_intern_str(mrb, symname);
        nextvalue = GETNAMEARG(mrb_symbol_value(id), start, (int)(p - start + 1));
        if (mrb_undef_p(nextvalue)) {
          mrb_raisef(mrb, E_KEY_ERROR, "key%S not found", mrb_str_new(mrb, start, p - start + 1));
        }
        if (term == '}') goto format_s;
        p++;
        goto retry;
      }

      case '*':
        CHECK_FOR_WIDTH(flags);
        flags |= FWIDTH;
        GETASTER(width);
        if (width < 0) {
          flags |= FMINUS;
          width = -width;
        }
        p++;
        goto retry;

      case '.':
        if (flags & FPREC0) {
          mrb_raise(mrb, E_ARGUMENT_ERROR, "precision given twice");
        }
        flags |= FPREC|FPREC0;

        prec = 0;
        p++;
        if (*p == '*') {
          GETASTER(prec);
          if (prec < 0) {  /* ignore negative precision */
            flags &= ~FPREC;
          }
          p++;
          goto retry;
        }

        GETNUM(prec, precision);
        goto retry;

      case '\n':
      case '\0':
        p--;

      case '%':
        if (flags != FNONE) {
          mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format character - %");
        }
        PUSH("%", 1);
        break;

      case 'c': {
        mrb_value val = GETARG();
        mrb_value tmp;
        unsigned int c;

        tmp = mrb_check_string_type(mrb, val);
        if (!mrb_nil_p(tmp)) {
          if (RSTRING_LEN(tmp) != 1 ) {
            mrb_raise(mrb, E_ARGUMENT_ERROR, "%c requires a character");
          }
          c = RSTRING_PTR(tmp)[0];
          n = 1;
        }
        else {
          c = mrb_fixnum(val);
          n = 1;
        }
        if (n <= 0) {
          mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid character");
        }
        if (!(flags & FWIDTH)) {
          CHECK(n);
          buf[blen] = c;
          blen += n;
        }
        else if ((flags & FMINUS)) {
          CHECK(n);
          buf[blen] = c;
          blen += n;
          FILL(' ', width-1);
        }
        else {
          FILL(' ', width-1);
          CHECK(n);
          buf[blen] = c;
          blen += n;
        }
      }
      break;

      case 's':
      case 'p':
  format_s:
      {
        mrb_value arg = GETARG();
        mrb_int len;
        mrb_int slen;

        if (*p == 'p') arg = mrb_inspect(mrb, arg);
        str = mrb_obj_as_string(mrb, arg);
        len = RSTRING_LEN(str);
        RSTRING_LEN(result) = blen;
        if (flags&(FPREC|FWIDTH)) {
          slen = RSTRING_LEN(str);
          if (slen < 0) {
            mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid mbstring sequence");
          }
          if ((flags&FPREC) && (prec < slen)) {
            char *p = RSTRING_PTR(str) + prec;
            slen = prec;
            len = p - RSTRING_PTR(str);
          }
          /* need to adjust multi-byte string pos */
          if ((flags&FWIDTH) && (width > slen)) {
            width -= (int)slen;
            if (!(flags&FMINUS)) {
              CHECK(width);
              while (width--) {
                buf[blen++] = ' ';
              }
            }
            CHECK(len);
            memcpy(&buf[blen], RSTRING_PTR(str), len);
            blen += len;
            if (flags&FMINUS) {
              CHECK(width);
              while (width--) {
                buf[blen++] = ' ';
              }
            }
            break;
          }
        }
        PUSH(RSTRING_PTR(str), len);
      }
      break;

      case 'd':
      case 'i':
      case 'o':
      case 'x':
      case 'X':
      case 'b':
      case 'B':
      case 'u': {
        mrb_value val = GETARG();
        char fbuf[32], nbuf[64], *s;
        const char *prefix = NULL;
        int sign = 0, dots = 0;
        char sc = 0;
        mrb_int v = 0, org_v = 0;
        int base;
        mrb_int len;

        switch (*p) {
          case 'd':
          case 'i':
          case 'u':
            sign = 1; break;
          case 'o':
          case 'x':
          case 'X':
          case 'b':
          case 'B':
            if (flags&(FPLUS|FSPACE)) sign = 1;
            break;
          default:
            break;
        }
        if (flags & FSHARP) {
          switch (*p) {
            case 'o': prefix = "0"; break;
            case 'x': prefix = "0x"; break;
            case 'X': prefix = "0X"; break;
            case 'b': prefix = "0b"; break;
            case 'B': prefix = "0B"; break;
            default: break;
          }
        }

  bin_retry:
        switch (mrb_type(val)) {
          case MRB_TT_FLOAT:
            if (FIXABLE(mrb_float(val))) {
              val = mrb_fixnum_value((mrb_int)mrb_float(val));
              goto bin_retry;
            }
            val = mrb_flt2big(mrb, mrb_float(val));
            if (mrb_fixnum_p(val)) goto bin_retry;
            break;
          case MRB_TT_STRING:
            val = mrb_str_to_inum(mrb, val, 0, TRUE);
            goto bin_retry;
          case MRB_TT_FIXNUM:
            v = mrb_fixnum(val);
            break;
          default:
            val = mrb_Integer(mrb, val);
            goto bin_retry;
        }

        switch (*p) {
          case 'o':
            base = 8; break;
          case 'x':
          case 'X':
            base = 16; break;
          case 'b':
          case 'B':
            base = 2; break;
          case 'u':
          case 'd':
          case 'i':
          default:
            base = 10; break;
        }

        if (base == 2) {
          org_v = v;
          if ( v < 0 && !sign ) {
            val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base);
            dots = 1;
          }
          else {
            val = mrb_fix2str(mrb, mrb_fixnum_value(v), base);
          }
          v = mrb_fixnum(mrb_str_to_inum(mrb, val, 10, 0/*Qfalse*/));
        }
        if (sign) {
          char c = *p;
          if (c == 'i') c = 'd'; /* %d and %i are identical */
          if (base == 2) c = 'd';
          if (v < 0) {
            v = -v;
            sc = '-';
            width--;
          }
          else if (flags & FPLUS) {
            sc = '+';
            width--;
          }
          else if (flags & FSPACE) {
            sc = ' ';
            width--;
          }
          snprintf(fbuf, sizeof(fbuf), "%%l%c", c);
          snprintf(nbuf, sizeof(nbuf), fbuf, v);
          s = nbuf;
        }
        else {
          char c = *p;
          if (c == 'X') c = 'x';
          if (base == 2) c = 'd';
          s = nbuf;
          if (v < 0) {
            dots = 1;
          }
          snprintf(fbuf, sizeof(fbuf), "%%l%c", c);
          snprintf(++s, sizeof(nbuf) - 1, fbuf, v);
          if (v < 0) {
            char d;

            s = remove_sign_bits(s, base);
            switch (base) {
              case 16: d = 'f'; break;
              case 8:  d = '7'; break;
              case 2:  d = '1'; break;
              default: d = 0; break;
            }

            if (d && *s != d) {
              *--s = d;
            }
          }
        }
        {
          size_t size;
          size = strlen(s);
          /* PARANOID: assert(size <= MRB_INT_MAX) */
          len = (mrb_int)size;
        }

        if (dots) {
          prec -= 2;
          width -= 2;
        }

        if (*p == 'X') {
          char *pp = s;
          int c;
          while ((c = (int)(unsigned char)*pp) != 0) {
            *pp = toupper(c);
            pp++;
          }
        }

        if (prefix && !prefix[1]) { /* octal */
          if (dots) {
            prefix = NULL;
          }
          else if (len == 1 && *s == '0') {
            len = 0;
            if (flags & FPREC) prec--;
          }
          else if ((flags & FPREC) && (prec > len)) {
            prefix = NULL;
          }
        }
        else if (len == 1 && *s == '0') {
          prefix = NULL;
        }

        if (prefix) {
          size_t size;
          size = strlen(prefix);
          /* PARANOID: assert(size <= MRB_INT_MAX).
           *  this check is absolutely paranoid. */
          width -= (mrb_int)size;
        }

        if ((flags & (FZERO|FMINUS|FPREC)) == FZERO) {
          prec = width;
          width = 0;
        }
        else {
          if (prec < len) {
            if (!prefix && prec == 0 && len == 1 && *s == '0') len = 0;
            prec = len;
          }
          width -= prec;
        }

        if (!(flags&FMINUS)) {
          CHECK(width);
          while (width-- > 0) {
            buf[blen++] = ' ';
          }
        }

        if (sc) PUSH(&sc, 1);

        if (prefix) {
          int plen = (int)strlen(prefix);
          PUSH(prefix, plen);
        }
        CHECK(prec - len);
        if (dots) PUSH("..", 2);

        if (v < 0 || (base == 2 && org_v < 0)) {
          char c = sign_bits(base, p);
          while (len < prec--) {
            buf[blen++] = c;
          }
        }
        else if ((flags & (FMINUS|FPREC)) != FMINUS) {
          char c = '0';
          while (len < prec--) {
            buf[blen++] = c;
          }
        }

        PUSH(s, len);
        CHECK(width);
        while (width-- > 0) {
          buf[blen++] = ' ';
        }
      }
      break;

      case 'f':
      case 'g':
      case 'G':
      case 'e':
      case 'E':
      case 'a':
      case 'A': {
        mrb_value val = GETARG();
        double fval;
        int i, need = 6;
        char fbuf[32];

        fval = mrb_float(mrb_Float(mrb, val));
        if (isnan(fval) || isinf(fval)) {
          const char *expr;
          const int elen = 3;

          if (isnan(fval)) {
            expr = "NaN";
          }
          else {
            expr = "Inf";
          }
          need = elen;
          if ((!isnan(fval) && fval < 0.0) || (flags & FPLUS))
            need++;
          if ((flags & FWIDTH) && need < width)
            need = width;

          CHECK(need + 1);
          n = snprintf(&buf[blen], need + 1, "%*s", need, "");
          if (flags & FMINUS) {
            if (!isnan(fval) && fval < 0.0)
              buf[blen++] = '-';
            else if (flags & FPLUS)
              buf[blen++] = '+';
            else if (flags & FSPACE)
              blen++;
            memcpy(&buf[blen], expr, elen);
          }
          else {
            if (!isnan(fval) && fval < 0.0)
              buf[blen + need - elen - 1] = '-';
            else if (flags & FPLUS)
              buf[blen + need - elen - 1] = '+';
            else if ((flags & FSPACE) && need > width)
              blen++;
            memcpy(&buf[blen + need - elen], expr, elen);
          }
          blen += strlen(&buf[blen]);
          break;
        }

        fmt_setup(fbuf, sizeof(fbuf), *p, flags, width, prec);
        need = 0;
        if (*p != 'e' && *p != 'E') {
          i = INT_MIN;
          frexp(fval, &i);
          if (i > 0)
            need = BIT_DIGITS(i);
        }
        need += (flags&FPREC) ? prec : 6;
        if ((flags&FWIDTH) && need < width)
          need = width;
        need += 20;

        CHECK(need);
        n = snprintf(&buf[blen], need, fbuf, fval);
        blen += n;
      }
      break;
    }
    flags = FNONE;
  }

  sprint_exit:
#if 0
  /* XXX - We cannot validate the number of arguments if (digit)$ style used.
   */
  if (posarg >= 0 && nextarg < argc) {
    const char *mesg = "too many arguments for format string";
    if (mrb_test(ruby_debug)) mrb_raise(mrb, E_ARGUMENT_ERROR, mesg);
    if (mrb_test(ruby_verbose)) mrb_warn("%s", mesg);
  }
#endif
  mrb_str_resize(mrb, result, blen);

  return result;
}
Example #28
0
mrb_value
mrb_inspect(mrb_state *mrb, mrb_value obj)
{
  return mrb_obj_as_string(mrb, mrb_funcall(mrb, obj, "inspect", 0, 0));
}
Example #29
0
mrb_value
mrb_str_format(mrb_state *mrb, mrb_int argc, const mrb_value *argv, mrb_value fmt)
{
  const char *p, *end;
  char *buf;
  mrb_int blen;
  mrb_int bsiz;
  mrb_value result;
  mrb_int n;
  mrb_int width;
  mrb_int prec;
  int nextarg = 1;
  int posarg = 0;
  mrb_value nextvalue;
  mrb_value str;
  mrb_value hash = mrb_undef_value();

#define CHECK_FOR_WIDTH(f)                                                  \
  if ((f) & FWIDTH) {                                                       \
    mrb_raise(mrb, E_ARGUMENT_ERROR, "width given twice");         \
  }                                                                         \
  if ((f) & FPREC0) {                                                       \
    mrb_raise(mrb, E_ARGUMENT_ERROR, "width after precision");     \
  }
#define CHECK_FOR_FLAGS(f)                                                  \
  if ((f) & FWIDTH) {                                                       \
    mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after width");          \
  }                                                                         \
  if ((f) & FPREC0) {                                                       \
    mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after precision");      \
  }

  ++argc;
  --argv;
  mrb_to_str(mrb, fmt);
  p = RSTRING_PTR(fmt);
  end = p + RSTRING_LEN(fmt);
  blen = 0;
  bsiz = 120;
  result = mrb_str_new_capa(mrb, bsiz);
  buf = RSTRING_PTR(result);
  memset(buf, 0, bsiz);

  for (; p < end; p++) {
    const char *t;
    mrb_sym id = 0;
    int flags = FNONE;

    for (t = p; t < end && *t != '%'; t++) ;
    if (t + 1 == end) ++t;
    PUSH(p, t - p);
    if (t >= end)
      goto sprint_exit; /* end of fmt string */

    p = t + 1;    /* skip '%' */

    width = prec = -1;
    nextvalue = mrb_undef_value();

retry:
    switch (*p) {
      default:
        mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - \\%%S", mrb_str_new(mrb, p, 1));
        break;

      case ' ':
        CHECK_FOR_FLAGS(flags);
        flags |= FSPACE;
        p++;
        goto retry;

      case '#':
        CHECK_FOR_FLAGS(flags);
        flags |= FSHARP;
        p++;
        goto retry;

      case '+':
        CHECK_FOR_FLAGS(flags);
        flags |= FPLUS;
        p++;
        goto retry;

      case '-':
        CHECK_FOR_FLAGS(flags);
        flags |= FMINUS;
        p++;
        goto retry;

      case '0':
        CHECK_FOR_FLAGS(flags);
        flags |= FZERO;
        p++;
        goto retry;

      case '1': case '2': case '3': case '4':
      case '5': case '6': case '7': case '8': case '9':
        n = 0;
        GETNUM(n, width);
        if (*p == '$') {
          if (!mrb_undef_p(nextvalue)) {
            mrb_raisef(mrb, E_ARGUMENT_ERROR, "value given twice - %S$", mrb_fixnum_value(n));
          }
          nextvalue = GETPOSARG(n);
          p++;
          goto retry;
        }
        CHECK_FOR_WIDTH(flags);
        width = n;
        flags |= FWIDTH;
        goto retry;

      case '<':
      case '{': {
        const char *start = p;
        char term = (*p == '<') ? '>' : '}';
        mrb_value symname;

        for (; p < end && *p != term; )
          p++;
        if (id) {
          mrb_raisef(mrb, E_ARGUMENT_ERROR, "name%S after <%S>",
                     mrb_str_new(mrb, start, p - start + 1), mrb_sym2str(mrb, id));
        }
        symname = mrb_str_new(mrb, start + 1, p - start - 1);
        id = mrb_intern_str(mrb, symname);
        nextvalue = GETNAMEARG(mrb_symbol_value(id), start, (mrb_int)(p - start + 1));
        if (mrb_undef_p(nextvalue)) {
          mrb_raisef(mrb, E_KEY_ERROR, "key%S not found", mrb_str_new(mrb, start, p - start + 1));
        }
        if (term == '}') goto format_s;
        p++;
        goto retry;
      }

      case '*':
        CHECK_FOR_WIDTH(flags);
        flags |= FWIDTH;
        GETASTER(width);
        if (width < 0) {
          flags |= FMINUS;
          width = -width;
        }
        p++;
        goto retry;

      case '.':
        if (flags & FPREC0) {
          mrb_raise(mrb, E_ARGUMENT_ERROR, "precision given twice");
        }
        flags |= FPREC|FPREC0;

        prec = 0;
        p++;
        if (*p == '*') {
          GETASTER(prec);
          if (prec < 0) {  /* ignore negative precision */
            flags &= ~FPREC;
          }
          p++;
          goto retry;
        }

        GETNUM(prec, precision);
        goto retry;

      case '\n':
      case '\0':
        p--;
        /* fallthrough */
      case '%':
        if (flags != FNONE) {
          mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format character - %");
        }
        PUSH("%", 1);
        break;

      case 'c': {
        mrb_value val = GETARG();
        mrb_value tmp;
        char *c;

        tmp = mrb_check_string_type(mrb, val);
        if (!mrb_nil_p(tmp)) {
          if (RSTRING_LEN(tmp) != 1) {
            mrb_raise(mrb, E_ARGUMENT_ERROR, "%c requires a character");
          }
        }
        else if (mrb_fixnum_p(val)) {
          mrb_int n = mrb_fixnum(val);

          if (n < 0x80) {
            char buf[1];

            buf[0] = (char)n;
            tmp = mrb_str_new(mrb, buf, 1);
          }
          else {
            tmp = mrb_funcall(mrb, val, "chr", 0);
            mrb_check_type(mrb, tmp, MRB_TT_STRING);
          }
        }
        else {
          mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid character");
        }
        c = RSTRING_PTR(tmp);
        n = RSTRING_LEN(tmp);
        if (!(flags & FWIDTH)) {
          PUSH(c, n);
        }
        else if ((flags & FMINUS)) {
          PUSH(c, n);
          if (width>0) FILL(' ', width-1);
        }
        else {
          if (width>0) FILL(' ', width-1);
          PUSH(c, n);
        }
      }
      break;

      case 's':
      case 'p':
  format_s:
      {
        mrb_value arg = GETARG();
        mrb_int len;
        mrb_int slen;

        if (*p == 'p') arg = mrb_inspect(mrb, arg);
        str = mrb_obj_as_string(mrb, arg);
        len = RSTRING_LEN(str);
        if (RSTRING(result)->flags & MRB_STR_EMBED) {
          mrb_int tmp_n = len;
          RSTRING(result)->flags &= ~MRB_STR_EMBED_LEN_MASK;
          RSTRING(result)->flags |= tmp_n << MRB_STR_EMBED_LEN_SHIFT;
        }
        else {
          RSTRING(result)->as.heap.len = blen;
        }
        if (flags&(FPREC|FWIDTH)) {
          slen = RSTRING_LEN(str);
          if (slen < 0) {
            mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid mbstring sequence");
          }
          if ((flags&FPREC) && (prec < slen)) {
            char *p = RSTRING_PTR(str) + prec;
            slen = prec;
            len = (mrb_int)(p - RSTRING_PTR(str));
          }
          /* need to adjust multi-byte string pos */
          if ((flags&FWIDTH) && (width > slen)) {
            width -= (int)slen;
            if (!(flags&FMINUS)) {
              FILL(' ', width);
            }
            PUSH(RSTRING_PTR(str), len);
            if (flags&FMINUS) {
              FILL(' ', width);
            }
            break;
          }
        }
        PUSH(RSTRING_PTR(str), len);
      }
      break;

      case 'd':
      case 'i':
      case 'o':
      case 'x':
      case 'X':
      case 'b':
      case 'B':
      case 'u': {
        mrb_value val = GETARG();
        char nbuf[68], *s;
        const char *prefix = NULL;
        int sign = 0, dots = 0;
        char sc = 0;
        mrb_int v = 0;
        int base;
        mrb_int len;

        if (flags & FSHARP) {
          switch (*p) {
            case 'o': prefix = "0"; break;
            case 'x': prefix = "0x"; break;
            case 'X': prefix = "0X"; break;
            case 'b': prefix = "0b"; break;
            case 'B': prefix = "0B"; break;
            default: break;
          }
        }

  bin_retry:
        switch (mrb_type(val)) {
#ifndef MRB_WITHOUT_FLOAT
          case MRB_TT_FLOAT:
            val = mrb_flo_to_fixnum(mrb, val);
            if (mrb_fixnum_p(val)) goto bin_retry;
            break;
#endif
          case MRB_TT_STRING:
            val = mrb_str_to_inum(mrb, val, 0, TRUE);
            goto bin_retry;
          case MRB_TT_FIXNUM:
            v = mrb_fixnum(val);
            break;
          default:
            val = mrb_Integer(mrb, val);
            goto bin_retry;
        }

        switch (*p) {
          case 'o':
            base = 8; break;
          case 'x':
          case 'X':
            base = 16; break;
          case 'b':
          case 'B':
            base = 2; break;
          case 'u':
          case 'd':
          case 'i':
            sign = 1;
          default:
            base = 10; break;
        }

        if (sign) {
          if (v >= 0) {
            if (flags & FPLUS) {
              sc = '+';
              width--;
            }
            else if (flags & FSPACE) {
              sc = ' ';
              width--;
            }
          }
          else {
            sc = '-';
            width--;
          }
          mrb_assert(base == 10);
          snprintf(nbuf, sizeof(nbuf), "%" MRB_PRId, v);
          s = nbuf;
          if (v < 0) s++;       /* skip minus sign */
        }
        else {
          s = nbuf;
          if (v < 0) {
            dots = 1;
          }
          switch (base) {
          case 2:
            if (v < 0) {
              val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base);
            }
            else {
              val = mrb_fixnum_to_str(mrb, mrb_fixnum_value(v), base);
            }
            strncpy(++s, RSTRING_PTR(val), sizeof(nbuf)-1);
            break;
          case 8:
            snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIo, v);
            break;
          case 16:
            snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIx, v);
            break;
          }
          if (v < 0) {
            char d;

            s = remove_sign_bits(s, base);
            switch (base) {
              case 16: d = 'f'; break;
              case 8:  d = '7'; break;
              case 2:  d = '1'; break;
              default: d = 0; break;
            }

            if (d && *s != d) {
              *--s = d;
            }
          }
        }
        {
          size_t size;
          size = strlen(s);
          /* PARANOID: assert(size <= MRB_INT_MAX) */
          len = (mrb_int)size;
        }

        if (*p == 'X') {
          char *pp = s;
          int c;
          while ((c = (int)(unsigned char)*pp) != 0) {
            *pp = toupper(c);
            pp++;
          }
        }

        if (prefix && !prefix[1]) { /* octal */
          if (dots) {
            prefix = NULL;
          }
          else if (len == 1 && *s == '0') {
            len = 0;
            if (flags & FPREC) prec--;
          }
          else if ((flags & FPREC) && (prec > len)) {
            prefix = NULL;
          }
        }
        else if (len == 1 && *s == '0') {
          prefix = NULL;
        }

        if (prefix) {
          size_t size;
          size = strlen(prefix);
          /* PARANOID: assert(size <= MRB_INT_MAX).
           *  this check is absolutely paranoid. */
          width -= (mrb_int)size;
        }

        if ((flags & (FZERO|FMINUS|FPREC)) == FZERO) {
          prec = width;
          width = 0;
        }
        else {
          if (prec < len) {
            if (!prefix && prec == 0 && len == 1 && *s == '0') len = 0;
            prec = len;
          }
          width -= prec;
        }

        if (!(flags&FMINUS) && width > 0) {
          FILL(' ', width);
          width = 0;
        }

        if (sc) PUSH(&sc, 1);

        if (prefix) {
          int plen = (int)strlen(prefix);
          PUSH(prefix, plen);
        }
        if (dots) {
          prec -= 2;
          width -= 2;
          PUSH("..", 2);
        }

        if (prec > len) {
          CHECK(prec - len);
          if ((flags & (FMINUS|FPREC)) != FMINUS) {
            char c = '0';
            FILL(c, prec - len);
          } else if (v < 0) {
            char c = sign_bits(base, p);
            FILL(c, prec - len);
          }
        }
        PUSH(s, len);
        if (width > 0) {
          FILL(' ', width);
        }
      }
      break;

#ifndef MRB_WITHOUT_FLOAT
      case 'f':
      case 'g':
      case 'G':
      case 'e':
      case 'E':
      case 'a':
      case 'A': {
        mrb_value val = GETARG();
        double fval;
        mrb_int i;
        mrb_int need = 6;
        char fbuf[32];
        int frexp_result;

        fval = mrb_float(mrb_Float(mrb, val));
        if (!isfinite(fval)) {
          const char *expr;
          const mrb_int elen = 3;
          char sign = '\0';

          if (isnan(fval)) {
            expr = "NaN";
          }
          else {
            expr = "Inf";
          }
          need = elen;
          if (!isnan(fval) && fval < 0.0)
            sign = '-';
          else if (flags & (FPLUS|FSPACE))
            sign = (flags & FPLUS) ? '+' : ' ';
          if (sign)
            ++need;
          if ((flags & FWIDTH) && need < width)
            need = width;

          if (need < 0) {
            mrb_raise(mrb, E_ARGUMENT_ERROR, "width too big");
          }
          FILL(' ', need);
          if (flags & FMINUS) {
            if (sign)
              buf[blen - need--] = sign;
            memcpy(&buf[blen - need], expr, elen);
          }
          else {
            if (sign)
              buf[blen - elen - 1] = sign;
            memcpy(&buf[blen - elen], expr, elen);
          }
          break;
        }

        fmt_setup(fbuf, sizeof(fbuf), *p, flags, width, prec);
        need = 0;
        if (*p != 'e' && *p != 'E') {
          i = INT_MIN;
          frexp(fval, &frexp_result);
          i = (mrb_int)frexp_result;
          if (i > 0)
            need = BIT_DIGITS(i);
        }
        if (need > MRB_INT_MAX - ((flags&FPREC) ? prec : 6)) {
        too_big_width:
          mrb_raise(mrb, E_ARGUMENT_ERROR,
                    (width > prec ? "width too big" : "prec too big"));
        }
        need += (flags&FPREC) ? prec : 6;
        if ((flags&FWIDTH) && need < width)
          need = width;
        if (need > MRB_INT_MAX - 20) {
          goto too_big_width;
        }
        need += 20;

        CHECK(need);
        n = snprintf(&buf[blen], need, fbuf, fval);
        if (n < 0 || n >= need) {
          mrb_raise(mrb, E_RUNTIME_ERROR, "formatting error");
        }
        blen += n;
      }
      break;
#endif
    }
    flags = FNONE;
  }

  sprint_exit:
#if 0
  /* XXX - We cannot validate the number of arguments if (digit)$ style used.
   */
  if (posarg >= 0 && nextarg < argc) {
    const char *mesg = "too many arguments for format string";
    if (mrb_test(ruby_debug)) mrb_raise(mrb, E_ARGUMENT_ERROR, mesg);
    if (mrb_test(ruby_verbose)) mrb_warn(mrb, "%S", mrb_str_new_cstr(mrb, mesg));
  }
#endif
  mrb_str_resize(mrb, result, blen);

  return result;
}
Example #30
0
int value_to_node(mrb_state *mrb,
  yaml_document_t *document, mrb_value value)
{
  int node;

  switch (mrb_type(value))
  {
    case MRB_TT_ARRAY:
    {
      mrb_int len = mrb_ary_len(mrb, value);
      mrb_int i;
      int ai = mrb_gc_arena_save(mrb);

      node = yaml_document_add_sequence(document, NULL,
        YAML_ANY_SEQUENCE_STYLE);

      for (i = 0; i < len; i++)
      {
        mrb_value child = mrb_ary_ref(mrb, value, i);
        int child_node = value_to_node(mrb, document, child);

        /* Add the child to the sequence */
        yaml_document_append_sequence_item(document, node, child_node);
        mrb_gc_arena_restore(mrb, ai);
      }

      break;
    }

    case MRB_TT_HASH:
    {
      /* Iterating a list of keys is slow, but it only
       * requires use of the interface defined in `hash.h`.
       */

      mrb_value keys = mrb_hash_keys(mrb, value);
      mrb_int len = mrb_ary_len(mrb, keys);
      mrb_int i;
      int ai = mrb_gc_arena_save(mrb);

      node = yaml_document_add_mapping(document, NULL,
        YAML_ANY_MAPPING_STYLE);

      for (i = 0; i < len; i++)
      {
        mrb_value key = mrb_ary_ref(mrb, keys, i);
        mrb_value child = mrb_hash_get(mrb, value, key);

        int key_node = value_to_node(mrb, document, key);
        int child_node = value_to_node(mrb, document, child);

        /* Add the key/value pair to the mapping */
        yaml_document_append_mapping_pair(document, node,
          key_node, child_node);
        mrb_gc_arena_restore(mrb, ai);
      }

      break;
    }

    default:
    {
      if (mrb_nil_p(value)) {
        /* http://yaml.org/type/null.html
           Canonical form */
        value = mrb_str_new_lit(mrb, "~");
      } else {
        /* Equivalent to `obj = obj#to_s` */
        value = mrb_obj_as_string(mrb, value);
      }
      /* Fallthrough */
    }

    case MRB_TT_STRING:
    {
      yaml_scalar_style_t style = YAML_ANY_SCALAR_STYLE;
      if (RSTRING_LEN(value) == 0) {
        /* If the String is empty, it may be reloaded as a nil instead of an
         * empty string, to avoid that place a quoted string instead */
        style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
      }
      yaml_char_t *value_chars = (unsigned char *) RSTRING_PTR(value);
      node = yaml_document_add_scalar(document, NULL,
        value_chars, RSTRING_LEN(value), style);
      break;
    }
  }

  return node;
}