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 *s, *t;
00034
00035 s = t = str;
00036
00037 if (base == 16) {
00038 while (*t == 'f') {
00039 t++;
00040 }
00041 }
00042 else if (base == 8) {
00043 *t |= EXTENDSIGN(3, strlen(t));
00044 while (*t == '7') {
00045 t++;
00046 }
00047 }
00048 else if (base == 2) {
00049 while (*t == '1') {
00050 t++;
00051 }
00052 }
00053
00054 return t;
00055 }
00056
00057 static char
00058 sign_bits(int base, const char *p)
00059 {
00060 char c = '.';
00061
00062 switch (base) {
00063 case 16:
00064 if (*p == 'X') c = 'F';
00065 else c = 'f';
00066 break;
00067 case 8:
00068 c = '7'; break;
00069 case 2:
00070 c = '1'; break;
00071 }
00072 return c;
00073 }
00074
00075 #define FNONE 0
00076 #define FSHARP 1
00077 #define FMINUS 2
00078 #define FPLUS 4
00079 #define FZERO 8
00080 #define FSPACE 16
00081 #define FWIDTH 32
00082 #define FPREC 64
00083 #define FPREC0 128
00084
00085 #define CHECK(l) do {\
00086 int cr = ENC_CODERANGE(result);\
00087 while (blen + (l) >= bsiz) {\
00088 bsiz*=2;\
00089 }\
00090 rb_str_resize(result, bsiz);\
00091 ENC_CODERANGE_SET(result, cr);\
00092 buf = RSTRING_PTR(result);\
00093 } while (0)
00094
00095 #define PUSH(s, l) do { \
00096 CHECK(l);\
00097 memcpy(&buf[blen], s, l);\
00098 blen += (l);\
00099 } while (0)
00100
00101 #define FILL(c, l) do { \
00102 CHECK(l);\
00103 memset(&buf[blen], c, l);\
00104 blen += (l);\
00105 } while (0)
00106
00107 #define GETARG() (nextvalue != Qundef ? nextvalue : \
00108 posarg == -1 ? \
00109 (rb_raise(rb_eArgError, "unnumbered(%d) mixed with numbered", nextarg), 0) : \
00110 posarg == -2 ? \
00111 (rb_raise(rb_eArgError, "unnumbered(%d) mixed with named", nextarg), 0) : \
00112 (posarg = nextarg++, GETNTHARG(posarg)))
00113
00114 #define GETPOSARG(n) (posarg > 0 ? \
00115 (rb_raise(rb_eArgError, "numbered(%d) after unnumbered(%d)", n, posarg), 0) : \
00116 posarg == -2 ? \
00117 (rb_raise(rb_eArgError, "numbered(%d) after named", n), 0) : \
00118 ((n < 1) ? (rb_raise(rb_eArgError, "invalid index - %d$", n), 0) : \
00119 (posarg = -1, GETNTHARG(n))))
00120
00121 #define GETNTHARG(nth) \
00122 ((nth >= argc) ? (rb_raise(rb_eArgError, "too few arguments"), 0) : argv[nth])
00123
00124 #define GETNAMEARG(id, name, len) ( \
00125 posarg > 0 ? \
00126 (rb_raise(rb_eArgError, "named%.*s after unnumbered(%d)", (len), (name), posarg), 0) : \
00127 posarg == -1 ? \
00128 (rb_raise(rb_eArgError, "named%.*s after numbered", (len), (name)), 0) : \
00129 (posarg = -2, rb_hash_lookup2(get_hash(&hash, argc, argv), id, Qundef)))
00130
00131 #define GETNUM(n, val) \
00132 for (; p < end && rb_enc_isdigit(*p, enc); p++) { \
00133 int next_n = 10 * n + (*p - '0'); \
00134 if (next_n / 10 != n) {\
00135 rb_raise(rb_eArgError, #val " too big"); \
00136 } \
00137 n = next_n; \
00138 } \
00139 if (p >= end) { \
00140 rb_raise(rb_eArgError, "malformed format string - %%*[0-9]"); \
00141 }
00142
00143 #define GETASTER(val) do { \
00144 t = p++; \
00145 n = 0; \
00146 GETNUM(n, val); \
00147 if (*p == '$') { \
00148 tmp = GETPOSARG(n); \
00149 } \
00150 else { \
00151 tmp = GETARG(); \
00152 p = t; \
00153 } \
00154 val = NUM2INT(tmp); \
00155 } while (0)
00156
00157 static VALUE
00158 get_hash(volatile VALUE *hash, int argc, const VALUE *argv)
00159 {
00160 VALUE tmp;
00161
00162 if (*hash != Qundef) return *hash;
00163 if (argc != 2) {
00164 rb_raise(rb_eArgError, "one hash required");
00165 }
00166 tmp = rb_check_convert_type(argv[1], T_HASH, "Hash", "to_hash");
00167 if (NIL_P(tmp)) {
00168 rb_raise(rb_eArgError, "one hash required");
00169 }
00170 return (*hash = tmp);
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
00433
00434 VALUE
00435 rb_f_sprintf(int argc, const VALUE *argv)
00436 {
00437 return rb_str_format(argc - 1, argv + 1, GETNTHARG(0));
00438 }
00439
00440 VALUE
00441 rb_str_format(int argc, const VALUE *argv, VALUE fmt)
00442 {
00443 rb_encoding *enc;
00444 const char *p, *end;
00445 char *buf;
00446 long blen, bsiz;
00447 VALUE result;
00448
00449 long scanned = 0;
00450 int coderange = ENC_CODERANGE_7BIT;
00451 int width, prec, flags = FNONE;
00452 int nextarg = 1;
00453 int posarg = 0;
00454 int tainted = 0;
00455 VALUE nextvalue;
00456 VALUE tmp;
00457 VALUE str;
00458 volatile VALUE hash = Qundef;
00459
00460 #define CHECK_FOR_WIDTH(f) \
00461 if ((f) & FWIDTH) { \
00462 rb_raise(rb_eArgError, "width given twice"); \
00463 } \
00464 if ((f) & FPREC0) { \
00465 rb_raise(rb_eArgError, "width after precision"); \
00466 }
00467 #define CHECK_FOR_FLAGS(f) \
00468 if ((f) & FWIDTH) { \
00469 rb_raise(rb_eArgError, "flag after width"); \
00470 } \
00471 if ((f) & FPREC0) { \
00472 rb_raise(rb_eArgError, "flag after precision"); \
00473 }
00474
00475 ++argc;
00476 --argv;
00477 if (OBJ_TAINTED(fmt)) tainted = 1;
00478 StringValue(fmt);
00479 enc = rb_enc_get(fmt);
00480 fmt = rb_str_new4(fmt);
00481 p = RSTRING_PTR(fmt);
00482 end = p + RSTRING_LEN(fmt);
00483 blen = 0;
00484 bsiz = 120;
00485 result = rb_str_buf_new(bsiz);
00486 rb_enc_copy(result, fmt);
00487 buf = RSTRING_PTR(result);
00488 memset(buf, 0, bsiz);
00489 ENC_CODERANGE_SET(result, coderange);
00490
00491 for (; p < end; p++) {
00492 const char *t;
00493 int n;
00494 ID id = 0;
00495
00496 for (t = p; t < end && *t != '%'; t++) ;
00497 PUSH(p, t - p);
00498 if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) {
00499 scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &coderange);
00500 ENC_CODERANGE_SET(result, coderange);
00501 }
00502 if (t >= end) {
00503
00504 goto sprint_exit;
00505 }
00506 p = t + 1;
00507
00508 width = prec = -1;
00509 nextvalue = Qundef;
00510 retry:
00511 switch (*p) {
00512 default:
00513 if (rb_enc_isprint(*p, enc))
00514 rb_raise(rb_eArgError, "malformed format string - %%%c", *p);
00515 else
00516 rb_raise(rb_eArgError, "malformed format string");
00517 break;
00518
00519 case ' ':
00520 CHECK_FOR_FLAGS(flags);
00521 flags |= FSPACE;
00522 p++;
00523 goto retry;
00524
00525 case '#':
00526 CHECK_FOR_FLAGS(flags);
00527 flags |= FSHARP;
00528 p++;
00529 goto retry;
00530
00531 case '+':
00532 CHECK_FOR_FLAGS(flags);
00533 flags |= FPLUS;
00534 p++;
00535 goto retry;
00536
00537 case '-':
00538 CHECK_FOR_FLAGS(flags);
00539 flags |= FMINUS;
00540 p++;
00541 goto retry;
00542
00543 case '0':
00544 CHECK_FOR_FLAGS(flags);
00545 flags |= FZERO;
00546 p++;
00547 goto retry;
00548
00549 case '1': case '2': case '3': case '4':
00550 case '5': case '6': case '7': case '8': case '9':
00551 n = 0;
00552 GETNUM(n, width);
00553 if (*p == '$') {
00554 if (nextvalue != Qundef) {
00555 rb_raise(rb_eArgError, "value given twice - %d$", n);
00556 }
00557 nextvalue = GETPOSARG(n);
00558 p++;
00559 goto retry;
00560 }
00561 CHECK_FOR_WIDTH(flags);
00562 width = n;
00563 flags |= FWIDTH;
00564 goto retry;
00565
00566 case '<':
00567 case '{':
00568 {
00569 const char *start = p;
00570 char term = (*p == '<') ? '>' : '}';
00571
00572 for (; p < end && *p != term; ) {
00573 p += rb_enc_mbclen(p, end, enc);
00574 }
00575 if (p >= end) {
00576 rb_raise(rb_eArgError, "malformed name - unmatched parenthesis");
00577 }
00578 if (id) {
00579 rb_raise(rb_eArgError, "name%.*s after <%s>",
00580 (int)(p - start + 1), start, rb_id2name(id));
00581 }
00582 id = rb_intern3(start + 1, p - start - 1, enc);
00583 nextvalue = GETNAMEARG(ID2SYM(id), start, (int)(p - start + 1));
00584 if (nextvalue == Qundef) {
00585 rb_raise(rb_eKeyError, "key%.*s not found", (int)(p - start + 1), start);
00586 }
00587 if (term == '}') goto format_s;
00588 p++;
00589 goto retry;
00590 }
00591
00592 case '*':
00593 CHECK_FOR_WIDTH(flags);
00594 flags |= FWIDTH;
00595 GETASTER(width);
00596 if (width < 0) {
00597 flags |= FMINUS;
00598 width = -width;
00599 }
00600 p++;
00601 goto retry;
00602
00603 case '.':
00604 if (flags & FPREC0) {
00605 rb_raise(rb_eArgError, "precision given twice");
00606 }
00607 flags |= FPREC|FPREC0;
00608
00609 prec = 0;
00610 p++;
00611 if (*p == '*') {
00612 GETASTER(prec);
00613 if (prec < 0) {
00614 flags &= ~FPREC;
00615 }
00616 p++;
00617 goto retry;
00618 }
00619
00620 GETNUM(prec, precision);
00621 goto retry;
00622
00623 case '\n':
00624 case '\0':
00625 p--;
00626 case '%':
00627 if (flags != FNONE) {
00628 rb_raise(rb_eArgError, "invalid format character - %%");
00629 }
00630 PUSH("%", 1);
00631 break;
00632
00633 case 'c':
00634 {
00635 VALUE val = GETARG();
00636 VALUE tmp;
00637 unsigned int c;
00638 int n;
00639
00640 tmp = rb_check_string_type(val);
00641 if (!NIL_P(tmp)) {
00642 if (rb_enc_strlen(RSTRING_PTR(tmp),RSTRING_END(tmp),enc) != 1) {
00643 rb_raise(rb_eArgError, "%%c requires a character");
00644 }
00645 c = rb_enc_codepoint_len(RSTRING_PTR(tmp), RSTRING_END(tmp), &n, enc);
00646 }
00647 else {
00648 c = NUM2INT(val);
00649 n = rb_enc_codelen(c, enc);
00650 }
00651 if (n <= 0) {
00652 rb_raise(rb_eArgError, "invalid character");
00653 }
00654 if (!(flags & FWIDTH)) {
00655 CHECK(n);
00656 rb_enc_mbcput(c, &buf[blen], enc);
00657 blen += n;
00658 }
00659 else if ((flags & FMINUS)) {
00660 CHECK(n);
00661 rb_enc_mbcput(c, &buf[blen], enc);
00662 blen += n;
00663 FILL(' ', width-1);
00664 }
00665 else {
00666 FILL(' ', width-1);
00667 CHECK(n);
00668 rb_enc_mbcput(c, &buf[blen], enc);
00669 blen += n;
00670 }
00671 }
00672 break;
00673
00674 case 's':
00675 case 'p':
00676 format_s:
00677 {
00678 VALUE arg = GETARG();
00679 long len, slen;
00680
00681 if (*p == 'p') arg = rb_inspect(arg);
00682 str = rb_obj_as_string(arg);
00683 if (OBJ_TAINTED(str)) tainted = 1;
00684 len = RSTRING_LEN(str);
00685 rb_str_set_len(result, blen);
00686 if (coderange != ENC_CODERANGE_BROKEN && scanned < blen) {
00687 int cr = coderange;
00688 scanned += rb_str_coderange_scan_restartable(buf+scanned, buf+blen, enc, &cr);
00689 ENC_CODERANGE_SET(result,
00690 (cr == ENC_CODERANGE_UNKNOWN ?
00691 ENC_CODERANGE_BROKEN : (coderange = cr)));
00692 }
00693 enc = rb_enc_check(result, str);
00694 if (flags&(FPREC|FWIDTH)) {
00695 slen = rb_enc_strlen(RSTRING_PTR(str),RSTRING_END(str),enc);
00696 if (slen < 0) {
00697 rb_raise(rb_eArgError, "invalid mbstring sequence");
00698 }
00699 if ((flags&FPREC) && (prec < slen)) {
00700 char *p = rb_enc_nth(RSTRING_PTR(str), RSTRING_END(str),
00701 prec, enc);
00702 slen = prec;
00703 len = p - RSTRING_PTR(str);
00704 }
00705
00706 if ((flags&FWIDTH) && (width > slen)) {
00707 width -= (int)slen;
00708 if (!(flags&FMINUS)) {
00709 CHECK(width);
00710 while (width--) {
00711 buf[blen++] = ' ';
00712 }
00713 }
00714 CHECK(len);
00715 memcpy(&buf[blen], RSTRING_PTR(str), len);
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_enc_associate(result, enc);
00729 }
00730 break;
00731
00732 case 'd':
00733 case 'i':
00734 case 'o':
00735 case 'x':
00736 case 'X':
00737 case 'b':
00738 case 'B':
00739 case 'u':
00740 {
00741 volatile VALUE tmp1;
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, pos;
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 tmp1 = 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 pos = -1;
00914 if (dots) {
00915 prec -= 2;
00916 width -= 2;
00917 }
00918
00919 if (*p == 'X') {
00920 char *pp = s;
00921 int c;
00922 while ((c = (int)(unsigned char)*pp) != 0) {
00923 *pp = rb_enc_toupper(c, enc);
00924 pp++;
00925 }
00926 }
00927 if (prefix && !prefix[1]) {
00928 if (dots) {
00929 prefix = 0;
00930 }
00931 else if (len == 1 && *s == '0') {
00932 len = 0;
00933 if (flags & FPREC) prec--;
00934 }
00935 else if ((flags & FPREC) && (prec > len)) {
00936 prefix = 0;
00937 }
00938 }
00939 else if (len == 1 && *s == '0') {
00940 prefix = 0;
00941 }
00942 if (prefix) {
00943 width -= (int)strlen(prefix);
00944 }
00945 if ((flags & (FZERO|FMINUS|FPREC)) == FZERO) {
00946 prec = width;
00947 width = 0;
00948 }
00949 else {
00950 if (prec < len) {
00951 if (!prefix && prec == 0 && len == 1 && *s == '0') len = 0;
00952 prec = len;
00953 }
00954 width -= prec;
00955 }
00956 if (!(flags&FMINUS)) {
00957 CHECK(width);
00958 while (width-- > 0) {
00959 buf[blen++] = ' ';
00960 }
00961 }
00962 if (sc) PUSH(&sc, 1);
00963 if (prefix) {
00964 int plen = (int)strlen(prefix);
00965 PUSH(prefix, plen);
00966 }
00967 CHECK(prec - len);
00968 if (dots) PUSH("..", 2);
00969 if (!bignum && v < 0) {
00970 char c = sign_bits(base, p);
00971 while (len < prec--) {
00972 buf[blen++] = c;
00973 }
00974 }
00975 else if ((flags & (FMINUS|FPREC)) != FMINUS) {
00976 char c;
00977
00978 if (!sign && bignum && !RBIGNUM_SIGN(val))
00979 c = sign_bits(base, p);
00980 else
00981 c = '0';
00982 while (len < prec--) {
00983 buf[blen++] = c;
00984 }
00985 }
00986 PUSH(s, len);
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
01072
01073 if (posarg >= 0 && nextarg < argc) {
01074 const char *mesg = "too many arguments for format string";
01075 if (RTEST(ruby_debug)) rb_raise(rb_eArgError, "%s", mesg);
01076 if (RTEST(ruby_verbose)) rb_warn("%s", mesg);
01077 }
01078 rb_str_resize(result, blen);
01079
01080 if (tainted) OBJ_TAINT(result);
01081 return result;
01082 }
01083
01084 static void
01085 fmt_setup(char *buf, size_t size, int c, int flags, int width, int prec)
01086 {
01087 char *end = buf + size;
01088 *buf++ = '%';
01089 if (flags & FSHARP) *buf++ = '#';
01090 if (flags & FPLUS) *buf++ = '+';
01091 if (flags & FMINUS) *buf++ = '-';
01092 if (flags & FZERO) *buf++ = '0';
01093 if (flags & FSPACE) *buf++ = ' ';
01094
01095 if (flags & FWIDTH) {
01096 snprintf(buf, end - buf, "%d", width);
01097 buf += strlen(buf);
01098 }
01099
01100 if (flags & FPREC) {
01101 snprintf(buf, end - buf, ".%d", prec);
01102 buf += strlen(buf);
01103 }
01104
01105 *buf++ = c;
01106 *buf = '\0';
01107 }
01108
01109 #undef FILE
01110 #define FILE rb_printf_buffer
01111 #define __sbuf rb_printf_sbuf
01112 #define __sFILE rb_printf_sfile
01113 #undef feof
01114 #undef ferror
01115 #undef clearerr
01116 #undef fileno
01117 #if SIZEOF_LONG < SIZEOF_VOIDP
01118 # if SIZEOF_LONG_LONG == SIZEOF_VOIDP
01119 # define _HAVE_SANE_QUAD_
01120 # define _HAVE_LLP64_
01121 # define quad_t LONG_LONG
01122 # define u_quad_t unsigned LONG_LONG
01123 # endif
01124 #endif
01125 #define FLOATING_POINT 1
01126 #define BSD__dtoa ruby_dtoa
01127 #include "vsnprintf.c"
01128
01129 static int
01130 ruby__sfvwrite(register rb_printf_buffer *fp, register struct __suio *uio)
01131 {
01132 struct __siov *iov;
01133 VALUE result = (VALUE)fp->_bf._base;
01134 char *buf = (char*)fp->_p;
01135 size_t len, n;
01136 size_t blen = buf - RSTRING_PTR(result), bsiz = fp->_w;
01137
01138 if (RBASIC(result)->klass) {
01139 rb_raise(rb_eRuntimeError, "rb_vsprintf reentered");
01140 }
01141 if ((len = uio->uio_resid) == 0)
01142 return 0;
01143 CHECK(len);
01144 buf += blen;
01145 fp->_w = bsiz;
01146 for (iov = uio->uio_iov; len > 0; ++iov) {
01147 MEMCPY(buf, iov->iov_base, char, n = iov->iov_len);
01148 buf += n;
01149 len -= n;
01150 }
01151 fp->_p = (unsigned char *)buf;
01152 return 0;
01153 }
01154
01155 VALUE
01156 rb_enc_vsprintf(rb_encoding *enc, const char *fmt, va_list ap)
01157 {
01158 rb_printf_buffer f;
01159 VALUE result;
01160
01161 f._flags = __SWR | __SSTR;
01162 f._bf._size = 0;
01163 f._w = 120;
01164 result = rb_str_buf_new(f._w);
01165 if (enc) rb_enc_associate(result, enc);
01166 f._bf._base = (unsigned char *)result;
01167 f._p = (unsigned char *)RSTRING_PTR(result);
01168 RBASIC(result)->klass = 0;
01169 f.vwrite = ruby__sfvwrite;
01170 BSD_vfprintf(&f, fmt, ap);
01171 RBASIC(result)->klass = rb_cString;
01172 rb_str_resize(result, (char *)f._p - RSTRING_PTR(result));
01173
01174 return result;
01175 }
01176
01177 VALUE
01178 rb_enc_sprintf(rb_encoding *enc, const char *format, ...)
01179 {
01180 VALUE result;
01181 va_list ap;
01182
01183 va_start(ap, format);
01184 result = rb_enc_vsprintf(enc, format, ap);
01185 va_end(ap);
01186
01187 return result;
01188 }
01189
01190 VALUE
01191 rb_vsprintf(const char *fmt, va_list ap)
01192 {
01193 return rb_enc_vsprintf(NULL, fmt, ap);
01194 }
01195
01196 VALUE
01197 rb_sprintf(const char *format, ...)
01198 {
01199 VALUE result;
01200 va_list ap;
01201
01202 va_start(ap, format);
01203 result = rb_vsprintf(format, ap);
01204 va_end(ap);
01205
01206 return result;
01207 }
01208
01209 VALUE
01210 rb_str_vcatf(VALUE str, const char *fmt, va_list ap)
01211 {
01212 rb_printf_buffer f;
01213 VALUE klass;
01214
01215 StringValue(str);
01216 rb_str_modify(str);
01217 f._flags = __SWR | __SSTR;
01218 f._bf._size = 0;
01219 f._w = rb_str_capacity(str);
01220 f._bf._base = (unsigned char *)str;
01221 f._p = (unsigned char *)RSTRING_END(str);
01222 klass = RBASIC(str)->klass;
01223 RBASIC(str)->klass = 0;
01224 f.vwrite = ruby__sfvwrite;
01225 BSD_vfprintf(&f, fmt, ap);
01226 RBASIC(str)->klass = klass;
01227 rb_str_resize(str, (char *)f._p - RSTRING_PTR(str));
01228
01229 return str;
01230 }
01231
01232 VALUE
01233 rb_str_catf(VALUE str, const char *format, ...)
01234 {
01235 va_list ap;
01236
01237 va_start(ap, format);
01238 str = rb_str_vcatf(str, format, ap);
01239 va_end(ap);
01240
01241 return str;
01242 }
01243