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() (nextvalue != Qundef ? 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 (*hash
!= Qundef
) 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 int 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"); \
252 enc
= rb_enc_get(fmt
);
254 fmt
= rb_str_tmp_frozen_acquire(fmt
);
255 p
= RSTRING_PTR(fmt
);
256 end
= p
+ RSTRING_LEN(fmt
);
259 result
= rb_str_buf_new(bsiz
);
260 rb_enc_associate(result
, enc
);
261 buf
= RSTRING_PTR(result
);
262 memset(buf
, 0, bsiz
);
263 ENC_CODERANGE_SET(result
, coderange
);
265 for (; p
< end
; p
++) {
270 for (t
= p
; t
< end
&& *t
!= '%'; t
++) ;
272 rb_raise(rb_eArgError
, "incomplete format specifier; use %%%% (double %%) instead");
275 if (coderange
!= ENC_CODERANGE_BROKEN
&& scanned
< blen
) {
276 scanned
+= rb_str_coderange_scan_restartable(buf
+scanned
, buf
+blen
, enc
, &coderange
);
277 ENC_CODERANGE_SET(result
, coderange
);
280 /* end of fmt string */
283 p
= t
+ 1; /* skip `%' */
290 if (rb_enc_isprint(*p
, enc
))
291 rb_raise(rb_eArgError
, "malformed format string - %%%c", *p
);
293 rb_raise(rb_eArgError
, "malformed format string");
297 CHECK_FOR_FLAGS(flags
);
303 CHECK_FOR_FLAGS(flags
);
309 CHECK_FOR_FLAGS(flags
);
315 CHECK_FOR_FLAGS(flags
);
321 CHECK_FOR_FLAGS(flags
);
326 case '1': case '2': case '3': case '4':
327 case '5': case '6': case '7': case '8': case '9':
331 if (nextvalue
!= Qundef
) {
332 rb_raise(rb_eArgError
, "value given twice - %d$", n
);
334 nextvalue
= GETPOSARG(n
);
338 CHECK_FOR_WIDTH(flags
);
346 const char *start
= p
;
347 char term
= (*p
== '<') ? '>' : '}';
350 for (; p
< end
&& *p
!= term
; ) {
351 p
+= rb_enc_mbclen(p
, end
, enc
);
354 rb_raise(rb_eArgError
, "malformed name - unmatched parenthesis");
356 #if SIZEOF_INT < SIZEOF_SIZE_T
357 if ((size_t)(p
- start
) >= INT_MAX
) {
358 const int message_limit
= 20;
359 len
= (int)(rb_enc_right_char_head(start
, start
+ message_limit
, p
, enc
) - start
);
360 rb_enc_raise(enc
, rb_eArgError
,
361 "too long name (%"PRIuSIZE
" bytes) - %.*s...%c",
362 (size_t)(p
- start
- 2), len
, start
, term
);
365 len
= (int)(p
- start
+ 1); /* including parenthesis */
367 rb_enc_raise(enc
, rb_eArgError
, "named%.*s after <%"PRIsVALUE
">",
368 len
, start
, rb_sym2str(sym
));
370 CHECKNAMEARG(start
, len
, enc
);
371 get_hash(&hash
, argc
, argv
);
372 sym
= rb_check_symbol_cstr(start
+ 1,
373 len
- 2 /* without parenthesis */,
375 if (!NIL_P(sym
)) nextvalue
= rb_hash_lookup2(hash
, sym
, Qundef
);
376 if (nextvalue
== Qundef
) {
378 sym
= rb_sym_intern(start
+ 1,
379 len
- 2 /* without parenthesis */,
382 nextvalue
= rb_hash_default_value(hash
, sym
);
383 if (NIL_P(nextvalue
)) {
384 rb_key_err_raise(rb_enc_sprintf(enc
, "key%.*s not found", len
, start
), hash
, sym
);
387 if (term
== '}') goto format_s
;
393 CHECK_FOR_WIDTH(flags
);
399 if (width
< 0) rb_raise(rb_eArgError
, "width too big");
405 if (flags
& FPREC0
) {
406 rb_raise(rb_eArgError
, "precision given twice");
408 flags
|= FPREC
|FPREC0
;
414 if (prec
< 0) { /* ignore negative precision */
421 GETNUM(prec
, precision
);
429 if (flags
!= FNONE
) {
430 rb_raise(rb_eArgError
, "invalid format character - %%");
437 VALUE val
= GETARG();
442 tmp
= rb_check_string_type(val
);
444 if (rb_enc_strlen(RSTRING_PTR(tmp
),RSTRING_END(tmp
),enc
) != 1) {
445 rb_raise(rb_eArgError
, "%%c requires a character");
447 c
= rb_enc_codepoint_len(RSTRING_PTR(tmp
), RSTRING_END(tmp
), &n
, enc
);
452 n
= rb_enc_codelen(c
, enc
);
455 rb_raise(rb_eArgError
, "invalid character");
457 if (!(flags
& FWIDTH
)) {
459 rb_enc_mbcput(c
, &buf
[blen
], enc
);
462 else if ((flags
& FMINUS
)) {
464 rb_enc_mbcput(c
, &buf
[blen
], enc
);
466 if (width
> 1) FILL(' ', width
-1);
469 if (width
> 1) FILL(' ', width
-1);
471 rb_enc_mbcput(c
, &buf
[blen
], enc
);
481 VALUE arg
= GETARG();
485 str
= rb_inspect(arg
);
488 str
= rb_obj_as_string(arg
);
490 len
= RSTRING_LEN(str
);
491 rb_str_set_len(result
, blen
);
492 if (coderange
!= ENC_CODERANGE_BROKEN
&& scanned
< blen
) {
494 scanned
+= rb_str_coderange_scan_restartable(buf
+scanned
, buf
+blen
, enc
, &cr
);
495 ENC_CODERANGE_SET(result
,
496 (cr
== ENC_CODERANGE_UNKNOWN
?
497 ENC_CODERANGE_BROKEN
: (coderange
= cr
)));
499 enc
= rb_enc_check(result
, str
);
500 if (flags
&(FPREC
|FWIDTH
)) {
501 slen
= rb_enc_strlen(RSTRING_PTR(str
),RSTRING_END(str
),enc
);
503 rb_raise(rb_eArgError
, "invalid mbstring sequence");
505 if ((flags
&FPREC
) && (prec
< slen
)) {
506 char *p
= rb_enc_nth(RSTRING_PTR(str
), RSTRING_END(str
),
509 len
= p
- RSTRING_PTR(str
);
511 /* need to adjust multi-byte string pos */
512 if ((flags
&FWIDTH
) && (width
> slen
)) {
514 if (!(flags
&FMINUS
)) {
519 memcpy(&buf
[blen
], RSTRING_PTR(str
), len
);
525 rb_enc_associate(result
, enc
);
529 PUSH(RSTRING_PTR(str
), len
);
531 rb_enc_associate(result
, enc
);
544 volatile VALUE val
= GETARG();
546 char nbuf
[BIT_DIGITS(SIZEOF_LONG
*CHAR_BIT
)+2], *s
;
547 const char *prefix
= 0;
548 int sign
= 0, dots
= 0;
551 int base
, bignum
= 0;
564 if (flags
&(FPLUS
|FSPACE
)) sign
= 1;
567 if (flags
& FSHARP
) {
572 prefix
= "0x"; break;
574 prefix
= "0X"; break;
576 prefix
= "0b"; break;
578 prefix
= "0B"; break;
585 if (FIXABLE(RFLOAT_VALUE(val
))) {
586 val
= LONG2FIX((long)RFLOAT_VALUE(val
));
589 val
= rb_dbl2big(RFLOAT_VALUE(val
));
590 if (FIXNUM_P(val
)) goto bin_retry
;
594 val
= rb_str_to_inum(val
, 0, TRUE
);
603 val
= rb_Integer(val
);
624 int numbits
= ffs(base
)-1;
626 size_t numdigits
= rb_absint_numwords(val
, numbits
, &abs_nlz_bits
);
628 if (INT_MAX
-1 < numdigits
) /* INT_MAX is used because rb_long2int is used later. */
629 rb_raise(rb_eArgError
, "size too big");
633 tmp
= rb_str_new(NULL
, numdigits
);
634 valsign
= rb_integer_pack(val
, RSTRING_PTR(tmp
), RSTRING_LEN(tmp
),
635 1, CHAR_BIT
-numbits
, INTEGER_PACK_BIG_ENDIAN
);
636 for (i
= 0; i
< RSTRING_LEN(tmp
); i
++)
637 RSTRING_PTR(tmp
)[i
] = ruby_digitmap
[((unsigned char *)RSTRING_PTR(tmp
))[i
]];
638 s
= RSTRING_PTR(tmp
);
643 else if (flags
& FPLUS
) {
647 else if (flags
& FSPACE
) {
653 /* Following conditional "numdigits++" guarantees the
654 * most significant digit as
655 * - '1'(bin), '7'(oct) or 'f'(hex) for negative numbers
657 * - not '0' for positive numbers.
659 * It also guarantees the most significant two
660 * digits will not be '11'(bin), '77'(oct), 'ff'(hex)
662 if (numdigits
== 0 ||
663 ((abs_nlz_bits
!= (size_t)(numbits
-1) ||
664 !rb_absint_singlebit_p(val
)) &&
665 (!bignum
? v
< 0 : BIGNUM_NEGATIVE_P(val
))))
667 tmp
= rb_str_new(NULL
, numdigits
);
668 valsign
= rb_integer_pack(val
, RSTRING_PTR(tmp
), RSTRING_LEN(tmp
),
669 1, CHAR_BIT
-numbits
, INTEGER_PACK_2COMP
| INTEGER_PACK_BIG_ENDIAN
);
670 for (i
= 0; i
< RSTRING_LEN(tmp
); i
++)
671 RSTRING_PTR(tmp
)[i
] = ruby_digitmap
[((unsigned char *)RSTRING_PTR(tmp
))[i
]];
672 s
= RSTRING_PTR(tmp
);
675 len
= rb_long2int(RSTRING_END(tmp
) - s
);
685 else if (flags
& FPLUS
) {
689 else if (flags
& FSPACE
) {
693 s
= ruby_ultoa((unsigned long)v
, nbuf
+ sizeof(nbuf
), 10, 0);
694 len
= (int)(nbuf
+ sizeof(nbuf
) - s
);
697 tmp
= rb_big2str(val
, 10);
698 s
= RSTRING_PTR(tmp
);
706 else if (flags
& FPLUS
) {
710 else if (flags
& FSPACE
) {
714 len
= rb_long2int(RSTRING_END(tmp
) - s
);
725 while ((c
= (int)(unsigned char)*pp
) != 0) {
726 *pp
= rb_enc_toupper(c
, enc
);
730 if (prefix
&& !prefix
[1]) { /* octal */
734 else if (len
== 1 && *s
== '0') {
736 if (flags
& FPREC
) prec
--;
738 else if ((flags
& FPREC
) && (prec
> len
)) {
742 else if (len
== 1 && *s
== '0') {
746 width
-= (int)strlen(prefix
);
748 if ((flags
& (FZERO
|FMINUS
|FPREC
)) == FZERO
) {
754 if (!prefix
&& prec
== 0 && len
== 1 && *s
== '0') len
= 0;
759 if (!(flags
&FMINUS
)) {
763 if (sc
) PUSH(&sc
, 1);
765 int plen
= (int)strlen(prefix
);
768 if (dots
) PUSH("..", 2);
771 if (!sign
&& valsign
< 0) {
772 char c
= sign_bits(base
, p
);
773 FILL_(c
, prec
- len
);
775 else if ((flags
& (FMINUS
|FPREC
)) != FMINUS
) {
776 FILL_('0', prec
- len
);
787 VALUE val
= GETARG(), num
, den
;
788 int sign
= (flags
&FPLUS
) ? 1 : 0, zero
= 0;
790 if (RB_INTEGER_TYPE_P(val
)) {
794 else if (RB_TYPE_P(val
, T_RATIONAL
)) {
795 den
= rb_rational_den(val
);
796 num
= rb_rational_num(val
);
802 if (!(flags
&FPREC
)) prec
= default_float_precision
;
804 if ((SIGNED_VALUE
)num
< 0) {
805 long n
= -FIX2LONG(num
);
810 else if (BIGNUM_NEGATIVE_P(num
)) {
812 num
= rb_big_uminus(num
);
814 if (den
!= INT2FIX(1)) {
815 num
= rb_int_mul(num
, rb_int_positive_pow(10, prec
));
816 num
= rb_int_plus(num
, rb_int_idiv(den
, INT2FIX(2)));
817 num
= rb_int_idiv(num
, den
);
819 else if (prec
>= 0) {
822 val
= rb_int2str(num
, 10);
823 len
= RSTRING_LEN(val
) + zero
;
824 if (prec
>= len
) len
= prec
+ 1; /* integer part 0 */
825 if (sign
|| (flags
&FSPACE
)) ++len
;
826 if (prec
> 0) ++len
; /* period */
827 fill
= width
> len
? width
- len
: 0;
829 if (fill
&& !(flags
&(FMINUS
|FZERO
))) {
832 if (sign
|| (flags
&FSPACE
)) {
833 buf
[blen
++] = sign
> 0 ? '+' : sign
< 0 ? '-' : ' ';
835 if (fill
&& (flags
&(FMINUS
|FZERO
)) == FZERO
) {
838 len
= RSTRING_LEN(val
) + zero
;
839 t
= RSTRING_PTR(val
);
841 PUSH_(t
, len
- prec
);
852 else if (prec
> len
) {
853 FILL_('0', prec
- len
);
857 PUSH_(t
+ len
- prec
, prec
);
859 if (fill
&& (flags
&FMINUS
)) {
869 /* TODO: rational support */
874 VALUE val
= GETARG();
877 fval
= RFLOAT_VALUE(rb_Float(val
));
878 if (!isfinite(fval
)) {
890 need
= (int)strlen(expr
);
892 if (!isnan(fval
) && fval
< 0.0)
894 else if (flags
& (FPLUS
|FSPACE
))
895 sign
= (flags
& FPLUS
) ? '+' : ' ';
898 if ((flags
& FWIDTH
) && need
< width
)
902 if (flags
& FMINUS
) {
904 buf
[blen
- need
--] = sign
;
905 memcpy(&buf
[blen
- need
], expr
, elen
);
909 buf
[blen
- elen
- 1] = sign
;
910 memcpy(&buf
[blen
- elen
], expr
, elen
);
915 int cr
= ENC_CODERANGE(result
);
916 char fbuf
[2*BIT_DIGITS(SIZEOF_INT
*CHAR_BIT
)+10];
917 char *fmt
= fmt_setup(fbuf
, sizeof(fbuf
), *p
, flags
, width
, prec
);
918 rb_str_set_len(result
, blen
);
919 rb_str_catf(result
, fmt
, fval
);
920 ENC_CODERANGE_SET(result
, cr
);
921 bsiz
= rb_str_capacity(result
);
922 RSTRING_GETMEM(result
, buf
, blen
);
931 rb_str_tmp_frozen_release(orig
, fmt
);
932 /* XXX - We cannot validate the number of arguments if (digit)$ style used.
934 if (posarg
>= 0 && nextarg
< argc
) {
935 const char *mesg
= "too many arguments for format string";
936 if (RTEST(ruby_debug
)) rb_raise(rb_eArgError
, "%s", mesg
);
937 if (RTEST(ruby_verbose
)) rb_warn("%s", mesg
);
939 rb_str_resize(result
, blen
);
945 fmt_setup(char *buf
, size_t size
, int c
, int flags
, int width
, int prec
)
952 buf
= ruby_ultoa(prec
, buf
, 10, 0);
956 if (flags
& FWIDTH
) {
957 buf
= ruby_ultoa(width
, buf
, 10, 0);
960 if (flags
& FSPACE
) *--buf
= ' ';
961 if (flags
& FZERO
) *--buf
= '0';
962 if (flags
& FMINUS
) *--buf
= '-';
963 if (flags
& FPLUS
) *--buf
= '+';
964 if (flags
& FSHARP
) *--buf
= '#';
970 #define FILE rb_printf_buffer
971 #define __sbuf rb_printf_sbuf
972 #define __sFILE rb_printf_sfile
977 #if SIZEOF_LONG < SIZEOF_LONG_LONG
978 # if SIZEOF_LONG_LONG == SIZEOF_VOIDP
979 /* actually this doesn't mean a pointer is strictly 64bit, but just
981 # define _HAVE_LLP64_
983 # define _HAVE_SANE_QUAD_
984 # define quad_t LONG_LONG
985 # define u_quad_t unsigned LONG_LONG
987 #define FLOATING_POINT 1
988 #define BSD__dtoa ruby_dtoa
989 #define BSD__hdtoa ruby_hdtoa
990 #ifdef RUBY_PRI_VALUE_MARK
991 # define PRI_EXTRA_MARK RUBY_PRI_VALUE_MARK
993 #define lower_hexdigits (ruby_hexdigits+0)
994 #define upper_hexdigits (ruby_hexdigits+16)
995 #include "vsnprintf.c"
998 ruby_ultoa(unsigned long val
, char *endp
, int base
, int flags
)
1000 const char *xdigs
= lower_hexdigits
;
1001 int octzero
= flags
& FSHARP
;
1002 return BSD__ultoa(val
, endp
, base
, octzero
, xdigs
);
1005 static int ruby_do_vsnprintf(char *str
, size_t n
, const char *fmt
, va_list ap
);
1008 ruby_vsnprintf(char *str
, size_t n
, const char *fmt
, va_list ap
)
1010 if (str
&& (ssize_t
)n
< 1)
1012 return ruby_do_vsnprintf(str
, n
, fmt
, ap
);
1016 ruby_do_vsnprintf(char *str
, size_t n
, const char *fmt
, va_list ap
)
1021 f
._flags
= __SWR
| __SSTR
;
1022 f
._bf
._base
= f
._p
= (unsigned char *)str
;
1023 f
._bf
._size
= f
._w
= str
? (n
- 1) : 0;
1024 f
.vwrite
= BSD__sfvwrite
;
1026 ret
= BSD_vfprintf(&f
, fmt
, ap
);
1028 #if SIZEOF_SIZE_T > SIZEOF_INT
1029 if (n
> INT_MAX
) return INT_MAX
;
1035 ruby_snprintf(char *str
, size_t n
, char const *fmt
, ...)
1040 if (str
&& (ssize_t
)n
< 1)
1044 ret
= ruby_do_vsnprintf(str
, n
, fmt
, ap
);
1050 rb_printf_buffer base
;
1051 volatile VALUE value
;
1052 } rb_printf_buffer_extra
;
1055 ruby__sfvwrite(register rb_printf_buffer
*fp
, register struct __suio
*uio
)
1058 VALUE result
= (VALUE
)fp
->_bf
._base
;
1059 char *buf
= (char*)fp
->_p
;
1061 long blen
= buf
- RSTRING_PTR(result
), bsiz
= fp
->_w
;
1063 if (RBASIC(result
)->klass
) {
1064 rb_raise(rb_eRuntimeError
, "rb_vsprintf reentered");
1066 if (uio
->uio_resid
== 0)
1068 #if SIZE_MAX > LONG_MAX
1069 if (uio
->uio_resid
>= LONG_MAX
)
1070 rb_raise(rb_eRuntimeError
, "too big string");
1072 len
= (long)uio
->uio_resid
;
1076 for (iov
= uio
->uio_iov
; len
> 0; ++iov
) {
1077 MEMCPY(buf
, iov
->iov_base
, char, n
= iov
->iov_len
);
1081 fp
->_p
= (unsigned char *)buf
;
1082 rb_str_set_len(result
, buf
- RSTRING_PTR(result
));
1087 ruby__sfvextra(rb_printf_buffer
*fp
, size_t valsize
, void *valp
, long *sz
, int sign
)
1089 VALUE value
, result
= (VALUE
)fp
->_bf
._base
;
1093 if (valsize
!= sizeof(VALUE
)) return 0;
1094 value
= *(VALUE
*)valp
;
1095 if (RBASIC(result
)->klass
) {
1096 rb_raise(rb_eRuntimeError
, "rb_vsprintf reentered");
1099 if (RB_TYPE_P(value
, T_CLASS
)) {
1100 # define LITERAL(str) (*sz = rb_strlen_lit(str), str)
1102 if (value
== rb_cNilClass
) {
1103 return LITERAL("nil");
1105 else if (value
== rb_cInteger
) {
1106 return LITERAL("Integer");
1108 else if (value
== rb_cSymbol
) {
1109 return LITERAL("Symbol");
1111 else if (value
== rb_cTrueClass
) {
1112 return LITERAL("true");
1114 else if (value
== rb_cFalseClass
) {
1115 return LITERAL("false");
1119 value
= rb_inspect(value
);
1121 else if (SYMBOL_P(value
)) {
1122 value
= rb_sym2str(value
);
1123 if (sign
== ' ' && !rb_str_symname_p(value
)) {
1124 value
= rb_str_escape(value
);
1128 value
= rb_obj_as_string(value
);
1129 if (sign
== ' ') value
= QUOTE(value
);
1131 enc
= rb_enc_compatible(result
, value
);
1133 rb_enc_associate(result
, enc
);
1136 enc
= rb_enc_get(result
);
1137 value
= rb_str_conv_enc_opts(value
, rb_enc_get(value
), enc
,
1138 ECONV_UNDEF_REPLACE
|ECONV_INVALID_REPLACE
,
1140 *(volatile VALUE
*)valp
= value
;
1142 StringValueCStr(value
);
1143 RSTRING_GETMEM(value
, cp
, *sz
);
1144 ((rb_printf_buffer_extra
*)fp
)->value
= value
;
1149 rb_enc_vsprintf(rb_encoding
*enc
, const char *fmt
, va_list ap
)
1151 rb_printf_buffer_extra buffer
;
1152 #define f buffer.base
1155 f
._flags
= __SWR
| __SSTR
;
1158 result
= rb_str_buf_new(f
._w
);
1160 if (rb_enc_mbminlen(enc
) > 1) {
1161 /* the implementation deeply depends on plain char */
1162 rb_raise(rb_eArgError
, "cannot construct wchar_t based encoding string: %s",
1165 rb_enc_associate(result
, enc
);
1167 f
._bf
._base
= (unsigned char *)result
;
1168 f
._p
= (unsigned char *)RSTRING_PTR(result
);
1169 RBASIC_CLEAR_CLASS(result
);
1170 f
.vwrite
= ruby__sfvwrite
;
1171 f
.vextra
= ruby__sfvextra
;
1173 BSD_vfprintf(&f
, fmt
, ap
);
1174 RBASIC_SET_CLASS_RAW(result
, rb_cString
);
1175 rb_str_resize(result
, (char *)f
._p
- RSTRING_PTR(result
));
1182 rb_enc_sprintf(rb_encoding
*enc
, const char *format
, ...)
1187 va_start(ap
, format
);
1188 result
= rb_enc_vsprintf(enc
, format
, ap
);
1195 rb_vsprintf(const char *fmt
, va_list ap
)
1197 return rb_enc_vsprintf(NULL
, fmt
, ap
);
1201 rb_sprintf(const char *format
, ...)
1206 va_start(ap
, format
);
1207 result
= rb_vsprintf(format
, ap
);
1214 rb_str_vcatf(VALUE str
, const char *fmt
, va_list ap
)
1216 rb_printf_buffer_extra buffer
;
1217 #define f buffer.base
1222 f
._flags
= __SWR
| __SSTR
;
1224 f
._w
= rb_str_capacity(str
);
1225 f
._bf
._base
= (unsigned char *)str
;
1226 f
._p
= (unsigned char *)RSTRING_END(str
);
1227 klass
= RBASIC(str
)->klass
;
1228 RBASIC_CLEAR_CLASS(str
);
1229 f
.vwrite
= ruby__sfvwrite
;
1230 f
.vextra
= ruby__sfvextra
;
1232 BSD_vfprintf(&f
, fmt
, ap
);
1233 RBASIC_SET_CLASS_RAW(str
, klass
);
1234 rb_str_resize(str
, (char *)f
._p
- RSTRING_PTR(str
));
1241 rb_str_catf(VALUE str
, const char *format
, ...)
1245 va_start(ap
, format
);
1246 str
= rb_str_vcatf(str
, format
, ap
);