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