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