Skip to content
This repository
Newer
Older
100644 907 lines (850 sloc) 26.986 kb
9c1d2307 » Laurent Sansonetti
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 » Laurent Sansonetti
2011-01-15 update copyrights to 2011
6 * Copyright (C) 2007-2011, Apple Inc. All rights reserved.
9c1d2307 » Laurent Sansonetti
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 » Laurent Sansonetti
2009-05-23 the great schism, part I
12 #include <stdarg.h>
13
d0898dd2 » Laurent Sansonetti
2011-01-08 include/ruby/macruby.h -> macruby_internal.h
14 #include "macruby_internal.h"
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
15 #include "ruby/encoding.h"
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
16 #include "encoding.h"
9c1d2307 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
266 ((nth >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : \
267 argv[nth])
9c1d2307 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
295 VALUE result = rb_enc_vsprintf(enc, format, ap);
9c1d2307 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
311 VALUE result = rb_vsprintf(format, ap);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
312 va_end(ap);
313 return result;
314 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
315
da7a6cdf » Watson1978
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 » Laurent Sansonetti
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 » Watson1978
2010-11-26 sprintf() will be given the positional arguments and precision tokens…
336 if (arg == 0 && ref_type != 0 && (type) != ref_type) { \
77a4b423 » Laurent Sansonetti
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 » Laurent Sansonetti
2009-05-23 the great schism, part I
351 static void
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
352 pad_format_value(VALUE arg, long start, long width, VALUE pad)
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
353 {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
354 const long slen = rb_str_chars_len(arg);
77a4b423 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-03-06 some sprintf fixes
363 rb_str_update(arg, start, 0, pad);
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
364 }
365 while (--width > 0);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
366 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
367
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
368 static long
4cecb13e » Laurent Sansonetti
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 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
370 {
4cecb13e » Laurent Sansonetti
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 » Laurent Sansonetti
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 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
380 }
381 if (replace_len != num) {
4cecb13e » Laurent Sansonetti
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 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
384 }
385 if (replace_len > 0) {
d1673a26 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
388 bcopy(replace_chars, *str + start, sizeof(UChar) * replace_len);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
389 }
390 return replace_len - num;
391 }
392
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
393 static VALUE
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
394 get_named_arg(UChar *format_str, long format_len, long *i, VALUE hash)
77a4b423 » Laurent Sansonetti
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 » Laurent Sansonetti
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 » Watson1978
2010-11-26 fixed the bug of sprintf() within "%<named>" format
402 long length = 0;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
403 while (*i < format_len && format_str[*i] != closing) {
404 (*i)++;
18c6303e » Watson1978
2010-11-26 fixed the bug of sprintf() within "%<named>" format
405 length++;
77a4b423 » Laurent Sansonetti
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 » Watson1978
2010-11-26 fixed the bug of sprintf() within "%<named>" format
411 VALUE substr = rb_unicode_str_new(str_ptr, (size_t)length);
4cecb13e » Laurent Sansonetti
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 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
421
422 long format_len = 0;
d1673a26 » Laurent Sansonetti
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 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
429 int j = 0;
430 int ref_type = 0;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
431 long format_str_capa = format_len;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
432
dad943ff » Watson1978
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 » Watson1978
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 » Watson1978
2012-01-30 check whether width is specified after precision
447
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
448 for (long i = 0; i < format_len; i++) {
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
449 if (format_str[i] != '%') {
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
450 continue;
451 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
452 if (format_str[i + 1] == '%') {
a539763d » Laurent Sansonetti
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 » Laurent Sansonetti
2009-05-23 the great schism, part I
455 continue;
456 }
77a4b423 » Laurent Sansonetti
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 » Watson1978
2010-11-23 sprintf() will throw an exception when was given width format twice.
463 bool width_flag = false;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
464 bool precision_flag = false;
9031bde6 » Watson1978
2010-11-26 sprintf() will throw an exception when was given named format twice.
465 bool named_flag = false;
77a4b423 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-03-06 some sprintf fixes
471 VALUE negative_pad = 0;
472 VALUE sharp_pad = rb_str_new2("");
473 const long start = i;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
474
475 while (i++ < format_len) {
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
476 switch (format_str[i]) {
477 case '#':
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
478 CHECK_FOR_FLAGS();
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
479 sharp_flag = true;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
480 break;
481
482 case '*':
42f22c95 » Watson1978
2010-11-23 sprintf() will throw an exception when was given width format twice.
483 CHECK_FOR_WIDTH();
484 width_flag = true;
77a4b423 » Laurent Sansonetti
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 » Laurent Sansonetti
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 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
502 else if (format_str[pos] == '$') {
c9853df5 » Watson1978
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 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
506 SET_REF_TYPE(ABS_REF);
507 width = NUM2LONG(rb_Integer(GETNTHARG(num - 1)));
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
508 i = pos;
77a4b423 » Laurent Sansonetti
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 » Watson1978
2012-01-30 allow omitting width at precision
518 CHECK_FOR_FLAGS();
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
519 if (!plus_flag) {
520 space_flag = true;
521 }
522 break;
523
524 case '+':
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
525 CHECK_FOR_FLAGS();
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
526 plus_flag = true;
527 space_flag = false;
528 break;
529
530 case '-':
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
531 CHECK_FOR_FLAGS();
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
532 zero_flag = false;
533 minus_flag = true;
534 break;
535
536 case '0':
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
537 CHECK_FOR_FLAGS();
77a4b423 » Laurent Sansonetti
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 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
555 if (num == 0) {
556 rb_raise(rb_eArgError, "invalid absolute argument");
557 }
09f5ee7d » Watson1978
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 » Laurent Sansonetti
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 » Watson1978
2010-11-23 sprintf() will throw an exception when was given width format twice.
568 CHECK_FOR_WIDTH();
569 width_flag = true;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
570 }
571 break;
572
573 case '.':
33142627 » Watson1978
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 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
589
590 num = rb_uchar_strtol(format_str, format_len,
591 i, &pos);
225e90fd » Watson1978
2010-11-26 sprintf() will be given a format which is width's * and precision's *.
592 if (format_str[pos] == '$') {
c9853df5 » Watson1978
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 » Laurent Sansonetti
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 » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
599 i = pos;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
600 }
225e90fd » Watson1978
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 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
607 }
608 }
609 else if (isdigit(format_str[i])) {
4cecb13e » Laurent Sansonetti
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 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
613 }
614 else {
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
615 i--;
77a4b423 » Laurent Sansonetti
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 » Watson1978
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
625 {
626 char term = (format_str[i] == '<') ? '>' : '}';
627
9031bde6 » Watson1978
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 }
53b78caf » Watson1978
2012-02-01 fix named argument
631 if (ref_type == ABS_REF) {
26e8df91 » Watson1978
2010-11-26 sprintf() will be given the positional arguments and precision tokens…
632 rb_raise(rb_eArgError, "named after numbered");
633 }
9031bde6 » Watson1978
2010-11-26 sprintf() will throw an exception when was given named format twice.
634 named_flag = true;
53b78caf » Watson1978
2012-02-01 fix named argument
635 ref_type = 0;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
636 SET_REF_TYPE(NAMED_REF);
637 arg = get_named_arg(format_str, format_len, &i,
638 GETNTHARG(0));
d8ba17fe » Watson1978
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
639 if (term == '}') {
640 if (TYPE(arg) != T_STRING) {
641 arg = rb_obj_as_string(arg);
642 }
643 goto format_s;
644 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
645 break;
d8ba17fe » Watson1978
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
646 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
647
648 case 'd':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
649 case 'D':
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
650 case 'i':
651 case 'u':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
652 case 'U':
653 base = 10;
eaf4b4a4 » Watson1978
2011-01-15 Fixed the bug of sprintf. "#" flag should be ignored with "dDiuU" for…
654 sharp_flag = false;
32b2e40c » Watson1978
2011-01-16 Fixed the bug of sprintf with format like a "%010.4u".
655 if (precision_flag) {
656 zero_flag = false;
657 }
658 complete = true;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
659 break;
660
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
661 case 'x':
662 case 'X':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
663 base = 16;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
664 negative_pad = rb_str_new2("f");
665 sharp_pad = rb_str_new2("0x");
1017c7f7 » Watson1978
2011-01-15 Fixed the bug of sprintf with format like a "%010.4f".
666 if (precision_flag) {
667 zero_flag = false;
668 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
669 complete = true;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
670 break;
671
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
672 case 'o':
673 case 'O':
674 base = 8;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
675 negative_pad = rb_str_new2("7");
676 sharp_pad = rb_str_new2("0");
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
677 complete = true;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
678 break;
679
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
680 case 'B':
681 case 'b':
682 base = 2;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
683 negative_pad = rb_str_new2("1");
684 sharp_pad = rb_str_new2("0b");
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
685 complete = true;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
686 break;
687
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
688 case 'c':
689 case 'C':
690 GET_ARG();
691 if (TYPE(arg) == T_STRING) {
abe5fa78 » Watson1978
2010-12-11 sprintf("%c") will throw an exception when does not pass one character.
692 if(RSTRING_LEN(arg) != 1) {
693 rb_raise(rb_eArgError, "%%c requires a character");
694 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
695 }
696 else {
110e3452 » Laurent Sansonetti
2010-03-18 fixed some bugs in Numeric#chr
697 long num = NUM2LONG(arg);
698 if (num < 0 || i > 0xff) {
699 rb_raise(rb_eRangeError, "%ld out of char range",
700 num);
701 }
702 char c = (char)num;
703 arg = rb_str_new(&c, 1);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
704 }
705 complete = true;
706 break;
707
708 case 'f':
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
709 case 'F':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
710 case 'e':
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
711 case 'E':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
712 case 'g':
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
713 case 'G':
714 case 'a':
715 case 'A':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
716 {
717 // here we construct a new format str and then use
718 // c's sprintf. why? because floats are retarded
719 GET_ARG();
720 double value = RFLOAT_VALUE(rb_Float(arg));
721 complete = true;
722
723 if (isnan(value) || isinf(value)) {
724 arg = rb_str_new2((char *)(isnan(value) ? "NaN" :
725 value < 0 ? "-Inf" : "Inf"));
726 if (isnan(value) || value > 0) {
727 if (plus_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
728 rb_str_update(arg, 0, 0, rb_str_new2("+"));
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
729 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
730 else if (space_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
731 rb_str_update(arg, 0, 0, rb_str_new2(" "));
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
732 }
733 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
734 break;
735 }
736
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
737 arg = rb_unicode_str_new(&format_str[i], 1);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
738 if (precision_flag) {
739 rb_str_update(arg, 0, 0, rb_big2str(LONG2NUM(precision),
740 10));
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
741 rb_str_update(arg, 0, 0, rb_str_new2("."));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
742 }
743 rb_str_update(arg, 0, 0, rb_big2str(LONG2NUM(width), 10));
744 if (minus_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
745 rb_str_update(arg, 0, 0, rb_str_new2("-"));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
746 }
747 else if (zero_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
748 rb_str_update(arg, 0, 0, rb_str_new2("0"));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
749 }
750 if (plus_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
751 rb_str_update(arg, 0, 0, rb_str_new2("+"));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
752 }
753 else if (space_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
754 rb_str_update(arg, 0, 0, rb_str_new2(" "));
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
755 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
756 if (sharp_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
757 rb_str_update(arg, 0, 0, rb_str_new2("#"));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
758 }
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
759 rb_str_update(arg, 0, 0, rb_str_new2("%"));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
760
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
761 char *ptr;
762 asprintf(&ptr, RSTRING_PTR(arg), value);
763 arg = rb_str_new2(ptr);
764 free(ptr);
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
765 break;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
766 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
767
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
768 case 's':
769 case 'S':
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
770 case 'p':
771 case '@':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
772 GET_ARG();
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
773 arg = (tolower(format_str[i]) != 's'
774 ? rb_inspect(arg) : TYPE(arg) == T_STRING
775 ? rb_str_new3(arg) : rb_obj_as_string(arg));
d8ba17fe » Watson1978
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
776 format_s:
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
777 if (precision_flag && precision < rb_str_chars_len(arg)) {
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
778 CFStringPad((CFMutableStringRef)arg, NULL, precision,
779 0);
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
780 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
781 complete = true;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
782 break;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
783
b62b4382 » Watson1978
2010-11-22 modified the style of r4928.
784 case '\n':
785 case '\0':
786 if (format_str[i - 1] == '%') {
421ab552 » Watson1978
2010-11-22 sprintf() will not throw exception when passed the format of single %…
787 if (format_str[i] == '\n') {
788 arg = rb_str_new("%\n", 2);
789 }
790 else {
b62b4382 » Watson1978
2010-11-22 modified the style of r4928.
791 if (format_len > i) {
792 arg = rb_str_new("%\0", 2);
793 }
794 else {
795 arg = rb_str_new("%", 1);
796 }
421ab552 » Watson1978
2010-11-22 sprintf() will not throw exception when passed the format of single %…
797 }
798 complete = true;
b62b4382 » Watson1978
2010-11-22 modified the style of r4928.
799 break;
421ab552 » Watson1978
2010-11-22 sprintf() will not throw exception when passed the format of single %…
800 }
b62b4382 » Watson1978
2010-11-22 modified the style of r4928.
801 rb_raise(rb_eArgError, "malformed format string - %%%c",
802 format_str[i]);
803 break;
804
805 default:
806 rb_raise(rb_eArgError, "malformed format string - %%%c",
807 format_str[i]);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
808 }
809 if (!complete) {
810 continue;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
811 }
812
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
813 GET_ARG();
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
814
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
815 if (base != 0) {
816 bool sign_pad = false;
817 unsigned long num_index = 0;
3e1645b5 » Watson1978
2011-01-15 Fixed the bug of sprintf with format "%# x".
818 unsigned long sharp_beg = 0;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
819 VALUE zero_pad = rb_str_new2("0");
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
820
821 VALUE num = rb_Integer(arg);
822 if (TYPE(num) == T_FIXNUM) {
823 num = rb_int2big(FIX2LONG(num));
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
824 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
825 if (plus_flag || space_flag) {
826 sign_pad = 1;
827 }
828 if (IS_NEG(num)) {
829 num_index = 1;
3e1645b5 » Watson1978
2011-01-15 Fixed the bug of sprintf with format "%# x".
830 sharp_beg = 1;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
831 if (!sign_pad && negative_pad != 0) {
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
832 zero_pad = negative_pad;
833 num = rb_big_clone(num);
834 rb_big_2comp(num);
835 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
836 }
837
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
838 arg = rb_big2str(num, base);
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
839 if (!sign_pad && IS_NEG(num) && negative_pad != 0) {
a539763d » Laurent Sansonetti
2010-03-19 fixed a few bugs in #sprintf
840 UChar neg = rb_str_get_uchar(negative_pad, 0);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
841 if (base == 8) {
a539763d » Laurent Sansonetti
2010-03-19 fixed a few bugs in #sprintf
842 UChar c = rb_str_get_uchar(arg, 1);
843 const long len = rb_str_chars_len(arg) - 1;
844 c |= ((~0 << 3) >> ((3 * len)
845 % (sizeof(BDIGIT) * 8))) & ~(~0 << 3);
846 rb_str_update(arg, 1, 1, rb_unicode_str_new(&c, 1));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
847 }
a539763d » Laurent Sansonetti
2010-03-19 fixed a few bugs in #sprintf
848 for (int i = 1, count = rb_str_chars_len(arg); i < count;
849 i++) {
850 if (rb_str_get_uchar(arg, i) != neg) {
851 break;
852 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
853 num_index++;
854 }
a539763d » Laurent Sansonetti
2010-03-19 fixed a few bugs in #sprintf
855 rb_str_update(arg, 0, num_index, negative_pad);
856 rb_str_update(arg, 0, 0, rb_str_new2(".."));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
857 num_index = 2;
3e1645b5 » Watson1978
2011-01-15 Fixed the bug of sprintf with format "%# x".
858 sharp_beg = 0;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
859 }
860 if (precision_flag) {
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
861 pad_format_value(arg, num_index,
862 precision + (IS_NEG(num)
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
863 && (sign_pad || negative_pad == 0) ? 1 : 0),
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
864 zero_pad);
865 }
e9d7b0c8 » Laurent Sansonetti
2010-02-11 sprintf can now be free of C++ evil
866 if (sharp_flag && rb_cmpint(num, Qfalse, Qfalse) != 0) {
3e1645b5 » Watson1978
2011-01-15 Fixed the bug of sprintf with format "%# x".
867 rb_str_update(arg, sharp_beg, 0, (VALUE)sharp_pad);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
868 num_index += 2;
869 }
870 if (sign_pad && RBIGNUM_POSITIVE_P(num)) {
871 rb_str_update(arg, 0, 0, (VALUE)(plus_flag ?
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
872 rb_str_new2("+") : rb_str_new2(" ")));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
873 num_index++;
874 }
875 if (zero_flag) {
876 pad_format_value(arg, num_index, width, zero_pad);
877 }
878 if (ISUPPER(format_str[i])) {
879 CFStringUppercase((CFMutableStringRef)arg, NULL);
880 }
881 }
882
883 if (OBJ_TAINTED(arg)) {
884 tainted = true;
885 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
886
d6e38f5b » Laurent Sansonetti
2010-08-30 #sprintf: don't try to mutate symbols
887 if (TYPE(arg) == T_SYMBOL) {
888 // Because symbols are not mutable and pad_format_value()
889 // mutates its first argument.
890 arg = rb_sym_to_s(arg);
891 }
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
892 pad_format_value(arg, minus_flag ? -1 : 0, width, rb_str_new2(" "));
893 num = cstr_update(&format_str, &format_str_capa, start,
894 i - start + 1, arg);
895 format_len += num;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
896 i += num;
897 break;
898 }
899 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
900
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
901 bail:
902 fmt = rb_unicode_str_new(format_str, format_len);
903 if (tainted) {
904 OBJ_TAINT(fmt);
905 }
906 return fmt;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
907 }
Something went wrong with that request. Please try again.