Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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