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