2 ** sprintf.c - Kernel.#sprintf
4 ** See Copyright Notice in mruby.h
10 #include <mruby/string.h>
11 #include <mruby/hash.h>
12 #include <mruby/numeric.h>
13 #ifndef MRB_WITHOUT_FLOAT
18 #define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */
19 #define BITSPERDIG MRB_INT_BIT
20 #define EXTENDSIGN(n, l) (((~0U << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0U << (n)))
22 mrb_value mrb_str_format(mrb_state *, mrb_int, const mrb_value *, mrb_value);
23 #ifndef MRB_WITHOUT_FLOAT
24 static void fmt_setup(char*,size_t,int,int,mrb_int,mrb_int);
28 remove_sign_bits(char *str, int base)
39 *t |= EXTENDSIGN(3, strlen(t));
54 sign_bits(int base, const char *p)
60 if (*p == 'X') c = 'F';
74 mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base)
76 char buf[66], *b = buf + sizeof buf;
77 mrb_int num = mrb_fixnum(x);
78 uint64_t val = (uint64_t)num;
82 mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %d", base);
85 return mrb_str_new_lit(mrb, "0");
89 *--b = mrb_digitmap[(int)(val % base)];
90 } while (val /= base);
93 b = remove_sign_bits(b, base);
95 case 16: d = 'f'; break;
96 case 8: d = '7'; break;
97 case 2: d = '1'; break;
98 default: d = 0; break;
106 return mrb_str_new_cstr(mrb, b);
119 #define CHECK(l) do {\
120 while ((l) >= bsiz - blen) {\
121 if (bsiz > MRB_INT_MAX/2) mrb_raise(mrb, E_ARGUMENT_ERROR, "too big specifier"); \
124 mrb_str_resize(mrb, result, bsiz);\
125 buf = RSTRING_PTR(result);\
128 #define PUSH(s, l) do { \
130 memcpy(&buf[blen], s, l);\
131 blen += (mrb_int)(l);\
134 #define FILL(c, l) do { \
136 memset(&buf[blen], c, l);\
141 check_next_arg(mrb_state *mrb, int posarg, int nextarg)
145 mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%d) mixed with numbered", nextarg);
148 mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%d) mixed with named", nextarg);
156 check_pos_arg(mrb_state *mrb, int posarg, mrb_int n)
159 mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%i) after unnumbered(%d)",
163 mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%i) after named", n);
166 mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid index - %i$", n);
171 check_name_arg(mrb_state *mrb, int posarg, const char *name, size_t len)
174 mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%l after unnumbered(%d)",
178 mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%l after numbered", name, len);
182 #define GETNEXTARG() (\
183 check_next_arg(mrb, posarg, nextarg),\
184 (posarg = nextarg++, GETNTHARG(posarg)))
186 #define GETARG() (!mrb_undef_p(nextvalue) ? nextvalue : GETNEXTARG())
188 #define GETPOSARG(n) (\
189 check_pos_arg(mrb, posarg, n),\
190 (posarg = -1, GETNTHARG(n)))
192 #define GETNTHARG(nth) \
193 ((nth >= argc) ? (mrb_raise(mrb, E_ARGUMENT_ERROR, "too few arguments"), mrb_undef_value()) : argv[nth])
195 #define GETNAMEARG(id, name, len) (\
196 check_name_arg(mrb, posarg, name, len),\
197 (posarg = -2, mrb_hash_fetch(mrb, get_hash(mrb, &hash, argc, argv), id, mrb_undef_value())))
199 #define GETNUM(n, val) \
200 for (; p < end && ISDIGIT(*p); p++) {\
201 if (n > (MRB_INT_MAX - (*p - '0'))/10) {\
202 mrb_raise(mrb, E_ARGUMENT_ERROR, #val " too big"); \
204 n = 10 * n + (*p - '0'); \
207 mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed format string - %*[0-9]"); \
210 #define GETASTER(num) do { \
216 tmp_v = GETPOSARG(n); \
219 tmp_v = GETNEXTARG(); \
222 num = mrb_int(mrb, tmp_v); \
226 get_hash(mrb_state *mrb, mrb_value *hash, mrb_int argc, const mrb_value *argv)
230 if (!mrb_undef_p(*hash)) return *hash;
232 mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required");
234 tmp = mrb_check_hash_type(mrb, argv[1]);
235 if (mrb_nil_p(tmp)) {
236 mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required");
238 return (*hash = tmp);
243 * format(format_string [, arguments...] ) -> string
244 * sprintf(format_string [, arguments...] ) -> string
246 * Returns the string resulting from applying <i>format_string</i> to
247 * any additional arguments. Within the format string, any characters
248 * other than format sequences are copied to the result.
250 * The syntax of a format sequence is follows.
252 * %[flags][width][.precision]type
255 * sequence consists of a percent sign, followed by optional flags,
256 * width, and precision indicators, then terminated with a field type
257 * character. The field type controls how the corresponding
258 * <code>sprintf</code> argument is to be interpreted, while the flags
259 * modify that interpretation.
261 * The field type characters are:
263 * Field | Integer Format
264 * ------+--------------------------------------------------------------
265 * b | Convert argument as a binary number.
266 * | Negative numbers will be displayed as a two's complement
267 * | prefixed with '..1'.
268 * B | Equivalent to 'b', but uses an uppercase 0B for prefix
269 * | in the alternative format by #.
270 * d | Convert argument as a decimal number.
271 * i | Identical to 'd'.
272 * o | Convert argument as an octal number.
273 * | Negative numbers will be displayed as a two's complement
274 * | prefixed with '..7'.
275 * u | Identical to 'd'.
276 * x | Convert argument as a hexadecimal number.
277 * | Negative numbers will be displayed as a two's complement
278 * | prefixed with '..f' (representing an infinite string of
280 * X | Equivalent to 'x', but uses uppercase letters.
282 * Field | Float Format
283 * ------+--------------------------------------------------------------
284 * e | Convert floating point argument into exponential notation
285 * | with one digit before the decimal point as [-]d.dddddde[+-]dd.
286 * | The precision specifies the number of digits after the decimal
287 * | point (defaulting to six).
288 * E | Equivalent to 'e', but uses an uppercase E to indicate
290 * f | Convert floating point argument as [-]ddd.dddddd,
291 * | where the precision specifies the number of digits after
292 * | the decimal point.
293 * g | Convert a floating point number using exponential form
294 * | if the exponent is less than -4 or greater than or
295 * | equal to the precision, or in dd.dddd form otherwise.
296 * | The precision specifies the number of significant digits.
297 * G | Equivalent to 'g', but use an uppercase 'E' in exponent form.
298 * a | Convert floating point argument as [-]0xh.hhhhp[+-]dd,
299 * | which is consisted from optional sign, "0x", fraction part
300 * | as hexadecimal, "p", and exponential part as decimal.
301 * A | Equivalent to 'a', but use uppercase 'X' and 'P'.
303 * Field | Other Format
304 * ------+--------------------------------------------------------------
305 * c | Argument is the numeric code for a single character or
306 * | a single character string itself.
307 * p | The valuing of argument.inspect.
308 * s | Argument is a string to be substituted. If the format
309 * | sequence contains a precision, at most that many characters
311 * % | A percent sign itself will be displayed. No argument taken.
313 * The flags modifies the behavior of the formats.
314 * The flag characters are:
316 * Flag | Applies to | Meaning
317 * ---------+---------------+-----------------------------------------
318 * space | bBdiouxX | Leave a space at the start of
319 * | aAeEfgG | non-negative numbers.
320 * | (numeric fmt) | For 'o', 'x', 'X', 'b' and 'B', use
321 * | | a minus sign with absolute value for
322 * | | negative values.
323 * ---------+---------------+-----------------------------------------
324 * (digit)$ | all | Specifies the absolute argument number
325 * | | for this field. Absolute and relative
326 * | | argument numbers cannot be mixed in a
327 * | | sprintf string.
328 * ---------+---------------+-----------------------------------------
329 * # | bBoxX | Use an alternative format.
330 * | aAeEfgG | For the conversions 'o', increase the precision
331 * | | until the first digit will be '0' if
332 * | | it is not formatted as complements.
333 * | | For the conversions 'x', 'X', 'b' and 'B'
334 * | | on non-zero, prefix the result with "0x",
335 * | | "0X", "0b" and "0B", respectively.
336 * | | For 'a', 'A', 'e', 'E', 'f', 'g', and 'G',
337 * | | force a decimal point to be added,
338 * | | even if no digits follow.
339 * | | For 'g' and 'G', do not remove trailing zeros.
340 * ---------+---------------+-----------------------------------------
341 * + | bBdiouxX | Add a leading plus sign to non-negative
342 * | aAeEfgG | numbers.
343 * | (numeric fmt) | For 'o', 'x', 'X', 'b' and 'B', use
344 * | | a minus sign with absolute value for
345 * | | negative values.
346 * ---------+---------------+-----------------------------------------
347 * - | all | Left-justify the result of this conversion.
348 * ---------+---------------+-----------------------------------------
349 * 0 (zero) | bBdiouxX | Pad with zeros, not spaces.
350 * | aAeEfgG | For 'o', 'x', 'X', 'b' and 'B', radix-1
351 * | (numeric fmt) | is used for negative numbers formatted as
353 * ---------+---------------+-----------------------------------------
354 * * | all | Use the next argument as the field width.
355 * | | If negative, left-justify the result. If the
356 * | | asterisk is followed by a number and a dollar
357 * | | sign, use the indicated argument as the width.
361 * # '+' and space flag specifies the sign of non-negative numbers.
362 * sprintf("%d", 123) #=> "123"
363 * sprintf("%+d", 123) #=> "+123"
364 * sprintf("% d", 123) #=> " 123"
366 * # '#' flag for 'o' increases number of digits to show '0'.
367 * # '+' and space flag changes format of negative numbers.
368 * sprintf("%o", 123) #=> "173"
369 * sprintf("%#o", 123) #=> "0173"
370 * sprintf("%+o", -123) #=> "-173"
371 * sprintf("%o", -123) #=> "..7605"
372 * sprintf("%#o", -123) #=> "..7605"
374 * # '#' flag for 'x' add a prefix '0x' for non-zero numbers.
375 * # '+' and space flag disables complements for negative numbers.
376 * sprintf("%x", 123) #=> "7b"
377 * sprintf("%#x", 123) #=> "0x7b"
378 * sprintf("%+x", -123) #=> "-7b"
379 * sprintf("%x", -123) #=> "..f85"
380 * sprintf("%#x", -123) #=> "0x..f85"
381 * sprintf("%#x", 0) #=> "0"
383 * # '#' for 'X' uses the prefix '0X'.
384 * sprintf("%X", 123) #=> "7B"
385 * sprintf("%#X", 123) #=> "0X7B"
387 * # '#' flag for 'b' add a prefix '0b' for non-zero numbers.
388 * # '+' and space flag disables complements for negative numbers.
389 * sprintf("%b", 123) #=> "1111011"
390 * sprintf("%#b", 123) #=> "0b1111011"
391 * sprintf("%+b", -123) #=> "-1111011"
392 * sprintf("%b", -123) #=> "..10000101"
393 * sprintf("%#b", -123) #=> "0b..10000101"
394 * sprintf("%#b", 0) #=> "0"
396 * # '#' for 'B' uses the prefix '0B'.
397 * sprintf("%B", 123) #=> "1111011"
398 * sprintf("%#B", 123) #=> "0B1111011"
400 * # '#' for 'e' forces to show the decimal point.
401 * sprintf("%.0e", 1) #=> "1e+00"
402 * sprintf("%#.0e", 1) #=> "1.e+00"
404 * # '#' for 'f' forces to show the decimal point.
405 * sprintf("%.0f", 1234) #=> "1234"
406 * sprintf("%#.0f", 1234) #=> "1234."
408 * # '#' for 'g' forces to show the decimal point.
409 * # It also disables stripping lowest zeros.
410 * sprintf("%g", 123.4) #=> "123.4"
411 * sprintf("%#g", 123.4) #=> "123.400"
412 * sprintf("%g", 123456) #=> "123456"
413 * sprintf("%#g", 123456) #=> "123456."
415 * The field width is an optional integer, followed optionally by a
416 * period and a precision. The width specifies the minimum number of
417 * characters that will be written to the result for this field.
421 * # padding is done by spaces, width=20
422 * # 0 or radix-1. <------------------>
423 * sprintf("%20d", 123) #=> " 123"
424 * sprintf("%+20d", 123) #=> " +123"
425 * sprintf("%020d", 123) #=> "00000000000000000123"
426 * sprintf("%+020d", 123) #=> "+0000000000000000123"
427 * sprintf("% 020d", 123) #=> " 0000000000000000123"
428 * sprintf("%-20d", 123) #=> "123 "
429 * sprintf("%-+20d", 123) #=> "+123 "
430 * sprintf("%- 20d", 123) #=> " 123 "
431 * sprintf("%020x", -123) #=> "..ffffffffffffffff85"
434 * numeric fields, the precision controls the number of decimal places
435 * displayed. For string fields, the precision determines the maximum
436 * number of characters to be copied from the string. (Thus, the format
437 * sequence <code>%10.10s</code> will always contribute exactly ten
438 * characters to the result.)
440 * Examples of precisions:
442 * # precision for 'd', 'o', 'x' and 'b' is
443 * # minimum number of digits <------>
444 * sprintf("%20.8d", 123) #=> " 00000123"
445 * sprintf("%20.8o", 123) #=> " 00000173"
446 * sprintf("%20.8x", 123) #=> " 0000007b"
447 * sprintf("%20.8b", 123) #=> " 01111011"
448 * sprintf("%20.8d", -123) #=> " -00000123"
449 * sprintf("%20.8o", -123) #=> " ..777605"
450 * sprintf("%20.8x", -123) #=> " ..ffff85"
451 * sprintf("%20.8b", -11) #=> " ..110101"
453 * # "0x" and "0b" for '#x' and '#b' is not counted for
454 * # precision but "0" for '#o' is counted. <------>
455 * sprintf("%#20.8d", 123) #=> " 00000123"
456 * sprintf("%#20.8o", 123) #=> " 00000173"
457 * sprintf("%#20.8x", 123) #=> " 0x0000007b"
458 * sprintf("%#20.8b", 123) #=> " 0b01111011"
459 * sprintf("%#20.8d", -123) #=> " -00000123"
460 * sprintf("%#20.8o", -123) #=> " ..777605"
461 * sprintf("%#20.8x", -123) #=> " 0x..ffff85"
462 * sprintf("%#20.8b", -11) #=> " 0b..110101"
464 * # precision for 'e' is number of
465 * # digits after the decimal point <------>
466 * sprintf("%20.8e", 1234.56789) #=> " 1.23456789e+03"
468 * # precision for 'f' is number of
469 * # digits after the decimal point <------>
470 * sprintf("%20.8f", 1234.56789) #=> " 1234.56789000"
472 * # precision for 'g' is number of
473 * # significant digits <------->
474 * sprintf("%20.8g", 1234.56789) #=> " 1234.5679"
477 * sprintf("%20.8g", 123456789) #=> " 1.2345679e+08"
479 * # precision for 's' is
480 * # maximum number of characters <------>
481 * sprintf("%20.8s", "string test") #=> " string t"
485 * sprintf("%d %04x", 123, 123) #=> "123 007b"
486 * sprintf("%08b '%4s'", 123, 123) #=> "01111011 ' 123'"
487 * sprintf("%1$*2$s %2$d %1$s", "hello", 8) #=> " hello 8 hello"
488 * sprintf("%1$*2$s %2$d", "hello", -8) #=> "hello -8"
489 * sprintf("%+g:% g:%-g", 1.23, 1.23, 1.23) #=> "+1.23: 1.23:1.23"
490 * sprintf("%u", -123) #=> "-123"
492 * For more complex formatting, Ruby supports a reference by name.
493 * %<name>s style uses format style, but %{name} style doesn't.
496 * sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 })
498 * sprintf("%{foo}f", { :foo => 1 })
503 mrb_f_sprintf(mrb_state *mrb, mrb_value obj)
508 mrb_get_args(mrb, "*", &argv, &argc);
511 mrb_raise(mrb, E_ARGUMENT_ERROR, "too few arguments");
512 return mrb_nil_value();
515 return mrb_str_format(mrb, argc - 1, argv + 1, argv[0]);
520 mrb_int2str(char *buf, size_t len, mrb_int n)
522 #ifdef MRB_DISABLE_STDIO
523 char *bufend = buf + len;
524 char *p = bufend - 1;
526 if (len < 1) return -1;
532 if (len < 1) return -1;
540 for (; n > 0; len --, n /= 10) {
541 if (len < 1) return -1;
543 *p -- = '0' + (n % 10);
555 memmove(buf, p, bufend - p);
557 return bufend - p - 1;
559 return snprintf(buf, len, "%" MRB_PRId, n);
560 #endif /* MRB_DISABLE_STDIO */
564 mrb_str_format(mrb_state *mrb, mrb_int argc, const mrb_value *argv, mrb_value fmt)
578 mrb_value hash = mrb_undef_value();
580 #define CHECK_FOR_WIDTH(f) \
581 if ((f) & FWIDTH) { \
582 mrb_raise(mrb, E_ARGUMENT_ERROR, "width given twice"); \
584 if ((f) & FPREC0) { \
585 mrb_raise(mrb, E_ARGUMENT_ERROR, "width after precision"); \
587 #define CHECK_FOR_FLAGS(f) \
588 if ((f) & FWIDTH) { \
589 mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after width"); \
591 if ((f) & FPREC0) { \
592 mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after precision"); \
597 mrb_to_str(mrb, fmt);
598 p = RSTRING_PTR(fmt);
599 end = p + RSTRING_LEN(fmt);
602 result = mrb_str_new_capa(mrb, bsiz);
603 buf = RSTRING_PTR(result);
604 memset(buf, 0, bsiz);
606 for (; p < end; p++) {
611 for (t = p; t < end && *t != '%'; t++) ;
612 if (t + 1 == end) ++t;
615 goto sprint_exit; /* end of fmt string */
617 p = t + 1; /* skip '%' */
620 nextvalue = mrb_undef_value();
625 mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - %%%c", *p);
629 CHECK_FOR_FLAGS(flags);
635 CHECK_FOR_FLAGS(flags);
641 CHECK_FOR_FLAGS(flags);
647 CHECK_FOR_FLAGS(flags);
653 CHECK_FOR_FLAGS(flags);
658 case '1': case '2': case '3': case '4':
659 case '5': case '6': case '7': case '8': case '9':
663 if (!mrb_undef_p(nextvalue)) {
664 mrb_raisef(mrb, E_ARGUMENT_ERROR, "value given twice - %i$", n);
666 nextvalue = GETPOSARG(n);
670 CHECK_FOR_WIDTH(flags);
677 const char *start = p;
678 char term = (*p == '<') ? '>' : '}';
681 for (; p < end && *p != term; )
684 mrb_raisef(mrb, E_ARGUMENT_ERROR, "name%l after <%n>",
685 start, p - start + 1, id);
687 symname = mrb_str_new(mrb, start + 1, p - start - 1);
688 id = mrb_intern_str(mrb, symname);
689 nextvalue = GETNAMEARG(mrb_symbol_value(id), start, p - start + 1);
690 if (mrb_undef_p(nextvalue)) {
691 mrb_raisef(mrb, E_KEY_ERROR, "key%l not found", start, p - start + 1);
693 if (term == '}') goto format_s;
699 CHECK_FOR_WIDTH(flags);
710 if (flags & FPREC0) {
711 mrb_raise(mrb, E_ARGUMENT_ERROR, "precision given twice");
713 flags |= FPREC|FPREC0;
719 if (prec < 0) { /* ignore negative precision */
726 GETNUM(prec, precision);
734 if (flags != FNONE) {
735 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format character - %");
741 mrb_value val = GETARG();
745 tmp = mrb_check_string_type(mrb, val);
746 if (!mrb_nil_p(tmp)) {
747 if (RSTRING_LEN(tmp) != 1) {
748 mrb_raise(mrb, E_ARGUMENT_ERROR, "%c requires a character");
751 else if (mrb_fixnum_p(val)) {
752 mrb_int n = mrb_fixnum(val);
753 #ifndef MRB_UTF8_STRING
756 buf[0] = (char)n&0xff;
757 tmp = mrb_str_new(mrb, buf, 1);
763 tmp = mrb_str_new(mrb, buf, 1);
766 tmp = mrb_funcall(mrb, val, "chr", 0);
767 mrb_check_type(mrb, tmp, MRB_TT_STRING);
772 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid character");
774 c = RSTRING_PTR(tmp);
775 n = RSTRING_LEN(tmp);
776 if (!(flags & FWIDTH)) {
779 else if ((flags & FMINUS)) {
781 if (width>0) FILL(' ', width-1);
784 if (width>0) FILL(' ', width-1);
794 mrb_value arg = GETARG();
798 if (*p == 'p') arg = mrb_inspect(mrb, arg);
799 str = mrb_obj_as_string(mrb, arg);
800 len = RSTRING_LEN(str);
801 if (RSTRING(result)->flags & MRB_STR_EMBED) {
803 RSTRING(result)->flags &= ~MRB_STR_EMBED_LEN_MASK;
804 RSTRING(result)->flags |= tmp_n << MRB_STR_EMBED_LEN_SHIFT;
807 RSTRING(result)->as.heap.len = blen;
809 if (flags&(FPREC|FWIDTH)) {
810 slen = RSTRING_LEN(str);
812 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid mbstring sequence");
814 if ((flags&FPREC) && (prec < slen)) {
815 char *p = RSTRING_PTR(str) + prec;
817 len = (mrb_int)(p - RSTRING_PTR(str));
819 /* need to adjust multi-byte string pos */
820 if ((flags&FWIDTH) && (width > slen)) {
822 if (!(flags&FMINUS)) {
825 PUSH(RSTRING_PTR(str), len);
832 PUSH(RSTRING_PTR(str), len);
844 mrb_value val = GETARG();
846 const char *prefix = NULL;
847 int sign = 0, dots = 0;
853 if (flags & FSHARP) {
855 case 'o': prefix = "0"; break;
856 case 'x': prefix = "0x"; break;
857 case 'X': prefix = "0X"; break;
858 case 'b': prefix = "0b"; break;
859 case 'B': prefix = "0B"; break;
865 switch (mrb_type(val)) {
866 #ifndef MRB_WITHOUT_FLOAT
868 val = mrb_flo_to_fixnum(mrb, val);
869 if (mrb_fixnum_p(val)) goto bin_retry;
873 val = mrb_str_to_inum(mrb, val, 0, TRUE);
879 val = mrb_Integer(mrb, val);
907 else if (flags & FSPACE) {
916 mrb_assert(base == 10);
917 mrb_int2str(nbuf, sizeof(nbuf)-1, v);
919 if (v < 0) s++; /* skip minus sign */
925 val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base);
928 val = mrb_fixnum_to_str(mrb, mrb_fixnum_value(v), base);
930 strncpy(++s, RSTRING_PTR(val), sizeof(nbuf)-2);
934 s = remove_sign_bits(s, base);
936 case 16: d = 'f'; break;
937 case 8: d = '7'; break;
938 case 2: d = '1'; break;
939 default: d = 0; break;
950 /* PARANOID: assert(size <= MRB_INT_MAX) */
957 while ((c = (int)(unsigned char)*pp) != 0) {
963 if (prefix && !prefix[1]) { /* octal */
967 else if (len == 1 && *s == '0') {
969 if (flags & FPREC) prec--;
971 else if ((flags & FPREC) && (prec > len)) {
975 else if (len == 1 && *s == '0') {
981 size = strlen(prefix);
982 /* PARANOID: assert(size <= MRB_INT_MAX).
983 * this check is absolutely paranoid. */
984 width -= (mrb_int)size;
987 if ((flags & (FZERO|FMINUS|FPREC)) == FZERO) {
993 if (!prefix && prec == 0 && len == 1 && *s == '0') len = 0;
999 if (!(flags&FMINUS) && width > 0) {
1004 if (sc) PUSH(&sc, 1);
1007 int plen = (int)strlen(prefix);
1018 if ((flags & (FMINUS|FPREC)) != FMINUS) {
1020 FILL(c, prec - len);
1022 char c = sign_bits(base, p);
1023 FILL(c, prec - len);
1033 #ifndef MRB_WITHOUT_FLOAT
1041 mrb_value val = GETARG();
1046 fval = mrb_float(mrb_Float(mrb, val));
1047 if (!isfinite(fval)) {
1049 const mrb_int elen = 3;
1059 if (!isnan(fval) && fval < 0.0)
1061 else if (flags & (FPLUS|FSPACE))
1062 sign = (flags & FPLUS) ? '+' : ' ';
1065 if ((flags & FWIDTH) && need < width)
1069 mrb_raise(mrb, E_ARGUMENT_ERROR, "width too big");
1072 if (flags & FMINUS) {
1074 buf[blen - need--] = sign;
1075 memcpy(&buf[blen - need], expr, elen);
1079 buf[blen - elen - 1] = sign;
1080 memcpy(&buf[blen - elen], expr, elen);
1086 if (*p != 'e' && *p != 'E') {
1090 need = BIT_DIGITS(i);
1092 if (need > MRB_INT_MAX - ((flags&FPREC) ? prec : 6)) {
1094 mrb_raise(mrb, E_ARGUMENT_ERROR,
1095 (width > prec ? "width too big" : "prec too big"));
1097 need += (flags&FPREC) ? prec : 6;
1098 if ((flags&FWIDTH) && need < width)
1100 if (need > MRB_INT_MAX - 20) {
1106 fmt_setup(fbuf, sizeof(fbuf), *p, flags, width, prec);
1107 n = mrb_float_to_cstr(mrb, &buf[blen], need, fbuf, fval);
1108 if (n < 0 || n >= need) {
1109 mrb_raise(mrb, E_RUNTIME_ERROR, "formatting error");
1121 /* XXX - We cannot validate the number of arguments if (digit)$ style used.
1123 if (posarg >= 0 && nextarg < argc) {
1124 const char *mesg = "too many arguments for format string";
1125 if (mrb_test(ruby_debug)) mrb_raise(mrb, E_ARGUMENT_ERROR, mesg);
1126 if (mrb_test(ruby_verbose)) mrb_warn(mrb, "%s", mesg);
1129 mrb_str_resize(mrb, result, blen);
1134 #ifndef MRB_WITHOUT_FLOAT
1136 fmt_setup(char *buf, size_t size, int c, int flags, mrb_int width, mrb_int prec)
1138 char *end = buf + size;
1142 if (flags & FSHARP) *buf++ = '#';
1143 if (flags & FPLUS) *buf++ = '+';
1144 if (flags & FMINUS) *buf++ = '-';
1145 if (flags & FZERO) *buf++ = '0';
1146 if (flags & FSPACE) *buf++ = ' ';
1148 if (flags & FWIDTH) {
1149 n = mrb_int2str(buf, end - buf, width);
1153 if (flags & FPREC) {
1155 n = mrb_int2str(buf, end - buf, prec);