Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 840 lines (773 sloc) 20.515 kB
7dff2ac 2000-05-09
matz authored
1 /**********************************************************************
99d0354 Initial revision
matz authored
2
3 sprintf.c -
4
5 $Author$
6 $Date$
7 created at: Fri Oct 15 10:39:26 JST 1993
8
42bc5d2 Updated Copyrights of Matz to 2003.
michal authored
9 Copyright (C) 1993-2003 Yukihiro Matsumoto
817a62d 2000-05-01
matz authored
10 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
7dff2ac 2000-05-09
matz authored
11 Copyright (C) 2000 Information-technology Promotion Agency, Japan
99d0354 Initial revision
matz authored
12
7dff2ac 2000-05-09
matz authored
13 **********************************************************************/
99d0354 Initial revision
matz authored
14
15 #include "ruby.h"
adc15cc * sprintf.c (rb_f_sprintf): adjust precision length to prevent
matz authored
16 #include "re.h"
99d0354 Initial revision
matz authored
17 #include <ctype.h>
07bb9f2 1.4.0
matz authored
18 #include <math.h>
99d0354 Initial revision
matz authored
19
07bb9f2 1.4.0
matz authored
20 #define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */
4de98bc @nobu * bignum.c (rb_big2str0): do not clobber space for sign.
nobu authored
21 #define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT)
22 #define EXTENDSIGN(n, l) (((~0 << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0 << (n)))
07bb9f2 1.4.0
matz authored
23
1f72ff9 regexp literal (e.g. \202) match, etc.
matz authored
24 static void fmt_setup _((char*,int,int,int,int));
99d0354 Initial revision
matz authored
25
26 static char*
27 remove_sign_bits(str, base)
28 char *str;
29 int base;
30 {
aec6e76 @nobu * sprintf.c (rb_f_sprintf): remove extra sign digit.
nobu authored
31 char *s, *t;
99d0354 Initial revision
matz authored
32
33 s = t = str;
34
35 if (base == 16) {
aec6e76 @nobu * sprintf.c (rb_f_sprintf): remove extra sign digit.
nobu authored
36 while (*t == 'f') {
6d3df63 * variable.c (rb_obj_remove_instance_variable): raise NameError if
matz authored
37 t++;
99d0354 Initial revision
matz authored
38 }
39 }
40 else if (base == 8) {
4de98bc @nobu * bignum.c (rb_big2str0): do not clobber space for sign.
nobu authored
41 *t |= EXTENDSIGN(3, strlen(t));
aec6e76 @nobu * sprintf.c (rb_f_sprintf): remove extra sign digit.
nobu authored
42 while (*t == '7') {
6d3df63 * variable.c (rb_obj_remove_instance_variable): raise NameError if
matz authored
43 t++;
99d0354 Initial revision
matz authored
44 }
45 }
46 else if (base == 2) {
aec6e76 @nobu * sprintf.c (rb_f_sprintf): remove extra sign digit.
nobu authored
47 while (*t == '1') {
6d3df63 * variable.c (rb_obj_remove_instance_variable): raise NameError if
matz authored
48 t++;
49 }
99d0354 Initial revision
matz authored
50 }
aec6e76 @nobu * sprintf.c (rb_f_sprintf): remove extra sign digit.
nobu authored
51 if (t > s) {
52 while (*t) *s++ = *t++;
53 *s = '\0';
54 }
99d0354 Initial revision
matz authored
55
56 return str;
57 }
58
7268098 * eval.c (load_dyna): clear ruby_errinfo. (ruby-bugs-ja PR#409)
matz authored
59 static char
60 sign_bits(base, p)
61 int base;
aec6e76 @nobu * sprintf.c (rb_f_sprintf): remove extra sign digit.
nobu authored
62 const char *p;
7268098 * eval.c (load_dyna): clear ruby_errinfo. (ruby-bugs-ja PR#409)
matz authored
63 {
64 char c = '.';
65
66 switch (base) {
67 case 16:
68 if (*p == 'X') c = 'F';
69 else c = 'f';
70 break;
71 case 8:
72 c = '7'; break;
73 case 2:
74 c = '1'; break;
75 }
76 return c;
77 }
78
99d0354 Initial revision
matz authored
79 #define FNONE 0
80 #define FSHARP 1
81 #define FMINUS 2
82 #define FPLUS 4
83 #define FZERO 8
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
84 #define FSPACE 16
85 #define FWIDTH 32
86 #define FPREC 64
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
87 #define FPREC0 128
99d0354 Initial revision
matz authored
88
646728f @nobu * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
nobu authored
89 #define CHECK(l) do {\
99d0354 Initial revision
matz authored
90 while (blen + (l) >= bsiz) {\
91 bsiz*=2;\
646728f @nobu * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
nobu authored
92 }\
93 rb_str_resize(result, bsiz);\
94 buf = RSTRING(result)->ptr;\
95 } while (0)
99d0354 Initial revision
matz authored
96
5550197 * re.c (rb_reg_expr_str): should treat backslash specially in
matz authored
97 #define PUSH(s, l) do { \
99d0354 Initial revision
matz authored
98 CHECK(l);\
99 memcpy(&buf[blen], s, l);\
100 blen += (l);\
5550197 * re.c (rb_reg_expr_str): should treat backslash specially in
matz authored
101 } while (0)
99d0354 Initial revision
matz authored
102
646728f @nobu * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
nobu authored
103 #define GETARG() (nextvalue != Qundef ? nextvalue : \
104 posarg < 0 ? \
105 (rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered", nextarg), 0) : \
106 (posarg = nextarg++, GETNTHARG(posarg)))
107
108 #define GETPOSARG(n) (posarg > 0 ? \
109 (rb_raise(rb_eArgError, "numbered(%d) after unnumbered(%d)", n, posarg), 0) : \
110 ((n < 1) ? (rb_raise(rb_eArgError, "invalid index - %d$", n), 0) : \
111 (posarg = -1, GETNTHARG(n))))
112
113 #define GETNTHARG(nth) \
8db23b3 * exception error messages updated. [ruby-core:04497]
matz authored
114 ((nth >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : argv[nth])
2ee41de 19991111
matz authored
115
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
116 #define GETNUM(n, val) \
2ee41de 19991111
matz authored
117 for (; p < end && ISDIGIT(*p); p++) { \
bef0d03 * sprintf.c (rb_f_sprintf): [ruby-dev:27967]
matz authored
118 int next_n = 10 * n + (*p - '0'); \
119 if (next_n / 10 != n) {\
46f0dbe * sprintf.c (rb_str_format): integer overflow check added.
matz authored
120 rb_raise(rb_eArgError, #val " too big"); \
121 } \
bef0d03 * sprintf.c (rb_f_sprintf): [ruby-dev:27967]
matz authored
122 n = next_n; \
2ee41de 19991111
matz authored
123 } \
124 if (p >= end) { \
125 rb_raise(rb_eArgError, "malformed format string - %%*[0-9]"); \
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
126 }
127
128 #define GETASTER(val) do { \
129 t = p++; \
130 n = 0; \
131 GETNUM(n, val); \
2ee41de 19991111
matz authored
132 if (*p == '$') { \
646728f @nobu * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
nobu authored
133 tmp = GETPOSARG(n); \
2ee41de 19991111
matz authored
134 } \
135 else { \
136 tmp = GETARG(); \
137 p = t; \
138 } \
139 val = NUM2INT(tmp); \
5550197 * re.c (rb_reg_expr_str): should treat backslash specially in
matz authored
140 } while (0)
99d0354 Initial revision
matz authored
141
6ef59c5 Add RDoc documentation for stuff in object.c
dave authored
142
143 /*
144 * call-seq:
145 * format(format_string [, arguments...] ) => string
146 * sprintf(format_string [, arguments...] ) => string
147 *
148 * Returns the string resulting from applying <i>format_string</i> to
149 * any additional arguments. Within the format string, any characters
150 * other than format sequences are copied to the result. A format
151 * sequence consists of a percent sign, followed by optional flags,
152 * width, and precision indicators, then terminated with a field type
153 * character. The field type controls how the corresponding
154 * <code>sprintf</code> argument is to be interpreted, while the flags
155 * modify that interpretation. The field type characters are listed
156 * in the table at the end of this section. The flag characters are:
157 *
158 * Flag | Applies to | Meaning
159 * ---------+--------------+-----------------------------------------
cef9f4a * ext/syck/rubyext.c (syck_resolver_transfer): remove C++ style
matz authored
160 * space | bdeEfgGiouxX | Leave a space at the start of
6ef59c5 Add RDoc documentation for stuff in object.c
dave authored
161 * | | positive numbers.
162 * ---------+--------------+-----------------------------------------
163 * (digit)$ | all | Specifies the absolute argument number
164 * | | for this field. Absolute and relative
165 * | | argument numbers cannot be mixed in a
166 * | | sprintf string.
167 * ---------+--------------+-----------------------------------------
168 * # | beEfgGoxX | Use an alternative format. For the
169 * | | conversions `o', `x', `X', and `b',
170 * | | prefix the result with ``0'', ``0x'', ``0X'',
171 * | | and ``0b'', respectively. For `e',
172 * | | `E', `f', `g', and 'G', force a decimal
173 * | | point to be added, even if no digits follow.
174 * | | For `g' and 'G', do not remove trailing zeros.
175 * ---------+--------------+-----------------------------------------
cef9f4a * ext/syck/rubyext.c (syck_resolver_transfer): remove C++ style
matz authored
176 * + | bdeEfgGiouxX | Add a leading plus sign to positive numbers.
6ef59c5 Add RDoc documentation for stuff in object.c
dave authored
177 * ---------+--------------+-----------------------------------------
178 * - | all | Left-justify the result of this conversion.
179 * ---------+--------------+-----------------------------------------
cef9f4a * ext/syck/rubyext.c (syck_resolver_transfer): remove C++ style
matz authored
180 * 0 (zero) | bdeEfgGiouxX | Pad with zeros, not spaces.
6ef59c5 Add RDoc documentation for stuff in object.c
dave authored
181 * ---------+--------------+-----------------------------------------
182 * * | all | Use the next argument as the field width.
183 * | | If negative, left-justify the result. If the
184 * | | asterisk is followed by a number and a dollar
185 * | | sign, use the indicated argument as the width.
186 *
187 *
188 * The field width is an optional integer, followed optionally by a
189 * period and a precision. The width specifies the minimum number of
190 * characters that will be written to the result for this field. For
191 * numeric fields, the precision controls the number of decimal places
192 * displayed. For string fields, the precision determines the maximum
193 * number of characters to be copied from the string. (Thus, the format
194 * sequence <code>%10.10s</code> will always contribute exactly ten
195 * characters to the result.)
196 *
197 * The field types are:
198 *
199 * Field | Conversion
200 * ------+--------------------------------------------------------------
201 * b | Convert argument as a binary number.
202 * c | Argument is the numeric code for a single character.
203 * d | Convert argument as a decimal number.
204 * E | Equivalent to `e', but uses an uppercase E to indicate
205 * | the exponent.
206 * e | Convert floating point argument into exponential notation
207 * | with one digit before the decimal point. The precision
208 * | determines the number of fractional digits (defaulting to six).
209 * f | Convert floating point argument as [-]ddd.ddd,
210 * | where the precision determines the number of digits after
211 * | the decimal point.
212 * G | Equivalent to `g', but use an uppercase `E' in exponent form.
213 * g | Convert a floating point number using exponential form
214 * | if the exponent is less than -4 or greater than or
215 * | equal to the precision, or in d.dddd form otherwise.
216 * i | Identical to `d'.
217 * o | Convert argument as an octal number.
218 * p | The valuing of argument.inspect.
219 * s | Argument is a string to be substituted. If the format
220 * | sequence contains a precision, at most that many characters
221 * | will be copied.
802dc17 * io.c (io_close): always calls "close" method of the receiver.
matz authored
222 * u | Treat argument as an unsigned decimal number. Negative integers
223 * | are displayed as a 32 bit two's complement plus one for the
224 * | underlying architecture; that is, 2 ** 32 + n. However, since
225 * | Ruby has no inherent limit on bits used to represent the
226 * | integer, this value is preceded by two dots (..) in order to
227 * | indicate a infinite number of leading sign bits.
6ef59c5 Add RDoc documentation for stuff in object.c
dave authored
228 * X | Convert argument as a hexadecimal number using uppercase
229 * | letters. Negative numbers will be displayed with two
230 * | leading periods (representing an infinite string of
231 * | leading 'FF's.
232 * x | Convert argument as a hexadecimal number.
233 * | Negative numbers will be displayed with two
234 * | leading periods (representing an infinite string of
235 * | leading 'ff's.
236 *
237 * Examples:
238 *
239 * sprintf("%d %04x", 123, 123) #=> "123 007b"
240 * sprintf("%08b '%4s'", 123, 123) #=> "01111011 ' 123'"
241 * sprintf("%1$*2$s %2$d %1$s", "hello", 8) #=> " hello 8 hello"
242 * sprintf("%1$*2$s %2$d", "hello", -8) #=> "hello -8"
243 * sprintf("%+g:% g:%-g", 1.23, 1.23, 1.23) #=> "+1.23: 1.23:1.23"
802dc17 * io.c (io_close): always calls "close" method of the receiver.
matz authored
244 * sprintf("%u", -123) #=> "..4294967173"
6ef59c5 Add RDoc documentation for stuff in object.c
dave authored
245 */
246
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
247 VALUE
248 rb_f_sprintf(argc, argv)
249 int argc;
250 VALUE *argv;
251 {
252 VALUE fmt;
aec6e76 @nobu * sprintf.c (rb_f_sprintf): remove extra sign digit.
nobu authored
253 const char *p, *end;
254 char *buf;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
255 int blen, bsiz;
256 VALUE result;
257
258 int width, prec, flags = FNONE;
646728f @nobu * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
nobu authored
259 int nextarg = 1;
260 int posarg = 0;
bd5567f 19991206
matz authored
261 int tainted = 0;
646728f @nobu * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
nobu authored
262 VALUE nextvalue;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
263 VALUE tmp;
264 VALUE str;
99d0354 Initial revision
matz authored
265
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
266 #define CHECK_FOR_WIDTH(f) \
267 if ((f) & FWIDTH) { \
268 rb_raise(rb_eArgError, "width given twice"); \
269 } \
270 if ((f) & FPREC0) { \
271 rb_raise(rb_eArgError, "width after precision"); \
272 }
273 #define CHECK_FOR_FLAGS(f) \
274 if ((f) & FWIDTH) { \
275 rb_raise(rb_eArgError, "flag after width"); \
276 } \
277 if ((f) & FPREC0) { \
278 rb_raise(rb_eArgError, "flag after precision"); \
279 }
280
646728f @nobu * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
nobu authored
281 fmt = GETNTHARG(0);
bd5567f 19991206
matz authored
282 if (OBJ_TAINTED(fmt)) tainted = 1;
7678f4b * eval.c (block_pass): should not downgrade safe level.
matz authored
283 StringValue(fmt);
42dabef * io.c (io_fwrite): change dereference for cosmetic reason.
matz authored
284 fmt = rb_str_new4(fmt);
7678f4b * eval.c (block_pass): should not downgrade safe level.
matz authored
285 p = RSTRING(fmt)->ptr;
286 end = p + RSTRING(fmt)->len;
99d0354 Initial revision
matz authored
287 blen = 0;
288 bsiz = 120;
646728f @nobu * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
nobu authored
289 result = rb_str_buf_new(bsiz);
290 buf = RSTRING(result)->ptr;
99d0354 Initial revision
matz authored
291
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
292 for (; p < end; p++) {
aec6e76 @nobu * sprintf.c (rb_f_sprintf): remove extra sign digit.
nobu authored
293 const char *t;
2ee41de 19991111
matz authored
294 int n;
99d0354 Initial revision
matz authored
295
296 for (t = p; t < end && *t != '%'; t++) ;
297 PUSH(p, t - p);
298 if (t >= end) {
299 /* end of fmt string */
300 goto sprint_exit;
301 }
302 p = t + 1; /* skip `%' */
303
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
304 width = prec = -1;
646728f @nobu * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
nobu authored
305 nextvalue = Qundef;
99d0354 Initial revision
matz authored
306 retry:
307 switch (*p) {
308 default:
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
309 if (ISPRINT(*p))
310 rb_raise(rb_eArgError, "malformed format string - %%%c", *p);
99d0354 Initial revision
matz authored
311 else
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
312 rb_raise(rb_eArgError, "malformed format string");
99d0354 Initial revision
matz authored
313 break;
314
315 case ' ':
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
316 CHECK_FOR_FLAGS(flags);
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
317 flags |= FSPACE;
99d0354 Initial revision
matz authored
318 p++;
319 goto retry;
320
321 case '#':
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
322 CHECK_FOR_FLAGS(flags);
99d0354 Initial revision
matz authored
323 flags |= FSHARP;
324 p++;
325 goto retry;
326
327 case '+':
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
328 CHECK_FOR_FLAGS(flags);
99d0354 Initial revision
matz authored
329 flags |= FPLUS;
330 p++;
331 goto retry;
332
333 case '-':
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
334 CHECK_FOR_FLAGS(flags);
99d0354 Initial revision
matz authored
335 flags |= FMINUS;
336 p++;
337 goto retry;
338
339 case '0':
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
340 CHECK_FOR_FLAGS(flags);
99d0354 Initial revision
matz authored
341 flags |= FZERO;
342 p++;
343 goto retry;
344
345 case '1': case '2': case '3': case '4':
346 case '5': case '6': case '7': case '8': case '9':
2ee41de 19991111
matz authored
347 n = 0;
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
348 GETNUM(n, width);
2ee41de 19991111
matz authored
349 if (*p == '$') {
646728f @nobu * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
nobu authored
350 if (nextvalue != Qundef) {
351 rb_raise(rb_eArgError, "value given twice - %d$", n);
352 }
353 nextvalue = GETPOSARG(n);
2ee41de 19991111
matz authored
354 p++;
355 goto retry;
356 }
fb873cd @nobu * sprintf.c (rb_f_sprintf): should not check positional number as
nobu authored
357 CHECK_FOR_WIDTH(flags);
2ee41de 19991111
matz authored
358 width = n;
359 flags |= FWIDTH;
99d0354 Initial revision
matz authored
360 goto retry;
361
362 case '*':
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
363 CHECK_FOR_WIDTH(flags);
99d0354 Initial revision
matz authored
364 flags |= FWIDTH;
2ee41de 19991111
matz authored
365 GETASTER(width);
99d0354 Initial revision
matz authored
366 if (width < 0) {
367 flags |= FMINUS;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
368 width = -width;
99d0354 Initial revision
matz authored
369 }
370 p++;
371 goto retry;
372
373 case '.':
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
374 if (flags & FPREC0) {
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
375 rb_raise(rb_eArgError, "precision given twice");
99d0354 Initial revision
matz authored
376 }
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
377 flags |= FPREC|FPREC0;
99d0354 Initial revision
matz authored
378
379 prec = 0;
380 p++;
381 if (*p == '*') {
2ee41de 19991111
matz authored
382 GETASTER(prec);
3b3b1e3 2000-06-19
matz authored
383 if (prec < 0) { /* ignore negative precision */
384 flags &= ~FPREC;
385 }
99d0354 Initial revision
matz authored
386 p++;
387 goto retry;
388 }
389
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
390 GETNUM(prec, precision);
99d0354 Initial revision
matz authored
391 goto retry;
392
393 case '\n':
394 case '\0':
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
395 p--;
99d0354 Initial revision
matz authored
396 case '%':
1f72ff9 regexp literal (e.g. \202) match, etc.
matz authored
397 if (flags != FNONE) {
398 rb_raise(rb_eArgError, "illegal format character - %%");
399 }
99d0354 Initial revision
matz authored
400 PUSH("%", 1);
401 break;
402
403 case 'c':
404 {
405 VALUE val = GETARG();
406 char c;
407
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
408 if (!(flags & FMINUS))
409 while (--width > 0)
410 PUSH(" ", 1);
99d0354 Initial revision
matz authored
411 c = NUM2INT(val) & 0xff;
412 PUSH(&c, 1);
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
413 while (--width > 0)
414 PUSH(" ", 1);
99d0354 Initial revision
matz authored
415 }
416 break;
417
418 case 's':
0a9bd7c * array.c (rb_values_at): extract common procedure from
matz authored
419 case 'p':
99d0354 Initial revision
matz authored
420 {
421 VALUE arg = GETARG();
fa79abb *.c: Int vs Long cleanup
michal authored
422 long len;
99d0354 Initial revision
matz authored
423
0a9bd7c * array.c (rb_values_at): extract common procedure from
matz authored
424 if (*p == 'p') arg = rb_inspect(arg);
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
425 str = rb_obj_as_string(arg);
bd5567f 19991206
matz authored
426 if (OBJ_TAINTED(str)) tainted = 1;
99d0354 Initial revision
matz authored
427 len = RSTRING(str)->len;
428 if (flags&FPREC) {
429 if (prec < len) {
47b45f8 matz
matz authored
430 len = prec;
99d0354 Initial revision
matz authored
431 }
432 }
bb5a9b1 * sprintf.c (rb_f_sprintf): need not to truncate string if no
matz authored
433 /* need to adjust multi-byte string pos */
99d0354 Initial revision
matz authored
434 if (flags&FWIDTH) {
435 if (width > len) {
436 CHECK(width);
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
437 width -= len;
99d0354 Initial revision
matz authored
438 if (!(flags&FMINUS)) {
439 while (width--) {
440 buf[blen++] = ' ';
441 }
442 }
bb5a9b1 * sprintf.c (rb_f_sprintf): need not to truncate string if no
matz authored
443 memcpy(&buf[blen], RSTRING_PTR(str), len);
99d0354 Initial revision
matz authored
444 blen += len;
445 if (flags&FMINUS) {
446 while (width--) {
447 buf[blen++] = ' ';
448 }
449 }
450 break;
451 }
452 }
6e52592 m17n cleanup ;_;
matz authored
453 PUSH(RSTRING(str)->ptr, len);
99d0354 Initial revision
matz authored
454 }
455 break;
456
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
457 case 'd':
458 case 'i':
99d0354 Initial revision
matz authored
459 case 'o':
460 case 'x':
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
461 case 'X':
462 case 'b':
2b65285 * class.c (rb_mod_clone): should not copy class name, since clone
matz authored
463 case 'B':
99d0354 Initial revision
matz authored
464 case 'u':
465 {
466 volatile VALUE val = GETARG();
467 char fbuf[32], nbuf[64], *s, *t;
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
468 const char *prefix = 0;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
469 int sign = 0;
470 char sc = 0;
379adab @knu * sprintf.c (rb_f_sprintf): Fix a bug caused by an uninitialized
knu authored
471 long v = 0;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
472 int base, bignum = 0;
473 int len, pos;
64ad39d @knu Merge from ruby_1_8.
knu authored
474 volatile VALUE tmp;
634ea6c @akr * sprintf.c (rb_str_format): fix a GC problem.
akr authored
475 volatile VALUE tmp1;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
476
477 switch (*p) {
478 case 'd':
479 case 'i':
480 sign = 1; break;
481 case 'o':
482 case 'x':
483 case 'X':
484 case 'b':
2b65285 * class.c (rb_mod_clone): should not copy class name, since clone
matz authored
485 case 'B':
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
486 case 'u':
487 default:
488 if (flags&(FPLUS|FSPACE)) sign = 1;
489 break;
490 }
491 if (flags & FSHARP) {
379adab @knu * sprintf.c (rb_f_sprintf): Fix a bug caused by an uninitialized
knu authored
492 switch (*p) {
493 case 'o':
494 prefix = "0"; break;
495 case 'x':
496 prefix = "0x"; break;
497 case 'X':
498 prefix = "0X"; break;
499 case 'b':
500 prefix = "0b"; break;
501 case 'B':
502 prefix = "0B"; break;
503 }
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
504 if (prefix) {
505 width -= strlen(prefix);
506 }
507 }
99d0354 Initial revision
matz authored
508
509 bin_retry:
510 switch (TYPE(val)) {
511 case T_FLOAT:
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
512 val = rb_dbl2big(RFLOAT(val)->value);
513 if (FIXNUM_P(val)) goto bin_retry;
99d0354 Initial revision
matz authored
514 bignum = 1;
515 break;
516 case T_STRING:
3a28abf @nobu * intern.h: prototypes for new functions; rb_cstr_to_inum(),
nobu authored
517 val = rb_str_to_inum(val, 0, Qtrue);
99d0354 Initial revision
matz authored
518 goto bin_retry;
519 case T_BIGNUM:
520 bignum = 1;
521 break;
56e60da 20000105
matz authored
522 case T_FIXNUM:
523 v = FIX2LONG(val);
99d0354 Initial revision
matz authored
524 break;
6d3df63 * variable.c (rb_obj_remove_instance_variable): raise NameError if
matz authored
525 default:
31230ec * string.c (rb_str_aset): should raise error if an indexing string
matz authored
526 val = rb_Integer(val);
527 goto bin_retry;
99d0354 Initial revision
matz authored
528 }
529
379adab @knu * sprintf.c (rb_f_sprintf): Fix a bug caused by an uninitialized
knu authored
530 switch (*p) {
531 case 'o':
532 base = 8; break;
533 case 'x':
534 case 'X':
535 base = 16; break;
536 case 'b':
537 case 'B':
538 base = 2; break;
539 case 'u':
540 case 'd':
541 case 'i':
542 default:
543 base = 10; break;
544 }
18d4461 @nobu * sprintf.c (rb_f_sprintf): more checks for format argument.
nobu authored
545
99d0354 Initial revision
matz authored
546 if (!bignum) {
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
547 if (base == 2) {
548 val = rb_int2big(v);
549 goto bin_retry;
99d0354 Initial revision
matz authored
550 }
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
551 if (sign) {
552 char c = *p;
553 if (c == 'i') c = 'd'; /* %d and %i are identical */
99d0354 Initial revision
matz authored
554 if (v < 0) {
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
555 v = -v;
556 sc = '-';
557 width--;
99d0354 Initial revision
matz authored
558 }
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
559 else if (flags & FPLUS) {
560 sc = '+';
561 width--;
99d0354 Initial revision
matz authored
562 }
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
563 else if (flags & FSPACE) {
564 sc = ' ';
565 width--;
566 }
567 sprintf(fbuf, "%%l%c", c);
568 sprintf(nbuf, fbuf, v);
99d0354 Initial revision
matz authored
569 s = nbuf;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
570 goto format_integer;
571 }
572 s = nbuf;
573 if (v < 0) {
8551a01 * ext/socket/socket.c (bsock_do_not_rev_lookup_set): should not be
matz authored
574 if (base == 10) {
575 rb_warning("negative number for %%u specifier");
576 }
b88714d * eval.c (return_jump): set return value to the return
matz authored
577 if (!(flags&(FPREC|FZERO))) {
8551a01 * ext/socket/socket.c (bsock_do_not_rev_lookup_set): should not be
matz authored
578 strcpy(s, "..");
579 s += 2;
580 }
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
581 }
aec6e76 @nobu * sprintf.c (rb_f_sprintf): remove extra sign digit.
nobu authored
582 sprintf(fbuf, "%%l%c", *p == 'X' ? 'x' : *p);
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
583 sprintf(s, fbuf, v);
584 if (v < 0) {
585 char d = 0;
586
587 remove_sign_bits(s, base);
588 switch (base) {
589 case 16:
6d3df63 * variable.c (rb_obj_remove_instance_variable): raise NameError if
matz authored
590 d = 'f'; break;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
591 case 8:
592 d = '7'; break;
593 }
594 if (d && *s != d) {
595 memmove(s+1, s, strlen(s)+1);
596 *s = d;
597 }
99d0354 Initial revision
matz authored
598 }
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
599 s = nbuf;
600 goto format_integer;
99d0354 Initial revision
matz authored
601 }
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
602
603 if (sign) {
b88714d * eval.c (return_jump): set return value to the return
matz authored
604 tmp = rb_big2str(val, base);
605 s = RSTRING(tmp)->ptr;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
606 if (s[0] == '-') {
607 s++;
608 sc = '-';
8ecb2ae * random.c (rb_f_rand): normalize bignum argument.
matz authored
609 width--;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
610 }
611 else if (flags & FPLUS) {
612 sc = '+';
8ecb2ae * random.c (rb_f_rand): normalize bignum argument.
matz authored
613 width--;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
614 }
615 else if (flags & FSPACE) {
616 sc = ' ';
8ecb2ae * random.c (rb_f_rand): normalize bignum argument.
matz authored
617 width--;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
618 }
619 goto format_integer;
620 }
621 if (!RBIGNUM(val)->sign) {
622 val = rb_big_clone(val);
623 rb_big_2comp(val);
99d0354 Initial revision
matz authored
624 }
6b0bde0 * sprintf.c (rb_str_format): should preserve leading zero
matz authored
625 tmp1 = tmp = rb_big2str0(val, base, RBIGNUM(val)->sign);
b88714d * eval.c (return_jump): set return value to the return
matz authored
626 s = RSTRING(tmp)->ptr;
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
627 if (*s == '-') {
8551a01 * ext/socket/socket.c (bsock_do_not_rev_lookup_set): should not be
matz authored
628 if (base == 10) {
629 rb_warning("negative number for %%u specifier");
630 }
c71a0a9 @nobu * sprintf.c (rb_f_sprintf): prepend ".." to %u for negative bignum,
nobu authored
631 remove_sign_bits(++s, base);
632 tmp = rb_str_new(0, 3+strlen(s));
633 t = RSTRING(tmp)->ptr;
634 if (!(flags&(FPREC|FZERO))) {
635 strcpy(t, "..");
636 t += 2;
637 }
638 switch (base) {
639 case 16:
640 if (s[0] != 'f') strcpy(t++, "f"); break;
641 case 8:
642 if (s[0] != '7') strcpy(t++, "7"); break;
643 case 2:
644 if (s[0] != '1') strcpy(t++, "1"); break;
99d0354 Initial revision
matz authored
645 }
c71a0a9 @nobu * sprintf.c (rb_f_sprintf): prepend ".." to %u for negative bignum,
nobu authored
646 strcpy(t, s);
647 bignum = 2;
99d0354 Initial revision
matz authored
648 }
b88714d * eval.c (return_jump): set return value to the return
matz authored
649 s = RSTRING(tmp)->ptr;
99d0354 Initial revision
matz authored
650
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
651 format_integer:
652 pos = -1;
653 len = strlen(s);
654
655 if (*p == 'X') {
656 char *pp = s;
657 while (*pp) {
658 *pp = toupper(*pp);
659 pp++;
99d0354 Initial revision
matz authored
660 }
661 }
9ef84c8 * sprintf.c (rb_f_sprintf): preceding ".." for negative numbers
matz authored
662 if ((flags&(FZERO|FPREC)) == FZERO) {
663 prec = width;
664 width = 0;
665 }
666 else {
667 if (prec < len) prec = len;
668 width -= prec;
669 }
670 if (!(flags&FMINUS)) {
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
671 CHECK(width);
9ef84c8 * sprintf.c (rb_f_sprintf): preceding ".." for negative numbers
matz authored
672 while (width-- > 0) {
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
673 buf[blen++] = ' ';
99d0354 Initial revision
matz authored
674 }
675 }
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
676 if (sc) PUSH(&sc, 1);
677 if (prefix) {
678 int plen = strlen(prefix);
6e52592 m17n cleanup ;_;
matz authored
679 PUSH(prefix, plen);
99d0354 Initial revision
matz authored
680 }
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
681 CHECK(prec - len);
379adab @knu * sprintf.c (rb_f_sprintf): Fix a bug caused by an uninitialized
knu authored
682 if (!bignum && v < 0) {
7268098 * eval.c (load_dyna): clear ruby_errinfo. (ruby-bugs-ja PR#409)
matz authored
683 char c = sign_bits(base, p);
9ef84c8 * sprintf.c (rb_f_sprintf): preceding ".." for negative numbers
matz authored
684 while (len < prec--) {
685 buf[blen++] = c;
99d0354 Initial revision
matz authored
686 }
687 }
9ef84c8 * sprintf.c (rb_f_sprintf): preceding ".." for negative numbers
matz authored
688 else {
9239b07 * sprintf.c (rb_f_sprintf): copy sign bits only if value is
matz authored
689 char c;
690
0177091 @nobu * sprintf.c (rb_f_sprintf): sign bit extension should not be done
nobu authored
691 if (!sign && bignum && !RBIGNUM(val)->sign)
9239b07 * sprintf.c (rb_f_sprintf): copy sign bits only if value is
matz authored
692 c = sign_bits(base, p);
693 else
694 c = '0';
9ef84c8 * sprintf.c (rb_f_sprintf): preceding ".." for negative numbers
matz authored
695 while (len < prec--) {
7268098 * eval.c (load_dyna): clear ruby_errinfo. (ruby-bugs-ja PR#409)
matz authored
696 buf[blen++] = c;
9ef84c8 * sprintf.c (rb_f_sprintf): preceding ".." for negative numbers
matz authored
697 }
698 }
699 PUSH(s, len);
700 CHECK(width);
701 while (width-- > 0) {
702 buf[blen++] = ' ';
703 }
99d0354 Initial revision
matz authored
704 }
705 break;
706
707 case 'f':
708 case 'g':
07bb9f2 1.4.0
matz authored
709 case 'G':
99d0354 Initial revision
matz authored
710 case 'e':
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
711 case 'E':
99d0354 Initial revision
matz authored
712 {
713 VALUE val = GETARG();
714 double fval;
07bb9f2 1.4.0
matz authored
715 int i, need = 6;
99d0354 Initial revision
matz authored
716 char fbuf[32];
717
5203cd3 * ruby.c (proc_options): should not alter origargv[].
matz authored
718 fval = RFLOAT(rb_Float(val))->value;
93c6fe8 @unak * sprintf.c (rb_f_sprintf): fix output of NaN, Inf and -Inf with
unak authored
719 #if defined(_WIN32) && !defined(__BORLANDC__)
720 if (isnan(fval) || isinf(fval)) {
95c01b7 @knu Merge changes from ruby_1_8 to reduce warnings and potentially improve
knu authored
721 const char *expr;
93c6fe8 @unak * sprintf.c (rb_f_sprintf): fix output of NaN, Inf and -Inf with
unak authored
722
723 if (isnan(fval)) {
724 expr = "NaN";
725 }
726 else {
727 expr = "Inf";
728 }
729 need = strlen(expr);
730 if ((!isnan(fval) && fval < 0.0) || (flags & FPLUS))
731 need++;
564f3fd @knu Merge from ruby_1_8.
knu authored
732 else if (flags & FSPACE)
733 need++;
93c6fe8 @unak * sprintf.c (rb_f_sprintf): fix output of NaN, Inf and -Inf with
unak authored
734 if ((flags & FWIDTH) && need < width)
735 need = width;
736
737 CHECK(need);
738 sprintf(&buf[blen], "%*s", need, "");
739 if (flags & FMINUS) {
740 if (!isnan(fval) && fval < 0.0)
741 buf[blen++] = '-';
742 else if (flags & FPLUS)
743 buf[blen++] = '+';
744 else if (flags & FSPACE)
745 blen++;
746 strncpy(&buf[blen], expr, strlen(expr));
747 }
748 else if (flags & FZERO) {
749 if (!isnan(fval) && fval < 0.0) {
750 buf[blen++] = '-';
751 need--;
752 }
753 else if (flags & FPLUS) {
754 buf[blen++] = '+';
755 need--;
756 }
757 else if (flags & FSPACE) {
758 blen++;
759 need--;
760 }
761 while (need-- - strlen(expr) > 0) {
762 buf[blen++] = '0';
763 }
764 strncpy(&buf[blen], expr, strlen(expr));
765 }
766 else {
767 if (!isnan(fval) && fval < 0.0)
768 buf[blen + need - strlen(expr) - 1] = '-';
769 else if (flags & FPLUS)
770 buf[blen + need - strlen(expr) - 1] = '+';
771 strncpy(&buf[blen + need - strlen(expr)], expr,
772 strlen(expr));
773 }
774 blen += strlen(&buf[blen]);
775 break;
776 }
777 #endif /* defined(_WIN32) && !defined(__BORLANDC__) */
99d0354 Initial revision
matz authored
778 fmt_setup(fbuf, *p, flags, width, prec);
07bb9f2 1.4.0
matz authored
779 need = 0;
780 if (*p != 'e' && *p != 'E') {
781 i = INT_MIN;
782 frexp(fval, &i);
783 if (i > 0)
784 need = BIT_DIGITS(i);
785 }
786 need += (flags&FPREC) ? prec : 6;
787 if ((flags&FWIDTH) && need < width)
788 need = width;
789 need += 20;
99d0354 Initial revision
matz authored
790
07bb9f2 1.4.0
matz authored
791 CHECK(need);
99d0354 Initial revision
matz authored
792 sprintf(&buf[blen], fbuf, fval);
793 blen += strlen(&buf[blen]);
794 }
795 break;
796 }
797 flags = FNONE;
798 }
799
800 sprint_exit:
54455c2 * eval.c (rb_call0): prohibit calling tainted method (>2) when
matz authored
801 /* XXX - We cannot validiate the number of arguments if (digit)$ style used.
2ee41de 19991111
matz authored
802 */
54455c2 * eval.c (rb_call0): prohibit calling tainted method (>2) when
matz authored
803 if (posarg >= 0 && nextarg < argc) {
804 const char *mesg = "too many arguments for format string";
805 if (RTEST(ruby_debug)) rb_raise(rb_eArgError, mesg);
806 if (RTEST(ruby_verbose)) rb_warn(mesg);
99d0354 Initial revision
matz authored
807 }
646728f @nobu * sprintf.c (rb_f_sprintf): disallow mixed usage of numbered and
nobu authored
808 rb_str_resize(result, blen);
99d0354 Initial revision
matz authored
809
bd5567f 19991206
matz authored
810 if (tainted) OBJ_TAINT(result);
99d0354 Initial revision
matz authored
811 return result;
812 }
813
814 static void
815 fmt_setup(buf, c, flags, width, prec)
1f72ff9 regexp literal (e.g. \202) match, etc.
matz authored
816 char *buf;
817 int c;
99d0354 Initial revision
matz authored
818 int flags, width, prec;
819 {
820 *buf++ = '%';
821 if (flags & FSHARP) *buf++ = '#';
822 if (flags & FPLUS) *buf++ = '+';
823 if (flags & FMINUS) *buf++ = '-';
824 if (flags & FZERO) *buf++ = '0';
a2af08d This commit was generated by cvs2svn to compensate for changes in r372,
matz authored
825 if (flags & FSPACE) *buf++ = ' ';
99d0354 Initial revision
matz authored
826
827 if (flags & FWIDTH) {
828 sprintf(buf, "%d", width);
829 buf += strlen(buf);
830 }
831
832 if (flags & FPREC) {
833 sprintf(buf, ".%d", prec);
834 buf += strlen(buf);
835 }
836
837 *buf++ = c;
838 *buf = '\0';
839 }
Something went wrong with that request. Please try again.