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 <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)
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
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 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
00502 goto sprint_exit;
00503 }
00504 p = t + 1;
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) {
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
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';
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]) {
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
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