1
/**********************************************************************
6
$Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $
7
created at: Fri Oct 15 10:39:26 JST 1993
9
Copyright (C) 1993-2003 Yukihiro Matsumoto
10
Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
11
Copyright (C) 2000 Information-technology Promotion Agency, Japan
13
**********************************************************************/
20
#define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */
22
static void fmt_setup _((char*,int,int,int,int));
25
remove_sign_bits(str, base)
50
while (*t) *s++ = *t++;
66
if (*p == 'X') c = 'F';
86
#define CHECK(l) do {\
87
while (blen + (l) >= bsiz) {\
90
rb_str_resize(result, bsiz);\
91
buf = RSTRING(result)->ptr;\
94
#define PUSH(s, l) do { \
96
memcpy(&buf[blen], s, l);\
100
#define GETARG() (nextvalue != Qundef ? nextvalue : \
102
(rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered", nextarg), 0) : \
103
(posarg = nextarg++, GETNTHARG(posarg)))
105
#define GETPOSARG(n) (posarg > 0 ? \
106
(rb_raise(rb_eArgError, "numbered(%d) after unnumbered(%d)", n, posarg), 0) : \
107
((n < 1) ? (rb_raise(rb_eArgError, "invalid index - %d$", n), 0) : \
108
(posarg = -1, GETNTHARG(n))))
110
#define GETNTHARG(nth) \
111
((nth >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : argv[nth])
113
#define GETASTER(val) do { \
116
for (; p < end && ISDIGIT(*p); p++) { \
117
int next_n = 10 * n + (*p - '0'); \
118
if (next_n / 10 != n) {\
119
rb_raise(rb_eArgError, #val " too big"); \
124
rb_raise(rb_eArgError, "malformed format string - %%*[0-9]"); \
127
tmp = GETPOSARG(n); \
133
val = NUM2INT(tmp); \
139
* format(format_string [, arguments...] ) => string
140
* sprintf(format_string [, arguments...] ) => string
142
* Returns the string resulting from applying <i>format_string</i> to
143
* any additional arguments. Within the format string, any characters
144
* other than format sequences are copied to the result. A format
145
* sequence consists of a percent sign, followed by optional flags,
146
* width, and precision indicators, then terminated with a field type
147
* character. The field type controls how the corresponding
148
* <code>sprintf</code> argument is to be interpreted, while the flags
149
* modify that interpretation. The field type characters are listed
150
* in the table at the end of this section. The flag characters are:
152
* Flag | Applies to | Meaning
153
* ---------+--------------+-----------------------------------------
154
* space | bdeEfgGiouxX | Leave a space at the start of
155
* | | positive numbers.
156
* ---------+--------------+-----------------------------------------
157
* (digit)$ | all | Specifies the absolute argument number
158
* | | for this field. Absolute and relative
159
* | | argument numbers cannot be mixed in a
160
* | | sprintf string.
161
* ---------+--------------+-----------------------------------------
162
* # | beEfgGoxX | Use an alternative format. For the
163
* | | conversions `o', `x', `X', and `b',
164
* | | prefix the result with ``0'', ``0x'', ``0X'',
165
* | | and ``0b'', respectively. For `e',
166
* | | `E', `f', `g', and 'G', force a decimal
167
* | | point to be added, even if no digits follow.
168
* | | For `g' and 'G', do not remove trailing zeros.
169
* ---------+--------------+-----------------------------------------
170
* + | bdeEfgGiouxX | Add a leading plus sign to positive numbers.
171
* ---------+--------------+-----------------------------------------
172
* - | all | Left-justify the result of this conversion.
173
* ---------+--------------+-----------------------------------------
174
* 0 (zero) | bdeEfgGiouxX | Pad with zeros, not spaces.
175
* ---------+--------------+-----------------------------------------
176
* * | all | Use the next argument as the field width.
177
* | | If negative, left-justify the result. If the
178
* | | asterisk is followed by a number and a dollar
179
* | | sign, use the indicated argument as the width.
182
* The field width is an optional integer, followed optionally by a
183
* period and a precision. The width specifies the minimum number of
184
* characters that will be written to the result for this field. For
185
* numeric fields, the precision controls the number of decimal places
186
* displayed. For string fields, the precision determines the maximum
187
* number of characters to be copied from the string. (Thus, the format
188
* sequence <code>%10.10s</code> will always contribute exactly ten
189
* characters to the result.)
191
* The field types are:
194
* ------+--------------------------------------------------------------
195
* b | Convert argument as a binary number.
196
* c | Argument is the numeric code for a single character.
197
* d | Convert argument as a decimal number.
198
* E | Equivalent to `e', but uses an uppercase E to indicate
200
* e | Convert floating point argument into exponential notation
201
* | with one digit before the decimal point. The precision
202
* | determines the number of fractional digits (defaulting to six).
203
* f | Convert floating point argument as [-]ddd.ddd,
204
* | where the precision determines the number of digits after
205
* | the decimal point.
206
* G | Equivalent to `g', but use an uppercase `E' in exponent form.
207
* g | Convert a floating point number using exponential form
208
* | if the exponent is less than -4 or greater than or
209
* | equal to the precision, or in d.dddd form otherwise.
210
* i | Identical to `d'.
211
* o | Convert argument as an octal number.
212
* p | The valuing of argument.inspect.
213
* s | Argument is a string to be substituted. If the format
214
* | sequence contains a precision, at most that many characters
216
* u | Treat argument as an unsigned decimal number. Negative integers
217
* | are displayed as a 32 bit two's complement plus one for the
218
* | underlying architecture; that is, 2 ** 32 + n. However, since
219
* | Ruby has no inherent limit on bits used to represent the
220
* | integer, this value is preceded by two dots (..) in order to
221
* | indicate a infinite number of leading sign bits.
222
* X | Convert argument as a hexadecimal number using uppercase
223
* | letters. Negative numbers will be displayed with two
224
* | leading periods (representing an infinite string of
226
* x | Convert argument as a hexadecimal number.
227
* | Negative numbers will be displayed with two
228
* | leading periods (representing an infinite string of
233
* sprintf("%d %04x", 123, 123) #=> "123 007b"
234
* sprintf("%08b '%4s'", 123, 123) #=> "01111011 ' 123'"
235
* sprintf("%1$*2$s %2$d %1$s", "hello", 8) #=> " hello 8 hello"
236
* sprintf("%1$*2$s %2$d", "hello", -8) #=> "hello -8"
237
* sprintf("%+g:% g:%-g", 1.23, 1.23, 1.23) #=> "+1.23: 1.23:1.23"
238
* sprintf("%u", -123) #=> "..4294967173"
242
rb_f_sprintf(argc, argv)
252
int width, prec, flags = FNONE;
261
if (OBJ_TAINTED(fmt)) tainted = 1;
263
fmt = rb_str_new4(fmt);
264
p = RSTRING(fmt)->ptr;
265
end = p + RSTRING(fmt)->len;
268
result = rb_str_buf_new(bsiz);
269
buf = RSTRING(result)->ptr;
271
for (; p < end; p++) {
275
for (t = p; t < end && *t != '%'; t++) ;
278
/* end of fmt string */
281
p = t + 1; /* skip `%' */
289
rb_raise(rb_eArgError, "malformed format string - %%%c", *p);
291
rb_raise(rb_eArgError, "malformed format string");
319
case '1': case '2': case '3': case '4':
320
case '5': case '6': case '7': case '8': case '9':
322
for (; p < end && ISDIGIT(*p); p++) {
323
int next_n = 10 * n + (*p - '0');
324
if (next_n / 10 != n) {
325
rb_raise(rb_eArgError, "width too big");
327
n = 10 * n + (*p - '0');
330
rb_raise(rb_eArgError, "malformed format string - %%[0-9]");
333
if (nextvalue != Qundef) {
334
rb_raise(rb_eArgError, "value given twice - %d$", n);
336
nextvalue = GETPOSARG(n);
345
if (flags & FWIDTH) {
346
rb_raise(rb_eArgError, "width given twice");
360
rb_raise(rb_eArgError, "precision given twice");
368
if (prec < 0) { /* ignore negative precision */
375
for (; p < end && ISDIGIT(*p); p++) {
376
prec = 10 * prec + (*p - '0');
379
rb_raise(rb_eArgError, "malformed format string - %%.[0-9]");
387
if (flags != FNONE) {
388
rb_raise(rb_eArgError, "illegal format character - %%");
395
VALUE val = GETARG();
398
if (!(flags & FMINUS))
401
c = NUM2INT(val) & 0xff;
411
VALUE arg = GETARG();
414
if (*p == 'p') arg = rb_inspect(arg);
415
str = rb_obj_as_string(arg);
416
if (OBJ_TAINTED(str)) tainted = 1;
417
len = RSTRING(str)->len;
423
/* need to adjust multi-byte string pos */
428
if (!(flags&FMINUS)) {
433
memcpy(&buf[blen], RSTRING_PTR(str), len);
443
PUSH(RSTRING(str)->ptr, len);
456
volatile VALUE val = GETARG();
457
char fbuf[32], nbuf[64], *s, *t;
462
int base, bignum = 0;
478
if (flags&(FPLUS|FSPACE)) sign = 1;
481
if (flags & FSHARP) {
486
prefix = "0x"; break;
488
prefix = "0X"; break;
490
prefix = "0b"; break;
492
prefix = "0B"; break;
495
width -= strlen(prefix);
502
val = rb_dbl2big(RFLOAT(val)->value);
503
if (FIXNUM_P(val)) goto bin_retry;
507
val = rb_str_to_inum(val, 0, Qtrue);
516
val = rb_Integer(val);
542
if (c == 'i') c = 'd'; /* %d and %i are identical */
548
else if (flags & FPLUS) {
552
else if (flags & FSPACE) {
556
sprintf(fbuf, "%%l%c", c);
557
sprintf(nbuf, fbuf, v);
564
rb_warning("negative number for %%u specifier");
566
if (!(flags&(FPREC|FZERO))) {
571
sprintf(fbuf, "%%l%c", *p == 'X' ? 'x' : *p);
576
remove_sign_bits(s, base);
584
memmove(s+1, s, strlen(s)+1);
593
tmp = rb_big2str(val, base);
594
s = RSTRING(tmp)->ptr;
600
else if (flags & FPLUS) {
604
else if (flags & FSPACE) {
610
if (!RBIGNUM(val)->sign) {
611
val = rb_big_clone(val);
614
tmp1 = tmp = rb_big2str0(val, base, RBIGNUM(val)->sign);
615
s = RSTRING(tmp)->ptr;
618
rb_warning("negative number for %%u specifier");
620
remove_sign_bits(++s, base);
621
tmp = rb_str_new(0, 3+strlen(s));
622
t = RSTRING(tmp)->ptr;
623
if (!(flags&(FPREC|FZERO))) {
629
if (s[0] != 'f') strcpy(t++, "f"); break;
631
if (s[0] != '7') strcpy(t++, "7"); break;
633
if (s[0] != '1') strcpy(t++, "1"); break;
638
s = RSTRING(tmp)->ptr;
651
if ((flags&(FZERO|FPREC)) == FZERO) {
656
if (prec < len) prec = len;
659
if (!(flags&FMINUS)) {
661
while (width-- > 0) {
665
if (sc) PUSH(&sc, 1);
667
int plen = strlen(prefix);
671
if (!bignum && v < 0) {
672
char c = sign_bits(base, p);
673
while (len < prec--) {
680
if (bignum && !RBIGNUM(val)->sign)
681
c = sign_bits(base, p);
684
while (len < prec--) {
690
while (width-- > 0) {
702
VALUE val = GETARG();
707
fval = RFLOAT(rb_Float(val))->value;
708
#if defined(_WIN32) && !defined(__BORLANDC__)
709
if (isnan(fval) || isinf(fval)) {
719
if ((!isnan(fval) && fval < 0.0) || (flags & FPLUS))
721
if ((flags & FWIDTH) && need < width)
725
sprintf(&buf[blen], "%*s", need, "");
726
if (flags & FMINUS) {
727
if (!isnan(fval) && fval < 0.0)
729
else if (flags & FPLUS)
731
else if (flags & FSPACE)
733
strncpy(&buf[blen], expr, strlen(expr));
735
else if (flags & FZERO) {
736
if (!isnan(fval) && fval < 0.0) {
740
else if (flags & FPLUS) {
744
else if (flags & FSPACE) {
748
while (need-- - strlen(expr) > 0) {
751
strncpy(&buf[blen], expr, strlen(expr));
754
if (!isnan(fval) && fval < 0.0)
755
buf[blen + need - strlen(expr) - 1] = '-';
756
else if (flags & FPLUS)
757
buf[blen + need - strlen(expr) - 1] = '+';
758
strncpy(&buf[blen + need - strlen(expr)], expr,
761
blen += strlen(&buf[blen]);
764
#endif /* defined(_WIN32) && !defined(__BORLANDC__) */
765
fmt_setup(fbuf, *p, flags, width, prec);
767
if (*p != 'e' && *p != 'E') {
771
need = BIT_DIGITS(i);
773
need += (flags&FPREC) ? prec : 6;
774
if ((flags&FWIDTH) && need < width)
779
sprintf(&buf[blen], fbuf, fval);
780
blen += strlen(&buf[blen]);
788
/* XXX - We cannot validiate the number of arguments if (digit)$ style used.
790
if (posarg >= 0 && nextarg < argc) {
791
const char *mesg = "too many arguments for format string";
792
if (RTEST(ruby_debug)) rb_raise(rb_eArgError, mesg);
793
if (RTEST(ruby_verbose)) rb_warn(mesg);
795
rb_str_resize(result, blen);
797
if (tainted) OBJ_TAINT(result);
802
fmt_setup(buf, c, flags, width, prec)
805
int flags, width, prec;
808
if (flags & FSHARP) *buf++ = '#';
809
if (flags & FPLUS) *buf++ = '+';
810
if (flags & FMINUS) *buf++ = '-';
811
if (flags & FZERO) *buf++ = '0';
812
if (flags & FSPACE) *buf++ = ' ';
814
if (flags & FWIDTH) {
815
sprintf(buf, "%d", width);
820
sprintf(buf, ".%d", prec);