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