Ruby 4.1.0dev (2026-03-01 revision d68e4be1873e364c5ee24ed112bce4bc86e3a406)
sprintf.c (d68e4be1873e364c5ee24ed112bce4bc86e3a406)
1/**********************************************************************
2
3 sprintf.c -
4
5 $Author$
6 created at: Fri Oct 15 10:39:26 JST 1993
7
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
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
16#include <math.h>
17#include <stdarg.h>
18
19#ifdef HAVE_IEEEFP_H
20# include <ieeefp.h>
21#endif
22
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"
34
35#define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */
36
37static char *fmt_setup(char*,size_t,int,int,int,int);
38static char *ruby_ultoa(unsigned long val, char *endp, int base, int octzero);
39
40static char
41sign_bits(int base, const char *p)
42{
43 char c = '.';
44
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;
54 }
55 return c;
56}
57
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
67
68#define CHECK(l) do {\
69 int cr = ENC_CODERANGE(result);\
70 RUBY_ASSERT(bsiz >= blen); \
71 while ((l) > bsiz - blen) {\
72 bsiz*=2;\
73 if (bsiz<0) rb_raise(rb_eArgError, "too big specifier");\
74 }\
75 rb_str_resize(result, bsiz);\
76 ENC_CODERANGE_SET(result, cr);\
77 buf = RSTRING_PTR(result);\
78} while (0)
79
80#define PUSH(s, l) do { \
81 CHECK(l);\
82 PUSH_(s, l);\
83} while (0)
84
85#define PUSH_(s, l) do { \
86 memcpy(&buf[blen], (s), (l));\
87 blen += (l);\
88} while (0)
89
90#define FILL(c, l) do { \
91 if ((l) <= 0) break;\
92 CHECK(l);\
93 FILL_(c, l);\
94} while (0)
95
96#define FILL_(c, l) do { \
97 memset(&buf[blen], (c), (l));\
98 blen += (l);\
99} while (0)
100
101#define GETARG() (!UNDEF_P(nextvalue) ? nextvalue : \
102 GETNEXTARG())
103
104#define GETNEXTARG() ( \
105 check_next_arg(posarg, nextarg), \
106 (posarg = nextarg++, GETNTHARG(posarg)))
107
108#define GETPOSARG(n) ( \
109 check_pos_arg(posarg, (n)), \
110 (posarg = -1, GETNTHARG(n)))
111
112#define GETNTHARG(nth) \
113 (((nth) >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : argv[(nth)])
114
115#define CHECKNAMEARG(name, len, enc) ( \
116 check_name_arg(posarg, name, len, enc), \
117 posarg = -2)
118
119#define GETNUM(n, val) \
120 (!(p = get_num(p, end, enc, &(n))) ? \
121 rb_raise(rb_eArgError, #val " too big") : (void)0)
122
123#define GETASTER(val) do { \
124 t = p++; \
125 n = 0; \
126 GETNUM(n, val); \
127 if (*p == '$') { \
128 tmp = GETPOSARG(n); \
129 } \
130 else { \
131 tmp = GETNEXTARG(); \
132 p = t; \
133 } \
134 (val) = NUM2INT(tmp); \
135} while (0)
136
137static const char *
138get_num(const char *p, const char *end, rb_encoding *enc, int *valp)
139{
140 int next_n = *valp;
141 for (; p < end && rb_enc_isdigit(*p, enc); p++) {
142 if (MUL_OVERFLOW_INT_P(10, next_n))
143 return NULL;
144 next_n *= 10;
145 if (INT_MAX - (*p - '0') < next_n)
146 return NULL;
147 next_n += *p - '0';
148 }
149 if (p >= end) {
150 rb_raise(rb_eArgError, "malformed format string - %%*[0-9]");
151 }
152 *valp = next_n;
153 return p;
154}
155
156static void
157check_next_arg(int posarg, int nextarg)
158{
159 switch (posarg) {
160 case -1:
161 rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered", nextarg);
162 case -2:
163 rb_raise(rb_eArgError, "unnumbered(%d) mixed with named", nextarg);
164 }
165}
166
167static void
168check_pos_arg(int posarg, int n)
169{
170 if (posarg > 0) {
171 rb_raise(rb_eArgError, "numbered(%d) after unnumbered(%d)", n, posarg);
172 }
173 if (posarg == -2) {
174 rb_raise(rb_eArgError, "numbered(%d) after named", n);
175 }
176 if (n < 1) {
177 rb_raise(rb_eArgError, "invalid index - %d$", n);
178 }
179}
180
181static void
182check_name_arg(int posarg, const char *name, int len, rb_encoding *enc)
183{
184 if (posarg > 0) {
185 rb_enc_raise(enc, rb_eArgError, "named%.*s after unnumbered(%d)", len, name, posarg);
186 }
187 if (posarg == -1) {
188 rb_enc_raise(enc, rb_eArgError, "named%.*s after numbered", len, name);
189 }
190}
191
192static VALUE
193get_hash(volatile VALUE *hash, int argc, const VALUE *argv)
194{
195 VALUE tmp;
196
197 if (!UNDEF_P(*hash)) return *hash;
198 if (argc != 2) {
199 rb_raise(rb_eArgError, "one hash required");
200 }
201 tmp = rb_check_hash_type(argv[1]);
202 if (NIL_P(tmp)) {
203 rb_raise(rb_eArgError, "one hash required");
204 }
205 return (*hash = tmp);
206}
207
208VALUE
209rb_f_sprintf(int argc, const VALUE *argv)
210{
211 return rb_str_format(argc - 1, argv + 1, GETNTHARG(0));
212}
213
214VALUE
215rb_str_format(int argc, const VALUE *argv, VALUE fmt)
216{
217 enum {default_float_precision = 6};
218 rb_encoding *enc;
219 const char *p, *end;
220 char *buf;
221 long blen, bsiz;
222 VALUE result;
223
224 long scanned = 0;
226 int width, prec, flags = FNONE;
227 int nextarg = 1;
228 int posarg = 0;
229 VALUE nextvalue;
230 VALUE tmp;
231 VALUE orig;
232 VALUE str;
233 volatile VALUE hash = Qundef;
234
235#define CHECK_FOR_WIDTH(f) \
236 if ((f) & FWIDTH) { \
237 rb_raise(rb_eArgError, "width given twice"); \
238 } \
239 if ((f) & FPREC0) { \
240 rb_raise(rb_eArgError, "width after precision"); \
241 }
242#define CHECK_FOR_FLAGS(f) \
243 if ((f) & FWIDTH) { \
244 rb_raise(rb_eArgError, "flag after width"); \
245 } \
246 if ((f) & FPREC0) { \
247 rb_raise(rb_eArgError, "flag after precision"); \
248 }
249
250#define update_coderange(partial) do { \
251 if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) { \
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))); \
257 } \
258 } while (0)
259 ++argc;
260 --argv;
261 StringValue(fmt);
262 enc = rb_enc_get(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);
275
276 for (; p < end; p++) {
277 const char *t;
278 int n;
279 VALUE sym = Qnil;
280
281 for (t = p; t < end && *t != '%'; t++) ;
282 if (t + 1 == end) {
283 rb_raise(rb_eArgError, "incomplete format specifier; use %%%% (double %%) instead");
284 }
285 PUSH(p, t - p);
286 update_coderange(FALSE);
287 if (t >= end) {
288 /* end of fmt string */
289 goto sprint_exit;
290 }
291 p = t + 1; /* skip `%' */
292
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;
303
304 case ' ':
305 CHECK_FOR_FLAGS(flags);
306 flags |= FSPACE;
307 p++;
308 goto retry;
309
310 case '#':
311 CHECK_FOR_FLAGS(flags);
312 flags |= FSHARP;
313 p++;
314 goto retry;
315
316 case '+':
317 CHECK_FOR_FLAGS(flags);
318 flags |= FPLUS;
319 p++;
320 goto retry;
321
322 case '-':
323 CHECK_FOR_FLAGS(flags);
324 flags |= FMINUS;
325 p++;
326 goto retry;
327
328 case '0':
329 CHECK_FOR_FLAGS(flags);
330 flags |= FZERO;
331 p++;
332 goto retry;
333
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);
341 }
342 nextvalue = GETPOSARG(n);
343 p++;
344 goto retry;
345 }
346 CHECK_FOR_WIDTH(flags);
347 width = n;
348 flags |= FWIDTH;
349 goto retry;
350
351 case '<':
352 case '{':
353 {
354 const char *start = p;
355 char term = (*p == '<') ? '>' : '}';
356 int len;
357
358 for (; p < end && *p != term; ) {
359 p += rb_enc_mbclen(p, end, enc);
360 }
361 if (p >= end) {
362 rb_raise(rb_eArgError, "malformed name - unmatched parenthesis");
363 }
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);
371 }
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));
377 }
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);
389 }
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);
393 }
394 }
395 if (term == '}') goto format_s;
396 p++;
397 goto retry;
398 }
399
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");
408 }
409 p++;
410 goto retry;
411
412 case '.':
413 if (flags & FPREC0) {
414 rb_raise(rb_eArgError, "precision given twice");
415 }
416 flags |= FPREC|FPREC0;
417
418 prec = 0;
419 p++;
420 if (*p == '*') {
421 GETASTER(prec);
422 if (prec < 0) { /* ignore negative precision */
423 flags &= ~FPREC;
424 }
425 p++;
426 goto retry;
427 }
428
429 GETNUM(prec, precision);
430 goto retry;
431
432 case '%':
433 if (flags != FNONE) {
434 rb_raise(rb_eArgError, "invalid format character - %%");
435 }
436 PUSH("%", 1);
437 break;
438
439 case 'c':
440 {
441 VALUE val = GETARG();
442 VALUE tmp;
443 unsigned int c;
444 int n, encidx;
445
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;
452 }
453 n = NUM2INT(val);
454 if (n >= 0) {
455 n = rb_enc_codelen((c = n), enc);
456 encidx = rb_ascii8bit_appendable_encoding_index(enc, c);
457 }
458 if (n <= 0) {
459 rb_raise(rb_eArgError, "invalid character");
460 }
461 if (encidx >= 0 && encidx != rb_enc_to_index(enc)) {
462 /* special case */
463 rb_enc_associate_index(result, encidx);
464 enc = rb_enc_from_index(encidx);
465 coderange = ENC_CODERANGE_VALID;
466 }
467 if (!(flags & FWIDTH)) {
468 CHECK(n);
469 rb_enc_mbcput(c, &buf[blen], enc);
470 blen += n;
471 }
472 else if ((flags & FMINUS)) {
473 --width;
474 CHECK(n + (width > 0 ? width : 0));
475 rb_enc_mbcput(c, &buf[blen], enc);
476 blen += n;
477 if (width > 0) FILL_(' ', width);
478 }
479 else {
480 --width;
481 CHECK(n + (width > 0 ? width : 0));
482 if (width > 0) FILL_(' ', width);
483 rb_enc_mbcput(c, &buf[blen], enc);
484 blen += n;
485 }
486 }
487 break;
488
489 case 's':
490 case 'p':
491 format_s:
492 {
493 VALUE arg = GETARG();
494 long len, slen;
495
496 if (*p == 'p') {
497 str = rb_inspect(arg);
498 }
499 else {
500 str = rb_obj_as_string(arg);
501 }
502 format_s1:
503 len = RSTRING_LEN(str);
504 rb_str_set_len(result, blen);
505 update_coderange(TRUE);
506 enc = rb_enc_check(result, str);
507 if (flags&(FPREC|FWIDTH)) {
508 slen = rb_enc_strlen(RSTRING_PTR(str),RSTRING_END(str),enc);
509 if (slen < 0) {
510 rb_raise(rb_eArgError, "invalid mbstring sequence");
511 }
512 if ((flags&FPREC) && (prec < slen)) {
513 char *p = rb_enc_nth(RSTRING_PTR(str), RSTRING_END(str),
514 prec, enc);
515 slen = prec;
516 len = p - RSTRING_PTR(str);
517 }
518 /* need to adjust multi-byte string pos */
519 if ((flags&FWIDTH) && (width > slen)) {
520 width -= (int)slen;
521 CHECK(len + width);
522 if (!(flags&FMINUS)) {
523 FILL_(' ', width);
524 width = 0;
525 }
526 memcpy(&buf[blen], RSTRING_PTR(str), len);
527 RB_GC_GUARD(str);
528 blen += len;
529 if (flags&FMINUS) {
530 FILL_(' ', width);
531 }
532 rb_enc_associate(result, enc);
533 break;
534 }
535 }
536 PUSH(RSTRING_PTR(str), len);
537 RB_GC_GUARD(str);
538 rb_enc_associate(result, enc);
539 }
540 break;
541
542 case 'd':
543 case 'i':
544 case 'o':
545 case 'x':
546 case 'X':
547 case 'b':
548 case 'B':
549 case 'u':
550 {
551 volatile VALUE val = GETARG();
552 int valsign;
553 char nbuf[BIT_DIGITS(SIZEOF_LONG*CHAR_BIT)+2], *s;
554 const char *prefix = 0;
555 int sign = 0, dots = 0;
556 char sc = 0;
557 long v = 0;
558 int base, bignum = 0;
559 int len;
560
561 switch (*p) {
562 case 'd':
563 case 'i':
564 case 'u':
565 sign = 1; break;
566 case 'o':
567 case 'x':
568 case 'X':
569 case 'b':
570 case 'B':
571 if (flags&(FPLUS|FSPACE)) sign = 1;
572 break;
573 }
574 if (flags & FSHARP) {
575 switch (*p) {
576 case 'o':
577 prefix = "0"; break;
578 case 'x':
579 prefix = "0x"; break;
580 case 'X':
581 prefix = "0X"; break;
582 case 'b':
583 prefix = "0b"; break;
584 case 'B':
585 prefix = "0B"; break;
586 }
587 }
588
589 bin_retry:
590 switch (TYPE(val)) {
591 case T_FLOAT:
592 if (FIXABLE(RFLOAT_VALUE(val))) {
593 val = LONG2FIX((long)RFLOAT_VALUE(val));
594 goto bin_retry;
595 }
596 val = rb_dbl2big(RFLOAT_VALUE(val));
597 if (FIXNUM_P(val)) goto bin_retry;
598 bignum = 1;
599 break;
600 case T_STRING:
601 val = rb_str_to_inum(val, 0, TRUE);
602 goto bin_retry;
603 case T_BIGNUM:
604 bignum = 1;
605 break;
606 case T_FIXNUM:
607 v = FIX2LONG(val);
608 break;
609 default:
610 val = rb_Integer(val);
611 goto bin_retry;
612 }
613
614 switch (*p) {
615 case 'o':
616 base = 8; break;
617 case 'x':
618 case 'X':
619 base = 16; break;
620 case 'b':
621 case 'B':
622 base = 2; break;
623 case 'u':
624 case 'd':
625 case 'i':
626 default:
627 base = 10; break;
628 }
629
630 if (base != 10) {
631 int numbits = ffs(base)-1;
632 size_t abs_nlz_bits;
633 size_t numdigits = rb_absint_numwords(val, numbits, &abs_nlz_bits);
634 long i;
635 if (INT_MAX-1 < numdigits) /* INT_MAX is used because rb_long2int is used later. */
636 rb_raise(rb_eArgError, "size too big");
637 if (sign) {
638 if (numdigits == 0)
639 numdigits = 1;
640 tmp = rb_str_new(NULL, numdigits);
641 valsign = rb_integer_pack(val, RSTRING_PTR(tmp), RSTRING_LEN(tmp),
642 1, CHAR_BIT-numbits, INTEGER_PACK_BIG_ENDIAN);
643 for (i = 0; i < RSTRING_LEN(tmp); i++)
644 RSTRING_PTR(tmp)[i] = ruby_digitmap[((unsigned char *)RSTRING_PTR(tmp))[i]];
645 s = RSTRING_PTR(tmp);
646 if (valsign < 0) {
647 sc = '-';
648 width--;
649 }
650 else if (flags & FPLUS) {
651 sc = '+';
652 width--;
653 }
654 else if (flags & FSPACE) {
655 sc = ' ';
656 width--;
657 }
658 }
659 else {
660 /* Following conditional "numdigits++" guarantees the
661 * most significant digit as
662 * - '1'(bin), '7'(oct) or 'f'(hex) for negative numbers
663 * - '0' for zero
664 * - not '0' for positive numbers.
665 *
666 * It also guarantees the most significant two
667 * digits will not be '11'(bin), '77'(oct), 'ff'(hex)
668 * or '00'. */
669 if (numdigits == 0 ||
670 ((abs_nlz_bits != (size_t)(numbits-1) ||
671 !rb_absint_singlebit_p(val)) &&
672 (!bignum ? v < 0 : BIGNUM_NEGATIVE_P(val))))
673 numdigits++;
674 tmp = rb_str_new(NULL, numdigits);
675 valsign = rb_integer_pack(val, RSTRING_PTR(tmp), RSTRING_LEN(tmp),
676 1, CHAR_BIT-numbits, INTEGER_PACK_2COMP | INTEGER_PACK_BIG_ENDIAN);
677 for (i = 0; i < RSTRING_LEN(tmp); i++)
678 RSTRING_PTR(tmp)[i] = ruby_digitmap[((unsigned char *)RSTRING_PTR(tmp))[i]];
679 s = RSTRING_PTR(tmp);
680 dots = valsign < 0;
681 }
682 len = rb_long2int(RSTRING_END(tmp) - s);
683 }
684 else if (!bignum) {
685 valsign = 1;
686 if (v < 0) {
687 v = -v;
688 sc = '-';
689 width--;
690 valsign = -1;
691 }
692 else if (flags & FPLUS) {
693 sc = '+';
694 width--;
695 }
696 else if (flags & FSPACE) {
697 sc = ' ';
698 width--;
699 }
700 s = ruby_ultoa((unsigned long)v, nbuf + sizeof(nbuf), 10, 0);
701 len = (int)(nbuf + sizeof(nbuf) - s);
702 }
703 else {
704 tmp = rb_big2str(val, 10);
705 s = RSTRING_PTR(tmp);
706 valsign = 1;
707 if (s[0] == '-') {
708 s++;
709 sc = '-';
710 width--;
711 valsign = -1;
712 }
713 else if (flags & FPLUS) {
714 sc = '+';
715 width--;
716 }
717 else if (flags & FSPACE) {
718 sc = ' ';
719 width--;
720 }
721 len = rb_long2int(RSTRING_END(tmp) - s);
722 }
723
724 if (dots) {
725 prec -= 2;
726 width -= 2;
727 }
728
729 if (*p == 'X') {
730 char *pp = s;
731 int c;
732 while ((c = (int)(unsigned char)*pp) != 0) {
733 *pp = rb_enc_toupper(c, enc);
734 pp++;
735 }
736 }
737 if (prefix && !prefix[1]) { /* octal */
738 if (dots) {
739 prefix = 0;
740 }
741 else if (len == 1 && *s == '0') {
742 len = 0;
743 if (flags & FPREC) prec--;
744 }
745 else if ((flags & FPREC) && (prec > len)) {
746 prefix = 0;
747 }
748 }
749 else if (len == 1 && *s == '0') {
750 prefix = 0;
751 }
752 if (prefix) {
753 width -= (int)strlen(prefix);
754 }
755 if ((flags & (FZERO|FMINUS|FPREC)) == FZERO) {
756 prec = width;
757 width = 0;
758 }
759 else {
760 if (prec < len) {
761 if (!prefix && prec == 0 && len == 1 && *s == '0') len = 0;
762 prec = len;
763 }
764 width -= prec;
765 }
766 if (!(flags&FMINUS)) {
767 FILL(' ', width);
768 width = 0;
769 }
770 if (sc) PUSH(&sc, 1);
771 if (prefix) {
772 int plen = (int)strlen(prefix);
773 PUSH(prefix, plen);
774 }
775 if (dots) PUSH("..", 2);
776 if (prec > len) {
777 CHECK(prec - len);
778 if (!sign && valsign < 0) {
779 char c = sign_bits(base, p);
780 FILL_(c, prec - len);
781 }
782 else if ((flags & (FMINUS|FPREC)) != FMINUS) {
783 FILL_('0', prec - len);
784 }
785 }
786 PUSH(s, len);
787 RB_GC_GUARD(tmp);
788 FILL(' ', width);
789 }
790 break;
791
792 case 'f':
793 {
794 VALUE val = GETARG(), num, den;
795 int sign = (flags&FPLUS) ? 1 : 0, zero = 0;
796 long len, fill;
797 if (RB_INTEGER_TYPE_P(val)) {
798 den = INT2FIX(1);
799 num = val;
800 }
801 else if (RB_TYPE_P(val, T_RATIONAL)) {
802 den = rb_rational_den(val);
803 num = rb_rational_num(val);
804 }
805 else {
806 nextvalue = val;
807 goto float_value;
808 }
809 if (!(flags&FPREC)) prec = default_float_precision;
810 if (FIXNUM_P(num)) {
811 if ((SIGNED_VALUE)num < 0) {
812 long n = -FIX2LONG(num);
813 num = LONG2NUM(n);
814 sign = -1;
815 }
816 }
817 else if (BIGNUM_NEGATIVE_P(num)) {
818 sign = -1;
819 num = rb_big_uminus(num);
820 }
821 if (den != INT2FIX(1)) {
822 num = rb_int_mul(num, rb_int_positive_pow(10, prec));
823 num = rb_int_plus(num, rb_int_idiv(den, INT2FIX(2)));
824 num = rb_int_idiv(num, den);
825 }
826 else if (prec >= 0) {
827 zero = prec;
828 }
829 val = rb_int2str(num, 10);
830 len = RSTRING_LEN(val) + zero;
831 if (prec >= len) len = prec + 1; /* integer part 0 */
832 if (sign || (flags&FSPACE)) ++len;
833 if (prec > 0) ++len; /* period */
834 fill = width > len ? width - len : 0;
835 CHECK(fill + len);
836 if (fill && !(flags&(FMINUS|FZERO))) {
837 FILL_(' ', fill);
838 }
839 if (sign || (flags&FSPACE)) {
840 buf[blen++] = sign > 0 ? '+' : sign < 0 ? '-' : ' ';
841 }
842 if (fill && (flags&(FMINUS|FZERO)) == FZERO) {
843 FILL_('0', fill);
844 }
845 len = RSTRING_LEN(val) + zero;
846 t = RSTRING_PTR(val);
847 if (len > prec) {
848 PUSH_(t, len - prec);
849 }
850 else {
851 buf[blen++] = '0';
852 }
853 if (prec > 0) {
854 buf[blen++] = '.';
855 }
856 if (zero) {
857 FILL_('0', zero);
858 }
859 else if (prec > len) {
860 FILL_('0', prec - len);
861 PUSH_(t, len);
862 }
863 else if (prec > 0) {
864 PUSH_(t + len - prec, prec);
865 }
866 if (fill && (flags&FMINUS)) {
867 FILL_(' ', fill);
868 }
869 RB_GC_GUARD(val);
870 break;
871 }
872 case 'g':
873 case 'G':
874 case 'e':
875 case 'E':
876 /* TODO: rational support */
877 case 'a':
878 case 'A':
879 float_value:
880 {
881 VALUE val = GETARG();
882 double fval;
883
884 fval = RFLOAT_VALUE(rb_Float(val));
885 if (!isfinite(fval)) {
886 const char *expr;
887 int need;
888 int elen;
889 char sign = '\0';
890
891 if (isnan(fval)) {
892 expr = "NaN";
893 }
894 else {
895 expr = "Inf";
896 }
897 need = (int)strlen(expr);
898 elen = need;
899 if (!isnan(fval) && fval < 0.0)
900 sign = '-';
901 else if (flags & (FPLUS|FSPACE))
902 sign = (flags & FPLUS) ? '+' : ' ';
903 if (sign)
904 ++need;
905 if ((flags & FWIDTH) && need < width)
906 need = width;
907
908 FILL(' ', need);
909 if (flags & FMINUS) {
910 if (sign)
911 buf[blen - need--] = sign;
912 memcpy(&buf[blen - need], expr, elen);
913 }
914 else {
915 if (sign)
916 buf[blen - elen - 1] = sign;
917 memcpy(&buf[blen - elen], expr, elen);
918 }
919 break;
920 }
921 else {
922 int cr = ENC_CODERANGE(result);
923 char fbuf[2*BIT_DIGITS(SIZEOF_INT*CHAR_BIT)+10];
924 char *fmt = fmt_setup(fbuf, sizeof(fbuf), *p, flags, width, prec);
925 rb_str_set_len(result, blen);
926 rb_str_catf(result, fmt, fval);
927 ENC_CODERANGE_SET(result, cr);
928 bsiz = rb_str_capacity(result);
929 RSTRING_GETMEM(result, buf, blen);
930 }
931 }
932 break;
933 }
934 flags = FNONE;
935 }
936
937 update_coderange(FALSE);
938 sprint_exit:
939 rb_str_tmp_frozen_release(orig, fmt);
940 /* XXX - We cannot validate the number of arguments if (digit)$ style used.
941 */
942 if (posarg >= 0 && nextarg < argc && !(argc == 2 && RB_TYPE_P(argv[1], T_HASH))) {
943 const char *mesg = "too many arguments for format string";
944 if (RTEST(ruby_debug)) rb_raise(rb_eArgError, "%s", mesg);
945 if (RTEST(ruby_verbose)) rb_warn("%s", mesg);
946 }
947 rb_str_resize(result, blen);
948
949 return result;
950}
951
952static char *
953fmt_setup(char *buf, size_t size, int c, int flags, int width, int prec)
954{
955 buf += size;
956 *--buf = '\0';
957 *--buf = c;
958
959 if (flags & FPREC) {
960 buf = ruby_ultoa(prec, buf, 10, 0);
961 *--buf = '.';
962 }
963
964 if (flags & FWIDTH) {
965 buf = ruby_ultoa(width, buf, 10, 0);
966 }
967
968 if (flags & FSPACE) *--buf = ' ';
969 if (flags & FZERO) *--buf = '0';
970 if (flags & FMINUS) *--buf = '-';
971 if (flags & FPLUS) *--buf = '+';
972 if (flags & FSHARP) *--buf = '#';
973 *--buf = '%';
974 return buf;
975}
976
977#undef FILE
978#define FILE rb_printf_buffer
979#define __sbuf rb_printf_sbuf
980#define __sFILE rb_printf_sfile
981#undef feof
982#undef ferror
983#undef clearerr
984#undef fileno
985#if SIZEOF_LONG < SIZEOF_LONG_LONG
986# if SIZEOF_LONG_LONG == SIZEOF_VOIDP
987/* actually this doesn't mean a pointer is strictly 64bit, but just
988 * quad_t size */
989# define _HAVE_LLP64_
990# endif
991# define _HAVE_SANE_QUAD_
992# define quad_t LONG_LONG
993# define u_quad_t unsigned LONG_LONG
994#endif
995#define FLOATING_POINT 1
996#define BSD__dtoa ruby_dtoa
997#define BSD__hdtoa ruby_hdtoa
998#ifdef RUBY_PRI_VALUE_MARK
999# define PRI_EXTRA_MARK RUBY_PRI_VALUE_MARK
1000#endif
1001#define lower_hexdigits (ruby_hexdigits+0)
1002#define upper_hexdigits (ruby_hexdigits+16)
1003#include "vsnprintf.c"
1004
1005static char *
1006ruby_ultoa(unsigned long val, char *endp, int base, int flags)
1007{
1008 const char *xdigs = lower_hexdigits;
1009 int octzero = flags & FSHARP;
1010 return BSD__ultoa(val, endp, base, octzero, xdigs);
1011}
1012
1013static int ruby_do_vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
1014
1015int
1016ruby_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
1017{
1018 if (str && (ssize_t)n < 1)
1019 return (EOF);
1020 return ruby_do_vsnprintf(str, n, fmt, ap);
1021}
1022
1023static int
1024ruby_do_vsnprintf(char *str, size_t n, const char *fmt, va_list ap)
1025{
1026 ssize_t ret;
1027 rb_printf_buffer f;
1028
1029 f._flags = __SWR | __SSTR;
1030 f._bf._base = f._p = (unsigned char *)str;
1031 f._bf._size = f._w = str ? (n - 1) : 0;
1032 f.vwrite = BSD__sfvwrite;
1033 f.vextra = 0;
1034 ret = BSD_vfprintf(&f, fmt, ap);
1035 if (str) *f._p = 0;
1036#if SIZEOF_SIZE_T > SIZEOF_INT
1037 if (n > INT_MAX) return INT_MAX;
1038#endif
1039 return (int)ret;
1040}
1041
1042int
1043ruby_snprintf(char *str, size_t n, char const *fmt, ...)
1044{
1045 int ret;
1046 va_list ap;
1047
1048 if (str && (ssize_t)n < 1)
1049 return (EOF);
1050
1051 va_start(ap, fmt);
1052 ret = ruby_do_vsnprintf(str, n, fmt, ap);
1053 va_end(ap);
1054 return ret;
1055}
1056
1057typedef struct {
1058 rb_printf_buffer base;
1059 volatile VALUE value;
1061
1062static int
1063ruby__sfvwrite(register rb_printf_buffer *fp, register struct __suio *uio)
1064{
1065 struct __siov *iov;
1066 VALUE result = (VALUE)fp->_bf._base;
1067 char *buf = (char*)fp->_p;
1068 long len, n;
1069 long blen = buf - RSTRING_PTR(result), bsiz = fp->_w;
1070
1071 if (RBASIC(result)->klass) {
1072 rb_raise(rb_eRuntimeError, "rb_vsprintf reentered");
1073 }
1074 if (uio->uio_resid == 0)
1075 return 0;
1076#if SIZE_MAX > LONG_MAX
1077 if (uio->uio_resid >= LONG_MAX)
1078 rb_raise(rb_eRuntimeError, "too big string");
1079#endif
1080 len = (long)uio->uio_resid;
1081 CHECK(len);
1082 buf += blen;
1083 fp->_w = bsiz;
1084 for (iov = uio->uio_iov; len > 0; ++iov) {
1085 MEMCPY(buf, iov->iov_base, char, n = iov->iov_len);
1086 buf += n;
1087 len -= n;
1088 }
1089 fp->_p = (unsigned char *)buf;
1090 rb_str_set_len(result, buf - RSTRING_PTR(result));
1091 return 0;
1092}
1093
1094static const char *
1095ruby__sfvextra(rb_printf_buffer *fp, size_t valsize, void *valp, long *sz, int sign)
1096{
1097 VALUE value, result = (VALUE)fp->_bf._base;
1098 rb_encoding *enc;
1099 char *cp;
1100
1101 if (valsize != sizeof(VALUE)) return 0;
1102 value = *(VALUE *)valp;
1103 if (RBASIC(result)->klass) {
1104 rb_raise(rb_eRuntimeError, "rb_vsprintf reentered");
1105 }
1106 if (sign == '+') {
1107# define LITERAL(str) (*sz = rb_strlen_lit(str), str)
1108 /* optimize special const cases */
1109 switch (value) {
1110# define LITERAL_CASE(x) case Q##x: return LITERAL(#x)
1111 LITERAL_CASE(nil);
1112 LITERAL_CASE(true);
1113 LITERAL_CASE(false);
1114# undef LITERAL_CASE
1115 }
1116# undef LITERAL
1117 value = rb_inspect(value);
1118 }
1119 else if (SYMBOL_P(value)) {
1120 value = rb_sym2str(value);
1121 if (sign == ' ' && !rb_str_symname_p(value)) {
1122 value = rb_str_escape(value);
1123 }
1124 }
1125 else {
1126 value = rb_obj_as_string(value);
1127 if (sign == ' ') value = QUOTE(value);
1128 }
1129 enc = rb_enc_compatible(result, value);
1130 if (enc) {
1131 rb_enc_associate(result, enc);
1132 }
1133 else {
1134 enc = rb_enc_get(result);
1135 value = rb_str_conv_enc_opts(value, rb_enc_get(value), enc,
1137 Qnil);
1138 *(volatile VALUE *)valp = value;
1139 }
1140 StringValueCStr(value);
1141 RSTRING_GETMEM(value, cp, *sz);
1142 ((rb_printf_buffer_extra *)fp)->value = value;
1143 return cp;
1144}
1145
1146static void
1147ruby_vsprintf0(VALUE result, char *p, const char *fmt, va_list ap)
1148{
1150#define f buffer.base
1151 VALUE klass = RBASIC(result)->klass;
1152 int coderange = ENC_CODERANGE(result);
1153 long scanned = 0;
1154
1155 if (coderange != ENC_CODERANGE_UNKNOWN) scanned = p - RSTRING_PTR(result);
1156
1157 f._flags = __SWR | __SSTR;
1158 f._bf._size = 0;
1159 f._w = rb_str_capacity(result);
1160 f._bf._base = (unsigned char *)result;
1161 f._p = (unsigned char *)p;
1162 RBASIC_CLEAR_CLASS(result);
1163 f.vwrite = ruby__sfvwrite;
1164 f.vextra = ruby__sfvextra;
1165 buffer.value = 0;
1166 BSD_vfprintf(&f, fmt, ap);
1167 RBASIC_SET_CLASS_RAW(result, klass);
1168 p = RSTRING_PTR(result);
1169 long blen = (char *)f._p - p;
1170
1171 coderange = ENC_CODERANGE(result);
1172 if (coderange != ENC_CODERANGE_UNKNOWN && scanned < blen) {
1173 rb_str_coderange_scan_restartable(p + scanned, p + blen, rb_enc_get(result), &coderange);
1174 ENC_CODERANGE_SET(result, coderange);
1175 }
1176 rb_str_resize(result, blen);
1177#undef f
1178}
1179
1180VALUE
1181rb_enc_vsprintf(rb_encoding *enc, const char *fmt, va_list ap)
1182{
1183 const int initial_len = 120;
1184 VALUE result;
1185
1186 result = rb_str_buf_new(initial_len);
1187 if (enc) {
1188 if (rb_enc_mbminlen(enc) > 1) {
1189 /* the implementation deeply depends on plain char */
1190 rb_raise(rb_eArgError, "cannot construct wchar_t based encoding string: %s",
1191 rb_enc_name(enc));
1192 }
1193 rb_enc_associate(result, enc);
1194 }
1195 ruby_vsprintf0(result, RSTRING_PTR(result), fmt, ap);
1196 return result;
1197}
1198
1199VALUE
1200rb_enc_sprintf(rb_encoding *enc, const char *format, ...)
1201{
1202 VALUE result;
1203 va_list ap;
1204
1205 va_start(ap, format);
1206 result = rb_enc_vsprintf(enc, format, ap);
1207 va_end(ap);
1208
1209 return result;
1210}
1211
1212VALUE
1213rb_vsprintf(const char *fmt, va_list ap)
1214{
1215 return rb_enc_vsprintf(NULL, fmt, ap);
1216}
1217
1218VALUE
1219rb_sprintf(const char *format, ...)
1220{
1221 VALUE result;
1222 va_list ap;
1223
1224 va_start(ap, format);
1225 result = rb_vsprintf(format, ap);
1226 va_end(ap);
1227
1228 return result;
1229}
1230
1231VALUE
1232rb_str_vcatf(VALUE str, const char *fmt, va_list ap)
1233{
1234 StringValue(str);
1235 rb_str_modify(str);
1236 ruby_vsprintf0(str, RSTRING_END(str), fmt, ap);
1237
1238 return str;
1239}
1240
1241VALUE
1242rb_str_catf(VALUE str, const char *format, ...)
1243{
1244 va_list ap;
1245
1246 va_start(ap, format);
1247 str = rb_str_vcatf(str, format, ap);
1248 va_end(ap);
1249
1250 return str;
1251}
ruby_coderange_type
What rb_enc_str_coderange() returns.
Definition coderange.h:33
static bool rb_enc_isprint(OnigCodePoint c, rb_encoding *enc)
Identical to rb_isprint(), except it additionally takes an encoding.
Definition ctype.h:180
static bool rb_enc_isdigit(OnigCodePoint c, rb_encoding *enc)
Identical to rb_isdigit(), except it additionally takes an encoding.
Definition ctype.h:208
VALUE rb_enc_vsprintf(rb_encoding *enc, const char *fmt, va_list ap)
Identical to rb_enc_sprintf(), except it takes a va_list instead of variadic arguments.
Definition sprintf.c:1181
VALUE rb_enc_sprintf(rb_encoding *enc, const char *fmt,...)
Identical to rb_sprintf(), except it additionally takes an encoding.
Definition sprintf.c:1200
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define T_FLOAT
Old name of RUBY_T_FLOAT.
Definition value_type.h:64
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define ECONV_UNDEF_REPLACE
Old name of RUBY_ECONV_UNDEF_REPLACE.
Definition transcode.h:526
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define ENC_CODERANGE(obj)
Old name of RB_ENC_CODERANGE.
Definition coderange.h:184
#define ENC_CODERANGE_UNKNOWN
Old name of RUBY_ENC_CODERANGE_UNKNOWN.
Definition coderange.h:179
#define FIXABLE
Old name of RB_FIXABLE.
Definition fixnum.h:25
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define ECONV_INVALID_REPLACE
Old name of RUBY_ECONV_INVALID_REPLACE.
Definition transcode.h:524
#define T_RATIONAL
Old name of RUBY_T_RATIONAL.
Definition value_type.h:76
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define NIL_P
Old name of RB_NIL_P.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:487
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1416
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
void rb_enc_raise(rb_encoding *enc, VALUE exc, const char *fmt,...)
Identical to rb_raise(), except it additionally takes an encoding.
Definition error.c:3826
VALUE rb_Float(VALUE val)
This is the logic behind Kernel#Float.
Definition object.c:3785
VALUE rb_Integer(VALUE val)
This is the logic behind Kernel#Integer.
Definition object.c:3440
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:686
Encoding relates APIs.
static char * rb_enc_right_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the right boundary of a character.
Definition encoding.h:704
char * rb_enc_nth(const char *head, const char *tail, long nth, rb_encoding *enc)
Queries the n-th character.
Definition string.c:3044
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
Identical to rb_str_conv_enc(), except it additionally takes IO encoder options.
Definition string.c:1209
long rb_enc_strlen(const char *head, const char *tail, rb_encoding *enc)
Counts the number of characters of the passed string, according to the passed encoding.
Definition string.c:2317
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:814
VALUE rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc)
Identical to rb_check_id_cstr(), except for the return type.
Definition symbol.c:1272
#define INTEGER_PACK_BIG_ENDIAN
Big endian combination.
Definition bignum.h:572
#define INTEGER_PACK_2COMP
Uses 2's complement representation.
Definition bignum.h:549
VALUE rb_int_positive_pow(long x, unsigned long y)
Raises the passed x to the power of y.
Definition numeric.c:4721
VALUE rb_rational_num(VALUE rat)
Queries the numerator of the passed Rational.
Definition rational.c:2000
VALUE rb_rational_den(VALUE rat)
Queries the denominator of the passed Rational.
Definition rational.c:2006
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:984
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3403
void rb_must_asciicompat(VALUE obj)
Asserts that the given string's encoding is (Ruby's definition of) ASCII compatible.
Definition string.c:2773
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2966
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1701
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1833
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1031
int len
Length of the buffer.
Definition io.h:8
VALUE rb_str_format(int argc, const VALUE *argv, VALUE fmt)
Formats a string.
Definition sprintf.c:215
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:209
VALUE rb_vsprintf(const char *fmt, va_list ap)
Identical to rb_sprintf(), except it takes a va_list.
Definition sprintf.c:1213
#define rb_long2int
Just another name of rb_long2int_inline.
Definition long.h:62
#define MEMCPY(p1, p2, type, n)
Handy macro to call memcpy.
Definition memory.h:372
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define RBASIC(obj)
Convenient casting macro.
Definition rbasic.h:40
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:409
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
int ruby_vsnprintf(char *str, size_t n, char const *fmt, va_list ap)
Identical to ruby_snprintf(), except it takes a va_list.
Definition sprintf.c:1016
int ruby_snprintf(char *str, size_t n, char const *fmt,...)
Our own locale-insensitive version of snprintf(3).
Definition sprintf.c:1043
#define RTEST
This is an old name of RB_TEST.
Defines old _.
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376