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