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 #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
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
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
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
00506 goto sprint_exit;
00507 }
00508 p = t + 1;
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);
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 ,
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) {
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
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';
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]) {
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
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
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