Example #1
0
File: error.c Project: nurse/ruby
void
rb_check_type(VALUE x, int t)
{
    const struct types *type = builtin_types;
    const struct types *const typeend = builtin_types +
	sizeof(builtin_types) / sizeof(builtin_types[0]);
    int xt;

    if (x == Qundef) {
	rb_bug("undef leaked to the Ruby space");
    }

    xt = TYPE(x);
    if (xt != t || (xt == T_DATA && RTYPEDDATA_P(x))) {
	while (type < typeend) {
	    if (type->type == t) {
		const char *etype;

		if (NIL_P(x)) {
		    etype = "nil";
		}
		else if (FIXNUM_P(x)) {
		    etype = "Fixnum";
		}
		else if (SYMBOL_P(x)) {
		    etype = "Symbol";
		}
		else if (rb_special_const_p(x)) {
		    etype = RSTRING_PTR(rb_obj_as_string(x));
		}
		else {
		    etype = rb_obj_classname(x);
		}
		rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
			 etype, type->name);
	    }
	    type++;
	}
	if (xt > T_MASK && xt <= 0x3f) {
	    rb_fatal("unknown type 0x%x (0x%x given, probably comes from extension library for ruby 1.8)", t, xt);
	}
	rb_bug("unknown type 0x%x (0x%x given)", t, xt);
    }
}
Example #2
0
/*
=begin
--- OraNumber.new()
=end
*/
static VALUE ora_number_initialize(int argc, VALUE *argv, VALUE self)
{
  ora_vnumber_t *ovn = get_ora_number(self);
  volatile VALUE arg;

  rb_scan_args(argc, argv, "01", &arg);
  ovn->size = 1;
  ovn->num.exponent = 0x80;
  memset(ovn->num.mantissa, 0, sizeof(ovn->num.mantissa));
  if (argc == 1) {
    if (TYPE(arg) != T_STRING) {
      arg = rb_obj_as_string(arg);
    }
    if (ora_number_from_str(ovn, RSTRING_ORATEXT(arg), RSTRING_LEN(arg)) != 0) {
      rb_raise(rb_eArgError, "could not convert '%s' to OraNumber", RSTRING_PTR(arg));
    }
  }
  return Qnil;
}
Example #3
0
static VALUE oci8_lob_write(VALUE self, VALUE data)
{
    oci8_lob_t *lob = DATA_PTR(self);
    oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc);
    ub4 amt;

    lob_open(lob);
    if (TYPE(data) != T_STRING) {
        data = rb_obj_as_string(data);
    }
    if (lob->lobtype == OCI_TEMP_CLOB) {
        data = rb_str_export_to_enc(data, oci8_encoding);
    }
    RB_GC_GUARD(data);
    amt = RSTRING_LEN(data);
    oci_lc(OCILobWrite_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &amt, lob->pos + 1, RSTRING_PTR(data), amt, OCI_ONE_PIECE, NULL, NULL, 0, lob->csfrm));
    lob->pos += amt;
    return UINT2NUM(amt);
}
Example #4
0
static VALUE
rg_write(VALUE self, VALUE buf)
{
    gssize count;
    gsize bytes_written;
    GIOStatus status;
    GError* err = NULL;

    buf = rb_obj_as_string(buf);

    StringValue(buf);

    count = RSTRING_LEN(buf);

    status = g_io_channel_write_chars(_SELF(self), RVAL2CSTR(buf), count, &bytes_written, &err);

    ioc_error(status, err);
    return UINT2NUM(bytes_written);
}
Example #5
0
static int
load_script(int argc, char **argv)
{
  VALUE r_argv, fname;
  int state, i;

  if (argc < 1) {
    return 0;
  }

  r_argv = rb_const_get(rb_mKernel, rb_intern("ARGV"));
  rb_ary_clear(r_argv);
  for (i = 1; i < argc; i++) {
    rb_ary_push(r_argv, rb_tainted_str_new2(argv[i]));
  }

  fname = rb_funcall(rb_cFile, ExpandPath, 1, rb_str_new2(argv[0]));
  rb_load_protect(fname, 1, &state);
  if (state) {
    VALUE errinfo, errstr, errat;
    int n, i;
    const char *cstr;

    errinfo = rb_errinfo();
    errstr = rb_obj_as_string(errinfo);
    cstr = StringValueCStr(errstr);
    if (strcmp(cstr, "exit")) {
      ngraph_err_puts(cstr);
      errat = rb_funcall(errinfo, rb_intern("backtrace"), 0);
      if (! NIL_P(errat)) {
	n = RARRAY_LEN(errat);
	for (i = 0; i < n; i ++) {
	  errstr = rb_str_new2("\tfrom ");
	  rb_str_append(errstr, rb_ary_entry(errat, i));
	  ngraph_err_puts(StringValueCStr(errstr));
	}
      }
    }
  }
  rb_gc_start();

  return 0;
}
/*
 * call-seq:
 *    context.register_namespace(prefix, uri) -> (true|false)
 *
 * Register the specified namespace URI with the specified prefix
 * in this context.

 *   context.register_namespace('xi', 'http://www.w3.org/2001/XInclude')
 */
static VALUE rxml_xpath_context_register_namespace(VALUE self, VALUE prefix, VALUE uri)
{
  xmlXPathContextPtr ctxt;
  Data_Get_Struct(self, xmlXPathContext, ctxt);

  /* Prefix could be a symbol. */
  prefix = rb_obj_as_string(prefix);
  
  if (xmlXPathRegisterNs(ctxt, (xmlChar*) StringValuePtr(prefix),
      (xmlChar*) StringValuePtr(uri)) == 0)
  {
    return (Qtrue);
  }
  else
  {
    /* Should raise an exception, IMHO (whose?, why shouldnt it? -danj)*/
    rb_warning("register namespace failed");
    return (Qfalse);
  }
}
Example #7
0
/*
 * call-seq:
 *
 *	s = Kgio::Socket.new(:INET, :STREAM)
 *	addr = Socket.pack_sockaddr_in(80, "example.com")
 *	s.kgio_fastopen("hello world", addr) -> nil
 *
 * Starts a TCP connection using TCP Fast Open.  This uses a blocking
 * sendto() syscall and is only available on Ruby 1.9 or later.
 * This raises exceptions (including Errno::EINPROGRESS/Errno::EAGAIN)
 * on errors.  Using this is only recommended for blocking sockets.
 *
 * Timeouts may be set with setsockopt:
 *
 *	s.setsockopt(:SOCKET, :SNDTIMEO, [1,0].pack("l_l_"))
 */
