Ruby 1.9.3p327(2012-11-10revision37606)
|
00001 /********************************************************************** 00002 00003 sprintf.c - 00004 00005 $Author: nagachika $ 00006 created at: Fri Oct 15 10:39:26 JST 1993 00007 00008 Copyright (C) 1993-2007 Yukihiro Matsumoto 00009 Copyright (C) 2000 Network Applied Communication Laboratory, Inc. 00010 Copyright (C) 2000 Information-technology Promotion Agency, Japan 00011 00012 **********************************************************************/ 00013 00014 #include "ruby/ruby.h" 00015 #include "ruby/re.h" 00016 #include "ruby/encoding.h" 00017 #include <math.h> 00018 #include <stdarg.h> 00019 00020 #ifdef HAVE_IEEEFP_H 00021 #include <ieeefp.h> 00022 #endif 00023 00024 #define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */ 00025 #define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT) 00026 #define EXTENDSIGN(n, l) (((~0 << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0 << (n))) 00027 00028 static void fmt_setup(char*,size_t,int,int,int,int); 00029 00030 static char* 00031 remove_sign_bits(char *str, int base) 00032 { 00033 char *t = str; 00034 00035 if (base == 16) { 00036 while (*t == 'f') { 00037 t++; 00038 } 00039 } 00040 else if (base == 8) { 00041 *t |= EXTENDSIGN(3, strlen(t)); 00042 while (*t == '7') { 00043 t++; 00044 } 00045 } 00046 else if (base == 2) { 00047 while (*t == '1') { 00048 t++; 00049 } 00050 } 00051 00052 return t; 00053 } 00054 00055 static char 00056 sign_bits(int base, const char *p) 00057 { 00058 char c = '.'; 00059 00060 switch (base) { 00061 case 16: 00062 if (*p == 'X') c = 'F'; 00063 else c = 'f'; 00064 break; 00065 case 8: 00066 c = '7'; break; 00067 case 2: 00068 c = '1'; break; 00069 } 00070 return c; 00071 } 00072 00073 #define FNONE 0 00074 #define FSHARP 1 00075 #define FMINUS 2 00076 #define FPLUS 4 00077 #define FZERO 8 00078 #define FSPACE 16 00079 #define FWIDTH 32 00080 #define FPREC 64 00081 #define FPREC0 128 00082 00083 #define CHECK(l) do {\ 00084 int cr = ENC_CODERANGE(result);\ 00085 while (blen + (l) >= bsiz) {\ 00086 bsiz*=2;\ 00087 }\ 00088 rb_str_resize(result, bsiz);\ 00089 ENC_CODERANGE_SET(result, cr);\ 00090 buf = RSTRING_PTR(result);\ 00091 } while (0) 00092 00093 #define PUSH(s, l) do { \ 00094 CHECK(l);\ 00095 memcpy(&buf[blen], (s), (l));\ 00096 blen += (l);\ 00097 } while (0) 00098 00099 #define FILL(c, l) do { \ 00100 CHECK(l);\ 00101 memset(&buf[blen], (c), (l));\ 00102 blen += (l);\ 00103 } while (0) 00104 00105 #define GETARG() (nextvalue != Qundef ? nextvalue : \ 00106 posarg == -1 ? \ 00107 (rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered", nextarg), 0) : \ 00108 posarg == -2 ? \ 00109 (rb_raise(rb_eArgError, "unnumbered(%d) mixed with named", nextarg), 0) : \ 00110 (posarg = nextarg++, GETNTHARG(posarg))) 00111 00112 #define GETPOSARG(n) (posarg > 0 ? \ 00113 (rb_raise(rb_eArgError, "numbered(%d) after unnumbered(%d)", (n), posarg), 0) : \ 00114 posarg == -2 ? \ 00115 (rb_raise(rb_eArgError, "numbered(%d) after named", (n)), 0) : \ 00116 (((n) < 1) ? (rb_raise(rb_eArgError, "invalid index - %d$", (n)), 0) : \ 00117 (posarg = -1, GETNTHARG(n)))) 00118 00119 #define GETNTHARG(nth) \ 00120 (((nth) >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : argv[(nth)]) 00121 00122 #define GETNAMEARG(id, name, len) ( \ 00123 posarg > 0 ? \ 00124 (rb_raise(rb_eArgError, "named%.*s after unnumbered(%d)", (len), (name), posarg), 0) : \ 00125 posarg == -1 ? \ 00126 (rb_raise(rb_eArgError, "named%.*s after numbered", (len), (name)), 0) : \ 00127 (posarg = -2, rb_hash_lookup2(get_hash(&hash, argc, argv), (id), Qundef))) 00128 00129 #define GETNUM(n, val) \ 00130 for (; p < end && rb_enc_isdigit(*p, enc); p++) { \ 00131 int next_n = 10 * (n) + (*p - '0'); \ 00132 if (next_n / 10 != (n)) {\ 00133 rb_raise(rb_eArgError, #val " too big"); \ 00134 } \ 00135 (n) = next_n; \ 00136 } \ 00137 if (p >= end) { \ 00138 rb_raise(rb_eArgError, "malformed format string - %%*[0-9]"); \ 00139 } 00140 00141 #define GETASTER(val) do { \ 00142 t = p++; \ 00143 n = 0; \ 00144 GETNUM(n, (val)); \ 00145 if (*p == '$') { \ 00146 tmp = GETPOSARG(n); \ 00147 } \ 00148 else { \ 00149 tmp = GETARG(); \ 00150 p = t; \ 00151 } \ 00152 (val) = NUM2INT(tmp); \ 00153 } while (0) 00154 00155 static VALUE 00156 get_hash(volatile VALUE *hash, int argc, const VALUE *argv) 00157 { 00158 VALUE tmp; 00159 00160 if (*hash != Qundef) return *hash; 00161 if (argc != 2) { 00162 rb_raise(rb_eArgError, "one hash required"); 00163 } 00164 tmp = rb_check_convert_type(argv[1], T_HASH, "Hash", "to_hash"); 00165 if (NIL_P(tmp)) { 00166 rb_raise(rb_eArgError, "one hash required"); 00167 } 00168 return (*hash = tmp); 00169 } 00170 00171 /* 00172 * call-seq: 00173 * format(format_string [, arguments...] ) -> string 00174 * sprintf(format_string [, arguments...] ) -> string 00175 * 00176 * Returns the string resulting from applying <i>format_string</i> to 00177 * any additional arguments. Within the format string, any characters 00178 * other than format sequences are copied to the result. 00179 * 00180 * The syntax of a format sequence is follows. 00181 * 00182 * %[flags][width][.precision]type 00183 * 00184 * A format 00185 * sequence consists of a percent sign, followed by optional flags, 00186 * width, and precision indicators, then terminated with a field type 00187 * character. The field type controls how the corresponding 00188 * <code>sprintf</code> argument is to be interpreted, while the flags 00189 * modify that interpretation. 00190 * 00191 * The field type characters are: 00192 * 00193 * Field | Integer Format 00194 * ------+-------------------------------------------------------------- 00195 * b | Convert argument as a binary number. 00196 * | Negative numbers will be displayed as a two's complement 00197 * | prefixed with `..1'. 00198 * B | Equivalent to `b', but uses an uppercase 0B for prefix 00199 * | in the alternative format by #. 00200 * d | Convert argument as a decimal number. 00201 * i | Identical to `d'. 00202 * o | Convert argument as an octal number. 00203 * | Negative numbers will be displayed as a two's complement 00204 * | prefixed with `..7'. 00205 * u | Identical to `d'. 00206 * x | Convert argument as a hexadecimal number. 00207 * | Negative numbers will be displayed as a two's complement 00208 * | prefixed with `..f' (representing an infinite string of 00209 * | leading 'ff's). 00210 * X | Equivalent to `x', but uses uppercase letters. 00211 * 00212 * Field | Float Format 00213 * ------+-------------------------------------------------------------- 00214 * e | Convert floating point argument into exponential notation 00215 * | with one digit before the decimal point as [-]d.dddddde[+-]dd. 00216 * | The precision specifies the number of digits after the decimal 00217 * | point (defaulting to six). 00218 * E | Equivalent to `e', but uses an uppercase E to indicate 00219 * | the exponent. 00220 * f | Convert floating point argument as [-]ddd.dddddd, 00221 * | where the precision specifies the number of digits after 00222 * | the decimal point. 00223 * g | Convert a floating point number using exponential form 00224 * | if the exponent is less than -4 or greater than or 00225 * | equal to the precision, or in dd.dddd form otherwise. 00226 * | The precision specifies the number of significant digits. 00227 * G | Equivalent to `g', but use an uppercase `E' in exponent form. 00228 * a | Convert floating point argument as [-]0xh.hhhhp[+-]dd, 00229 * | which is consisted from optional sign, "0x", fraction part 00230 * | as hexadecimal, "p", and exponential part as decimal. 00231 * A | Equivalent to `a', but use uppercase `X' and `P'. 00232 * 00233 * Field | Other Format 00234 * ------+-------------------------------------------------------------- 00235 * c | Argument is the numeric code for a single character or 00236 * | a single character string itself. 00237 * p | The valuing of argument.inspect. 00238 * s | Argument is a string to be substituted. If the format 00239 * | sequence contains a precision, at most that many characters 00240 * | will be copied. 00241 * % | A percent sign itself will be displayed. No argument taken. 00242 * 00243 * The flags modifies the behavior of the formats. 00244 * The flag characters are: 00245 * 00246 * Flag | Applies to | Meaning 00247 * ---------+---------------+----------------------------------------- 00248 * space | bBdiouxX | Leave a space at the start of 00249 * | aAeEfgG | non-negative numbers. 00250 * | (numeric fmt) | For `o', `x', `X', `b' and `B', use 00251 * | | a minus sign with absolute value for 00252 * | | negative values. 00253 * ---------+---------------+----------------------------------------- 00254 * (digit)$ | all | Specifies the absolute argument number 00255 * | | for this field. Absolute and relative 00256 * | | argument numbers cannot be mixed in a 00257 * | | sprintf string. 00258 * ---------+---------------+----------------------------------------- 00259 * # | bBoxX | Use an alternative format. 00260 * | aAeEfgG | For the conversions `o', increase the precision 00261 * | | until the first digit will be `0' if 00262 * | | it is not formatted as complements. 00263 * | | For the conversions `x', `X', `b' and `B' 00264 * | | on non-zero, prefix the result with ``0x'', 00265 * | | ``0X'', ``0b'' and ``0B'', respectively. 00266 * | | For `a', `A', `e', `E', `f', `g', and 'G', 00267 * | | force a decimal point to be added, 00268 * | | even if no digits follow. 00269 * | | For `g' and 'G', do not remove trailing zeros. 00270 * ---------+---------------+----------------------------------------- 00271 * + | bBdiouxX | Add a leading plus sign to non-negative 00272 * | aAeEfgG | numbers. 00273 * | (numeric fmt) | For `o', `x', `X', `b' and `B', use 00274 * | | a minus sign with absolute value for 00275 * | | negative values. 00276 * ---------+---------------+----------------------------------------- 00277 * - | all | Left-justify the result of this conversion. 00278 * ---------+---------------+----------------------------------------- 00279 * 0 (zero) | bBdiouxX | Pad with zeros, not spaces. 00280 * | aAeEfgG | For `o', `x', `X', `b' and `B', radix-1 00281 * | (numeric fmt) | is used for negative numbers formatted as 00282 * | | complements. 00283 * ---------+---------------+----------------------------------------- 00284 * * | all | Use the next argument as the field width. 00285 * | | If negative, left-justify the result. If the 00286 * | | asterisk is followed by a number and a dollar 00287 * | | sign, use the indicated argument as the width. 00288 * 00289 * Examples of flags: 00290 * 00291 * # `+' and space flag specifies the sign of non-negative numbers. 00292 * sprintf("%d", 123) #=> "123" 00293 * sprintf("%+d", 123) #=> "+123" 00294 * sprintf("% d", 123) #=> " 123" 00295 * 00296 * # `#' flag for `o' increases number of digits to show `0'. 00297 * # `+' and space flag changes format of negative numbers. 00298 * sprintf("%o", 123) #=> "173" 00299 * sprintf("%#o", 123) #=> "0173" 00300 * sprintf("%+o", -123) #=> "-173" 00301 * sprintf("%o", -123) #=> "..7605" 00302 * sprintf("%#o", -123) #=> "..7605" 00303 * 00304 * # `#' flag for `x' add a prefix `0x' for non-zero numbers. 00305 * # `+' and space flag disables complements for negative numbers. 00306 * sprintf("%x", 123) #=> "7b" 00307 * sprintf("%#x", 123) #=> "0x7b" 00308 * sprintf("%+x", -123) #=> "-7b" 00309 * sprintf("%x", -123) #=> "..f85" 00310 * sprintf("%#x", -123) #=> "0x..f85" 00311 * sprintf("%#x", 0) #=> "0" 00312 * 00313 * # `#' for `X' uses the prefix `0X'. 00314 * sprintf("%X", 123) #=> "7B" 00315 * sprintf("%#X", 123) #=> "0X7B" 00316 * 00317 * # `#' flag for `b' add a prefix `0b' for non-zero numbers. 00318 * # `+' and space flag disables complements for negative numbers. 00319 * sprintf("%b", 123) #=> "1111011" 00320 * sprintf("%#b", 123) #=> "0b1111011" 00321 * sprintf("%+b", -123) #=> "-1111011" 00322 * sprintf("%b", -123) #=> "..10000101" 00323 * sprintf("%#b", -123) #=> "0b..10000101" 00324 * sprintf("%#b", 0) #=> "0" 00325 * 00326 * # `#' for `B' uses the prefix `0B'. 00327 * sprintf("%B", 123) #=> "1111011" 00328 * sprintf("%#B", 123) #=> "0B1111011" 00329 * 00330 * # `#' for `e' forces to show the decimal point. 00331 * sprintf("%.0e", 1) #=> "1e+00" 00332 * sprintf("%#.0e", 1) #=> "1.e+00" 00333 * 00334 * # `#' for `f' forces to show the decimal point. 00335 * sprintf("%.0f", 1234) #=> "1234" 00336 * sprintf("%#.0f", 1234) #=> "1234." 00337 * 00338 * # `#' for `g' forces to show the decimal point. 00339 * # It also disables stripping lowest zeros. 00340 * sprintf("%g", 123.4) #=> "123.4" 00341 * sprintf("%#g", 123.4) #=> "123.400" 00342 * sprintf("%g", 123456) #=> "123456" 00343 * sprintf("%#g", 123456) #=> "123456." 00344 * 00345 * The field width is an optional integer, followed optionally by a 00346 * period and a precision. The width specifies the minimum number of 00347 * characters that will be written to the result for this field. 00348 * 00349 * Examples of width: 00350 * 00351 * # padding is done by spaces, width=20 00352 * # 0 or radix-1. <------------------> 00353 * sprintf("%20d", 123) #=> " 123" 00354 * sprintf("%+20d", 123) #=> " +123" 00355 * sprintf("%020d", 123) #=> "00000000000000000123" 00356 * sprintf("%+020d", 123) #=> "+0000000000000000123" 00357 * sprintf("% 020d", 123) #=> " 0000000000000000123" 00358 * sprintf("%-20d", 123) #=> "123 " 00359 * sprintf("%-+20d", 123) #=> "+123 " 00360 * sprintf("%- 20d", 123) #=> " 123 " 00361 * sprintf("%020x", -123) #=> "..ffffffffffffffff85" 00362 * 00363 * For 00364 * numeric fields, the precision controls the number of decimal places 00365 * displayed. For string fields, the precision determines the maximum 00366 * number of characters to be copied from the string. (Thus, the format 00367 * sequence <code>%10.10s</code> will always contribute exactly ten 00368 * characters to the result.) 00369 * 00370 * Examples of precisions: 00371 * 00372 * # precision for `d', 'o', 'x' and 'b' is 00373 * # minimum number of digits <------> 00374 * sprintf("%20.8d", 123) #=> " 00000123" 00375 * sprintf("%20.8o", 123) #=> " 00000173" 00376 * sprintf("%20.8x", 123) #=> " 0000007b" 00377 * sprintf("%20.8b", 123) #=> " 01111011" 00378 * sprintf("%20.8d", -123) #=> " -00000123" 00379 * sprintf("%20.8o", -123) #=> " ..777605" 00380 * sprintf("%20.8x", -123) #=> " ..ffff85" 00381 * sprintf("%20.8b", -11) #=> " ..110101" 00382 * 00383 * # "0x" and "0b" for `#x' and `#b' is not counted for 00384 * # precision but "0" for `#o' is counted. <------> 00385 * sprintf("%#20.8d", 123) #=> " 00000123" 00386 * sprintf("%#20.8o", 123) #=> " 00000173" 00387 * sprintf("%#20.8x", 123) #=> " 0x0000007b" 00388 * sprintf("%#20.8b", 123) #=> " 0b01111011" 00389 * sprintf("%#20.8d", -123) #=> " -00000123" 00390 * sprintf("%#20.8o", -123) #=> " ..777605" 00391 * sprintf("%#20.8x", -123) #=> " 0x..ffff85" 00392 * sprintf("%#20.8b", -11) #=> " 0b..110101" 00393 * 00394 * # precision for `e' is number of 00395 * # digits after the decimal point <------> 00396 * sprintf("%20.8e", 1234.56789) #=> " 1.23456789e+03" 00397 * 00398 * # precision for `f' is number of 00399 * # digits after the decimal point <------> 00400 * sprintf("%20.8f", 1234.56789) #=> " 1234.56789000" 00401 * 00402 * # precision for `g' is number of 00403 * # significant digits <-------> 00404 * sprintf("%20.8g", 1234.56789) #=> " 1234.5679" 00405 * 00406 * # <-------> 00407 * sprintf("%20.8g", 123456789) #=> " 1.2345679e+08" 00408 * 00409 * # precision for `s' is 00410 * # maximum number of characters <------> 00411 * sprintf("%20.8s", "string test") #=> " string t" 00412 * 00413 * Examples: 00414 * 00415 * sprintf("%d %04x", 123, 123) #=> "123 007b" 00416 * sprintf("%08b '%4s'", 123, 123) #=> "01111011 ' 123'" 00417 * sprintf("%1$*2$s %2$d %1$s", "hello", 8) #=> " hello 8 hello" 00418 * sprintf("%1$*2$s %2$d", "hello", -8) #=> "hello -8" 00419 * sprintf("%+g:% g:%-g", 1.23, 1.23, 1.23) #=> "+1.23: 1.23:1.23" 00420 * sprintf("%u", -123) #=> "-123" 00421 * 00422 * For more complex formatting, Ruby supports a reference by name. 00423 * %<name>s style uses format style, but %{name} style doesn't. 00424 * 00425 * Exapmles: 00426 * sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 }) 00427 * #=> 1 : 2.000000 00428 * sprintf("%{foo}f", { :foo => 1 }) 00429 * # => "1f" 00430 */ 00431 00432 VALUE 00433 rb_f_sprintf(int argc, const VALUE *argv) 00434 { 00435 return rb_str_format(argc - 1, argv + 1, GETNTHARG(0)); 00436 } 00437 00438 VALUE 00439 rb_str_format(int argc, const VALUE *argv, VALUE fmt) 00440 { 00441 rb_encoding *enc; 00442 const char *p, *end; 00443 char *buf; 00444 long blen, bsiz; 00445 VALUE result; 00446 00447 long scanned = 0; 00448 int coderange = ENC_CODERANGE_7BIT; 00449 int width, prec, flags = FNONE; 00450 int nextarg = 1; 00451 int posarg = 0; 00452 int tainted = 0; 00453 VALUE nextvalue; 00454 VALUE tmp; 00455 VALUE str; 00456 volatile VALUE hash = Qundef; 00457 00458 #define CHECK_FOR_WIDTH(f) \ 00459 if ((f) & FWIDTH) { \ 00460 rb_raise(rb_eArgError, "width given twice"); \ 00461 } \ 00462 if ((f) & FPREC0) { \ 00463 rb_raise(rb_eArgError, "width after precision"); \ 00464 } 00465 #define CHECK_FOR_FLAGS(f) \ 00466 if ((f) & FWIDTH) { \ 00467 rb_raise(rb_eArgError, "flag after width"); \ 00468 } \ 00469 if ((f) & FPREC0) { \ 00470 rb_raise(rb_eArgError, "flag after precision"); \ 00471 } 00472 00473 ++argc; 00474 --argv; 00475 if (OBJ_TAINTED(fmt)) tainted = 1; 00476 StringValue(fmt); 00477 enc = rb_enc_get(fmt); 00478 fmt = rb_str_new4(fmt); 00479 p = RSTRING_PTR(fmt); 00480 end = p + RSTRING_LEN(fmt); 00481 blen = 0; 00482 bsiz = 120; 00483 result = rb_str_buf_new(bsiz); 00484 rb_enc_copy(result, fmt); 00485 buf = RSTRING_PTR(result); 00486 memset(buf, 0, bsiz); 00487 ENC_CODERANGE_SET(result, coderange); 00488 00489 for (; p < end; p++) { 00490 const char *t; 00491 int n; 00492 ID id = 0; 00493 00494 for (t = p; t < end && *t != '%'; t++) ; 00495 PUSH(p, t - p); 00496 if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) { 00497 scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &coderange); 00498 ENC_CODERANGE_SET(result, coderange); 00499 } 00500 if (t >= end) { 00501 /* end of fmt string */ 00502 goto sprint_exit; 00503 } 00504 p = t + 1; /* skip `%' */ 00505 00506 width = prec = -1; 00507 nextvalue = Qundef; 00508 retry: 00509 switch (*p) { 00510 default: 00511 if (rb_enc_isprint(*p, enc)) 00512 rb_raise(rb_eArgError, "malformed format string - %%%c", *p); 00513 else 00514 rb_raise(rb_eArgError, "malformed format string"); 00515 break; 00516 00517 case ' ': 00518 CHECK_FOR_FLAGS(flags); 00519 flags |= FSPACE; 00520 p++; 00521 goto retry; 00522 00523 case '#': 00524 CHECK_FOR_FLAGS(flags); 00525 flags |= FSHARP; 00526 p++; 00527 goto retry; 00528 00529 case '+': 00530 CHECK_FOR_FLAGS(flags); 00531 flags |= FPLUS; 00532 p++; 00533 goto retry; 00534 00535 case '-': 00536 CHECK_FOR_FLAGS(flags); 00537 flags |= FMINUS; 00538 p++; 00539 goto retry; 00540 00541 case '0': 00542 CHECK_FOR_FLAGS(flags); 00543 flags |= FZERO; 00544 p++; 00545 goto retry; 00546 00547 case '1': case '2': case '3': case '4': 00548 case '5': case '6': case '7': case '8': case '9': 00549 n = 0; 00550 GETNUM(n, width); 00551 if (*p == '$') { 00552 if (nextvalue != Qundef) { 00553 rb_raise(rb_eArgError, "value given twice - %d$", n); 00554 } 00555 nextvalue = GETPOSARG(n); 00556 p++; 00557 goto retry; 00558 } 00559 CHECK_FOR_WIDTH(flags); 00560 width = n; 00561 flags |= FWIDTH; 00562 goto retry; 00563 00564 case '<': 00565 case '{': 00566 { 00567 const char *start = p; 00568 char term = (*p == '<') ? '>' : '}'; 00569 00570 for (; p < end && *p != term; ) { 00571 p += rb_enc_mbclen(p, end, enc); 00572 } 00573 if (p >= end) { 00574 rb_raise(rb_eArgError, "malformed name - unmatched parenthesis"); 00575 } 00576 if (id) { 00577 rb_raise(rb_eArgError, "name%.*s after <%s>", 00578 (int)(p - start + 1), start, rb_id2name(id)); 00579 } 00580 id = rb_intern3(start + 1, p - start - 1, enc); 00581 nextvalue = GETNAMEARG(ID2SYM(id), start, (int)(p - start + 1)); 00582 if (nextvalue == Qundef) { 00583 rb_raise(rb_eKeyError, "key%.*s not found", (int)(p - start + 1), start); 00584 } 00585 if (term == '}') goto format_s; 00586 p++; 00587 goto retry; 00588 } 00589 00590 case '*': 00591 CHECK_FOR_WIDTH(flags); 00592 flags |= FWIDTH; 00593 GETASTER(width); 00594 if (width < 0) { 00595 flags |= FMINUS; 00596 width = -width; 00597 } 00598 p++; 00599 goto retry; 00600 00601 case '.': 00602 if (flags & FPREC0) { 00603 rb_raise(rb_eArgError, "precision given twice"); 00604 } 00605 flags |= FPREC|FPREC0; 00606 00607 prec = 0; 00608 p++; 00609 if (*p == '*') { 00610 GETASTER(prec); 00611 if (prec < 0) { /* ignore negative precision */ 00612 flags &= ~FPREC; 00613 } 00614 p++; 00615 goto retry; 00616 } 00617 00618 GETNUM(prec, precision); 00619 goto retry; 00620 00621 case '\n': 00622 case '\0': 00623 p--; 00624 case '%': 00625 if (flags != FNONE) { 00626 rb_raise(rb_eArgError, "invalid format character - %%"); 00627 } 00628 PUSH("%", 1); 00629 break; 00630 00631 case 'c': 00632 { 00633 VALUE val = GETARG(); 00634 VALUE tmp; 00635 unsigned int c; 00636 int n; 00637 00638 tmp = rb_check_string_type(val); 00639 if (!NIL_P(tmp)) { 00640 if (rb_enc_strlen(RSTRING_PTR(tmp),RSTRING_END(tmp),enc) != 1) { 00641 rb_raise(rb_eArgError, "%%c requires a character"); 00642 } 00643 c = rb_enc_codepoint_len(RSTRING_PTR(tmp), RSTRING_END(tmp), &n, enc); 00644 RB_GC_GUARD(tmp); 00645 } 00646 else { 00647 c = NUM2INT(val); 00648 n = rb_enc_codelen(c, enc); 00649 } 00650 if (n <= 0) { 00651 rb_raise(rb_eArgError, "invalid character"); 00652 } 00653 if (!(flags & FWIDTH)) { 00654 CHECK(n); 00655 rb_enc_mbcput(c, &buf[blen], enc); 00656 blen += n; 00657 } 00658 else if ((flags & FMINUS)) { 00659 CHECK(n); 00660 rb_enc_mbcput(c, &buf[blen], enc); 00661 blen += n; 00662 FILL(' ', width-1); 00663 } 00664 else { 00665 FILL(' ', width-1); 00666 CHECK(n); 00667 rb_enc_mbcput(c, &buf[blen], enc); 00668 blen += n; 00669 } 00670 } 00671 break; 00672 00673 case 's': 00674 case 'p': 00675 format_s: 00676 { 00677 VALUE arg = GETARG(); 00678 long len, slen; 00679 00680 if (*p == 'p') arg = rb_inspect(arg); 00681 str = rb_obj_as_string(arg); 00682 if (OBJ_TAINTED(str)) tainted = 1; 00683 len = RSTRING_LEN(str); 00684 rb_str_set_len(result, blen); 00685 if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) { 00686 int cr = coderange; 00687 scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &cr); 00688 ENC_CODERANGE_SET(result, 00689 (cr == ENC_CODERANGE_UNKNOWN ? 00690 ENC_CODERANGE_BROKEN : (coderange = cr))); 00691 } 00692 enc = rb_enc_check(result, str); 00693 if (flags&(FPREC|FWIDTH)) { 00694 slen = rb_enc_strlen(RSTRING_PTR(str),RSTRING_END(str),enc); 00695 if (slen < 0) { 00696 rb_raise(rb_eArgError, "invalid mbstring sequence"); 00697 } 00698 if ((flags&FPREC) && (prec < slen)) { 00699 char *p = rb_enc_nth(RSTRING_PTR(str), RSTRING_END(str), 00700 prec, enc); 00701 slen = prec; 00702 len = p - RSTRING_PTR(str); 00703 } 00704 /* need to adjust multi-byte string pos */ 00705 if ((flags&FWIDTH) && (width > slen)) { 00706 width -= (int)slen; 00707 if (!(flags&FMINUS)) { 00708 CHECK(width); 00709 while (width--) { 00710 buf[blen++] = ' '; 00711 } 00712 } 00713 CHECK(len); 00714 memcpy(&buf[blen], RSTRING_PTR(str), len); 00715 RB_GC_GUARD(str); 00716 blen += len; 00717 if (flags&FMINUS) { 00718 CHECK(width); 00719 while (width--) { 00720 buf[blen++] = ' '; 00721 } 00722 } 00723 rb_enc_associate(result, enc); 00724 break; 00725 } 00726 } 00727 PUSH(RSTRING_PTR(str), len); 00728 RB_GC_GUARD(str); 00729 rb_enc_associate(result, enc); 00730 } 00731 break; 00732 00733 case 'd': 00734 case 'i': 00735 case 'o': 00736 case 'x': 00737 case 'X': 00738 case 'b': 00739 case 'B': 00740 case 'u': 00741 { 00742 volatile VALUE val = GETARG(); 00743 char fbuf[32], nbuf[64], *s; 00744 const char *prefix = 0; 00745 int sign = 0, dots = 0; 00746 char sc = 0; 00747 long v = 0; 00748 int base, bignum = 0; 00749 int len; 00750 00751 switch (*p) { 00752 case 'd': 00753 case 'i': 00754 case 'u': 00755 sign = 1; break; 00756 case 'o': 00757 case 'x': 00758 case 'X': 00759 case 'b': 00760 case 'B': 00761 if (flags&(FPLUS|FSPACE)) sign = 1; 00762 break; 00763 } 00764 if (flags & FSHARP) { 00765 switch (*p) { 00766 case 'o': 00767 prefix = "0"; break; 00768 case 'x': 00769 prefix = "0x"; break; 00770 case 'X': 00771 prefix = "0X"; break; 00772 case 'b': 00773 prefix = "0b"; break; 00774 case 'B': 00775 prefix = "0B"; break; 00776 } 00777 } 00778 00779 bin_retry: 00780 switch (TYPE(val)) { 00781 case T_FLOAT: 00782 if (FIXABLE(RFLOAT_VALUE(val))) { 00783 val = LONG2FIX((long)RFLOAT_VALUE(val)); 00784 goto bin_retry; 00785 } 00786 val = rb_dbl2big(RFLOAT_VALUE(val)); 00787 if (FIXNUM_P(val)) goto bin_retry; 00788 bignum = 1; 00789 break; 00790 case T_STRING: 00791 val = rb_str_to_inum(val, 0, TRUE); 00792 goto bin_retry; 00793 case T_BIGNUM: 00794 bignum = 1; 00795 break; 00796 case T_FIXNUM: 00797 v = FIX2LONG(val); 00798 break; 00799 default: 00800 val = rb_Integer(val); 00801 goto bin_retry; 00802 } 00803 00804 switch (*p) { 00805 case 'o': 00806 base = 8; break; 00807 case 'x': 00808 case 'X': 00809 base = 16; break; 00810 case 'b': 00811 case 'B': 00812 base = 2; break; 00813 case 'u': 00814 case 'd': 00815 case 'i': 00816 default: 00817 base = 10; break; 00818 } 00819 00820 if (!bignum) { 00821 if (base == 2) { 00822 val = rb_int2big(v); 00823 goto bin_retry; 00824 } 00825 if (sign) { 00826 char c = *p; 00827 if (c == 'i') c = 'd'; /* %d and %i are identical */ 00828 if (v < 0) { 00829 v = -v; 00830 sc = '-'; 00831 width--; 00832 } 00833 else if (flags & FPLUS) { 00834 sc = '+'; 00835 width--; 00836 } 00837 else if (flags & FSPACE) { 00838 sc = ' '; 00839 width--; 00840 } 00841 snprintf(fbuf, sizeof(fbuf), "%%l%c", c); 00842 snprintf(nbuf, sizeof(nbuf), fbuf, v); 00843 s = nbuf; 00844 } 00845 else { 00846 s = nbuf; 00847 if (v < 0) { 00848 dots = 1; 00849 } 00850 snprintf(fbuf, sizeof(fbuf), "%%l%c", *p == 'X' ? 'x' : *p); 00851 snprintf(++s, sizeof(nbuf) - 1, fbuf, v); 00852 if (v < 0) { 00853 char d = 0; 00854 00855 s = remove_sign_bits(s, base); 00856 switch (base) { 00857 case 16: 00858 d = 'f'; break; 00859 case 8: 00860 d = '7'; break; 00861 } 00862 if (d && *s != d) { 00863 *--s = d; 00864 } 00865 } 00866 } 00867 len = (int)strlen(s); 00868 } 00869 else { 00870 if (sign) { 00871 tmp = rb_big2str(val, base); 00872 s = RSTRING_PTR(tmp); 00873 if (s[0] == '-') { 00874 s++; 00875 sc = '-'; 00876 width--; 00877 } 00878 else if (flags & FPLUS) { 00879 sc = '+'; 00880 width--; 00881 } 00882 else if (flags & FSPACE) { 00883 sc = ' '; 00884 width--; 00885 } 00886 } 00887 else { 00888 if (!RBIGNUM_SIGN(val)) { 00889 val = rb_big_clone(val); 00890 rb_big_2comp(val); 00891 } 00892 tmp = rb_big2str0(val, base, RBIGNUM_SIGN(val)); 00893 s = RSTRING_PTR(tmp); 00894 if (*s == '-') { 00895 dots = 1; 00896 if (base == 10) { 00897 rb_warning("negative number for %%u specifier"); 00898 } 00899 s = remove_sign_bits(++s, base); 00900 switch (base) { 00901 case 16: 00902 if (s[0] != 'f') *--s = 'f'; break; 00903 case 8: 00904 if (s[0] != '7') *--s = '7'; break; 00905 case 2: 00906 if (s[0] != '1') *--s = '1'; break; 00907 } 00908 } 00909 } 00910 len = rb_long2int(RSTRING_END(tmp) - s); 00911 } 00912 00913 if (dots) { 00914 prec -= 2; 00915 width -= 2; 00916 } 00917 00918 if (*p == 'X') { 00919 char *pp = s; 00920 int c; 00921 while ((c = (int)(unsigned char)*pp) != 0) { 00922 *pp = rb_enc_toupper(c, enc); 00923 pp++; 00924 } 00925 } 00926 if (prefix && !prefix[1]) { /* octal */ 00927 if (dots) { 00928 prefix = 0; 00929 } 00930 else if (len == 1 && *s == '0') { 00931 len = 0; 00932 if (flags & FPREC) prec--; 00933 } 00934 else if ((flags & FPREC) && (prec > len)) { 00935 prefix = 0; 00936 } 00937 } 00938 else if (len == 1 && *s == '0') { 00939 prefix = 0; 00940 } 00941 if (prefix) { 00942 width -= (int)strlen(prefix); 00943 } 00944 if ((flags & (FZERO|FMINUS|FPREC)) == FZERO) { 00945 prec = width; 00946 width = 0; 00947 } 00948 else { 00949 if (prec < len) { 00950 if (!prefix && prec == 0 && len == 1 && *s == '0') len = 0; 00951 prec = len; 00952 } 00953 width -= prec; 00954 } 00955 if (!(flags&FMINUS)) { 00956 CHECK(width); 00957 while (width-- > 0) { 00958 buf[blen++] = ' '; 00959 } 00960 } 00961 if (sc) PUSH(&sc, 1); 00962 if (prefix) { 00963 int plen = (int)strlen(prefix); 00964 PUSH(prefix, plen); 00965 } 00966 CHECK(prec - len); 00967 if (dots) PUSH("..", 2); 00968 if (!bignum && v < 0) { 00969 char c = sign_bits(base, p); 00970 while (len < prec--) { 00971 buf[blen++] = c; 00972 } 00973 } 00974 else if ((flags & (FMINUS|FPREC)) != FMINUS) { 00975 char c; 00976 00977 if (!sign && bignum && !RBIGNUM_SIGN(val)) 00978 c = sign_bits(base, p); 00979 else 00980 c = '0'; 00981 while (len < prec--) { 00982 buf[blen++] = c; 00983 } 00984 } 00985 PUSH(s, len); 00986 RB_GC_GUARD(tmp); 00987 CHECK(width); 00988 while (width-- > 0) { 00989 buf[blen++] = ' '; 00990 } 00991 } 00992 break; 00993 00994 case 'f': 00995 case 'g': 00996 case 'G': 00997 case 'e': 00998 case 'E': 00999 case 'a': 01000 case 'A': 01001 { 01002 VALUE val = GETARG(); 01003 double fval; 01004 int i, need = 6; 01005 char fbuf[32]; 01006 01007 fval = RFLOAT_VALUE(rb_Float(val)); 01008 if (isnan(fval) || isinf(fval)) { 01009 const char *expr; 01010 01011 if (isnan(fval)) { 01012 expr = "NaN"; 01013 } 01014 else { 01015 expr = "Inf"; 01016 } 01017 need = (int)strlen(expr); 01018 if ((!isnan(fval) && fval < 0.0) || (flags & FPLUS)) 01019 need++; 01020 if ((flags & FWIDTH) && need < width) 01021 need = width; 01022 01023 CHECK(need + 1); 01024 snprintf(&buf[blen], need + 1, "%*s", need, ""); 01025 if (flags & FMINUS) { 01026 if (!isnan(fval) && fval < 0.0) 01027 buf[blen++] = '-'; 01028 else if (flags & FPLUS) 01029 buf[blen++] = '+'; 01030 else if (flags & FSPACE) 01031 blen++; 01032 memcpy(&buf[blen], expr, strlen(expr)); 01033 } 01034 else { 01035 if (!isnan(fval) && fval < 0.0) 01036 buf[blen + need - strlen(expr) - 1] = '-'; 01037 else if (flags & FPLUS) 01038 buf[blen + need - strlen(expr) - 1] = '+'; 01039 else if ((flags & FSPACE) && need > width) 01040 blen++; 01041 memcpy(&buf[blen + need - strlen(expr)], expr, 01042 strlen(expr)); 01043 } 01044 blen += strlen(&buf[blen]); 01045 break; 01046 } 01047 01048 fmt_setup(fbuf, sizeof(fbuf), *p, flags, width, prec); 01049 need = 0; 01050 if (*p != 'e' && *p != 'E') { 01051 i = INT_MIN; 01052 frexp(fval, &i); 01053 if (i > 0) 01054 need = BIT_DIGITS(i); 01055 } 01056 need += (flags&FPREC) ? prec : 6; 01057 if ((flags&FWIDTH) && need < width) 01058 need = width; 01059 need += 20; 01060 01061 CHECK(need); 01062 snprintf(&buf[blen], need, fbuf, fval); 01063 blen += strlen(&buf[blen]); 01064 } 01065 break; 01066 } 01067 flags = FNONE; 01068 } 01069 01070 sprint_exit: 01071 RB_GC_GUARD(fmt); 01072 /* XXX - We cannot validate the number of arguments if (digit)$ style used. 01073 */ 01074 if (posarg >= 0 && nextarg < argc) { 01075 const char *mesg = "too many arguments for format string"; 01076 if (RTEST(ruby_debug)) rb_raise(rb_eArgError, "%s", mesg); 01077 if (RTEST(ruby_verbose)) rb_warn("%s", mesg); 01078 } 01079 rb_str_resize(result, blen); 01080 01081 if (tainted) OBJ_TAINT(result); 01082 return result; 01083 } 01084 01085 static void 01086 fmt_setup(char *buf, size_t size, int c, int flags, int width, int prec) 01087 { 01088 char *end = buf + size; 01089 *buf++ = '%'; 01090 if (flags & FSHARP) *buf++ = '#'; 01091 if (flags & FPLUS) *buf++ = '+'; 01092 if (flags & FMINUS) *buf++ = '-'; 01093 if (flags & FZERO) *buf++ = '0'; 01094 if (flags & FSPACE) *buf++ = ' '; 01095 01096 if (flags & FWIDTH) { 01097 snprintf(buf, end - buf, "%d", width); 01098 buf += strlen(buf); 01099 } 01100 01101 if (flags & FPREC) { 01102 snprintf(buf, end - buf, ".%d", prec); 01103 buf += strlen(buf); 01104 } 01105 01106 *buf++ = c; 01107 *buf = '\0'; 01108 } 01109 01110 #undef FILE 01111 #define FILE rb_printf_buffer 01112 #define __sbuf rb_printf_sbuf 01113 #define __sFILE rb_printf_sfile 01114 #undef feof 01115 #undef ferror 01116 #undef clearerr 01117 #undef fileno 01118 #if SIZEOF_LONG < SIZEOF_VOIDP 01119 # if SIZEOF_LONG_LONG == SIZEOF_VOIDP 01120 # define _HAVE_SANE_QUAD_ 01121 # define _HAVE_LLP64_ 01122 # define quad_t LONG_LONG 01123 # define u_quad_t unsigned LONG_LONG 01124 # endif 01125 #elif SIZEOF_LONG != SIZEOF_LONG_LONG && SIZEOF_LONG_LONG == 8 01126 # define _HAVE_SANE_QUAD_ 01127 # define quad_t LONG_LONG 01128 # define u_quad_t unsigned LONG_LONG 01129 #endif 01130 #define FLOATING_POINT 1 01131 #define BSD__dtoa ruby_dtoa 01132 #define BSD__hdtoa ruby_hdtoa 01133 #include "vsnprintf.c" 01134 01135 static int 01136 ruby__sfvwrite(register rb_printf_buffer *fp, register struct __suio *uio) 01137 { 01138 struct __siov *iov; 01139 VALUE result = (VALUE)fp->_bf._base; 01140 char *buf = (char*)fp->_p; 01141 size_t len, n; 01142 size_t blen = buf - RSTRING_PTR(result), bsiz = fp->_w; 01143 01144 if (RBASIC(result)->klass) { 01145 rb_raise(rb_eRuntimeError, "rb_vsprintf reentered"); 01146 } 01147 if ((len = uio->uio_resid) == 0) 01148 return 0; 01149 CHECK(len); 01150 buf += blen; 01151 fp->_w = bsiz; 01152 for (iov = uio->uio_iov; len > 0; ++iov) { 01153 MEMCPY(buf, iov->iov_base, char, n = iov->iov_len); 01154 buf += n; 01155 len -= n; 01156 } 01157 fp->_p = (unsigned char *)buf; 01158 return 0; 01159 } 01160 01161 VALUE 01162 rb_enc_vsprintf(rb_encoding *enc, const char *fmt, va_list ap) 01163 { 01164 rb_printf_buffer f; 01165 VALUE result; 01166 01167 f._flags = __SWR | __SSTR; 01168 f._bf._size = 0; 01169 f._w = 120; 01170 result = rb_str_buf_new(f._w); 01171 if (enc) rb_enc_associate(result, enc); 01172 f._bf._base = (unsigned char *)result; 01173 f._p = (unsigned char *)RSTRING_PTR(result); 01174 RBASIC(result)->klass = 0; 01175 f.vwrite = ruby__sfvwrite; 01176 BSD_vfprintf(&f, fmt, ap); 01177 RBASIC(result)->klass = rb_cString; 01178 rb_str_resize(result, (char *)f._p - RSTRING_PTR(result)); 01179 01180 return result; 01181 } 01182 01183 VALUE 01184 rb_enc_sprintf(rb_encoding *enc, const char *format, ...) 01185 { 01186 VALUE result; 01187 va_list ap; 01188 01189 va_start(ap, format); 01190 result = rb_enc_vsprintf(enc, format, ap); 01191 va_end(ap); 01192 01193 return result; 01194 } 01195 01196 VALUE 01197 rb_vsprintf(const char *fmt, va_list ap) 01198 { 01199 return rb_enc_vsprintf(NULL, fmt, ap); 01200 } 01201 01202 VALUE 01203 rb_sprintf(const char *format, ...) 01204 { 01205 VALUE result; 01206 va_list ap; 01207 01208 va_start(ap, format); 01209 result = rb_vsprintf(format, ap); 01210 va_end(ap); 01211 01212 return result; 01213 } 01214 01215 VALUE 01216 rb_str_vcatf(VALUE str, const char *fmt, va_list ap) 01217 { 01218 rb_printf_buffer f; 01219 VALUE klass; 01220 01221 StringValue(str); 01222 rb_str_modify(str); 01223 f._flags = __SWR | __SSTR; 01224 f._bf._size = 0; 01225 f._w = rb_str_capacity(str); 01226 f._bf._base = (unsigned char *)str; 01227 f._p = (unsigned char *)RSTRING_END(str); 01228 klass = RBASIC(str)->klass; 01229 RBASIC(str)->klass = 0; 01230 f.vwrite = ruby__sfvwrite; 01231 BSD_vfprintf(&f, fmt, ap); 01232 RBASIC(str)->klass = klass; 01233 rb_str_resize(str, (char *)f._p - RSTRING_PTR(str)); 01234 01235 return str; 01236 } 01237 01238 VALUE 01239 rb_str_catf(VALUE str, const char *format, ...) 01240 { 01241 va_list ap; 01242 01243 va_start(ap, format); 01244 str = rb_str_vcatf(str, format, ap); 01245 va_end(ap); 01246 01247 return str; 01248 } 01249