Remove prism compiler warning
[ruby.git] / sprintf.c
blob98877d25d27d05b015caa07daa4dbc69396f3e4f
1 /**********************************************************************
3 sprintf.c -
5 $Author$
6 created at: Fri Oct 15 10:39:26 JST 1993
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
12 **********************************************************************/
14 #include "ruby/internal/config.h"
16 #include <math.h>
17 #include <stdarg.h>
19 #ifdef HAVE_IEEEFP_H
20 # include <ieeefp.h>
21 #endif
23 #include "id.h"
24 #include "internal.h"
25 #include "internal/error.h"
26 #include "internal/hash.h"
27 #include "internal/numeric.h"
28 #include "internal/object.h"
29 #include "internal/sanitizers.h"
30 #include "internal/symbol.h"
31 #include "ruby/encoding.h"
32 #include "ruby/re.h"
33 #include "ruby/util.h"
35 #define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */
37 static char *fmt_setup(char*,size_t,int,int,int,int);
38 static char *ruby_ultoa(unsigned long val, char *endp, int base, int octzero);
40 static char
41 sign_bits(int base, const char *p)
43 char c = '.';
45 switch (base) {
46 case 16:
47 if (*p == 'X') c = 'F';
48 else c = 'f';
49 break;
50 case 8:
51 c = '7'; break;
52 case 2:
53 c = '1'; break;
55 return c;
58 #define FNONE 0
59 #define FSHARP 1
60 #define FMINUS 2
61 #define FPLUS 4
62 #define FZERO 8
63 #define FSPACE 16
64 #define FWIDTH 32
65 #define FPREC 64
66 #define FPREC0 128
68 #define CHECK(l) do {\
69 int cr = ENC_CODERANGE(result);\
70 while ((l) >= bsiz - blen) {\
71 bsiz*=2;\
72 if (bsiz<0) rb_raise(rb_eArgError, "too big specifier");\
74 rb_str_resize(result, bsiz);\
75 ENC_CODERANGE_SET(result, cr);\
76 buf = RSTRING_PTR(result);\
77 } while (0)
79 #define PUSH(s, l) do { \
80 CHECK(l);\
81 PUSH_(s, l);\
82 } while (0)
84 #define PUSH_(s, l) do { \
85 memcpy(&buf[blen], (s), (l));\
86 blen += (l);\
87 } while (0)
89 #define FILL(c, l) do { \
90 if ((l) <= 0) break;\
91 CHECK(l);\
92 FILL_(c, l);\
93 } while (0)
95 #define FILL_(c, l) do { \
96 memset(&buf[blen], (c), (l));\
97 blen += (l);\
98 } while (0)
100 #define GETARG() (!UNDEF_P(nextvalue) ? nextvalue : \
101 GETNEXTARG())
103 #define GETNEXTARG() ( \
104 check_next_arg(posarg, nextarg), \
105 (posarg = nextarg++, GETNTHARG(posarg)))
107 #define GETPOSARG(n) ( \
108 check_pos_arg(posarg, (n)), \
109 (posarg = -1, GETNTHARG(n)))
111 #define GETNTHARG(nth) \
112 (((nth) >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : argv[(nth)])
114 #define CHECKNAMEARG(name, len, enc) ( \
115 check_name_arg(posarg, name, len, enc), \
116 posarg = -2)
118 #define GETNUM(n, val) \
119 (!(p = get_num(p, end, enc, &(n))) ? \
120 rb_raise(rb_eArgError, #val " too big") : (void)0)
122 #define GETASTER(val) do { \
123 t = p++; \
124 n = 0; \
125 GETNUM(n, val); \
126 if (*p == '$') { \
127 tmp = GETPOSARG(n); \
129 else { \
130 tmp = GETNEXTARG(); \
131 p = t; \
133 (val) = NUM2INT(tmp); \
134 } while (0)
136 static const char *
137 get_num(const char *p, const char *end, rb_encoding *enc, int *valp)
139 int next_n = *valp;
140 for (; p < end && rb_enc_isdigit(*p, enc); p++) {
141 if (MUL_OVERFLOW_INT_P(10, next_n))
142 return NULL;
143 next_n *= 10;
144 if (INT_MAX - (*p - '0') < next_n)
145 return NULL;
146 next_n += *p - '0';
148 if (p >= end) {
149 rb_raise(rb_eArgError, "malformed format string - %%*[0-9]");
151 *valp = next_n;
152 return p;
155 static void
156 check_next_arg(int posarg, int nextarg)
158 switch (posarg) {
159 case -1:
160 rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered", nextarg);
161 case -2:
162 rb_raise(rb_eArgError, "unnumbered(%d) mixed with named", nextarg);
166 static void
167 check_pos_arg(int posarg, int n)
169 if (posarg > 0) {
170 rb_raise(rb_eArgError, "numbered(%d) after unnumbered(%d)", n, posarg);
172 if (posarg == -2) {
173 rb_raise(rb_eArgError, "numbered(%d) after named", n);
175 if (n < 1) {
176 rb_raise(rb_eArgError, "invalid index - %d$", n);
180 static void
181 check_name_arg(int posarg, const char *name, int len, rb_encoding *enc)
183 if (posarg > 0) {
184 rb_enc_raise(enc, rb_eArgError, "named%.*s after unnumbered(%d)", len, name, posarg);
186 if (posarg == -1) {
187 rb_enc_raise(enc, rb_eArgError, "named%.*s after numbered", len, name);
191 static VALUE
192 get_hash(volatile VALUE *hash, int argc, const VALUE *argv)
194 VALUE tmp;
196 if (!UNDEF_P(*hash)) return *hash;
197 if (argc != 2) {
198 rb_raise(rb_eArgError, "one hash required");
200 tmp = rb_check_hash_type(argv[1]);
201 if (NIL_P(tmp)) {
202 rb_raise(rb_eArgError, "one hash required");
204 return (*hash = tmp);
207 VALUE
208 rb_f_sprintf(int argc, const VALUE *argv)
210 return rb_str_format(argc - 1, argv + 1, GETNTHARG(0));
213 VALUE
214 rb_str_format(int argc, const VALUE *argv, VALUE fmt)
216 enum {default_float_precision = 6};
217 rb_encoding *enc;
218 const char *p, *end;
219 char *buf;
220 long blen, bsiz;
221 VALUE result;
223 long scanned = 0;
224 enum ruby_coderange_type coderange = ENC_CODERANGE_7BIT;
225 int width, prec, flags = FNONE;
226 int nextarg = 1;
227 int posarg = 0;
228 VALUE nextvalue;
229 VALUE tmp;
230 VALUE orig;
231 VALUE str;
232 volatile VALUE hash = Qundef;
234 #define CHECK_FOR_WIDTH(f) \
235 if ((f) & FWIDTH) { \
236 rb_raise(rb_eArgError, "width given twice"); \
238 if ((f) & FPREC0) { \
239 rb_raise(rb_eArgError, "width after precision"); \
241 #define CHECK_FOR_FLAGS(f) \
242 if ((f) & FWIDTH) { \
243 rb_raise(rb_eArgError, "flag after width"); \
245 if ((f) & FPREC0) { \
246 rb_raise(rb_eArgError, "flag after precision"); \
249 #define update_coderange(partial) do { \
250 if (coderange != ENC_CODERANGE_BROKEN && scanned < blen \
251 && rb_enc_to_index(enc) /* != ENCINDEX_ASCII_8BIT */) { \
252 int cr = coderange; \
253 scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &cr); \
254 ENC_CODERANGE_SET(result, \
255 (partial && cr == ENC_CODERANGE_UNKNOWN ? \
256 ENC_CODERANGE_BROKEN : (coderange = cr))); \
258 } while (0)
259 ++argc;
260 --argv;
261 StringValue(fmt);
262 enc = rb_enc_get(fmt);
263 rb_must_asciicompat(fmt);
264 orig = fmt;
265 fmt = rb_str_tmp_frozen_acquire(fmt);
266 p = RSTRING_PTR(fmt);
267 end = p + RSTRING_LEN(fmt);
268 blen = 0;
269 bsiz = 120;
270 result = rb_str_buf_new(bsiz);
271 rb_enc_associate(result, enc);
272 buf = RSTRING_PTR(result);
273 memset(buf, 0, bsiz);
274 ENC_CODERANGE_SET(result, coderange);
276 for (; p < end; p++) {
277 const char *t;
278 int n;
279 VALUE sym = Qnil;
281 for (t = p; t < end && *t != '%'; t++) ;
282 if (t + 1 == end) {
283 rb_raise(rb_eArgError, "incomplete format specifier; use %%%% (double %%) instead");
285 PUSH(p, t - p);
286 update_coderange(FALSE);
287 if (t >= end) {
288 /* end of fmt string */
289 goto sprint_exit;
291 p = t + 1; /* skip `%' */
293 width = prec = -1;
294 nextvalue = Qundef;
295 retry:
296 switch (*p) {
297 default:
298 if (rb_enc_isprint(*p, enc))
299 rb_raise(rb_eArgError, "malformed format string - %%%c", *p);
300 else
301 rb_raise(rb_eArgError, "malformed format string");
302 break;
304 case ' ':
305 CHECK_FOR_FLAGS(flags);
306 flags |= FSPACE;
307 p++;
308 goto retry;
310 case '#':
311 CHECK_FOR_FLAGS(flags);
312 flags |= FSHARP;
313 p++;
314 goto retry;
316 case '+':
317 CHECK_FOR_FLAGS(flags);
318 flags |= FPLUS;
319 p++;
320 goto retry;
322 case '-':
323 CHECK_FOR_FLAGS(flags);
324 flags |= FMINUS;
325 p++;
326 goto retry;
328 case '0':
329 CHECK_FOR_FLAGS(flags);
330 flags |= FZERO;
331 p++;
332 goto retry;
334 case '1': case '2': case '3': case '4':
335 case '5': case '6': case '7': case '8': case '9':
336 n = 0;
337 GETNUM(n, width);
338 if (*p == '$') {
339 if (!UNDEF_P(nextvalue)) {
340 rb_raise(rb_eArgError, "value given twice - %d$", n);
342 nextvalue = GETPOSARG(n);
343 p++;
344 goto retry;
346 CHECK_FOR_WIDTH(flags);
347 width = n;
348 flags |= FWIDTH;
349 goto retry;
351 case '<':
352 case '{':
354 const char *start = p;
355 char term = (*p == '<') ? '>' : '}';
356 int len;
358 for (; p < end && *p != term; ) {
359 p += rb_enc_mbclen(p, end, enc);
361 if (p >= end) {
362 rb_raise(rb_eArgError, "malformed name - unmatched parenthesis");
364 #if SIZEOF_INT < SIZEOF_SIZE_T
365 if ((size_t)(p - start) >= INT_MAX) {
366 const int message_limit = 20;
367 len = (int)(rb_enc_right_char_head(start, start + message_limit, p, enc) - start);
368 rb_enc_raise(enc, rb_eArgError,
369 "too long name (%"PRIuSIZE" bytes) - %.*s...%c",
370 (size_t)(p - start - 2), len, start, term);
372 #endif
373 len = (int)(p - start + 1); /* including parenthesis */
374 if (sym != Qnil) {
375 rb_enc_raise(enc, rb_eArgError, "named%.*s after <%"PRIsVALUE">",
376 len, start, rb_sym2str(sym));
378 CHECKNAMEARG(start, len, enc);
379 get_hash(&hash, argc, argv);
380 sym = rb_check_symbol_cstr(start + 1,
381 len - 2 /* without parenthesis */,
382 enc);
383 if (!NIL_P(sym)) nextvalue = rb_hash_lookup2(hash, sym, Qundef);
384 if (UNDEF_P(nextvalue)) {
385 if (NIL_P(sym)) {
386 sym = rb_sym_intern(start + 1,
387 len - 2 /* without parenthesis */,
388 enc);
390 nextvalue = rb_hash_default_value(hash, sym);
391 if (NIL_P(nextvalue)) {
392 rb_key_err_raise(rb_enc_sprintf(enc, "key%.*s not found", len, start), hash, sym);
395 if (term == '}') goto format_s;
396 p++;
397 goto retry;
400 case '*':
401 CHECK_FOR_WIDTH(flags);
402 flags |= FWIDTH;
403 GETASTER(width);
404 if (width < 0) {
405 flags |= FMINUS;
406 width = -width;
407 if (width < 0) rb_raise(rb_eArgError, "width too big");
409 p++;
410 goto retry;
412 case '.':
413 if (flags & FPREC0) {
414 rb_raise(rb_eArgError, "precision given twice");
416 flags |= FPREC|FPREC0;
418 prec = 0;
419 p++;
420 if (*p == '*') {
421 GETASTER(prec);
422 if (prec < 0) { /* ignore negative precision */
423 flags &= ~FPREC;
425 p++;
426 goto retry;
429 GETNUM(prec, precision);
430 goto retry;
432 case '%':
433 if (flags != FNONE) {
434 rb_raise(rb_eArgError, "invalid format character - %%");
436 PUSH("%", 1);
437 break;
439 case 'c':
441 VALUE val = GETARG();
442 VALUE tmp;
443 unsigned int c;
444 int n;
446 tmp = rb_check_string_type(val);
447 if (!NIL_P(tmp)) {
448 flags |= FPREC;
449 prec = 1;
450 str = tmp;
451 goto format_s1;
453 n = NUM2INT(val);
454 if (n >= 0) n = rb_enc_codelen((c = n), enc);
455 if (n <= 0) {
456 rb_raise(rb_eArgError, "invalid character");
458 int encidx = rb_ascii8bit_appendable_encoding_index(enc, c);
459 if (encidx >= 0 && encidx != rb_enc_to_index(enc)) {
460 /* special case */
461 rb_enc_associate_index(result, encidx);
462 enc = rb_enc_from_index(encidx);
463 coderange = ENC_CODERANGE_VALID;
465 if (!(flags & FWIDTH)) {
466 CHECK(n);
467 rb_enc_mbcput(c, &buf[blen], enc);
468 blen += n;
470 else if ((flags & FMINUS)) {
471 --width;
472 CHECK(n + (width > 0 ? width : 0));
473 rb_enc_mbcput(c, &buf[blen], enc);
474 blen += n;
475 if (width > 0) FILL_(' ', width);
477 else {
478 --width;
479 CHECK(n + (width > 0 ? width : 0));
480 if (width > 0) FILL_(' ', width);
481 rb_enc_mbcput(c, &buf[blen], enc);
482 blen += n;
485 break;
487 case 's':
488 case 'p':
489 format_s:
491 VALUE arg = GETARG();
492 long len, slen;
494 if (*p == 'p') {
495 str = rb_inspect(arg);
497 else {
498 str = rb_obj_as_string(arg);
500 format_s1:
501 len = RSTRING_LEN(str);
502 rb_str_set_len(result, blen);
503 update_coderange(TRUE);
504 enc = rb_enc_check(result, str);
505 if (flags&(FPREC|FWIDTH)) {
506 slen = rb_enc_strlen(RSTRING_PTR(str),RSTRING_END(str),enc);
507 if (slen < 0) {
508 rb_raise(rb_eArgError, "invalid mbstring sequence");
510 if ((flags&FPREC) && (prec < slen)) {
511 char *p = rb_enc_nth(RSTRING_PTR(str), RSTRING_END(str),
512 prec, enc);
513 slen = prec;
514 len = p - RSTRING_PTR(str);
516 /* need to adjust multi-byte string pos */
517 if ((flags&FWIDTH) && (width > slen)) {
518 width -= (int)slen;
519 CHECK(len + width);
520 if (!(flags&FMINUS)) {
521 FILL_(' ', width);
522 width = 0;
524 memcpy(&buf[blen], RSTRING_PTR(str), len);
525 RB_GC_GUARD(str);
526 blen += len;
527 if (flags&FMINUS) {
528 FILL_(' ', width);
530 rb_enc_associate(result, enc);
531 break;
534 PUSH(RSTRING_PTR(str), len);
535 RB_GC_GUARD(str);
536 rb_enc_associate(result, enc);
538 break;
540 case 'd':
541 case 'i':
542 case 'o':
543 case 'x':
544 case 'X':
545 case 'b':
546 case 'B':
547 case 'u':
549 volatile VALUE val = GETARG();
550 int valsign;
551 char nbuf[BIT_DIGITS(SIZEOF_LONG*CHAR_BIT)+2], *s;
552 const char *prefix = 0;
553 int sign = 0, dots = 0;
554 char sc = 0;
555 long v = 0;
556 int base, bignum = 0;
557 int len;
559 switch (*p) {
560 case 'd':
561 case 'i':
562 case 'u':
563 sign = 1; break;
564 case 'o':
565 case 'x':
566 case 'X':
567 case 'b':
568 case 'B':
569 if (flags&(FPLUS|FSPACE)) sign = 1;
570 break;
572 if (flags & FSHARP) {
573 switch (*p) {
574 case 'o':
575 prefix = "0"; break;
576 case 'x':
577 prefix = "0x"; break;
578 case 'X':
579 prefix = "0X"; break;
580 case 'b':
581 prefix = "0b"; break;
582 case 'B':
583 prefix = "0B"; break;
587 bin_retry:
588 switch (TYPE(val)) {
589 case T_FLOAT:
590 if (FIXABLE(RFLOAT_VALUE(val))) {
591 val = LONG2FIX((long)RFLOAT_VALUE(val));
592 goto bin_retry;
594 val = rb_dbl2big(RFLOAT_VALUE(val));
595 if (FIXNUM_P(val)) goto bin_retry;
596 bignum = 1;
597 break;
598 case T_STRING:
599 val = rb_str_to_inum(val, 0, TRUE);
600 goto bin_retry;
601 case T_BIGNUM:
602 bignum = 1;
603 break;
604 case T_FIXNUM:
605 v = FIX2LONG(val);
606 break;
607 default:
608 val = rb_Integer(val);
609 goto bin_retry;
612 switch (*p) {
613 case 'o':
614 base = 8; break;
615 case 'x':
616 case 'X':
617 base = 16; break;
618 case 'b':
619 case 'B':
620 base = 2; break;
621 case 'u':
622 case 'd':
623 case 'i':
624 default:
625 base = 10; break;
628 if (base != 10) {
629 int numbits = ffs(base)-1;
630 size_t abs_nlz_bits;
631 size_t numdigits = rb_absint_numwords(val, numbits, &abs_nlz_bits);
632 long i;
633 if (INT_MAX-1 < numdigits) /* INT_MAX is used because rb_long2int is used later. */
634 rb_raise(rb_eArgError, "size too big");
635 if (sign) {
636 if (numdigits == 0)
637 numdigits = 1;
638 tmp = rb_str_new(NULL, numdigits);
639 valsign = rb_integer_pack(val, RSTRING_PTR(tmp), RSTRING_LEN(tmp),
640 1, CHAR_BIT-numbits, INTEGER_PACK_BIG_ENDIAN);
641 for (i = 0; i < RSTRING_LEN(tmp); i++)
642 RSTRING_PTR(tmp)[i] = ruby_digitmap[((unsigned char *)RSTRING_PTR(tmp))[i]];
643 s = RSTRING_PTR(tmp);
644 if (valsign < 0) {
645 sc = '-';
646 width--;
648 else if (flags & FPLUS) {
649 sc = '+';
650 width--;
652 else if (flags & FSPACE) {
653 sc = ' ';
654 width--;
657 else {
658 /* Following conditional "numdigits++" guarantees the
659 * most significant digit as
660 * - '1'(bin), '7'(oct) or 'f'(hex) for negative numbers
661 * - '0' for zero
662 * - not '0' for positive numbers.
664 * It also guarantees the most significant two
665 * digits will not be '11'(bin), '77'(oct), 'ff'(hex)
666 * or '00'. */
667 if (numdigits == 0 ||
668 ((abs_nlz_bits != (size_t)(numbits-1) ||
669 !rb_absint_singlebit_p(val)) &&
670 (!bignum ? v < 0 : BIGNUM_NEGATIVE_P(val))))
671 numdigits++;
672 tmp = rb_str_new(NULL, numdigits);
673 valsign = rb_integer_pack(val, RSTRING_PTR(tmp), RSTRING_LEN(tmp),
674 1, CHAR_BIT-numbits, INTEGER_PACK_2COMP | INTEGER_PACK_BIG_ENDIAN);
675 for (i = 0; i < RSTRING_LEN(tmp); i++)
676 RSTRING_PTR(tmp)[i] = ruby_digitmap[((unsigned char *)RSTRING_PTR(tmp))[i]];
677 s = RSTRING_PTR(tmp);
678 dots = valsign < 0;
680 len = rb_long2int(RSTRING_END(tmp) - s);
682 else if (!bignum) {
683 valsign = 1;
684 if (v < 0) {
685 v = -v;
686 sc = '-';
687 width--;
688 valsign = -1;
690 else if (flags & FPLUS) {
691 sc = '+';
692 width--;
694 else if (flags & FSPACE) {
695 sc = ' ';
696 width--;
698 s = ruby_ultoa((unsigned long)v, nbuf + sizeof(nbuf), 10, 0);
699 len = (int)(nbuf + sizeof(nbuf) - s);
701 else {
702 tmp = rb_big2str(val, 10);
703 s = RSTRING_PTR(tmp);
704 valsign = 1;
705 if (s[0] == '-') {
706 s++;
707 sc = '-';
708 width--;
709 valsign = -1;
711 else if (flags & FPLUS) {
712 sc = '+';
713 width--;
715 else if (flags & FSPACE) {
716 sc = ' ';
717 width--;
719 len = rb_long2int(RSTRING_END(tmp) - s);
722 if (dots) {
723 prec -= 2;
724 width -= 2;
727 if (*p == 'X') {
728 char *pp = s;
729 int c;
730 while ((c = (int)(unsigned char)*pp) != 0) {
731 *pp = rb_enc_toupper(c, enc);
732 pp++;
735 if (prefix && !prefix[1]) { /* octal */
736 if (dots) {
737 prefix = 0;
739 else if (len == 1 && *s == '0') {
740 len = 0;
741 if (flags & FPREC) prec--;
743 else if ((flags & FPREC) && (prec > len)) {
744 prefix = 0;
747 else if (len == 1 && *s == '0') {
748 prefix = 0;
750 if (prefix) {
751 width -= (int)strlen(prefix);
753 if ((flags & (FZERO|FMINUS|FPREC)) == FZERO) {
754 prec = width;
755 width = 0;
757 else {
758 if (prec < len) {
759 if (!prefix && prec == 0 && len == 1 && *s == '0') len = 0;
760 prec = len;
762 width -= prec;
764 if (!(flags&FMINUS)) {
765 FILL(' ', width);
766 width = 0;
768 if (sc) PUSH(&sc, 1);
769 if (prefix) {
770 int plen = (int)strlen(prefix);
771 PUSH(prefix, plen);
773 if (dots) PUSH("..", 2);
774 if (prec > len) {
775 CHECK(prec - len);
776 if (!sign && valsign < 0) {
777 char c = sign_bits(base, p);
778 FILL_(c, prec - len);
780 else if ((flags & (FMINUS|FPREC)) != FMINUS) {
781 FILL_('0', prec - len);
784 PUSH(s, len);
785 RB_GC_GUARD(tmp);
786 FILL(' ', width);
788 break;
790 case 'f':
792 VALUE val = GETARG(), num, den;
793 int sign = (flags&FPLUS) ? 1 : 0, zero = 0;
794 long len, fill;
795 if (RB_INTEGER_TYPE_P(val)) {
796 den = INT2FIX(1);
797 num = val;
799 else if (RB_TYPE_P(val, T_RATIONAL)) {
800 den = rb_rational_den(val);
801 num = rb_rational_num(val);
803 else {
804 nextvalue = val;
805 goto float_value;
807 if (!(flags&FPREC)) prec = default_float_precision;
808 if (FIXNUM_P(num)) {
809 if ((SIGNED_VALUE)num < 0) {
810 long n = -FIX2LONG(num);
811 num = LONG2FIX(n);
812 sign = -1;
815 else if (BIGNUM_NEGATIVE_P(num)) {
816 sign = -1;
817 num = rb_big_uminus(num);
819 if (den != INT2FIX(1)) {
820 num = rb_int_mul(num, rb_int_positive_pow(10, prec));
821 num = rb_int_plus(num, rb_int_idiv(den, INT2FIX(2)));
822 num = rb_int_idiv(num, den);
824 else if (prec >= 0) {
825 zero = prec;
827 val = rb_int2str(num, 10);
828 len = RSTRING_LEN(val) + zero;
829 if (prec >= len) len = prec + 1; /* integer part 0 */
830 if (sign || (flags&FSPACE)) ++len;
831 if (prec > 0) ++len; /* period */
832 fill = width > len ? width - len : 0;
833 CHECK(fill + len);
834 if (fill && !(flags&(FMINUS|FZERO))) {
835 FILL_(' ', fill);
837 if (sign || (flags&FSPACE)) {
838 buf[blen++] = sign > 0 ? '+' : sign < 0 ? '-' : ' ';
840 if (fill && (flags&(FMINUS|FZERO)) == FZERO) {
841 FILL_('0', fill);
843 len = RSTRING_LEN(val) + zero;
844 t = RSTRING_PTR(val);
845 if (len > prec) {
846 PUSH_(t, len - prec);
848 else {
849 buf[blen++] = '0';
851 if (prec > 0) {
852 buf[blen++] = '.';
854 if (zero) {
855 FILL_('0', zero);
857 else if (prec > len) {
858 FILL_('0', prec - len);
859 PUSH_(t, len);
861 else if (prec > 0) {
862 PUSH_(t + len - prec, prec);
864 if (fill && (flags&FMINUS)) {
865 FILL_(' ', fill);
867 RB_GC_GUARD(val);
868 break;
870 case 'g':
871 case 'G':
872 case 'e':
873 case 'E':
874 /* TODO: rational support */
875 case 'a':
876 case 'A':
877 float_value:
879 VALUE val = GETARG();
880 double fval;
882 fval = RFLOAT_VALUE(rb_Float(val));
883 if (!isfinite(fval)) {
884 const char *expr;
885 int need;
886 int elen;
887 char sign = '\0';
889 if (isnan(fval)) {
890 expr = "NaN";
892 else {
893 expr = "Inf";
895 need = (int)strlen(expr);
896 elen = need;
897 if (!isnan(fval) && fval < 0.0)
898 sign = '-';
899 else if (flags & (FPLUS|FSPACE))
900 sign = (flags & FPLUS) ? '+' : ' ';
901 if (sign)
902 ++need;
903 if ((flags & FWIDTH) && need < width)
904 need = width;
906 FILL(' ', need);
907 if (flags & FMINUS) {
908 if (sign)
909 buf[blen - need--] = sign;
910 memcpy(&buf[blen - need], expr, elen);
912 else {
913 if (sign)
914 buf[blen - elen - 1] = sign;
915 memcpy(&buf[blen - elen], expr, elen);
917 break;
919 else {
920 int cr = ENC_CODERANGE(result);
921 char fbuf[2*BIT_DIGITS(SIZEOF_INT*CHAR_BIT)+10];
922 char *fmt = fmt_setup(fbuf, sizeof(fbuf), *p, flags, width, prec);
923 rb_str_set_len(result, blen);
924 rb_str_catf(result, fmt, fval);
925 ENC_CODERANGE_SET(result, cr);
926 bsiz = rb_str_capacity(result);
927 RSTRING_GETMEM(result, buf, blen);
930 break;
932 flags = FNONE;
935 update_coderange(FALSE);
936 sprint_exit:
937 rb_str_tmp_frozen_release(orig, fmt);
938 /* XXX - We cannot validate the number of arguments if (digit)$ style used.
940 if (posarg >= 0 && nextarg < argc) {
941 const char *mesg = "too many arguments for format string";
942 if (RTEST(ruby_debug)) rb_raise(rb_eArgError, "%s", mesg);
943 if (RTEST(ruby_verbose)) rb_warn("%s", mesg);
945 rb_str_resize(result, blen);
947 return result;
950 static char *
951 fmt_setup(char *buf, size_t size, int c, int flags, int width, int prec)
953 buf += size;
954 *--buf = '\0';
955 *--buf = c;
957 if (flags & FPREC) {
958 buf = ruby_ultoa(prec, buf, 10, 0);
959 *--buf = '.';
962 if (flags & FWIDTH) {
963 buf = ruby_ultoa(width, buf, 10, 0);
966 if (flags & FSPACE) *--buf = ' ';
967 if (flags & FZERO) *--buf = '0';
968 if (flags & FMINUS) *--buf = '-';
969 if (flags & FPLUS) *--buf = '+';
970 if (flags & FSHARP) *--buf = '#';
971 *--buf = '%';
972 return buf;
975 #undef FILE
976 #define FILE rb_printf_buffer
977 #define __sbuf rb_printf_sbuf
978 #define __sFILE rb_printf_sfile
979 #undef feof
980 #undef ferror
981 #undef clearerr
982 #undef fileno
983 #if SIZEOF_LONG < SIZEOF_LONG_LONG
984 # if SIZEOF_LONG_LONG == SIZEOF_VOIDP
985 /* actually this doesn't mean a pointer is strictly 64bit, but just
986 * quad_t size */
987 # define _HAVE_LLP64_
988 # endif
989 # define _HAVE_SANE_QUAD_
990 # define quad_t LONG_LONG
991 # define u_quad_t unsigned LONG_LONG
992 #endif
993 #define FLOATING_POINT 1
994 #define BSD__dtoa ruby_dtoa
995 #define BSD__hdtoa ruby_hdtoa
996 #ifdef RUBY_PRI_VALUE_MARK
997 # define PRI_EXTRA_MARK RUBY_PRI_VALUE_MARK
998 #endif
999 #define lower_hexdigits (ruby_hexdigits+0)
1000 #define upper_hexdigits (ruby_hexdigits+16)
1001 #include "vsnprintf.c"
1003 static char *
1004 ruby_ultoa(unsigned long val, char *endp, int base, int flags)
1006 const char *xdigs = lower_hexdigits;
1007 int octzero = flags & FSHARP;
1008 return BSD__ultoa(val, endp, base, octzero, xdigs);
1011 static int ruby_do_vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
1014 ruby_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
1016 if (str && (ssize_t)n < 1)
1017 return (EOF);
1018 return ruby_do_vsnprintf(str, n, fmt, ap);
1021 static int
1022 ruby_do_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
1024 ssize_t ret;
1025 rb_printf_buffer f;
1027 f._flags = __SWR | __SSTR;
1028 f._bf._base = f._p = (unsigned char *)str;
1029 f._bf._size = f._w = str ? (n - 1) : 0;
1030 f.vwrite = BSD__sfvwrite;
1031 f.vextra = 0;
1032 ret = BSD_vfprintf(&f, fmt, ap);
1033 if (str) *f._p = 0;
1034 #if SIZEOF_SIZE_T > SIZEOF_INT
1035 if (n > INT_MAX) return INT_MAX;
1036 #endif
1037 return (int)ret;
1041 ruby_snprintf(char *str, size_t n, char const *fmt, ...)
1043 int ret;
1044 va_list ap;
1046 if (str && (ssize_t)n < 1)
1047 return (EOF);
1049 va_start(ap, fmt);
1050 ret = ruby_do_vsnprintf(str, n, fmt, ap);
1051 va_end(ap);
1052 return ret;
1055 typedef struct {
1056 rb_printf_buffer base;
1057 volatile VALUE value;
1058 } rb_printf_buffer_extra;
1060 static int
1061 ruby__sfvwrite(register rb_printf_buffer *fp, register struct __suio *uio)
1063 struct __siov *iov;
1064 VALUE result = (VALUE)fp->_bf._base;
1065 char *buf = (char*)fp->_p;
1066 long len, n;
1067 long blen = buf - RSTRING_PTR(result), bsiz = fp->_w;
1069 if (RBASIC(result)->klass) {
1070 rb_raise(rb_eRuntimeError, "rb_vsprintf reentered");
1072 if (uio->uio_resid == 0)
1073 return 0;
1074 #if SIZE_MAX > LONG_MAX
1075 if (uio->uio_resid >= LONG_MAX)
1076 rb_raise(rb_eRuntimeError, "too big string");
1077 #endif
1078 len = (long)uio->uio_resid;
1079 CHECK(len);
1080 buf += blen;
1081 fp->_w = bsiz;
1082 for (iov = uio->uio_iov; len > 0; ++iov) {
1083 MEMCPY(buf, iov->iov_base, char, n = iov->iov_len);
1084 buf += n;
1085 len -= n;
1087 fp->_p = (unsigned char *)buf;
1088 rb_str_set_len(result, buf - RSTRING_PTR(result));
1089 return 0;
1092 static const char *
1093 ruby__sfvextra(rb_printf_buffer *fp, size_t valsize, void *valp, long *sz, int sign)
1095 VALUE value, result = (VALUE)fp->_bf._base;
1096 rb_encoding *enc;
1097 char *cp;
1099 if (valsize != sizeof(VALUE)) return 0;
1100 value = *(VALUE *)valp;
1101 if (RBASIC(result)->klass) {
1102 rb_raise(rb_eRuntimeError, "rb_vsprintf reentered");
1104 if (sign == '+') {
1105 # define LITERAL(str) (*sz = rb_strlen_lit(str), str)
1106 /* optimize special const cases */
1107 switch (value) {
1108 # define LITERAL_CASE(x) case Q##x: return LITERAL(#x)
1109 LITERAL_CASE(nil);
1110 LITERAL_CASE(true);
1111 LITERAL_CASE(false);
1112 # undef LITERAL_CASE
1114 # undef LITERAL
1115 value = rb_inspect(value);
1117 else if (SYMBOL_P(value)) {
1118 value = rb_sym2str(value);
1119 if (sign == ' ' && !rb_str_symname_p(value)) {
1120 value = rb_str_escape(value);
1123 else {
1124 value = rb_obj_as_string(value);
1125 if (sign == ' ') value = QUOTE(value);
1127 enc = rb_enc_compatible(result, value);
1128 if (enc) {
1129 rb_enc_associate(result, enc);
1131 else {
1132 enc = rb_enc_get(result);
1133 value = rb_str_conv_enc_opts(value, rb_enc_get(value), enc,
1134 ECONV_UNDEF_REPLACE|ECONV_INVALID_REPLACE,
1135 Qnil);
1136 *(volatile VALUE *)valp = value;
1138 StringValueCStr(value);
1139 RSTRING_GETMEM(value, cp, *sz);
1140 ((rb_printf_buffer_extra *)fp)->value = value;
1141 return cp;
1144 static void
1145 ruby_vsprintf0(VALUE result, char *p, const char *fmt, va_list ap)
1147 rb_printf_buffer_extra buffer;
1148 #define f buffer.base
1149 VALUE klass = RBASIC(result)->klass;
1150 int coderange = ENC_CODERANGE(result);
1151 long scanned = 0;
1153 if (coderange != ENC_CODERANGE_UNKNOWN) scanned = p - RSTRING_PTR(result);
1155 f._flags = __SWR | __SSTR;
1156 f._bf._size = 0;
1157 f._w = rb_str_capacity(result);
1158 f._bf._base = (unsigned char *)result;
1159 f._p = (unsigned char *)p;
1160 RBASIC_CLEAR_CLASS(result);
1161 f.vwrite = ruby__sfvwrite;
1162 f.vextra = ruby__sfvextra;
1163 buffer.value = 0;
1164 BSD_vfprintf(&f, fmt, ap);
1165 RBASIC_SET_CLASS_RAW(result, klass);
1166 p = RSTRING_PTR(result);
1167 long blen = (char *)f._p - p;
1168 if (scanned < blen) {
1169 rb_str_coderange_scan_restartable(p + scanned, p + blen, rb_enc_get(result), &coderange);
1170 ENC_CODERANGE_SET(result, coderange);
1172 rb_str_resize(result, blen);
1173 #undef f
1176 VALUE
1177 rb_enc_vsprintf(rb_encoding *enc, const char *fmt, va_list ap)
1179 const int initial_len = 120;
1180 VALUE result;
1182 result = rb_str_buf_new(initial_len);
1183 if (enc) {
1184 if (rb_enc_mbminlen(enc) > 1) {
1185 /* the implementation deeply depends on plain char */
1186 rb_raise(rb_eArgError, "cannot construct wchar_t based encoding string: %s",
1187 rb_enc_name(enc));
1189 rb_enc_associate(result, enc);
1191 ruby_vsprintf0(result, RSTRING_PTR(result), fmt, ap);
1192 return result;
1195 VALUE
1196 rb_enc_sprintf(rb_encoding *enc, const char *format, ...)
1198 VALUE result;
1199 va_list ap;
1201 va_start(ap, format);
1202 result = rb_enc_vsprintf(enc, format, ap);
1203 va_end(ap);
1205 return result;
1208 VALUE
1209 rb_vsprintf(const char *fmt, va_list ap)
1211 return rb_enc_vsprintf(NULL, fmt, ap);
1214 VALUE
1215 rb_sprintf(const char *format, ...)
1217 VALUE result;
1218 va_list ap;
1220 va_start(ap, format);
1221 result = rb_vsprintf(format, ap);
1222 va_end(ap);
1224 return result;
1227 VALUE
1228 rb_str_vcatf(VALUE str, const char *fmt, va_list ap)
1230 StringValue(str);
1231 rb_str_modify(str);
1232 ruby_vsprintf0(str, RSTRING_END(str), fmt, ap);
1234 return str;
1237 VALUE
1238 rb_str_catf(VALUE str, const char *format, ...)
1240 va_list ap;
1242 va_start(ap, format);
1243 str = rb_str_vcatf(str, format, ap);
1244 va_end(ap);
1246 return str;