static VALUE fastopen(VALUE sock, VALUE buf, VALUE addr)
{
	struct tfo_args a;
	VALUE str = (TYPE(buf) == T_STRING) ? buf : rb_obj_as_string(buf);
	ssize_t w;

	a.fd = my_fileno(sock);
	a.buf = RSTRING_PTR(str);
	a.buflen = (size_t)RSTRING_LEN(str);
	a.addr = sockaddr_from(&a.addrlen, addr);

	/* n.b. rb_thread_blocking_region preserves errno */
	w = (ssize_t)rb_thread_io_blocking_region(tfo_sendto, &a, a.fd);
	if (w < 0)
		rb_sys_fail("sendto");
	if ((size_t)w == a.buflen)
		return Qnil;

	return rb_str_subseq(str, w, a.buflen - w);
}
Example #8
0
File: error.c Project: knugie/ruby
static VALUE
exc_inspect(VALUE exc)
{
    VALUE str, klass;

    klass = CLASS_OF(exc);
    exc = rb_obj_as_string(exc);
    if (RSTRING_LEN(exc) == 0) {
	return rb_str_dup(rb_class_name(klass));
    }

    str = rb_str_buf_new2("#<");
    klass = rb_class_name(klass);
    rb_str_buf_append(str, klass);
    rb_str_buf_cat(str, ": ", 2);
    rb_str_buf_append(str, exc);
    rb_str_buf_cat(str, ">", 1);

    return str;
}
Example #9
0
static void
err_append(const char *s)
{
  rb_thread_t *th = GET_THREAD();
  if (th->parse_in_eval) {
    if (NIL_P(th->errinfo)) {
      th->errinfo = rb_exc_new2(rb_eSyntaxError, s);
    }
    else {
      VALUE str = rb_obj_as_string(GET_THREAD()->errinfo);

      rb_str_cat2(str, "\n");
      rb_str_cat2(str, s);
      th->errinfo = rb_exc_new3(rb_eSyntaxError, str);
    }
  }
  else {
    rb_write_error(s);
    rb_write_error("\n");
  }
}
Example #10
0
static void
ruby_script_error()
{
  VALUE errinfo, lasterr, array;
  int i;

  errinfo = rb_errinfo();
  if(!NIL_P(errinfo))
  {
    lasterr = rb_gv_get("$!");
    VALUE tmp2 = rb_class_path(CLASS_OF(lasterr));
    VALUE tmp = rb_obj_as_string(lasterr);
    ilog(L_ERROR, "RUBY ERROR: %s: %s", StringValueCStr(tmp2), StringValueCStr(tmp));
    array = rb_funcall(errinfo, rb_intern("backtrace"), 0);
    for (i = 0; i < RARRAY_LEN(array); ++i)
    {
      tmp = rb_ary_entry(array, i);
      ilog(L_DEBUG, "RUBY BACKTRACE:   %s", StringValueCStr(tmp));
    }
  }
}
Example #11
0
/*
 * call-seq:
 *    node << ("string" | node) -> XML::Node
 * 
 * Add the specified string or XML::Node to this node's
 * content.  The returned node is the node that was
 * added and not self, thereby allowing << calls to
 * be chained.
 */
VALUE
ruby_xml_node_content_add(VALUE self, VALUE obj) {
  xmlNodePtr xnode;
  VALUE str;

  Data_Get_Struct(self, xmlNode, xnode);
  /* XXX This should only be legal for a CDATA type node, I think,
   * resulting in a merge of content, as if a string were passed
   * danj 070827
   */
  if (rb_obj_is_kind_of(obj, cXMLNode)) {
    ruby_xml_node_child_set(self, obj);
  } else {
    str = rb_obj_as_string(obj);
    if (NIL_P(str) || TYPE(str) != T_STRING)
      rb_raise(rb_eTypeError, "invalid argument: must be string or XML::Node");

		xmlNodeAddContent(xnode, (xmlChar*)StringValuePtr(str));
  }
  return(self);
}
Example #12
0
/*
 *  call-seq:
 *     query_parser.parse(query_string) -> Query
 *
 *  Parse a query string returning a Query object if parsing was successful.
 *  Will raise a QueryParseException if unsuccessful. 
 */
static VALUE
frt_qp_parse(VALUE self, VALUE rstr)
{
    const char *msg = NULL;
    volatile VALUE rq;
    GET_QP;
    rstr = rb_obj_as_string(rstr);
    TRY
        rq = frt_get_q(qp_parse(qp, RSTRING(rstr)->ptr));
        break;
    default:
        msg = xcontext.msg;
        HANDLED();
    XENDTRY

    if (msg) {
        rb_raise(cQueryParseException, msg);
    }

    return rq;
}
Example #13
0
void
rb_check_type(VALUE x, int t)
{
    const struct types *type = builtin_types;
    const struct types *const typeend = builtin_types +
	sizeof(builtin_types) / sizeof(builtin_types[0]);

    if (x == Qundef) {
	rb_bug("undef leaked to the Ruby space");
    }

    if (TYPE(x) != t) {
	while (type < typeend) {
	    if (type->type == t) {
		const char *etype;

		if (NIL_P(x)) {
		    etype = "nil";
		}
		else if (FIXNUM_P(x)) {
		    etype = "Fixnum";
		}
		else if (SYMBOL_P(x)) {
		    etype = "Symbol";
		}
		else if (rb_special_const_p(x)) {
		    etype = RSTRING_PTR(rb_obj_as_string(x));
		}
		else {
		    etype = rb_obj_classname(x);
		}
		rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
			 etype, type->name);
	    }
	    type++;
	}
	rb_bug("unknown type 0x%x (0x%x given)", t, TYPE(x));
    }
}
Example #14
0
static void
err_append(const char *s)
{
    extern VALUE ruby_errinfo;

    if (ruby_in_eval) {
	if (NIL_P(ruby_errinfo)) {
	    ruby_errinfo = rb_exc_new2(rb_eSyntaxError, s);
	}
	else {
	    VALUE str = rb_obj_as_string(ruby_errinfo);

	    rb_str_cat2(str, "\n");
	    rb_str_cat2(str, s);
	    ruby_errinfo = rb_exc_new3(rb_eSyntaxError, str);
	}
    }
    else {
	rb_write_error(s);
	rb_write_error("\n");
    }
}
Example #15
0
/*
 * call-seq:
 *    XML::Node.new_comment(content = nil) -> XML::Node
 *
 * Create a new comment node, optionally setting
 * the node's content.
 *
 */
