Skip to content
This repository
Newer
Older
100644 910 lines (852 sloc) 27.02 kb
9c1d2307 »
2009-03-11 committing experimental branch content
1 /*
2 * MacRuby implementation of Ruby 1.9's sprintf.c.
3 *
4 * This file is covered by the Ruby license. See COPYING for more details.
5 *
95957256 »
2011-01-15 update copyrights to 2011
6 * Copyright (C) 2007-2011, Apple Inc. All rights reserved.
9c1d2307 »
2009-03-11 committing experimental branch content
7 * Copyright (C) 1993-2007 Yukihiro Matsumoto
8 * Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
9 * Copyright (C) 2000 Information-technology Promotion Agency, Japan
10 */
11
cb654164 »
2009-05-23 the great schism, part I
12 #include <stdarg.h>
13
d0898dd2 »
2011-01-08 include/ruby/macruby.h -> macruby_internal.h
14 #include "macruby_internal.h"
9c1d2307 »
2009-03-11 committing experimental branch content
15 #include "ruby/encoding.h"
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
16 #include "encoding.h"
9c1d2307 »
2009-03-11 committing experimental branch content
17
18 /*
19 * call-seq:
20 * format(format_string [, arguments...] ) => string
21 * sprintf(format_string [, arguments...] ) => string
22 *
23 * Returns the string resulting from applying <i>format_string</i> to
24 * any additional arguments. Within the format string, any characters
25 * other than format sequences are copied to the result.
26 *
27 * The syntax of a format sequence is follows.
28 *
29 * %[flags][width][.precision]type
30 *
31 * A format
32 * sequence consists of a percent sign, followed by optional flags,
33 * width, and precision indicators, then terminated with a field type
34 * character. The field type controls how the corresponding
35 * <code>sprintf</code> argument is to be interpreted, while the flags
36 * modify that interpretation.
37 *
38 * The field type characters are:
39 *
40 * Field | Integer Format
41 * ------+--------------------------------------------------------------
42 * b | Convert argument as a binary number.
43 * | Negative numbers will be displayed as a two's complement
44 * | prefixed with `..1'.
45 * B | Equivalent to `b', but uses an uppercase 0B for prefix
46 * | in the alternative format by #.
47 * d | Convert argument as a decimal number.
48 * i | Identical to `d'.
49 * o | Convert argument as an octal number.
50 * | Negative numbers will be displayed as a two's complement
51 * | prefixed with `..7'.
52 * u | Identical to `d'.
53 * x | Convert argument as a hexadecimal number.
54 * | Negative numbers will be displayed as a two's complement
55 * | prefixed with `..f' (representing an infinite string of
56 * | leading 'ff's).
57 * X | Equivalent to `x', but uses uppercase letters.
58 *
59 * Field | Float Format
60 * ------+--------------------------------------------------------------
61 * e | Convert floating point argument into exponential notation
62 * | with one digit before the decimal point as [-]d.dddddde[+-]dd.
63 * | The precision specifies the number of digits after the decimal
64 * | point (defaulting to six).
65 * E | Equivalent to `e', but uses an uppercase E to indicate
66 * | the exponent.
67 * f | Convert floating point argument as [-]ddd.dddddd,
68 * | where the precision specifies the number of digits after
69 * | the decimal point.
70 * g | Convert a floating point number using exponential form
71 * | if the exponent is less than -4 or greater than or
72 * | equal to the precision, or in dd.dddd form otherwise.
73 * | The precision specifies the number of significant digits.
74 * G | Equivalent to `g', but use an uppercase `E' in exponent form.
75 *
76 * Field | Other Format
77 * ------+--------------------------------------------------------------
78 * c | Argument is the numeric code for a single character or
79 * | a single character string itself.
80 * p | The valuing of argument.inspect.
81 * s | Argument is a string to be substituted. If the format
82 * | sequence contains a precision, at most that many characters
83 * | will be copied.
84 *
85 * The flags modifies the behavior of the formats.
86 * The flag characters are:
87 *
88 * Flag | Applies to | Meaning
89 * ---------+---------------+-----------------------------------------
90 * space | bBdiouxX | Leave a space at the start of
91 * | eEfgG | non-negative numbers.
92 * | (numeric fmt) | For `o', `x', `X', `b' and `B', use
93 * | | a minus sign with absolute value for
94 * | | negative values.
95 * ---------+---------------+-----------------------------------------
96 * (digit)$ | all | Specifies the absolute argument number
97 * | | for this field. Absolute and relative
98 * | | argument numbers cannot be mixed in a
99 * | | sprintf string.
100 * ---------+---------------+-----------------------------------------
101 * # | bBoxX | Use an alternative format.
102 * | eEfgG | For the conversions `o', increase the precision
103 * | | until the first digit will be `0' if
104 * | | it is not formatted as complements.
105 * | | For the conversions `x', `X', `b' and `B'
106 * | | on non-zero, prefix the result with ``0x'',
107 * | | ``0X'', ``0b'' and ``0B'', respectively.
108 * | | For `e', `E', `f', `g', and 'G',
109 * | | force a decimal point to be added,
110 * | | even if no digits follow.
111 * | | For `g' and 'G', do not remove trailing zeros.
112 * ---------+---------------+-----------------------------------------
113 * + | bBdiouxX | Add a leading plus sign to non-negative
114 * | eEfgG | numbers.
115 * | (numeric fmt) | For `o', `x', `X', `b' and `B', use
116 * | | a minus sign with absolute value for
117 * | | negative values.
118 * ---------+---------------+-----------------------------------------
119 * - | all | Left-justify the result of this conversion.
120 * ---------+---------------+-----------------------------------------
121 * 0 (zero) | bBdiouxX | Pad with zeros, not spaces.
122 * | eEfgG | For `o', `x', `X', `b' and `B', radix-1
123 * | (numeric fmt) | is used for negative numbers formatted as
124 * | | complements.
125 * ---------+---------------+-----------------------------------------
126 * * | all | Use the next argument as the field width.
127 * | | If negative, left-justify the result. If the
128 * | | asterisk is followed by a number and a dollar
129 * | | sign, use the indicated argument as the width.
130 *
131 * Examples of flags:
132 *
133 * # `+' and space flag specifies the sign of non-negative numbers.
134 * sprintf("%d", 123) #=> "123"
135 * sprintf("%+d", 123) #=> "+123"
136 * sprintf("% d", 123) #=> " 123"
137 *
138 * # `#' flag for `o' increases number of digits to show `0'.
139 * # `+' and space flag changes format of negative numbers.
140 * sprintf("%o", 123) #=> "173"
141 * sprintf("%#o", 123) #=> "0173"
142 * sprintf("%+o", -123) #=> "-173"
143 * sprintf("%o", -123) #=> "..7605"
144 * sprintf("%#o", -123) #=> "..7605"
145 *
146 * # `#' flag for `x' add a prefix `0x' for non-zero numbers.
147 * # `+' and space flag disables complements for negative numbers.
148 * sprintf("%x", 123) #=> "7b"
149 * sprintf("%#x", 123) #=> "0x7b"
150 * sprintf("%+x", -123) #=> "-7b"
151 * sprintf("%x", -123) #=> "..f85"
152 * sprintf("%#x", -123) #=> "0x..f85"
153 * sprintf("%#x", 0) #=> "0"
154 *
155 * # `#' for `X' uses the prefix `0X'.
156 * sprintf("%X", 123) #=> "7B"
157 * sprintf("%#X", 123) #=> "0X7B"
158 *
159 * # `#' flag for `b' add a prefix `0b' for non-zero numbers.
160 * # `+' and space flag disables complements for negative numbers.
161 * sprintf("%b", 123) #=> "1111011"
162 * sprintf("%#b", 123) #=> "0b1111011"
163 * sprintf("%+b", -123) #=> "-1111011"
164 * sprintf("%b", -123) #=> "..10000101"
165 * sprintf("%#b", -123) #=> "0b..10000101"
166 * sprintf("%#b", 0) #=> "0"
167 *
168 * # `#' for `B' uses the prefix `0B'.
169 * sprintf("%B", 123) #=> "1111011"
170 * sprintf("%#B", 123) #=> "0B1111011"
171 *
172 * # `#' for `e' forces to show the decimal point.
173 * sprintf("%.0e", 1) #=> "1e+00"
174 * sprintf("%#.0e", 1) #=> "1.e+00"
175 *
176 * # `#' for `f' forces to show the decimal point.
177 * sprintf("%.0f", 1234) #=> "1234"
178 * sprintf("%#.0f", 1234) #=> "1234."
179 *
180 * # `#' for `g' forces to show the decimal point.
181 * # It also disables stripping lowest zeros.
182 * sprintf("%g", 123.4) #=> "123.4"
183 * sprintf("%#g", 123.4) #=> "123.400"
184 * sprintf("%g", 123456) #=> "123456"
185 * sprintf("%#g", 123456) #=> "123456."
186 *
187 * The field width is an optional integer, followed optionally by a
188 * period and a precision. The width specifies the minimum number of
189 * characters that will be written to the result for this field.
190 *
191 * Examples of width:
192 *
193 * # padding is done by spaces, width=20
194 * # 0 or radix-1. <------------------>
195 * sprintf("%20d", 123) #=> " 123"
196 * sprintf("%+20d", 123) #=> " +123"
197 * sprintf("%020d", 123) #=> "00000000000000000123"
198 * sprintf("%+020d", 123) #=> "+0000000000000000123"
199 * sprintf("% 020d", 123) #=> " 0000000000000000123"
200 * sprintf("%-20d", 123) #=> "123 "
201 * sprintf("%-+20d", 123) #=> "+123 "
202 * sprintf("%- 20d", 123) #=> " 123 "
203 * sprintf("%020x", -123) #=> "..ffffffffffffffff85"
204 *
205 * For
206 * numeric fields, the precision controls the number of decimal places
207 * displayed. For string fields, the precision determines the maximum
208 * number of characters to be copied from the string. (Thus, the format
209 * sequence <code>%10.10s</code> will always contribute exactly ten
210 * characters to the result.)
211 *
212 * Examples of precisions:
213 *
214 * # precision for `d', 'o', 'x' and 'b' is
215 * # minimum number of digits <------>
216 * sprintf("%20.8d", 123) #=> " 00000123"
217 * sprintf("%20.8o", 123) #=> " 00000173"
218 * sprintf("%20.8x", 123) #=> " 0000007b"
219 * sprintf("%20.8b", 123) #=> " 01111011"
220 * sprintf("%20.8d", -123) #=> " -00000123"
221 * sprintf("%20.8o", -123) #=> " ..777605"
222 * sprintf("%20.8x", -123) #=> " ..ffff85"
223 * sprintf("%20.8b", -11) #=> " ..110101"
224 *
225 * # "0x" and "0b" for `#x' and `#b' is not counted for
226 * # precision but "0" for `#o' is counted. <------>
227 * sprintf("%#20.8d", 123) #=> " 00000123"
228 * sprintf("%#20.8o", 123) #=> " 00000173"
229 * sprintf("%#20.8x", 123) #=> " 0x0000007b"
230 * sprintf("%#20.8b", 123) #=> " 0b01111011"
231 * sprintf("%#20.8d", -123) #=> " -00000123"
232 * sprintf("%#20.8o", -123) #=> " ..777605"
233 * sprintf("%#20.8x", -123) #=> " 0x..ffff85"
234 * sprintf("%#20.8b", -11) #=> " 0b..110101"
235 *
236 * # precision for `e' is number of
237 * # digits after the decimal point <------>
238 * sprintf("%20.8e", 1234.56789) #=> " 1.23456789e+03"
239 *
240 * # precision for `f' is number of
241 * # digits after the decimal point <------>
242 * sprintf("%20.8f", 1234.56789) #=> " 1234.56789000"
243 *
244 * # precision for `g' is number of
245 * # significant digits <------->
246 * sprintf("%20.8g", 1234.56789) #=> " 1234.5679"
247 *
248 * # <------->
249 * sprintf("%20.8g", 123456789) #=> " 1.2345679e+08"
250 *
251 * # precision for `s' is
252 * # maximum number of characters <------>
253 * sprintf("%20.8s", "string test") #=> " string t"
254 *
255 * Examples:
256 *
257 * sprintf("%d %04x", 123, 123) #=> "123 007b"
258 * sprintf("%08b '%4s'", 123, 123) #=> "01111011 ' 123'"
259 * sprintf("%1$*2$s %2$d %1$s", "hello", 8) #=> " hello 8 hello"
260 * sprintf("%1$*2$s %2$d", "hello", -8) #=> "hello -8"
261 * sprintf("%+g:% g:%-g", 1.23, 1.23, 1.23) #=> "+1.23: 1.23:1.23"
262 * sprintf("%u", -123) #=> "-123"
263 */
264
265 #define GETNTHARG(nth) \
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
266 ((nth >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : \
267 argv[nth])
9c1d2307 »
2009-03-11 committing experimental branch content
268
269 VALUE
270 rb_f_sprintf_imp(VALUE recv, SEL sel, int argc, VALUE *argv)
271 {
272 return rb_str_format(argc - 1, argv + 1, GETNTHARG(0));
273 }
274
275 VALUE
276 rb_f_sprintf(int argc, const VALUE *argv)
277 {
278 return rb_str_format(argc - 1, argv + 1, GETNTHARG(0));
279 }
280
281 VALUE
282 rb_enc_vsprintf(rb_encoding *enc, const char *fmt, va_list ap)
283 {
284 char buffer[512];
285 int n;
286 n = vsnprintf(buffer, sizeof buffer, fmt, ap);
287 return rb_enc_str_new(buffer, n, enc);
288 }
289
290 VALUE
291 rb_enc_sprintf(rb_encoding *enc, const char *format, ...)
292 {
293 va_list ap;
294 va_start(ap, format);
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
295 VALUE result = rb_enc_vsprintf(enc, format, ap);
9c1d2307 »
2009-03-11 committing experimental branch content
296 va_end(ap);
297 return result;
298 }
299
300 VALUE
301 rb_vsprintf(const char *fmt, va_list ap)
302 {
303 return rb_enc_vsprintf(NULL, fmt, ap);
304 }
305
306 VALUE
307 rb_sprintf(const char *format, ...)
308 {
309 va_list ap;
310 va_start(ap, format);
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
311 VALUE result = rb_vsprintf(format, ap);
9c1d2307 »
2009-03-11 committing experimental branch content
312 va_end(ap);
313 return result;
314 }
cb654164 »
2009-05-23 the great schism, part I
315
da7a6cdf »
2011-12-19 add a rb_str_catf() as CRuby API.
316 VALUE
317 rb_str_catf(VALUE str, const char *format, ...)
318 {
319 va_list ap;
320 va_start(ap, format);
321 VALUE result = rb_vsprintf(format, ap);
322 va_end(ap);
323 rb_str_concat(str, result);
324 return str;
325 }
326
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
327 #define IS_NEG(num) RBIGNUM_NEGATIVE_P(num)
328 #define REL_REF 1
329 #define ABS_REF 2
330 #define NAMED_REF 3
331
332 #define REF_NAME(type) \
333 ((type) == REL_REF ? "relative" : (type) == ABS_REF ? "absolute" : "named")
334
335 #define SET_REF_TYPE(type) \
26e8df91 »
2010-11-26 sprintf() will be given the positional arguments and precision tokens…
336 if (arg == 0 && ref_type != 0 && (type) != ref_type) { \
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
337 rb_raise(rb_eArgError, "can't mix %s references with %s references", \
338 REF_NAME(type), REF_NAME(ref_type)); \
339 } \
340 ref_type = (type);
341
342 #define GET_ARG() \
343 if (arg == 0) { \
344 SET_REF_TYPE(REL_REF); \
345 arg = GETNTHARG(j); \
346 j++; \
347 }
348
349 #define isprenum(ch) ((ch) == '-' || (ch) == ' ' || (ch) == '+')
350
cb654164 »
2009-05-23 the great schism, part I
351 static void
87717e75 »
2010-03-06 some sprintf fixes
352 pad_format_value(VALUE arg, long start, long width, VALUE pad)
cb654164 »
2009-05-23 the great schism, part I
353 {
87717e75 »
2010-03-06 some sprintf fixes
354 const long slen = rb_str_chars_len(arg);
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
355 if (width <= slen) {
356 return;
357 }
358 if (start < 0) {
359 start += slen + 1;
360 }
361 width -= slen;
362 do {
87717e75 »
2010-03-06 some sprintf fixes
363 rb_str_update(arg, start, 0, pad);
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
364 }
365 while (--width > 0);
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
366 }
cb654164 »
2009-05-23 the great schism, part I
367
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
368 static long
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
369 cstr_update(UChar **str, long *str_len, long start, long num, VALUE replace)
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
370 {
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
371 const long len = *str_len;
372 long replace_len = replace == 0 ? 0 : rb_str_chars_len(replace);
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
373 if (start + num > len) {
374 num = len - start;
375 }
376 if (replace_len >= num) {
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
377 *str_len = len + replace_len - num;
378 *str = (UChar *)xrealloc(*str,
379 sizeof(UChar) * (len + replace_len - num));
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
380 }
381 if (replace_len != num) {
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
382 bcopy(*str + start + num, *str + start + replace_len,
383 sizeof(UChar) * (len - start - num));
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
384 }
385 if (replace_len > 0) {
d1673a26 »
2011-01-05 introduce a better unichar API, which should be as fast as before the…
386 RB_STR_GET_UCHARS(replace, replace_chars, replace_len2);
387 assert(replace_len2 == replace_len);
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
388 bcopy(replace_chars, *str + start, sizeof(UChar) * replace_len);
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
389 }
390 return replace_len - num;
391 }
392
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
393 static VALUE
87717e75 »
2010-03-06 some sprintf fixes
394 get_named_arg(UChar *format_str, long format_len, long *i, VALUE hash)
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
395 {
396 if (TYPE(hash) != T_HASH) {
397 rb_raise(rb_eArgError,
398 "hash required for named references");
399 }
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
400 UChar closing = format_str[(*i)++] + 2;
401 UChar *str_ptr = &format_str[*i];
18c6303e »
2010-11-26 fixed the bug of sprintf() within "%<named>" format
402 long length = 0;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
403 while (*i < format_len && format_str[*i] != closing) {
404 (*i)++;
18c6303e »
2010-11-26 fixed the bug of sprintf() within "%<named>" format
405 length++;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
406 }
407 if (*i == format_len) {
408 rb_raise(rb_eArgError,
409 "malformed name - unmatched parenthesis");
410 }
18c6303e »
2010-11-26 fixed the bug of sprintf() within "%<named>" format
411 VALUE substr = rb_unicode_str_new(str_ptr, (size_t)length);
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
412 hash = rb_hash_aref(hash, ID2SYM(rb_intern_str(substr)));
413 return hash;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
414 }
415
416 // XXX look for arguments that are altered but not duped
417 VALUE
418 rb_str_format(int argc, const VALUE *argv, VALUE fmt)
419 {
420 bool tainted = OBJ_TAINTED(fmt);
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
421
422 long format_len = 0;
d1673a26 »
2011-01-05 introduce a better unichar API, which should be as fast as before the…
423 UChar *format_str = rb_str_xcopy_uchars(fmt, &format_len);
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
424 if (format_len == 0) {
425 goto bail;
426 }
427
428 long num, pos;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
429 int j = 0;
430 int ref_type = 0;
87717e75 »
2010-03-06 some sprintf fixes
431 long format_str_capa = format_len;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
432
dad943ff »
2012-01-30 check whether width is specified after precision
433 #define CHECK_FOR_WIDTH() \
434 if (width_flag) { \
435 rb_raise(rb_eArgError, "width given twice"); \
436 } \
437 if (precision_flag) { \
438 rb_raise(rb_eArgError, "width after precision"); \
439 }
95a47d31 »
2012-01-30 allow omitting width at precision
440 #define CHECK_FOR_FLAGS() \
441 if (width_flag) { \
442 rb_raise(rb_eArgError, "flag after width"); \
443 } \
444 if (precision_flag) { \
445 rb_raise(rb_eArgError, "flag after precision"); \
446 }
dad943ff »
2012-01-30 check whether width is specified after precision
447
87717e75 »
2010-03-06 some sprintf fixes
448 for (long i = 0; i < format_len; i++) {
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
449 if (format_str[i] != '%') {
cb654164 »
2009-05-23 the great schism, part I
450 continue;
451 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
452 if (format_str[i + 1] == '%') {
a539763d »
2010-03-19 fixed a few bugs in #sprintf
453 num = cstr_update(&format_str, &format_str_capa, i, 1, 0);
454 format_len += num;
cb654164 »
2009-05-23 the great schism, part I
455 continue;
456 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
457
458 bool sharp_flag = false;
459 bool space_flag = false;
460 bool plus_flag = false;
461 bool minus_flag = false;
462 bool zero_flag = false;
42f22c95 »
2010-11-23 sprintf() will throw an exception when was given width format twice.
463 bool width_flag = false;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
464 bool precision_flag = false;
9031bde6 »
2010-11-26 sprintf() will throw an exception when was given named format twice.
465 bool named_flag = false;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
466 bool complete = false;
467 VALUE arg = 0;
468 long width = 0;
469 long precision = 0;
470 int base = 0;
87717e75 »
2010-03-06 some sprintf fixes
471 VALUE negative_pad = 0;
472 VALUE sharp_pad = rb_str_new2("");
473 const long start = i;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
474
475 while (i++ < format_len) {
cb654164 »
2009-05-23 the great schism, part I
476 switch (format_str[i]) {
477 case '#':
95a47d31 »
2012-01-30 allow omitting width at precision
478 CHECK_FOR_FLAGS();
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
479 sharp_flag = true;
cb654164 »
2009-05-23 the great schism, part I
480 break;
481
482 case '*':
42f22c95 »
2010-11-23 sprintf() will throw an exception when was given width format twice.
483 CHECK_FOR_WIDTH();
484 width_flag = true;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
485 if (format_str[++i] == '<' || format_str[i] == '{') {
486 SET_REF_TYPE(NAMED_REF);
487 width = NUM2LONG(rb_Integer(get_named_arg(format_str,
488 format_len, &i, GETNTHARG(0))));
489 }
490 else {
491 if (isprenum(format_str[i])) {
492 i--;
493 break;
494 }
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
495
496 num = rb_uchar_strtol(format_str, format_len, i, &pos);
497 if (pos == i--) {
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
498 SET_REF_TYPE(REL_REF);
499 width = NUM2LONG(rb_Integer(GETNTHARG(j)));
500 j++;
501 }
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
502 else if (format_str[pos] == '$') {
c9853df5 »
2010-11-23 String#% will throw an ArgumentError when was given "*0$" format.
503 if (num == 0) {
504 rb_raise(rb_eArgError, "invalid absolute argument");
505 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
506 SET_REF_TYPE(ABS_REF);
507 width = NUM2LONG(rb_Integer(GETNTHARG(num - 1)));
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
508 i = pos;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
509 }
510 }
511 if (width < 0) {
512 minus_flag = true;
513 width = -width;
514 }
515 break;
516
517 case ' ':
95a47d31 »
2012-01-30 allow omitting width at precision
518 CHECK_FOR_FLAGS();
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
519 if (!plus_flag) {
520 space_flag = true;
521 }
522 break;
523
524 case '+':
95a47d31 »
2012-01-30 allow omitting width at precision
525 CHECK_FOR_FLAGS();
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
526 plus_flag = true;
527 space_flag = false;
528 break;
529
530 case '-':
95a47d31 »
2012-01-30 allow omitting width at precision
531 CHECK_FOR_FLAGS();
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
532 zero_flag = false;
533 minus_flag = true;
534 break;
535
536 case '0':
95a47d31 »
2012-01-30 allow omitting width at precision
537 CHECK_FOR_FLAGS();
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
538 if (!precision_flag && !minus_flag) {
539 zero_flag = true;
540 }
541 break;
542
543 case '1':
544 case '2':
545 case '3':
546 case '4':
547 case '5':
548 case '6':
549 case '7':
550 case '8':
551 case '9':
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
552 num = rb_uchar_strtol(format_str, format_len, i, &pos);
553 i = pos;
554 if (format_str[pos] == '$') {
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
555 if (num == 0) {
556 rb_raise(rb_eArgError, "invalid absolute argument");
557 }
09f5ee7d »
2010-11-23 sprintf() will throw an exception when was given positional format tw…
558 if (arg != 0) {
559 rb_raise(rb_eArgError, "value given twice");
560 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
561 SET_REF_TYPE(ABS_REF);
562 arg = GETNTHARG(num - 1);
563 }
564 else {
565 SET_REF_TYPE(REL_REF);
566 width = num;
567 i--;
42f22c95 »
2010-11-23 sprintf() will throw an exception when was given width format twice.
568 CHECK_FOR_WIDTH();
569 width_flag = true;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
570 }
571 break;
572
573 case '.':
33142627 »
2010-11-23 sprintf() will throw an exception when was given precision format twice.
574 if (precision_flag) {
575 rb_raise(rb_eArgError, "precision given twice");
576 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
577 precision_flag = true;
578 if (format_str[++i] == '*') {
579 if (format_str[++i] == '<' || format_str[i] == '{') {
580 SET_REF_TYPE(NAMED_REF);
581 precision = NUM2LONG(rb_Integer(get_named_arg(
582 format_str, format_len, &i, GETNTHARG(0))));
583 }
584 else {
585 if (isprenum(format_str[i])) {
586 i--;
587 break;
588 }
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
589
590 num = rb_uchar_strtol(format_str, format_len,
591 i, &pos);
225e90fd »
2010-11-26 sprintf() will be given a format which is width's * and precision's *.
592 if (format_str[pos] == '$') {
c9853df5 »
2010-11-23 String#% will throw an ArgumentError when was given "*0$" format.
593 if (num == 0) {
594 rb_raise(rb_eArgError, "invalid absolute argument");
595 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
596 SET_REF_TYPE(ABS_REF);
597 precision = NUM2LONG(rb_Integer(GETNTHARG(
598 num - 1)));
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
599 i = pos;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
600 }
225e90fd »
2010-11-26 sprintf() will be given a format which is width's * and precision's *.
601 else {
602 SET_REF_TYPE(REL_REF);
603 precision = NUM2LONG(rb_Integer(GETNTHARG(j)));
604 j++;
605 i--;
606 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
607 }
608 }
609 else if (isdigit(format_str[i])) {
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
610 precision = rb_uchar_strtol(format_str, format_len,
611 i, &pos);
612 i = pos - 1;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
613 }
614 else {
95a47d31 »
2012-01-30 allow omitting width at precision
615 i--;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
616 }
617
618 if (precision < 0) {
619 precision = 0;
620 }
621 break;
622
623 case '<':
624 case '{':
d8ba17fe »
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
625 {
626 char term = (format_str[i] == '<') ? '>' : '}';
627
9031bde6 »
2010-11-26 sprintf() will throw an exception when was given named format twice.
628 if (named_flag) {
629 rb_raise(rb_eArgError, "named given twice");
630 }
26e8df91 »
2010-11-26 sprintf() will be given the positional arguments and precision tokens…
631 if (ref_type != 0) {
632 rb_raise(rb_eArgError, "named after numbered");
633 }
9031bde6 »
2010-11-26 sprintf() will throw an exception when was given named format twice.
634 named_flag = true;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
635 SET_REF_TYPE(NAMED_REF);
636 arg = get_named_arg(format_str, format_len, &i,
637 GETNTHARG(0));
d8ba17fe »
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
638 if (term == '}') {
639 if (TYPE(arg) != T_STRING) {
640 arg = rb_obj_as_string(arg);
641 }
642 goto format_s;
643 }
cb654164 »
2009-05-23 the great schism, part I
644 break;
d8ba17fe »
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
645 }
cb654164 »
2009-05-23 the great schism, part I
646
647 case 'd':
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
648 case 'D':
cb654164 »
2009-05-23 the great schism, part I
649 case 'i':
650 case 'u':
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
651 case 'U':
652 base = 10;
eaf4b4a4 »
2011-01-15 Fixed the bug of sprintf. "#" flag should be ignored with "dDiuU" for…
653 sharp_flag = false;
32b2e40c »
2011-01-16 Fixed the bug of sprintf with format like a "%010.4u".
654 if (precision_flag) {
655 zero_flag = false;
656 }
657 complete = true;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
658 break;
659
cb654164 »
2009-05-23 the great schism, part I
660 case 'x':
661 case 'X':
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
662 base = 16;
87717e75 »
2010-03-06 some sprintf fixes
663 negative_pad = rb_str_new2("f");
664 sharp_pad = rb_str_new2("0x");
1017c7f7 »
2011-01-15 Fixed the bug of sprintf with format like a "%010.4f".
665 if (precision_flag) {
666 zero_flag = false;
667 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
668 complete = true;
cb654164 »
2009-05-23 the great schism, part I
669 break;
670
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
671 case 'o':
672 case 'O':
673 base = 8;
87717e75 »
2010-03-06 some sprintf fixes
674 negative_pad = rb_str_new2("7");
675 sharp_pad = rb_str_new2("0");
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
676 complete = true;
cb654164 »
2009-05-23 the great schism, part I
677 break;
678
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
679 case 'B':
680 case 'b':
681 base = 2;
87717e75 »
2010-03-06 some sprintf fixes
682 negative_pad = rb_str_new2("1");
683 sharp_pad = rb_str_new2("0b");
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
684 complete = true;
cb654164 »
2009-05-23 the great schism, part I
685 break;
686
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
687 case 'c':
688 case 'C':
689 GET_ARG();
690 if (TYPE(arg) == T_STRING) {
abe5fa78 »
2010-12-11 sprintf("%c") will throw an exception when does not pass one character.
691 if(RSTRING_LEN(arg) != 1) {
692 rb_raise(rb_eArgError, "%%c requires a character");
693 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
694 }
695 else {
110e3452 »
2010-03-18 fixed some bugs in Numeric#chr
696 long num = NUM2LONG(arg);
697 if (num < 0 || i > 0xff) {
698 rb_raise(rb_eRangeError, "%ld out of char range",
699 num);
700 }
701 char c = (char)num;
702 arg = rb_str_new(&c, 1);
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
703 }
704 complete = true;
705 break;
706
707 case 'f':
cb654164 »
2009-05-23 the great schism, part I
708 case 'F':
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
709 case 'e':
cb654164 »
2009-05-23 the great schism, part I
710 case 'E':
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
711 case 'g':
cb654164 »
2009-05-23 the great schism, part I
712 case 'G':
713 case 'a':
714 case 'A':
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
715 {
716 // here we construct a new format str and then use
717 // c's sprintf. why? because floats are retarded
718 GET_ARG();
719 double value = RFLOAT_VALUE(rb_Float(arg));
720 complete = true;
721
722 if (isnan(value) || isinf(value)) {
723 arg = rb_str_new2((char *)(isnan(value) ? "NaN" :
724 value < 0 ? "-Inf" : "Inf"));
725 if (isnan(value) || value > 0) {
726 if (plus_flag) {
87717e75 »
2010-03-06 some sprintf fixes
727 rb_str_update(arg, 0, 0, rb_str_new2("+"));
cb654164 »
2009-05-23 the great schism, part I
728 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
729 else if (space_flag) {
87717e75 »
2010-03-06 some sprintf fixes
730 rb_str_update(arg, 0, 0, rb_str_new2(" "));
cb654164 »
2009-05-23 the great schism, part I
731 }
732 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
733 break;
734 }
735
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
736 arg = rb_unicode_str_new(&format_str[i], 1);
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
737 if (precision_flag) {
738 rb_str_update(arg, 0, 0, rb_big2str(LONG2NUM(precision),
739 10));
87717e75 »
2010-03-06 some sprintf fixes
740 rb_str_update(arg, 0, 0, rb_str_new2("."));
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
741 }
742 rb_str_update(arg, 0, 0, rb_big2str(LONG2NUM(width), 10));
743 if (minus_flag) {
87717e75 »
2010-03-06 some sprintf fixes
744 rb_str_update(arg, 0, 0, rb_str_new2("-"));
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
745 }
746 else if (zero_flag) {
87717e75 »
2010-03-06 some sprintf fixes
747 rb_str_update(arg, 0, 0, rb_str_new2("0"));
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
748 }
749 if (plus_flag) {
87717e75 »
2010-03-06 some sprintf fixes
750 rb_str_update(arg, 0, 0, rb_str_new2("+"));
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
751 }
752 else if (space_flag) {
87717e75 »
2010-03-06 some sprintf fixes
753 rb_str_update(arg, 0, 0, rb_str_new2(" "));
cb654164 »
2009-05-23 the great schism, part I
754 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
755 if (sharp_flag) {
87717e75 »
2010-03-06 some sprintf fixes
756 rb_str_update(arg, 0, 0, rb_str_new2("#"));
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
757 }
87717e75 »
2010-03-06 some sprintf fixes
758 rb_str_update(arg, 0, 0, rb_str_new2("%"));
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
759
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
760 char *ptr;
761 asprintf(&ptr, RSTRING_PTR(arg), value);
762 arg = rb_str_new2(ptr);
763 free(ptr);
cb654164 »
2009-05-23 the great schism, part I
764 break;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
765 }
cb654164 »
2009-05-23 the great schism, part I
766
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
767 case 's':
768 case 'S':
cb654164 »
2009-05-23 the great schism, part I
769 case 'p':
770 case '@':
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
771 GET_ARG();
87717e75 »
2010-03-06 some sprintf fixes
772 arg = (tolower(format_str[i]) != 's'
773 ? rb_inspect(arg) : TYPE(arg) == T_STRING
774 ? rb_str_new3(arg) : rb_obj_as_string(arg));
d8ba17fe »
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
775 format_s:
87717e75 »
2010-03-06 some sprintf fixes
776 if (precision_flag && precision < rb_str_chars_len(arg)) {
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
777 CFStringPad((CFMutableStringRef)arg, NULL, precision,
778 0);
cb654164 »
2009-05-23 the great schism, part I
779 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
780 complete = true;
cb654164 »
2009-05-23 the great schism, part I
781 break;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
782
b62b4382 »
2010-11-22 modified the style of r4928.
783 case '\n':
784 case '\0':
785 if (format_str[i - 1] == '%') {
421ab552 »
2010-11-22 sprintf() will not throw exception when passed the format of single %…
786 if (format_str[i] == '\n') {
787 arg = rb_str_new("%\n", 2);
788 }
789 else {
b62b4382 »
2010-11-22 modified the style of r4928.
790 if (format_len > i) {
791 arg = rb_str_new("%\0", 2);
792 }
793 else {
794 arg = rb_str_new("%", 1);
795 }
421ab552 »
2010-11-22 sprintf() will not throw exception when passed the format of single %…
796 }
797 complete = true;
b62b4382 »
2010-11-22 modified the style of r4928.
798 break;
421ab552 »
2010-11-22 sprintf() will not throw exception when passed the format of single %…
799 }
b62b4382 »
2010-11-22 modified the style of r4928.
800 rb_raise(rb_eArgError, "malformed format string - %%%c",
801 format_str[i]);
802 break;
803
804 default:
805 rb_raise(rb_eArgError, "malformed format string - %%%c",
806 format_str[i]);
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
807 }
808 if (!complete) {
809 continue;
cb654164 »
2009-05-23 the great schism, part I
810 }
811
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
812 GET_ARG();
cb654164 »
2009-05-23 the great schism, part I
813
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
814 if (base != 0) {
815 bool sign_pad = false;
816 unsigned long num_index = 0;
3e1645b5 »
2011-01-15 Fixed the bug of sprintf with format "%# x".
817 unsigned long sharp_beg = 0;
87717e75 »
2010-03-06 some sprintf fixes
818 VALUE zero_pad = rb_str_new2("0");
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
819
820 VALUE num = rb_Integer(arg);
821 if (TYPE(num) == T_FIXNUM) {
822 num = rb_int2big(FIX2LONG(num));
cb654164 »
2009-05-23 the great schism, part I
823 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
824 if (plus_flag || space_flag) {
825 sign_pad = 1;
826 }
827 if (IS_NEG(num)) {
828 num_index = 1;
3e1645b5 »
2011-01-15 Fixed the bug of sprintf with format "%# x".
829 sharp_beg = 1;
87717e75 »
2010-03-06 some sprintf fixes
830 if (!sign_pad && negative_pad != 0) {
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
831 zero_pad = negative_pad;
832 num = rb_big_clone(num);
833 rb_big_2comp(num);
834 }
cb654164 »
2009-05-23 the great schism, part I
835 }
836
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
837 arg = rb_big2str(num, base);
87717e75 »
2010-03-06 some sprintf fixes
838 if (!sign_pad && IS_NEG(num) && negative_pad != 0) {
a539763d »
2010-03-19 fixed a few bugs in #sprintf
839 UChar neg = rb_str_get_uchar(negative_pad, 0);
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
840 if (base == 8) {
a539763d »
2010-03-19 fixed a few bugs in #sprintf
841 UChar c = rb_str_get_uchar(arg, 1);
842 const long len = rb_str_chars_len(arg) - 1;
843 c |= ((~0 << 3) >> ((3 * len)
844 % (sizeof(BDIGIT) * 8))) & ~(~0 << 3);
845 rb_str_update(arg, 1, 1, rb_unicode_str_new(&c, 1));
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
846 }
a539763d »
2010-03-19 fixed a few bugs in #sprintf
847 for (int i = 1, count = rb_str_chars_len(arg); i < count;
848 i++) {
849 if (rb_str_get_uchar(arg, i) != neg) {
850 break;
851 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
852 num_index++;
853 }
a539763d »
2010-03-19 fixed a few bugs in #sprintf
854 rb_str_update(arg, 0, num_index, negative_pad);
855 rb_str_update(arg, 0, 0, rb_str_new2(".."));
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
856 num_index = 2;
3e1645b5 »
2011-01-15 Fixed the bug of sprintf with format "%# x".
857 sharp_beg = 0;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
858 }
859 if (precision_flag) {
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
860 pad_format_value(arg, num_index,
861 precision + (IS_NEG(num)
87717e75 »
2010-03-06 some sprintf fixes
862 && (sign_pad || negative_pad == 0) ? 1 : 0),
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
863 zero_pad);
864 }
e9d7b0c8 »
2010-02-11 sprintf can now be free of C++ evil
865 if (sharp_flag && rb_cmpint(num, Qfalse, Qfalse) != 0) {
3e1645b5 »
2011-01-15 Fixed the bug of sprintf with format "%# x".
866 rb_str_update(arg, sharp_beg, 0, (VALUE)sharp_pad);
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
867 num_index += 2;
868 }
869 if (sign_pad && RBIGNUM_POSITIVE_P(num)) {
870 rb_str_update(arg, 0, 0, (VALUE)(plus_flag ?
87717e75 »
2010-03-06 some sprintf fixes
871 rb_str_new2("+") : rb_str_new2(" ")));
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
872 num_index++;
873 }
874 if (zero_flag) {
875 pad_format_value(arg, num_index, width, zero_pad);
876 }
877 if (ISUPPER(format_str[i])) {
878 CFStringUppercase((CFMutableStringRef)arg, NULL);
879 }
880 }
881
882 if (OBJ_TAINTED(arg)) {
883 tainted = true;
884 }
cb654164 »
2009-05-23 the great schism, part I
885
d6e38f5b »
2010-08-30 #sprintf: don't try to mutate symbols
886 if (TYPE(arg) == T_SYMBOL) {
887 // Because symbols are not mutable and pad_format_value()
888 // mutates its first argument.
889 arg = rb_sym_to_s(arg);
890 }
87717e75 »
2010-03-06 some sprintf fixes
891 pad_format_value(arg, minus_flag ? -1 : 0, width, rb_str_new2(" "));
892 num = cstr_update(&format_str, &format_str_capa, start,
893 i - start + 1, arg);
894 format_len += num;
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
895 i += num;
b78d2b61 »
2012-01-29 allow multiple named argument in String#%. fix #1342
896 if (ref_type == NAMED_REF) {
897 SET_REF_TYPE(0);
898 }
77a4b423 »
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
899 break;
900 }
901 }
cb654164 »
2009-05-23 the great schism, part I
902
4cecb13e »
2010-03-02 unicode string formats (a work in progress)
903 bail:
904 fmt = rb_unicode_str_new(format_str, format_len);
905 if (tainted) {
906 OBJ_TAINT(fmt);
907 }
908 return fmt;
cb654164 »
2009-05-23 the great schism, part I
909 }
Something went wrong with that request. Please try again.