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