static VALUE rxml_node_new_comment(int argc, VALUE *argv, VALUE klass)
{
  VALUE content = Qnil;
  xmlNodePtr xnode;

  rb_scan_args(argc, argv, "01", &content);

  if (NIL_P(content))
  {
    xnode = xmlNewComment(NULL);
  }
  else
  {
    content = rb_obj_as_string(content);
    xnode = xmlNewComment((xmlChar*) StringValueCStr(content));
  }

  if (xnode == NULL)
    rxml_raise(&xmlLastError);

  return rxml_node_wrap(xnode);
}
static void * initFunc(xsltTransformContextPtr ctxt, const xmlChar *uri)
{
    VALUE modules = rb_iv_get(xslt, "@modules");
    VALUE obj = rb_hash_aref(modules, rb_str_new2((const char *)uri));
    VALUE args = { Qfalse };
    VALUE methods = rb_funcall(obj, rb_intern("instance_methods"), 1, args);
    VALUE inst;
    nokogiriXsltStylesheetTuple *wrapper;
    int i;

    for(i = 0; i < RARRAY_LEN(methods); i++) {
	VALUE method_name = rb_obj_as_string(RARRAY_PTR(methods)[i]);
	xsltRegisterExtFunction(ctxt,
          (unsigned char *)StringValuePtr(method_name), uri, method_caller);
    }

    Data_Get_Struct(ctxt->style->_private, nokogiriXsltStylesheetTuple,
                    wrapper);
    inst = rb_class_new_instance(0, NULL, obj);
    rb_ary_push(wrapper->func_instances, inst);

    return (void *)inst;
}
Example #17
0
char *	rubyeval (char *input)
{
	VALUE	rubyval;
	char *	retval = NULL;

	if (input && *input) 
	{
		ruby_startstop(1);
		rubyval = rb_rescue2(internal_rubyeval, (VALUE)input, 
					eval_failed, 0,
					rb_eException, 0);
		if (rubyval == Qnil)
			retval = NULL;
		else
		{
			VALUE x;
			x = rb_obj_as_string(rubyval);
			retval = StringValuePtr(x);
		}
	}

	RETURN_STR(retval);	/* XXX Is this malloced or not? */
}
Example #18
0
/*
 * call-seq:
 *    XML::Node.new_cdata(content = nil) -> XML::Node
 *
 * Create a new #CDATA node, optionally setting
 * the node's content.
 */
static VALUE rxml_node_new_cdata(int argc, VALUE *argv, VALUE klass)
{
  VALUE content = Qnil;
  xmlNodePtr xnode;

  rb_scan_args(argc, argv, "01", &content);

  if (NIL_P(content))
  {
    xnode = xmlNewCDataBlock(NULL, NULL, 0);
  }
  else
  {
    content = rb_obj_as_string(content);
    xnode = xmlNewCDataBlock(NULL, (xmlChar*) StringValuePtr(content),
        RSTRING_LEN(content));
  }

  if (xnode == NULL)
    rxml_raise(&xmlLastError);

  return rxml_node_wrap(xnode);
}
Example #19
0
/**
 * Print the Ruby Stack Trace in an ows:ExceptionReport XML Document
 *
 * @param m the conf maps containing the main.cfg settings
 * @see printExceptionReportResponse
 */
void ruby_trace_error(maps* m){
#if RUBY_VERSION_MINOR == 8
  VALUE lasterr = rb_gv_get("$!");
#else
  VALUE lasterr = rb_errinfo();
  VALUE ruby_errinfo = lasterr;
#endif
  VALUE message = rb_obj_as_string(lasterr);
  VALUE lklass = rb_class_path(CLASS_OF(lasterr));
#if RUBY_VERSION_MINOR == 8
  char *trace=(char*)malloc((strlen(RSTRING(lklass)->ptr)+strlen(RSTRING(message)->ptr)+3)*sizeof(char));
  sprintf(trace,"%s: %s",RSTRING_PTR(lklass),RSTRING_PTR(message));
#else
  char *trace=(char*)malloc((strlen(RSTRING_PTR(lklass))+strlen(RSTRING_PTR(message))+3)*sizeof(char));
  sprintf(trace,"%s: %s",RSTRING_PTR(lklass),RSTRING_PTR(message));
#endif
  if(!NIL_P(ruby_errinfo))
    {
      VALUE ary = rb_funcall(ruby_errinfo, rb_intern("backtrace"), 0);
      int c;
      for (c=0; c<RARRAY_LEN(ary); c++) {
	int len=strlen(trace);
	char *tmp0=zStrdup(trace);
#if RUBY_VERSION_MINOR == 8
	trace=(char *) realloc(trace,(len+strlen(RSTRING(RARRAY(ary)->ptr[c])->ptr)+2)*sizeof(char));
	sprintf(trace,"%s\n%s",tmp0,RSTRING(RARRAY(ary)->ptr[c])->ptr);
#else
	trace=(char *) realloc(trace,(len+strlen(RSTRING_PTR(RARRAY_PTR(ary)[c]))+2)*sizeof(char));
	sprintf(trace,"%s\n%s",tmp0,RSTRING_PTR(RARRAY_PTR(ary)[c]));
#endif
	free(tmp0);
      }
    }
  map* err=createMap("text",trace);
  addToMap(err,"code","NoApplicableCode");
  printExceptionReportResponse(m,err);
}
Example #20
0
/*
 * call-seq:
 *    conn.putline( str)         -> nil
 *    conn.putline( ary)         -> nil
 *    conn.putline( str) { ... } -> nil
 *
 * Sends the string to the backend server.
 * You have to open the stream with a +COPY+ command using +copy_stdin+.
 *
 * If +str+ doesn't end in a newline, one is appended.  If the argument
 * is +ary+, a line will be built using +stringize_line+.
 *
 * If the connection is in nonblocking mode and no data could be sent
 * the closure will be called and its value will be returned.
 */
