Skip to content
This repository
Newer
Older
100644 908 lines (851 sloc) 27.048 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 *
7d7d3e80 » ferrous26
2012-04-22 Change ownership to The MacRuby Team and update copyrights
6 * Copyright (C) 2012, The MacRuby Team. All rights reserved.
95957256 » Laurent Sansonetti
2011-01-15 update copyrights to 2011
7 * Copyright (C) 2007-2011, Apple Inc. All rights reserved.
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
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
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
13 #include <stdarg.h>
14
d0898dd2 » Laurent Sansonetti
2011-01-08 include/ruby/macruby.h -> macruby_internal.h
15 #include "macruby_internal.h"
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
16 #include "ruby/encoding.h"
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
17 #include "encoding.h"
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
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) \
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
267 ((nth >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : \
268 argv[nth])
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
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);
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
296 VALUE result = rb_enc_vsprintf(enc, format, ap);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
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);
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
312 VALUE result = rb_vsprintf(format, ap);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
313 va_end(ap);
314 return result;
315 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
316
da7a6cdf » Watson1978
2011-12-19 add a rb_str_catf() as CRuby API.
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
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
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) \
26e8df91 » Watson1978
2010-11-26 sprintf() will be given the positional arguments and precision tokens…
337 if (arg == 0 && ref_type != 0 && (type) != ref_type) { \
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
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
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
352 static void
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
353 pad_format_value(VALUE arg, long start, long width, VALUE pad)
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
354 {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
355 const long slen = rb_str_chars_len(arg);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
356 if (width <= slen) {
357 return;
358 }
359 if (start < 0) {
360 start += slen + 1;
361 }
362 width -= slen;
363 do {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
364 rb_str_update(arg, start, 0, pad);
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
365 }
366 while (--width > 0);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
367 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
368
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
369 static long
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
370 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)
371 {
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
372 const long len = *str_len;
373 long replace_len = replace == 0 ? 0 : rb_str_chars_len(replace);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
374 if (start + num > len) {
375 num = len - start;
376 }
377 if (replace_len >= num) {
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
378 *str_len = len + replace_len - num;
379 *str = (UChar *)xrealloc(*str,
380 sizeof(UChar) * (len + replace_len - num));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
381 }
382 if (replace_len != num) {
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
383 bcopy(*str + start + num, *str + start + replace_len,
384 sizeof(UChar) * (len - start - num));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
385 }
386 if (replace_len > 0) {
d1673a26 » Laurent Sansonetti
2011-01-05 introduce a better unichar API, which should be as fast as before the…
387 RB_STR_GET_UCHARS(replace, replace_chars, replace_len2);
388 assert(replace_len2 == replace_len);
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
389 bcopy(replace_chars, *str + start, sizeof(UChar) * replace_len);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
390 }
391 return replace_len - num;
392 }
393
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
394 static VALUE
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
395 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)
396 {
397 if (TYPE(hash) != T_HASH) {
398 rb_raise(rb_eArgError,
399 "hash required for named references");
400 }
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
401 UChar closing = format_str[(*i)++] + 2;
402 UChar *str_ptr = &format_str[*i];
18c6303e » Watson1978
2010-11-26 fixed the bug of sprintf() within "%<named>" format
403 long length = 0;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
404 while (*i < format_len && format_str[*i] != closing) {
405 (*i)++;
18c6303e » Watson1978
2010-11-26 fixed the bug of sprintf() within "%<named>" format
406 length++;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
407 }
408 if (*i == format_len) {
409 rb_raise(rb_eArgError,
410 "malformed name - unmatched parenthesis");
411 }
18c6303e » Watson1978
2010-11-26 fixed the bug of sprintf() within "%<named>" format
412 VALUE substr = rb_unicode_str_new(str_ptr, (size_t)length);
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
413 hash = rb_hash_aref(hash, ID2SYM(rb_intern_str(substr)));
414 return hash;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
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);
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
422
423 long format_len = 0;
d1673a26 » Laurent Sansonetti
2011-01-05 introduce a better unichar API, which should be as fast as before the…
424 UChar *format_str = rb_str_xcopy_uchars(fmt, &format_len);
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
425 if (format_len == 0) {
426 goto bail;
427 }
428
429 long num, pos;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
430 int j = 0;
431 int ref_type = 0;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
432 long format_str_capa = format_len;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
433
dad943ff » Watson1978
2012-01-30 check whether width is specified after precision
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 }
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
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 }
dad943ff » Watson1978
2012-01-30 check whether width is specified after precision
448
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
449 for (long i = 0; i < format_len; i++) {
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
450 if (format_str[i] != '%') {
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
451 continue;
452 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
453 if (format_str[i + 1] == '%') {
a539763d » Laurent Sansonetti
2010-03-19 fixed a few bugs in #sprintf
454 num = cstr_update(&format_str, &format_str_capa, i, 1, 0);
455 format_len += num;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
456 continue;
457 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
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;
42f22c95 » Watson1978
2010-11-23 sprintf() will throw an exception when was given width format twice.
464 bool width_flag = false;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
465 bool precision_flag = false;
9031bde6 » Watson1978
2010-11-26 sprintf() will throw an exception when was given named format twice.
466 bool named_flag = false;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
467 bool complete = false;
468 VALUE arg = 0;
469 long width = 0;
470 long precision = 0;
471 int base = 0;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
472 VALUE negative_pad = 0;
473 VALUE sharp_pad = rb_str_new2("");
474 const long start = i;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
475
476 while (i++ < format_len) {
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
477 switch (format_str[i]) {
478 case '#':
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
479 CHECK_FOR_FLAGS();
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
480 sharp_flag = true;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
481 break;
482
483 case '*':
42f22c95 » Watson1978
2010-11-23 sprintf() will throw an exception when was given width format twice.
484 CHECK_FOR_WIDTH();
485 width_flag = true;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
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 }
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
496
497 num = rb_uchar_strtol(format_str, format_len, i, &pos);
498 if (pos == i--) {
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
499 SET_REF_TYPE(REL_REF);
500 width = NUM2LONG(rb_Integer(GETNTHARG(j)));
501 j++;
502 }
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
503 else if (format_str[pos] == '$') {
c9853df5 » Watson1978
2010-11-23 String#% will throw an ArgumentError when was given "*0$" format.
504 if (num == 0) {
505 rb_raise(rb_eArgError, "invalid absolute argument");
506 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
507 SET_REF_TYPE(ABS_REF);
508 width = NUM2LONG(rb_Integer(GETNTHARG(num - 1)));
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
509 i = pos;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
510 }
511 }
512 if (width < 0) {
513 minus_flag = true;
514 width = -width;
515 }
516 break;
517
518 case ' ':
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
519 CHECK_FOR_FLAGS();
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
520 if (!plus_flag) {
521 space_flag = true;
522 }
523 break;
524
525 case '+':
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
526 CHECK_FOR_FLAGS();
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
527 plus_flag = true;
528 space_flag = false;
529 break;
530
531 case '-':
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
532 CHECK_FOR_FLAGS();
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
533 zero_flag = false;
534 minus_flag = true;
535 break;
536
537 case '0':
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
538 CHECK_FOR_FLAGS();
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
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':
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
553 num = rb_uchar_strtol(format_str, format_len, i, &pos);
554 i = pos;
555 if (format_str[pos] == '$') {
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
556 if (num == 0) {
557 rb_raise(rb_eArgError, "invalid absolute argument");
558 }
09f5ee7d » Watson1978
2010-11-23 sprintf() will throw an exception when was given positional format tw…
559 if (arg != 0) {
560 rb_raise(rb_eArgError, "value given twice");
561 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
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--;
42f22c95 » Watson1978
2010-11-23 sprintf() will throw an exception when was given width format twice.
569 CHECK_FOR_WIDTH();
570 width_flag = true;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
571 }
572 break;
573
574 case '.':
33142627 » Watson1978
2010-11-23 sprintf() will throw an exception when was given precision format twice.
575 if (precision_flag) {
576 rb_raise(rb_eArgError, "precision given twice");
577 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
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 }
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
590
591 num = rb_uchar_strtol(format_str, format_len,
592 i, &pos);
225e90fd » Watson1978
2010-11-26 sprintf() will be given a format which is width's * and precision's *.
593 if (format_str[pos] == '$') {
c9853df5 » Watson1978
2010-11-23 String#% will throw an ArgumentError when was given "*0$" format.
594 if (num == 0) {
595 rb_raise(rb_eArgError, "invalid absolute argument");
596 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
597 SET_REF_TYPE(ABS_REF);
598 precision = NUM2LONG(rb_Integer(GETNTHARG(
599 num - 1)));
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
600 i = pos;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
601 }
225e90fd » Watson1978
2010-11-26 sprintf() will be given a format which is width's * and precision's *.
602 else {
603 SET_REF_TYPE(REL_REF);
604 precision = NUM2LONG(rb_Integer(GETNTHARG(j)));
605 j++;
606 i--;
607 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
608 }
609 }
610 else if (isdigit(format_str[i])) {
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
611 precision = rb_uchar_strtol(format_str, format_len,
612 i, &pos);
613 i = pos - 1;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
614 }
615 else {
95a47d31 » Watson1978
2012-01-30 allow omitting width at precision
616 i--;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
617 }
618
619 if (precision < 0) {
620 precision = 0;
621 }
622 break;
623
624 case '<':
625 case '{':
d8ba17fe » Watson1978
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
626 {
627 char term = (format_str[i] == '<') ? '>' : '}';
628
9031bde6 » Watson1978
2010-11-26 sprintf() will throw an exception when was given named format twice.
629 if (named_flag) {
630 rb_raise(rb_eArgError, "named given twice");
631 }
53b78caf » Watson1978
2012-02-01 fix named argument
632 if (ref_type == ABS_REF) {
26e8df91 » Watson1978
2010-11-26 sprintf() will be given the positional arguments and precision tokens…
633 rb_raise(rb_eArgError, "named after numbered");
634 }
9031bde6 » Watson1978
2010-11-26 sprintf() will throw an exception when was given named format twice.
635 named_flag = true;
53b78caf » Watson1978
2012-02-01 fix named argument
636 ref_type = 0;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
637 SET_REF_TYPE(NAMED_REF);
638 arg = get_named_arg(format_str, format_len, &i,
639 GETNTHARG(0));
d8ba17fe » Watson1978
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
640 if (term == '}') {
641 if (TYPE(arg) != T_STRING) {
642 arg = rb_obj_as_string(arg);
643 }
644 goto format_s;
645 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
646 break;
d8ba17fe » Watson1978
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
647 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
648
649 case 'd':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
650 case 'D':
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
651 case 'i':
652 case 'u':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
653 case 'U':
654 base = 10;
eaf4b4a4 » Watson1978
2011-01-15 Fixed the bug of sprintf. "#" flag should be ignored with "dDiuU" for…
655 sharp_flag = false;
32b2e40c » Watson1978
2011-01-16 Fixed the bug of sprintf with format like a "%010.4u".
656 if (precision_flag) {
657 zero_flag = false;
658 }
659 complete = true;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
660 break;
661
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
662 case 'x':
663 case 'X':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
664 base = 16;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
665 negative_pad = rb_str_new2("f");
666 sharp_pad = rb_str_new2("0x");
1017c7f7 » Watson1978
2011-01-15 Fixed the bug of sprintf with format like a "%010.4f".
667 if (precision_flag) {
668 zero_flag = false;
669 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
670 complete = true;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
671 break;
672
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
673 case 'o':
674 case 'O':
675 base = 8;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
676 negative_pad = rb_str_new2("7");
677 sharp_pad = rb_str_new2("0");
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
678 complete = true;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
679 break;
680
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
681 case 'B':
682 case 'b':
683 base = 2;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
684 negative_pad = rb_str_new2("1");
685 sharp_pad = rb_str_new2("0b");
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
686 complete = true;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
687 break;
688
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
689 case 'c':
690 case 'C':
691 GET_ARG();
692 if (TYPE(arg) == T_STRING) {
abe5fa78 » Watson1978
2010-12-11 sprintf("%c") will throw an exception when does not pass one character.
693 if(RSTRING_LEN(arg) != 1) {
694 rb_raise(rb_eArgError, "%%c requires a character");
695 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
696 }
697 else {
110e3452 » Laurent Sansonetti
2010-03-18 fixed some bugs in Numeric#chr
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);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
705 }
706 complete = true;
707 break;
708
709 case 'f':
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
710 case 'F':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
711 case 'e':
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
712 case 'E':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
713 case 'g':
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
714 case 'G':
715 case 'a':
716 case 'A':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
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) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
729 rb_str_update(arg, 0, 0, rb_str_new2("+"));
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
730 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
731 else if (space_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
732 rb_str_update(arg, 0, 0, rb_str_new2(" "));
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
733 }
734 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
735 break;
736 }
737
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
738 arg = rb_unicode_str_new(&format_str[i], 1);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
739 if (precision_flag) {
740 rb_str_update(arg, 0, 0, rb_big2str(LONG2NUM(precision),
741 10));
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
742 rb_str_update(arg, 0, 0, rb_str_new2("."));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
743 }
744 rb_str_update(arg, 0, 0, rb_big2str(LONG2NUM(width), 10));
745 if (minus_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
746 rb_str_update(arg, 0, 0, rb_str_new2("-"));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
747 }
748 else if (zero_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
749 rb_str_update(arg, 0, 0, rb_str_new2("0"));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
750 }
751 if (plus_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
752 rb_str_update(arg, 0, 0, rb_str_new2("+"));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
753 }
754 else if (space_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
755 rb_str_update(arg, 0, 0, rb_str_new2(" "));
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
756 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
757 if (sharp_flag) {
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
758 rb_str_update(arg, 0, 0, rb_str_new2("#"));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
759 }
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
760 rb_str_update(arg, 0, 0, rb_str_new2("%"));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
761
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
762 char *ptr;
763 asprintf(&ptr, RSTRING_PTR(arg), value);
764 arg = rb_str_new2(ptr);
765 free(ptr);
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
766 break;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
767 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
768
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
769 case 's':
770 case 'S':
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
771 case 'p':
772 case '@':
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
773 GET_ARG();
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
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));
d8ba17fe » Watson1978
2010-11-26 fixed the bug of sprintf() within "%{named}" format.
777 format_s:
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
778 if (precision_flag && precision < rb_str_chars_len(arg)) {
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
779 CFStringPad((CFMutableStringRef)arg, NULL, precision,
780 0);
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
781 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
782 complete = true;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
783 break;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
784
b62b4382 » Watson1978
2010-11-22 modified the style of r4928.
785 case '\n':
786 case '\0':
787 if (format_str[i - 1] == '%') {
421ab552 » Watson1978
2010-11-22 sprintf() will not throw exception when passed the format of single %…
788 if (format_str[i] == '\n') {
789 arg = rb_str_new("%\n", 2);
790 }
791 else {
b62b4382 » Watson1978
2010-11-22 modified the style of r4928.
792 if (format_len > i) {
793 arg = rb_str_new("%\0", 2);
794 }
795 else {
796 arg = rb_str_new("%", 1);
797 }
421ab552 » Watson1978
2010-11-22 sprintf() will not throw exception when passed the format of single %…
798 }
799 complete = true;
b62b4382 » Watson1978
2010-11-22 modified the style of r4928.
800 break;
421ab552 » Watson1978
2010-11-22 sprintf() will not throw exception when passed the format of single %…
801 }
b62b4382 » Watson1978
2010-11-22 modified the style of r4928.
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]);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
809 }
810 if (!complete) {
811 continue;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
812 }
813
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
814 GET_ARG();
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
815
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
816 if (base != 0) {
817 bool sign_pad = false;
818 unsigned long num_index = 0;
3e1645b5 » Watson1978
2011-01-15 Fixed the bug of sprintf with format "%# x".
819 unsigned long sharp_beg = 0;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
820 VALUE zero_pad = rb_str_new2("0");
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
821
822 VALUE num = rb_Integer(arg);
823 if (TYPE(num) == T_FIXNUM) {
824 num = rb_int2big(FIX2LONG(num));
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
825 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
826 if (plus_flag || space_flag) {
827 sign_pad = 1;
828 }
829 if (IS_NEG(num)) {
830 num_index = 1;
3e1645b5 » Watson1978
2011-01-15 Fixed the bug of sprintf with format "%# x".
831 sharp_beg = 1;
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
832 if (!sign_pad && negative_pad != 0) {
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
833 zero_pad = negative_pad;
834 num = rb_big_clone(num);
835 rb_big_2comp(num);
836 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
837 }
838
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
839 arg = rb_big2str(num, base);
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
840 if (!sign_pad && IS_NEG(num) && negative_pad != 0) {
a539763d » Laurent Sansonetti
2010-03-19 fixed a few bugs in #sprintf
841 UChar neg = rb_str_get_uchar(negative_pad, 0);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
842 if (base == 8) {
a539763d » Laurent Sansonetti
2010-03-19 fixed a few bugs in #sprintf
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));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
848 }
a539763d » Laurent Sansonetti
2010-03-19 fixed a few bugs in #sprintf
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 }
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
854 num_index++;
855 }
a539763d » Laurent Sansonetti
2010-03-19 fixed a few bugs in #sprintf
856 rb_str_update(arg, 0, num_index, negative_pad);
857 rb_str_update(arg, 0, 0, rb_str_new2(".."));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
858 num_index = 2;
3e1645b5 » Watson1978
2011-01-15 Fixed the bug of sprintf with format "%# x".
859 sharp_beg = 0;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
860 }
861 if (precision_flag) {
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
862 pad_format_value(arg, num_index,
863 precision + (IS_NEG(num)
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
864 && (sign_pad || negative_pad == 0) ? 1 : 0),
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
865 zero_pad);
866 }
e9d7b0c8 » Laurent Sansonetti
2010-02-11 sprintf can now be free of C++ evil
867 if (sharp_flag && rb_cmpint(num, Qfalse, Qfalse) != 0) {
3e1645b5 » Watson1978
2011-01-15 Fixed the bug of sprintf with format "%# x".
868 rb_str_update(arg, sharp_beg, 0, (VALUE)sharp_pad);
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
869 num_index += 2;
870 }
871 if (sign_pad && RBIGNUM_POSITIVE_P(num)) {
872 rb_str_update(arg, 0, 0, (VALUE)(plus_flag ?
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
873 rb_str_new2("+") : rb_str_new2(" ")));
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
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 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
887
d6e38f5b » Laurent Sansonetti
2010-08-30 #sprintf: don't try to mutate symbols
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 }
87717e75 » Laurent Sansonetti
2010-03-06 some sprintf fixes
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;
77a4b423 » Laurent Sansonetti
2010-02-11 new sprintf implementation (thanks Daniel Cavanagh)
897 i += num;
898 break;
899 }
900 }
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
901
4cecb13e » Laurent Sansonetti
2010-03-02 unicode string formats (a work in progress)
902 bail:
903 fmt = rb_unicode_str_new(format_str, format_len);
904 if (tainted) {
905 OBJ_TAINT(fmt);
906 }
907 return fmt;
cb654164 » Laurent Sansonetti
2009-05-23 the great schism, part I
908 }
Something went wrong with that request. Please try again.