Ruby: sprintf.c Source File

Ruby 3.3.7p123 (2025-01-15 revision be31f993d7fa0219d85f7b3c694d454da4ecc10b)

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