VALUE
pgconn_putline( VALUE self, VALUE arg)
{
    struct pgconn_data *c;
    VALUE str;
    const char *p;
    int l;
    int r;

    switch (TYPE( arg)) {
    case T_STRING:
        str = arg;
        break;
    case T_ARRAY:
        str = pgconn_stringize_line( self, arg);
        break;
    default:
        str = rb_obj_as_string( arg);
        break;
    }
    if (RSTRING_PTR( str)[ RSTRING_LEN( str) - 1] != '\n') {
        VALUE t;

        t = rb_str_dup( str);
        rb_str_buf_cat( t, "\n", 1);
        str = t;
    }

    Data_Get_Struct( self, struct pgconn_data, c);
    p = pgconn_destring( c, str, &l);
    r = PQputCopyData( c->conn, p, l);
    if (r < 0)
        rb_raise( rb_ePgConnCopy, "Copy from stdin failed.");
    else if (r == 0)
        return rb_yield( Qnil);
    return Qnil;
}
Example #21
0
static VALUE
rg_puts(int argc, VALUE *argv, VALUE self)
{
    int i;
    VALUE line;

    /* if no argument given, print newline. */
    if (argc == 0) {
        rg_write(self, default_rs);
        return Qnil;
    }
    for (i=0; i<argc; i++) {
        if (NIL_P(argv[i])) {
            line = rb_str_new2("nil");
        }
        else {
          line = rbg_check_array_type(argv[i]);
          if (!NIL_P(line)) {
#ifdef HAVE_RB_EXEC_RECURSIVE
            rb_exec_recursive(ioc_puts_ary, line, self);
#else
            rb_protect_inspect(ioc_puts_ary, line, self);
#endif
            continue;
          }
          line = rb_obj_as_string(argv[i]);
        }
        rg_write(self, line);
        if (RSTRING_LEN(line) == 0 ||
            RSTRING_PTR(line)[RSTRING_LEN(line)-1] != '\n') {
            rg_write(self, default_rs);
        }
    }

    return Qnil;
}
Example #22
0
static void xmlformatter_write_obj(gonzui_xmlformatter_t *xf, VALUE obj)
{
  char *p;
  char *data;
  size_t size;
  if (SYMBOL_P(obj)) {
    data = rb_id2name(SYM2ID(obj));
    size = strlen(data);
  } else {
    struct RString *s = RSTRING(rb_obj_as_string(obj));
    data = s->ptr;
    size = s->len;
  }
  if (xf->size + size * 6 > xf->max_size) {
    xf->max_size += BLOCK_SIZE;
    xf->data = realloc(xf->data, xf->max_size);
  }
  for (p = data; *p; p++) {
    int c = *p;
    if (c == '<') {
      memcpy(xf->data + xf->size, "&lt;", 4);
      xf->size += 4;
    } else if (c == '>') {
      memcpy(xf->data + xf->size, "&gt;", 4);
      xf->size += 4;
    } else if (c == '&') {
      memcpy(xf->data + xf->size, "&amp;", 5);
      xf->size += 5;
    } else if (c == '"') {
      memcpy(xf->data + xf->size, "&quot;", 6);
      xf->size += 6;
    } else {
      xf->data[xf->size++] = c;
    }
  }
}
Example #23
0
//
// This function was borrowed from the kross code. It puts out
// an error message and stacktrace on stderr for the current exception.
//
static void
show_exception_message()
{
    VALUE info = rb_gv_get("$!");
    VALUE bt = rb_funcall(info, rb_intern("backtrace"), 0);
    VALUE message = RARRAY_PTR(bt)[0];
    VALUE message2 = rb_obj_as_string(info);

    QString errormessage = QString("%1: %2 (%3)")
                            .arg( StringValueCStr(message) )
                            .arg( StringValueCStr(message2) )
                            .arg( rb_class2name(CLASS_OF(info)) );
    fprintf(stderr, "%s\n", errormessage.toLatin1().data());

    QString tracemessage;
    for(int i = 1; i < RARRAY_LEN(bt); ++i) {
        if( TYPE(RARRAY_PTR(bt)[i]) == T_STRING ) {
            QString s = QString("%1\n").arg( StringValueCStr(RARRAY_PTR(bt)[i]) );
            Q_ASSERT( ! s.isNull() );
            tracemessage += s;
            fprintf(stderr, "\t%s", s.toLatin1().data());
        }
    }
}
Example #24
0
static void fill_iovec(struct wrv_args *a)
{
	int i;
	struct iovec *curvec;

	a->iov_cnt = RARRAY_LENINT(a->buf);
	a->batch_len = 0;
	if (a->iov_cnt == 0) return;
	if (a->iov_cnt > iov_max) a->iov_cnt = iov_max;
	rb_str_resize(a->vec_buf, sizeof(struct iovec) * a->iov_cnt);
	curvec = a->vec = (struct iovec*)RSTRING_PTR(a->vec_buf);

	for (i=0; i < a->iov_cnt; i++, curvec++) {
		VALUE str = rb_ary_entry(a->buf, i);
		long str_len, next_len;

		if (TYPE(str) != T_STRING) {
			str = rb_obj_as_string(str);
			rb_ary_store(a->buf, i, str);
		}

		str_len = RSTRING_LEN(str);

		/* lets limit total memory to write,
		 * but always take first string */
		next_len = a->batch_len + str_len;
		if (i && next_len > WRITEV_MEMLIMIT) {
			a->iov_cnt = i;
			break;
		}
		a->batch_len = next_len;

		curvec->iov_base = RSTRING_PTR(str);
		curvec->iov_len = str_len;
	}
}
Example #25
0
static char *
ruby__sfvextra(rb_printf_buffer *fp, size_t valsize, void *valp, long *sz, int sign)
{
    VALUE value, result = (VALUE)fp->_bf._base;
    rb_encoding *enc;
    char *cp;

    if (valsize != sizeof(VALUE)) return 0;
    value = *(VALUE *)valp;
    if (RBASIC(result)->klass) {
	rb_raise(rb_eRuntimeError, "rb_vsprintf reentered");
    }
    if (sign == '+') {
	value = rb_inspect(value);
    }
    else {
	value = rb_obj_as_string(value);
	if (sign == ' ') value = QUOTE(value);
    }
    enc = rb_enc_compatible(result, value);
    if (enc) {
	rb_enc_associate(result, enc);
    }
    else {
	enc = rb_enc_get(result);
	value = rb_str_conv_enc_opts(value, rb_enc_get(value), enc,
				     ECONV_UNDEF_REPLACE|ECONV_INVALID_REPLACE,
				     Qnil);
	*(volatile VALUE *)valp = value;
    }
    StringValueCStr(value);
    RSTRING_GETMEM(value, cp, *sz);
    ((rb_printf_buffer_extra *)fp)->value = value;
    OBJ_INFECT(result, value);
    return cp;
}
Example #26
0
static VALUE defout_write(VALUE self, VALUE str)
{
    str = rb_obj_as_string(str);
    rb_str_cat(self, RSTRING_PTR(str), RSTRING_LEN(str));
    return Qnil;
}
Example #27
0
static void exception_print(FILE *out, int cgi)
{
    VALUE errat;
    VALUE eclass;
    VALUE einfo;

    if (NIL_P(ruby_errinfo)) return;

    errat = rb_funcall(ruby_errinfo, rb_intern("backtrace"), 0);
    if (!NIL_P(errat)) {
	VALUE mesg = RARRAY_PTR(errat)[0];

	if (NIL_P(mesg)) {
	    error_pos(out, cgi);
	}
	else {
	    if (cgi)
		write_escaping_html(out, RSTRING_PTR(mesg), RSTRING_LEN(mesg));
	    else
		fwrite(RSTRING_PTR(mesg), 1, RSTRING_LEN(mesg), out);
	}
    }

    eclass = CLASS_OF(ruby_errinfo);
    einfo = rb_obj_as_string(ruby_errinfo);
    if (eclass == rb_eRuntimeError && RSTRING_LEN(einfo) == 0) {
	fprintf(out, ": unhandled exception\n");
    }
    else {
	VALUE epath;

	epath = rb_class_path(eclass);
	if (RSTRING_LEN(einfo) == 0) {
	    fprintf(out, ": ");
	    if (cgi)
		write_escaping_html(out, RSTRING_PTR(epath), RSTRING_LEN(epath));
	    else
		fwrite(RSTRING_PTR(epath), 1, RSTRING_LEN(epath), out);
	    if (cgi)
		fprintf(out, "<br>\n");
	    else
		fprintf(out, "\n");
	}
	else {
	    char *tail  = 0;
	    int len = RSTRING_LEN(einfo);

	    if (RSTRING_PTR(epath)[0] == '#') epath = 0;
	    if ((tail = strchr(RSTRING_PTR(einfo), '\n')) != NULL) {
		len = tail - RSTRING_PTR(einfo);
		tail++;		/* skip newline */
	    }
	    fprintf(out, ": ");
	    if (cgi)
		write_escaping_html(out, RSTRING_PTR(einfo), len);
	    else
		fwrite(RSTRING_PTR(einfo), 1, len, out);
	    if (epath) {
		fprintf(out, " (");
		if (cgi)
		    write_escaping_html(out, RSTRING_PTR(epath), RSTRING_LEN(epath));
		else
		    fwrite(RSTRING_PTR(epath), 1, RSTRING_LEN(epath), out);
		if (cgi)
		    fprintf(out, ")<br>\n");
		else
		    fprintf(out, ")\n");
	    }
	    if (tail) {
		if (cgi)
		    write_escaping_html(out, tail, RSTRING_LEN(einfo) - len - 1);
		else
		    fwrite(tail, 1, RSTRING_LEN(einfo) - len - 1, out);
		if (cgi)
		    fprintf(out, "<br>\n");
		else
		    fprintf(out, "\n");
	    }
	}
    }

    if (!NIL_P(errat)) {
	int i;
	struct RArray *ep = RARRAY(errat);

#define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
#define TRACE_HEAD 8
#define TRACE_TAIL 5

	rb_ary_pop(errat);
	ep = RARRAY(errat);
	for (i=1; i<RARRAY_LEN(ep); i++) {
	    if (TYPE(RARRAY_PTR(ep)[i]) == T_STRING) {
		if (cgi) {
		    fprintf(out, "<div class=\"backtrace\">from ");
		    write_escaping_html(out,
					RSTRING_PTR(RARRAY_PTR(ep)[i]),
					RSTRING_LEN(RARRAY_PTR(ep)[i]));
		}
		else {
		    fprintf(out, "        from ");
		    fwrite(RSTRING_PTR(RARRAY_PTR(ep)[i]), 1,
			   RSTRING_LEN(RARRAY_PTR(ep)[i]), out);
		}
		if (cgi)
		    fprintf(out, "<br></div>\n");
		else
		    fprintf(out, "\n");
	    }
	    if (i == TRACE_HEAD && RARRAY_LEN(ep) > TRACE_MAX) {
		char buff[BUFSIZ];
		if (cgi)
		    snprintf(buff, BUFSIZ,
			     "<div class=\"backtrace\">... %ld levels...\n",
			     RARRAY_LEN(ep) - TRACE_HEAD - TRACE_TAIL);
		else
		    snprintf(buff, BUFSIZ, "         ... %ld levels...<br></div>\n",
			     RARRAY_LEN(ep) - TRACE_HEAD - TRACE_TAIL);
		if (cgi)
		    write_escaping_html(out, buff, strlen(buff));
		else
		    fputs(buff, out);
		i = RARRAY_LEN(ep) - TRACE_TAIL;
	    }
	}
    }
}
Example #28
0
VALUE rb_czmq_timer_s_new(int argc, VALUE *argv, VALUE timer)
{
    VALUE delay, times, proc, callback;
    size_t timer_delay;
    zmq_timer_wrapper *tr = NULL;
    rb_scan_args(argc, argv, "21&", &delay, &times, &proc, &callback);
    if (NIL_P(proc) && NIL_P(callback)) rb_raise(rb_eArgError, "no callback given!");
    if (NIL_P(proc)) {
        rb_need_block();
    } else {
        callback = proc;
    }
    if (TYPE(delay) != T_FIXNUM && TYPE(delay) != T_FLOAT) rb_raise(rb_eTypeError, "wrong delay type %s (expected Fixnum or Float)", RSTRING_PTR(rb_obj_as_string(delay)));
    Check_Type(times, T_FIXNUM);
    timer_delay = (size_t)(((TYPE(delay) == T_FIXNUM) ? FIX2LONG(delay) : RFLOAT_VALUE(delay)) * 1000); 
    timer = Data_Make_Struct(rb_cZmqTimer, zmq_timer_wrapper, rb_czmq_mark_timer, rb_czmq_free_timer_gc, tr);
    tr->cancelled = FALSE;
    tr->delay = timer_delay;
    tr->times = FIX2INT(times);
    tr->callback = callback;
    rb_obj_call_init(timer, 0, NULL);
    return timer;
}
Example #29
0
static void setup_send_buffer(struct rw_args *x, VALUE buffer)
{
	buffer = rb_obj_as_string(buffer);
	x->msg_ptr = RSTRING_PTR(buffer);
	x->msg_len = (size_t)RSTRING_LEN(buffer);
}
Example #30
0
VALUE
rb_str_format(int argc, const VALUE *argv, VALUE fmt)
{
    enum {default_float_precision = 6};
    rb_encoding *enc;
    const char *p, *end;
    char *buf;
    long blen, bsiz;
    VALUE result;

    long scanned = 0;
    int coderange = ENC_CODERANGE_7BIT;
    int width, prec, flags = FNONE;
    int nextarg = 1;
    int posarg = 0;
    int tainted = 0;
    VALUE nextvalue;
    VALUE tmp;
    VALUE str;
    volatile VALUE hash = Qundef;

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

    ++argc;
    --argv;
    if (OBJ_TAINTED(fmt)) tainted = 1;
    StringValue(fmt);
    enc = rb_enc_get(fmt);
    fmt = rb_str_new4(fmt);
    p = RSTRING_PTR(fmt);
    end = p + RSTRING_LEN(fmt);
    blen = 0;
    bsiz = 120;
    result = rb_str_buf_new(bsiz);
    rb_enc_copy(result, fmt);
    buf = RSTRING_PTR(result);
    memset(buf, 0, bsiz);
    ENC_CODERANGE_SET(result, coderange);

    for (; p < end; p++) {
	const char *t;
	int n;
	VALUE sym = Qnil;

	for (t = p; t < end && *t != '%'; t++) ;
	PUSH(p, t - p);
	if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) {
	    scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &coderange);
	    ENC_CODERANGE_SET(result, coderange);
	}
	if (t >= end) {
	    /* end of fmt string */
	    goto sprint_exit;
	}
	p = t + 1;		/* skip `%' */

	width = prec = -1;
	nextvalue = Qundef;
      retry:
	switch (*p) {
	  default:
	    if (rb_enc_isprint(*p, enc))
		rb_raise(rb_eArgError, "malformed format string - %%%c", *p);
	    else
		rb_raise(rb_eArgError, "malformed format string");
	    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 (nextvalue != Qundef) {
		    rb_raise(rb_eArgError, "value given twice - %d$", 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 == '<') ? '>' : '}';
		int len;

		for (; p < end && *p != term; ) {
		    p += rb_enc_mbclen(p, end, enc);
		}
		if (p >= end) {
		    rb_raise(rb_eArgError, "malformed name - unmatched parenthesis");
		}
#if SIZEOF_INT < SIZEOF_SIZE_T
		if ((size_t)(p - start) >= INT_MAX) {
		    const int message_limit = 20;
		    len = (int)(rb_enc_right_char_head(start, start + message_limit, p, enc) - start);
		    rb_enc_raise(enc, rb_eArgError,
				 "too long name (%"PRIdSIZE" bytes) - %.*s...%c",
				 (size_t)(p - start - 2), len, start, term);
		}
#endif
		len = (int)(p - start + 1); /* including parenthesis */
		if (sym != Qnil) {
		    rb_enc_raise(enc, rb_eArgError, "named%.*s after <%"PRIsVALUE">",
				 len, start, rb_sym2str(sym));
		}
		CHECKNAMEARG(start, len, enc);
		get_hash(&hash, argc, argv);
		sym = rb_check_symbol_cstr(start + 1,
					   len - 2 /* without parenthesis */,
					   enc);
		if (sym != Qnil) nextvalue = rb_hash_lookup2(hash, sym, Qundef);
		if (nextvalue == Qundef) {
		    rb_enc_raise(enc, rb_eKeyError, "key%.*s not found", len, start);
		}
		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) {
		rb_raise(rb_eArgError, "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) {
		rb_raise(rb_eArgError, "invalid format character - %%");
	    }
	    PUSH("%", 1);
	    break;

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

		tmp = rb_check_string_type(val);
		if (!NIL_P(tmp)) {
		    if (rb_enc_strlen(RSTRING_PTR(tmp),RSTRING_END(tmp),enc) != 1) {
			rb_raise(rb_eArgError, "%%c requires a character");
		    }
		    c = rb_enc_codepoint_len(RSTRING_PTR(tmp), RSTRING_END(tmp), &n, enc);
		    RB_GC_GUARD(tmp);
		}
		else {
		    c = NUM2INT(val);
		    n = rb_enc_codelen(c, enc);
		}
		if (n <= 0) {
		    rb_raise(rb_eArgError, "invalid character");
		}
		if (!(flags & FWIDTH)) {
		    CHECK(n);
		    rb_enc_mbcput(c, &buf[blen], enc);
		    blen += n;
		}
		else if ((flags & FMINUS)) {
		    CHECK(n);
		    rb_enc_mbcput(c, &buf[blen], enc);
		    blen += n;
		    FILL(' ', width-1);
		}
		else {
		    FILL(' ', width-1);
		    CHECK(n);
		    rb_enc_mbcput(c, &buf[blen], enc);
		    blen += n;
		}
	    }
	    break;

	  case 's':
	  case 'p':
	  format_s:
	    {
		VALUE arg = GETARG();
		long len, slen;

		if (*p == 'p') arg = rb_inspect(arg);
		str = rb_obj_as_string(arg);
		if (OBJ_TAINTED(str)) tainted = 1;
		len = RSTRING_LEN(str);
		rb_str_set_len(result, blen);
		if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) {
		    int cr = coderange;
		    scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &cr);
		    ENC_CODERANGE_SET(result,
				      (cr == ENC_CODERANGE_UNKNOWN ?
				       ENC_CODERANGE_BROKEN : (coderange = cr)));
		}
		enc = rb_enc_check(result, str);
		if (flags&(FPREC|FWIDTH)) {
		    slen = rb_enc_strlen(RSTRING_PTR(str),RSTRING_END(str),enc);
		    if (slen < 0) {
			rb_raise(rb_eArgError, "invalid mbstring sequence");
		    }
		    if ((flags&FPREC) && (prec < slen)) {
			char *p = rb_enc_nth(RSTRING_PTR(str), RSTRING_END(str),
					     prec, enc);
			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);
			RB_GC_GUARD(str);
			blen += len;
			if (flags&FMINUS) {
			    CHECK(width);
			    while (width--) {
				buf[blen++] = ' ';
			    }
			}
			rb_enc_associate(result, enc);
			break;
		    }
		}
		PUSH(RSTRING_PTR(str), len);
		RB_GC_GUARD(str);
		rb_enc_associate(result, enc);
	    }
	    break;

	  case 'd':
	  case 'i':
	  case 'o':
	  case 'x':
	  case 'X':
	  case 'b':
	  case 'B':
	  case 'u':
	    {
		volatile VALUE val = GETARG();
                int valsign;
		char nbuf[64], *s;
		const char *prefix = 0;
		int sign = 0, dots = 0;
		char sc = 0;
		long v = 0;
		int base, bignum = 0;
		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;
		}
		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;
		    }
		}

	      bin_retry:
		switch (TYPE(val)) {
		  case T_FLOAT:
		    if (FIXABLE(RFLOAT_VALUE(val))) {
			val = LONG2FIX((long)RFLOAT_VALUE(val));
			goto bin_retry;
		    }
		    val = rb_dbl2big(RFLOAT_VALUE(val));
		    if (FIXNUM_P(val)) goto bin_retry;
		    bignum = 1;
		    break;
		  case T_STRING:
		    val = rb_str_to_inum(val, 0, TRUE);
		    goto bin_retry;
		  case T_BIGNUM:
		    bignum = 1;
		    break;
		  case T_FIXNUM:
		    v = FIX2LONG(val);
		    break;
		  default:
		    val = rb_Integer(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 != 10) {
                    int numbits = ffs(base)-1;
                    size_t abs_nlz_bits;
                    size_t numdigits = rb_absint_numwords(val, numbits, &abs_nlz_bits);
                    long i;
                    if (INT_MAX-1 < numdigits) /* INT_MAX is used because rb_long2int is used later. */
                        rb_raise(rb_eArgError, "size too big");
                    if (sign) {
                        if (numdigits == 0)
                            numdigits = 1;
                        tmp = rb_str_new(NULL, numdigits);
                        valsign = rb_integer_pack(val, RSTRING_PTR(tmp), RSTRING_LEN(tmp),
                                1, CHAR_BIT-numbits, INTEGER_PACK_BIG_ENDIAN);
                        for (i = 0; i < RSTRING_LEN(tmp); i++)
                            RSTRING_PTR(tmp)[i] = ruby_digitmap[((unsigned char *)RSTRING_PTR(tmp))[i]];
                        s = RSTRING_PTR(tmp);
                        if (valsign < 0) {
                            sc = '-';
                            width--;
                        }
                        else if (flags & FPLUS) {
                            sc = '+';
                            width--;
                        }
                        else if (flags & FSPACE) {
                            sc = ' ';
                            width--;
                        }
                    }
                    else {
                        /* Following conditional "numdigits++" guarantees the
                         * most significant digit as
                         * - '1'(bin), '7'(oct) or 'f'(hex) for negative numbers
                         * - '0' for zero
                         * - not '0' for positive numbers.
                         *
                         * It also guarantees the most significant two
                         * digits will not be '11'(bin), '77'(oct), 'ff'(hex)
                         * or '00'.  */
                        if (numdigits == 0 ||
                                ((abs_nlz_bits != (size_t)(numbits-1) ||
                                  !rb_absint_singlebit_p(val)) &&
                                 (!bignum ? v < 0 : BIGNUM_NEGATIVE_P(val))))
                            numdigits++;
                        tmp = rb_str_new(NULL, numdigits);
                        valsign = rb_integer_pack(val, RSTRING_PTR(tmp), RSTRING_LEN(tmp),
                                1, CHAR_BIT-numbits, INTEGER_PACK_2COMP | INTEGER_PACK_BIG_ENDIAN);
                        for (i = 0; i < RSTRING_LEN(tmp); i++)
                            RSTRING_PTR(tmp)[i] = ruby_digitmap[((unsigned char *)RSTRING_PTR(tmp))[i]];
                        s = RSTRING_PTR(tmp);
                        dots = valsign < 0;
                    }
                    len = rb_long2int(RSTRING_END(tmp) - s);
                }
                else if (!bignum) {
                    valsign = 1;
                    if (v < 0) {
                        v = -v;
                        sc = '-';
                        width--;
                        valsign = -1;
                    }
                    else if (flags & FPLUS) {
                        sc = '+';
                        width--;
                    }
                    else if (flags & FSPACE) {
                        sc = ' ';
                        width--;
                    }
                    snprintf(nbuf, sizeof(nbuf), "%ld", v);
                    s = nbuf;
		    len = (int)strlen(s);
		}
		else {
                    tmp = rb_big2str(val, 10);
                    s = RSTRING_PTR(tmp);
                    valsign = 1;
                    if (s[0] == '-') {
                        s++;
                        sc = '-';
                        width--;
                        valsign = -1;
                    }
                    else if (flags & FPLUS) {
                        sc = '+';
                        width--;
                    }
                    else if (flags & FSPACE) {
                        sc = ' ';
                        width--;
                    }
		    len = rb_long2int(RSTRING_END(tmp) - s);
		}

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

		if (*p == 'X') {
		    char *pp = s;
		    int c;
		    while ((c = (int)(unsigned char)*pp) != 0) {
			*pp = rb_enc_toupper(c, enc);
			pp++;
		    }
		}
		if (prefix && !prefix[1]) { /* octal */
		    if (dots) {
			prefix = 0;
		    }
		    else if (len == 1 && *s == '0') {
			len = 0;
			if (flags & FPREC) prec--;
		    }
		    else if ((flags & FPREC) && (prec > len)) {
			prefix = 0;
		    }
		}
		else if (len == 1 && *s == '0') {
		    prefix = 0;
		}
		if (prefix) {
		    width -= (int)strlen(prefix);
		}
		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 (!sign && valsign < 0) {
		    char c = sign_bits(base, p);
		    while (len < prec--) {
			buf[blen++] = c;
		    }
		}
		else if ((flags & (FMINUS|FPREC)) != FMINUS) {
		    while (len < prec--) {
			buf[blen++] = '0';
		    }
		}
		PUSH(s, len);
		RB_GC_GUARD(tmp);
		CHECK(width);
		while (width-- > 0) {
		    buf[blen++] = ' ';
		}
	    }
	    break;

	  case 'f':
	    {
		VALUE val = GETARG(), num, den;
		int sign = (flags&FPLUS) ? 1 : 0, zero = 0;
		long len, done = 0;
		int prefix = 0;
		if (!RB_TYPE_P(val, T_RATIONAL)) {
		    nextvalue = val;
		    goto float_value;
		}
		if (!(flags&FPREC)) prec = default_float_precision;
		den = rb_rational_den(val);
		num = rb_rational_num(val);
		if (FIXNUM_P(num)) {
		    if ((SIGNED_VALUE)num < 0) {
			long n = -FIX2LONG(num);
			num = LONG2FIX(n);
			sign = -1;
		    }
		}
		else if (rb_num_negative_p(num)) {
		    sign = -1;
		    num = rb_funcallv(num, idUMinus, 0, 0);
		}
		if (den != INT2FIX(1) || prec > 1) {
		    const ID idDiv = rb_intern("div");
		    VALUE p10 = rb_int_positive_pow(10, prec);
		    VALUE den_2 = rb_funcall(den, idDiv, 1, INT2FIX(2));
		    num = rb_funcallv(num, '*', 1, &p10);
		    num = rb_funcallv(num, '+', 1, &den_2);
		    num = rb_funcallv(num, idDiv, 1, &den);
		}
		else if (prec >= 0) {
		    zero = prec;
		}
		val = rb_obj_as_string(num);
		len = RSTRING_LEN(val) + zero;
		if (prec >= len) ++len; /* integer part 0 */
		if (sign || (flags&FSPACE)) ++len;
		if (prec > 0) ++len; /* period */
		CHECK(len > width ? len : width);
		if (sign || (flags&FSPACE)) {
		    buf[blen++] = sign > 0 ? '+' : sign < 0 ? '-' : ' ';
		    prefix++;
		    done++;
		}
		len = RSTRING_LEN(val) + zero;
		t = RSTRING_PTR(val);
		if (len > prec) {
		    memcpy(&buf[blen], t, len - prec);
		    blen += len - prec;
		    done += len - prec;
		}
		else {
		    buf[blen++] = '0';
		    done++;
		}
		if (prec > 0) {
		    buf[blen++] = '.';
		    done++;
		}
		if (zero) {
		    FILL('0', zero);
		    done += zero;
		}
		else if (prec > len) {
		    FILL('0', prec - len);
		    memcpy(&buf[blen], t, len);
		    blen += len;
		    done += prec;
		}
		else if (prec > 0) {
		    memcpy(&buf[blen], t + len - prec, prec);
		    blen += prec;
		    done += prec;
		}
		if ((flags & FWIDTH) && width > done) {
		    int fill = ' ';
		    long shifting = 0;
		    if (!(flags&FMINUS)) {
			shifting = done;
			if (flags&FZERO) {
			    shifting -= prefix;
			    fill = '0';
			}
			blen -= shifting;
			memmove(&buf[blen + width - done], &buf[blen], shifting);
		    }
		    FILL(fill, width - done);
		    blen += shifting;
		}
		RB_GC_GUARD(val);
		break;
	    }
	  case 'g':
	  case 'G':
	  case 'e':
	  case 'E':
	    /* TODO: rational support */
	  case 'a':
	  case 'A':
	  float_value:
	    {
		VALUE val = GETARG();
		double fval;
		int i, need;
		char fbuf[32];

		fval = RFLOAT_VALUE(rb_Float(val));
		if (isnan(fval) || isinf(fval)) {
		    const char *expr;

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

		    CHECK(need + 1);
		    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, strlen(expr));
		    }
		    else {
			if (!isnan(fval) && fval < 0.0)
			    buf[blen + need - strlen(expr) - 1] = '-';
			else if (flags & FPLUS)
			    buf[blen + need - strlen(expr) - 1] = '+';
			else if ((flags & FSPACE) && need > width)
			    blen++;
			memcpy(&buf[blen + need - strlen(expr)], expr,
			       strlen(expr));
		    }
		    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 : default_float_precision;
		if ((flags&FWIDTH) && need < width)
		    need = width;
		need += 20;

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

  sprint_exit:
    RB_GC_GUARD(fmt);
    /* 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 (RTEST(ruby_debug)) rb_raise(rb_eArgError, "%s", mesg);
	if (RTEST(ruby_verbose)) rb_warn("%s", mesg);
    }
    rb_str_resize(result, blen);

    if (tainted) OBJ_TAINT(result);
    return result;
}