1 /**********************************************************************
6 created at: Fri Oct 15 10:39:26 JST 1993
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
12 **********************************************************************/
14 #include "ruby/internal/config.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"
33 #include "ruby/util.h"
35 #define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */
37 static char *fmt_setup(char*,size_t,int,int,int,int);
38 static char *ruby_ultoa(unsigned long val
, char *endp
, int base
, int octzero
);
41 sign_bits(int base
, const char *p
)
47 if (*p
== 'X') c
= 'F';
68 #define CHECK(l) do {\
69 int cr = ENC_CODERANGE(result);\
70 while ((l) >= bsiz - blen) {\
72 if (bsiz<0) rb_raise(rb_eArgError, "too big specifier");\
74 rb_str_resize(result, bsiz);\
75 ENC_CODERANGE_SET(result, cr);\
76 buf = RSTRING_PTR(result);\
79 #define PUSH(s, l) do { \
84 #define PUSH_(s, l) do { \
85 memcpy(&buf[blen], (s), (l));\
89 #define FILL(c, l) do { \
95 #define FILL_(c, l) do { \
96 memset(&buf[blen], (c), (l));\
100 #define GETARG() (!UNDEF_P(nextvalue) ? nextvalue : \
103 #define GETNEXTARG() ( \
104 check_next_arg(posarg, nextarg), \
105 (posarg = nextarg++, GETNTHARG(posarg)))
107 #define GETPOSARG(n) ( \
108 check_pos_arg(posarg, (n)), \
109 (posarg = -1, GETNTHARG(n)))
111 #define GETNTHARG(nth) \
112 (((nth) >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : argv[(nth)])
114 #define CHECKNAMEARG(name, len, enc) ( \
115 check_name_arg(posarg, name, len, enc), \
118 #define GETNUM(n, val) \
119 (!(p = get_num(p, end, enc, &(n))) ? \
120 rb_raise(rb_eArgError, #val " too big") : (void)0)
122 #define GETASTER(val) do { \
127 tmp = GETPOSARG(n); \
130 tmp = GETNEXTARG(); \
133 (val) = NUM2INT(tmp); \
137 get_num(const char *p
, const char *end
, rb_encoding
*enc
, int *valp
)
140 for (; p
< end
&& rb_enc_isdigit(*p
, enc
); p
++) {
141 if (MUL_OVERFLOW_INT_P(10, next_n
))
144 if (INT_MAX
- (*p
- '0') < next_n
)
149 rb_raise(rb_eArgError
, "malformed format string - %%*[0-9]");
156 check_next_arg(int posarg
, int nextarg
)
160 rb_raise(rb_eArgError
, "unnumbered(%d) mixed with numbered", nextarg
);
162 rb_raise(rb_eArgError
, "unnumbered(%d) mixed with named", nextarg
);
167 check_pos_arg(int posarg
, int n
)
170 rb_raise(rb_eArgError
, "numbered(%d) after unnumbered(%d)", n
, posarg
);
173 rb_raise(rb_eArgError
, "numbered(%d) after named", n
);
176 rb_raise(rb_eArgError
, "invalid index - %d$", n
);
181 check_name_arg(int posarg
, const char *name
, int len
, rb_encoding
*enc
)
184 rb_enc_raise(enc
, rb_eArgError
, "named%.*s after unnumbered(%d)", len
, name
, posarg
);
187 rb_enc_raise(enc
, rb_eArgError
, "named%.*s after numbered", len
, name
);
192 get_hash(volatile VALUE
*hash
, int argc
, const VALUE
*argv
)
196 if (!UNDEF_P(*hash
)) return *hash
;
198 rb_raise(rb_eArgError
, "one hash required");
200 tmp
= rb_check_hash_type(argv
[1]);
202 rb_raise(rb_eArgError
, "one hash required");
204 return (*hash
= tmp
);
208 rb_f_sprintf(int argc
, const VALUE
*argv
)
210 return rb_str_format(argc
- 1, argv
+ 1, GETNTHARG(0));
214 rb_str_format(int argc
, const VALUE
*argv
, VALUE fmt
)
216 enum {default_float_precision
= 6};
224 enum ruby_coderange_type coderange
= ENC_CODERANGE_7BIT
;
225 int width
, prec
, flags
= FNONE
;
232 volatile VALUE hash
= Qundef
;
234 #define CHECK_FOR_WIDTH(f) \
235 if ((f) & FWIDTH) { \
236 rb_raise(rb_eArgError, "width given twice"); \
238 if ((f) & FPREC0) { \
239 rb_raise(rb_eArgError, "width after precision"); \
241 #define CHECK_FOR_FLAGS(f) \
242 if ((f) & FWIDTH) { \
243 rb_raise(rb_eArgError, "flag after width"); \
245 if ((f) & FPREC0) { \
246 rb_raise(rb_eArgError, "flag after precision"); \
249 #define update_coderange(partial) do { \
250 if (coderange != ENC_CODERANGE_BROKEN && scanned < blen \
251 && rb_enc_to_index(enc) /* != ENCINDEX_ASCII_8BIT */) { \
252 int cr = coderange; \
253 scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &cr); \
254 ENC_CODERANGE_SET(result, \
255 (partial && cr == ENC_CODERANGE_UNKNOWN ? \
256 ENC_CODERANGE_BROKEN : (coderange = cr))); \
262 enc
= rb_enc_get(fmt
);
263 rb_must_asciicompat(fmt
);
265 fmt
= rb_str_tmp_frozen_acquire(fmt
);
266 p
= RSTRING_PTR(fmt
);
267 end
= p
+ RSTRING_LEN(fmt
);
270 result
= rb_str_buf_new(bsiz
);
271 rb_enc_associate(result
, enc
);
272 buf
= RSTRING_PTR(result
);
273 memset(buf
, 0, bsiz
);
274 ENC_CODERANGE_SET(result
, coderange
);
276 for (; p
< end
; p
++) {
281 for (t
= p
; t
< end
&& *t
!= '%'; t
++) ;
283 rb_raise(rb_eArgError
, "incomplete format specifier; use %%%% (double %%) instead");
286 update_coderange(FALSE
);
288 /* end of fmt string */
291 p
= t
+ 1; /* skip `%' */
298 if (rb_enc_isprint(*p
, enc
))
299 rb_raise(rb_eArgError
, "malformed format string - %%%c", *p
);
301 rb_raise(rb_eArgError
, "malformed format string");
305 CHECK_FOR_FLAGS(flags
);
311 CHECK_FOR_FLAGS(flags
);
317 CHECK_FOR_FLAGS(flags
);
323 CHECK_FOR_FLAGS(flags
);
329 CHECK_FOR_FLAGS(flags
);
334 case '1': case '2': case '3': case '4':
335 case '5': case '6': case '7': case '8': case '9':
339 if (!UNDEF_P(nextvalue
)) {
340 rb_raise(rb_eArgError
, "value given twice - %d$", n
);
342 nextvalue
= GETPOSARG(n
);
346 CHECK_FOR_WIDTH(flags
);
354 const char *start
= p
;
355 char term
= (*p
== '<') ? '>' : '}';
358 for (; p
< end
&& *p
!= term
; ) {
359 p
+= rb_enc_mbclen(p
, end
, enc
);
362 rb_raise(rb_eArgError
, "malformed name - unmatched parenthesis");
364 #if SIZEOF_INT < SIZEOF_SIZE_T
365 if ((size_t)(p
- start
) >= INT_MAX
) {
366 const int message_limit
= 20;
367 len
= (int)(rb_enc_right_char_head(start
, start
+ message_limit
, p
, enc
) - start
);
368 rb_enc_raise(enc
, rb_eArgError
,
369 "too long name (%"PRIuSIZE
" bytes) - %.*s...%c",
370 (size_t)(p
- start
- 2), len
, start
, term
);
373 len
= (int)(p
- start
+ 1); /* including parenthesis */
375 rb_enc_raise(enc
, rb_eArgError
, "named%.*s after <%"PRIsVALUE
">",
376 len
, start
, rb_sym2str(sym
));
378 CHECKNAMEARG(start
, len
, enc
);
379 get_hash(&hash
, argc
, argv
);
380 sym
= rb_check_symbol_cstr(start
+ 1,
381 len
- 2 /* without parenthesis */,
383 if (!NIL_P(sym
)) nextvalue
= rb_hash_lookup2(hash
, sym
, Qundef
);
384 if (UNDEF_P(nextvalue
)) {
386 sym
= rb_sym_intern(start
+ 1,
387 len
- 2 /* without parenthesis */,
390 nextvalue
= rb_hash_default_value(hash
, sym
);
391 if (NIL_P(nextvalue
)) {
392 rb_key_err_raise(rb_enc_sprintf(enc
, "key%.*s not found", len
, start
), hash
, sym
);
395 if (term
== '}') goto format_s
;
401 CHECK_FOR_WIDTH(flags
);
407 if (width
< 0) rb_raise(rb_eArgError
, "width too big");
413 if (flags
& FPREC0
) {
414 rb_raise(rb_eArgError
, "precision given twice");
416 flags
|= FPREC
|FPREC0
;
422 if (prec
< 0) { /* ignore negative precision */
429 GETNUM(prec
, precision
);
433 if (flags
!= FNONE
) {
434 rb_raise(rb_eArgError
, "invalid format character - %%");
441 VALUE val
= GETARG();
446 tmp
= rb_check_string_type(val
);
454 if (n
>= 0) n
= rb_enc_codelen((c
= n
), enc
);
456 rb_raise(rb_eArgError
, "invalid character");
458 int encidx
= rb_ascii8bit_appendable_encoding_index(enc
, c
);
459 if (encidx
>= 0 && encidx
!= rb_enc_to_index(enc
)) {
461 rb_enc_associate_index(result
, encidx
);
462 enc
= rb_enc_from_index(encidx
);
463 coderange
= ENC_CODERANGE_VALID
;
465 if (!(flags
& FWIDTH
)) {
467 rb_enc_mbcput(c
, &buf
[blen
], enc
);
470 else if ((flags
& FMINUS
)) {
472 CHECK(n
+ (width
> 0 ? width
: 0));
473 rb_enc_mbcput(c
, &buf
[blen
], enc
);
475 if (width
> 0) FILL_(' ', width
);
479 CHECK(n
+ (width
> 0 ? width
: 0));
480 if (width
> 0) FILL_(' ', width
);
481 rb_enc_mbcput(c
, &buf
[blen
], enc
);
491 VALUE arg
= GETARG();
495 str
= rb_inspect(arg
);
498 str
= rb_obj_as_string(arg
);
501 len
= RSTRING_LEN(str
);
502 rb_str_set_len(result
, blen
);
503 update_coderange(TRUE
);
504 enc
= rb_enc_check(result
, str
);
505 if (flags
&(FPREC
|FWIDTH
)) {
506 slen
= rb_enc_strlen(RSTRING_PTR(str
),RSTRING_END(str
),enc
);
508 rb_raise(rb_eArgError
, "invalid mbstring sequence");
510 if ((flags
&FPREC
) && (prec
< slen
)) {
511 char *p
= rb_enc_nth(RSTRING_PTR(str
), RSTRING_END(str
),
514 len
= p
- RSTRING_PTR(str
);
516 /* need to adjust multi-byte string pos */
517 if ((flags
&FWIDTH
) && (width
> slen
)) {
520 if (!(flags
&FMINUS
)) {
524 memcpy(&buf
[blen
], RSTRING_PTR(str
), len
);
530 rb_enc_associate(result
, enc
);
534 PUSH(RSTRING_PTR(str
), len
);
536 rb_enc_associate(result
, enc
);
549 volatile VALUE val
= GETARG();
551 char nbuf
[BIT_DIGITS(SIZEOF_LONG
*CHAR_BIT
)+2], *s
;
552 const char *prefix
= 0;
553 int sign
= 0, dots
= 0;
556 int base
, bignum
= 0;
569 if (flags
&(FPLUS
|FSPACE
)) sign
= 1;
572 if (flags
& FSHARP
) {
577 prefix
= "0x"; break;
579 prefix
= "0X"; break;
581 prefix
= "0b"; break;
583 prefix
= "0B"; break;
590 if (FIXABLE(RFLOAT_VALUE(val
))) {
591 val
= LONG2FIX((long)RFLOAT_VALUE(val
));
594 val
= rb_dbl2big(RFLOAT_VALUE(val
));
595 if (FIXNUM_P(val
)) goto bin_retry
;
599 val
= rb_str_to_inum(val
, 0, TRUE
);
608 val
= rb_Integer(val
);
629 int numbits
= ffs(base
)-1;
631 size_t numdigits
= rb_absint_numwords(val
, numbits
, &abs_nlz_bits
);
633 if (INT_MAX
-1 < numdigits
) /* INT_MAX is used because rb_long2int is used later. */
634 rb_raise(rb_eArgError
, "size too big");
638 tmp
= rb_str_new(NULL
, numdigits
);
639 valsign
= rb_integer_pack(val
, RSTRING_PTR(tmp
), RSTRING_LEN(tmp
),
640 1, CHAR_BIT
-numbits
, INTEGER_PACK_BIG_ENDIAN
);
641 for (i
= 0; i
< RSTRING_LEN(tmp
); i
++)
642 RSTRING_PTR(tmp
)[i
] = ruby_digitmap
[((unsigned char *)RSTRING_PTR(tmp
))[i
]];
643 s
= RSTRING_PTR(tmp
);
648 else if (flags
& FPLUS
) {
652 else if (flags
& FSPACE
) {
658 /* Following conditional "numdigits++" guarantees the
659 * most significant digit as
660 * - '1'(bin), '7'(oct) or 'f'(hex) for negative numbers
662 * - not '0' for positive numbers.
664 * It also guarantees the most significant two
665 * digits will not be '11'(bin), '77'(oct), 'ff'(hex)
667 if (numdigits
== 0 ||
668 ((abs_nlz_bits
!= (size_t)(numbits
-1) ||
669 !rb_absint_singlebit_p(val
)) &&
670 (!bignum
? v
< 0 : BIGNUM_NEGATIVE_P(val
))))
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_2COMP
| 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
);
680 len
= rb_long2int(RSTRING_END(tmp
) - s
);
690 else if (flags
& FPLUS
) {
694 else if (flags
& FSPACE
) {
698 s
= ruby_ultoa((unsigned long)v
, nbuf
+ sizeof(nbuf
), 10, 0);
699 len
= (int)(nbuf
+ sizeof(nbuf
) - s
);
702 tmp
= rb_big2str(val
, 10);
703 s
= RSTRING_PTR(tmp
);
711 else if (flags
& FPLUS
) {
715 else if (flags
& FSPACE
) {
719 len
= rb_long2int(RSTRING_END(tmp
) - s
);
730 while ((c
= (int)(unsigned char)*pp
) != 0) {
731 *pp
= rb_enc_toupper(c
, enc
);
735 if (prefix
&& !prefix
[1]) { /* octal */
739 else if (len
== 1 && *s
== '0') {
741 if (flags
& FPREC
) prec
--;
743 else if ((flags
& FPREC
) && (prec
> len
)) {
747 else if (len
== 1 && *s
== '0') {
751 width
-= (int)strlen(prefix
);
753 if ((flags
& (FZERO
|FMINUS
|FPREC
)) == FZERO
) {
759 if (!prefix
&& prec
== 0 && len
== 1 && *s
== '0') len
= 0;
764 if (!(flags
&FMINUS
)) {
768 if (sc
) PUSH(&sc
, 1);
770 int plen
= (int)strlen(prefix
);
773 if (dots
) PUSH("..", 2);
776 if (!sign
&& valsign
< 0) {
777 char c
= sign_bits(base
, p
);
778 FILL_(c
, prec
- len
);
780 else if ((flags
& (FMINUS
|FPREC
)) != FMINUS
) {
781 FILL_('0', prec
- len
);
792 VALUE val
= GETARG(), num
, den
;
793 int sign
= (flags
&FPLUS
) ? 1 : 0, zero
= 0;
795 if (RB_INTEGER_TYPE_P(val
)) {
799 else if (RB_TYPE_P(val
, T_RATIONAL
)) {
800 den
= rb_rational_den(val
);
801 num
= rb_rational_num(val
);
807 if (!(flags
&FPREC
)) prec
= default_float_precision
;
809 if ((SIGNED_VALUE
)num
< 0) {
810 long n
= -FIX2LONG(num
);
815 else if (BIGNUM_NEGATIVE_P(num
)) {
817 num
= rb_big_uminus(num
);
819 if (den
!= INT2FIX(1)) {
820 num
= rb_int_mul(num
, rb_int_positive_pow(10, prec
));
821 num
= rb_int_plus(num
, rb_int_idiv(den
, INT2FIX(2)));
822 num
= rb_int_idiv(num
, den
);
824 else if (prec
>= 0) {
827 val
= rb_int2str(num
, 10);
828 len
= RSTRING_LEN(val
) + zero
;
829 if (prec
>= len
) len
= prec
+ 1; /* integer part 0 */
830 if (sign
|| (flags
&FSPACE
)) ++len
;
831 if (prec
> 0) ++len
; /* period */
832 fill
= width
> len
? width
- len
: 0;
834 if (fill
&& !(flags
&(FMINUS
|FZERO
))) {
837 if (sign
|| (flags
&FSPACE
)) {
838 buf
[blen
++] = sign
> 0 ? '+' : sign
< 0 ? '-' : ' ';
840 if (fill
&& (flags
&(FMINUS
|FZERO
)) == FZERO
) {
843 len
= RSTRING_LEN(val
) + zero
;
844 t
= RSTRING_PTR(val
);
846 PUSH_(t
, len
- prec
);
857 else if (prec
> len
) {
858 FILL_('0', prec
- len
);
862 PUSH_(t
+ len
- prec
, prec
);
864 if (fill
&& (flags
&FMINUS
)) {
874 /* TODO: rational support */
879 VALUE val
= GETARG();
882 fval
= RFLOAT_VALUE(rb_Float(val
));
883 if (!isfinite(fval
)) {
895 need
= (int)strlen(expr
);
897 if (!isnan(fval
) && fval
< 0.0)
899 else if (flags
& (FPLUS
|FSPACE
))
900 sign
= (flags
& FPLUS
) ? '+' : ' ';
903 if ((flags
& FWIDTH
) && need
< width
)
907 if (flags
& FMINUS
) {
909 buf
[blen
- need
--] = sign
;
910 memcpy(&buf
[blen
- need
], expr
, elen
);
914 buf
[blen
- elen
- 1] = sign
;
915 memcpy(&buf
[blen
- elen
], expr
, elen
);
920 int cr
= ENC_CODERANGE(result
);
921 char fbuf
[2*BIT_DIGITS(SIZEOF_INT
*CHAR_BIT
)+10];
922 char *fmt
= fmt_setup(fbuf
, sizeof(fbuf
), *p
, flags
, width
, prec
);
923 rb_str_set_len(result
, blen
);
924 rb_str_catf(result
, fmt
, fval
);
925 ENC_CODERANGE_SET(result
, cr
);
926 bsiz
= rb_str_capacity(result
);
927 RSTRING_GETMEM(result
, buf
, blen
);
935 update_coderange(FALSE
);
937 rb_str_tmp_frozen_release(orig
, fmt
);
938 /* XXX - We cannot validate the number of arguments if (digit)$ style used.
940 if (posarg
>= 0 && nextarg
< argc
) {
941 const char *mesg
= "too many arguments for format string";
942 if (RTEST(ruby_debug
)) rb_raise(rb_eArgError
, "%s", mesg
);
943 if (RTEST(ruby_verbose
)) rb_warn("%s", mesg
);
945 rb_str_resize(result
, blen
);
951 fmt_setup(char *buf
, size_t size
, int c
, int flags
, int width
, int prec
)
958 buf
= ruby_ultoa(prec
, buf
, 10, 0);
962 if (flags
& FWIDTH
) {
963 buf
= ruby_ultoa(width
, buf
, 10, 0);
966 if (flags
& FSPACE
) *--buf
= ' ';
967 if (flags
& FZERO
) *--buf
= '0';
968 if (flags
& FMINUS
) *--buf
= '-';
969 if (flags
& FPLUS
) *--buf
= '+';
970 if (flags
& FSHARP
) *--buf
= '#';
976 #define FILE rb_printf_buffer
977 #define __sbuf rb_printf_sbuf
978 #define __sFILE rb_printf_sfile
983 #if SIZEOF_LONG < SIZEOF_LONG_LONG
984 # if SIZEOF_LONG_LONG == SIZEOF_VOIDP
985 /* actually this doesn't mean a pointer is strictly 64bit, but just
987 # define _HAVE_LLP64_
989 # define _HAVE_SANE_QUAD_
990 # define quad_t LONG_LONG
991 # define u_quad_t unsigned LONG_LONG
993 #define FLOATING_POINT 1
994 #define BSD__dtoa ruby_dtoa
995 #define BSD__hdtoa ruby_hdtoa
996 #ifdef RUBY_PRI_VALUE_MARK
997 # define PRI_EXTRA_MARK RUBY_PRI_VALUE_MARK
999 #define lower_hexdigits (ruby_hexdigits+0)
1000 #define upper_hexdigits (ruby_hexdigits+16)
1001 #include "vsnprintf.c"
1004 ruby_ultoa(unsigned long val
, char *endp
, int base
, int flags
)
1006 const char *xdigs
= lower_hexdigits
;
1007 int octzero
= flags
& FSHARP
;
1008 return BSD__ultoa(val
, endp
, base
, octzero
, xdigs
);
1011 static int ruby_do_vsnprintf(char *str
, size_t n
, const char *fmt
, va_list ap
);
1014 ruby_vsnprintf(char *str
, size_t n
, const char *fmt
, va_list ap
)
1016 if (str
&& (ssize_t
)n
< 1)
1018 return ruby_do_vsnprintf(str
, n
, fmt
, ap
);
1022 ruby_do_vsnprintf(char *str
, size_t n
, const char *fmt
, va_list ap
)
1027 f
._flags
= __SWR
| __SSTR
;
1028 f
._bf
._base
= f
._p
= (unsigned char *)str
;
1029 f
._bf
._size
= f
._w
= str
? (n
- 1) : 0;
1030 f
.vwrite
= BSD__sfvwrite
;
1032 ret
= BSD_vfprintf(&f
, fmt
, ap
);
1034 #if SIZEOF_SIZE_T > SIZEOF_INT
1035 if (n
> INT_MAX
) return INT_MAX
;
1041 ruby_snprintf(char *str
, size_t n
, char const *fmt
, ...)
1046 if (str
&& (ssize_t
)n
< 1)
1050 ret
= ruby_do_vsnprintf(str
, n
, fmt
, ap
);
1056 rb_printf_buffer base
;
1057 volatile VALUE value
;
1058 } rb_printf_buffer_extra
;
1061 ruby__sfvwrite(register rb_printf_buffer
*fp
, register struct __suio
*uio
)
1064 VALUE result
= (VALUE
)fp
->_bf
._base
;
1065 char *buf
= (char*)fp
->_p
;
1067 long blen
= buf
- RSTRING_PTR(result
), bsiz
= fp
->_w
;
1069 if (RBASIC(result
)->klass
) {
1070 rb_raise(rb_eRuntimeError
, "rb_vsprintf reentered");
1072 if (uio
->uio_resid
== 0)
1074 #if SIZE_MAX > LONG_MAX
1075 if (uio
->uio_resid
>= LONG_MAX
)
1076 rb_raise(rb_eRuntimeError
, "too big string");
1078 len
= (long)uio
->uio_resid
;
1082 for (iov
= uio
->uio_iov
; len
> 0; ++iov
) {
1083 MEMCPY(buf
, iov
->iov_base
, char, n
= iov
->iov_len
);
1087 fp
->_p
= (unsigned char *)buf
;
1088 rb_str_set_len(result
, buf
- RSTRING_PTR(result
));
1093 ruby__sfvextra(rb_printf_buffer
*fp
, size_t valsize
, void *valp
, long *sz
, int sign
)
1095 VALUE value
, result
= (VALUE
)fp
->_bf
._base
;
1099 if (valsize
!= sizeof(VALUE
)) return 0;
1100 value
= *(VALUE
*)valp
;
1101 if (RBASIC(result
)->klass
) {
1102 rb_raise(rb_eRuntimeError
, "rb_vsprintf reentered");
1105 # define LITERAL(str) (*sz = rb_strlen_lit(str), str)
1106 /* optimize special const cases */
1108 # define LITERAL_CASE(x) case Q##x: return LITERAL(#x)
1111 LITERAL_CASE(false);
1112 # undef LITERAL_CASE
1115 value
= rb_inspect(value
);
1117 else if (SYMBOL_P(value
)) {
1118 value
= rb_sym2str(value
);
1119 if (sign
== ' ' && !rb_str_symname_p(value
)) {
1120 value
= rb_str_escape(value
);
1124 value
= rb_obj_as_string(value
);
1125 if (sign
== ' ') value
= QUOTE(value
);
1127 enc
= rb_enc_compatible(result
, value
);
1129 rb_enc_associate(result
, enc
);
1132 enc
= rb_enc_get(result
);
1133 value
= rb_str_conv_enc_opts(value
, rb_enc_get(value
), enc
,
1134 ECONV_UNDEF_REPLACE
|ECONV_INVALID_REPLACE
,
1136 *(volatile VALUE
*)valp
= value
;
1138 StringValueCStr(value
);
1139 RSTRING_GETMEM(value
, cp
, *sz
);
1140 ((rb_printf_buffer_extra
*)fp
)->value
= value
;
1145 ruby_vsprintf0(VALUE result
, char *p
, const char *fmt
, va_list ap
)
1147 rb_printf_buffer_extra buffer
;
1148 #define f buffer.base
1149 VALUE klass
= RBASIC(result
)->klass
;
1150 int coderange
= ENC_CODERANGE(result
);
1153 if (coderange
!= ENC_CODERANGE_UNKNOWN
) scanned
= p
- RSTRING_PTR(result
);
1155 f
._flags
= __SWR
| __SSTR
;
1157 f
._w
= rb_str_capacity(result
);
1158 f
._bf
._base
= (unsigned char *)result
;
1159 f
._p
= (unsigned char *)p
;
1160 RBASIC_CLEAR_CLASS(result
);
1161 f
.vwrite
= ruby__sfvwrite
;
1162 f
.vextra
= ruby__sfvextra
;
1164 BSD_vfprintf(&f
, fmt
, ap
);
1165 RBASIC_SET_CLASS_RAW(result
, klass
);
1166 p
= RSTRING_PTR(result
);
1167 long blen
= (char *)f
._p
- p
;
1168 if (scanned
< blen
) {
1169 rb_str_coderange_scan_restartable(p
+ scanned
, p
+ blen
, rb_enc_get(result
), &coderange
);
1170 ENC_CODERANGE_SET(result
, coderange
);
1172 rb_str_resize(result
, blen
);
1177 rb_enc_vsprintf(rb_encoding
*enc
, const char *fmt
, va_list ap
)
1179 const int initial_len
= 120;
1182 result
= rb_str_buf_new(initial_len
);
1184 if (rb_enc_mbminlen(enc
) > 1) {
1185 /* the implementation deeply depends on plain char */
1186 rb_raise(rb_eArgError
, "cannot construct wchar_t based encoding string: %s",
1189 rb_enc_associate(result
, enc
);
1191 ruby_vsprintf0(result
, RSTRING_PTR(result
), fmt
, ap
);
1196 rb_enc_sprintf(rb_encoding
*enc
, const char *format
, ...)
1201 va_start(ap
, format
);
1202 result
= rb_enc_vsprintf(enc
, format
, ap
);
1209 rb_vsprintf(const char *fmt
, va_list ap
)
1211 return rb_enc_vsprintf(NULL
, fmt
, ap
);
1215 rb_sprintf(const char *format
, ...)
1220 va_start(ap
, format
);
1221 result
= rb_vsprintf(format
, ap
);
1228 rb_str_vcatf(VALUE str
, const char *fmt
, va_list ap
)
1232 ruby_vsprintf0(str
, RSTRING_END(str
), fmt
, ap
);
1238 rb_str_catf(VALUE str
, const char *format
, ...)
1242 va_start(ap
, format
);
1243 str
= rb_str_vcatf(str
, format
, ap
);