22 #define BIT_DIGITS(N) (((N)*146)/485 + 1)
23 #define BITSPERDIG (sizeof(mrb_int)*CHAR_BIT)
24 #define EXTENDSIGN(n, l) (((~0 << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0 << (n)))
29 remove_sign_bits(
char *str,
int base)
55 sign_bits(
int base,
const char *p)
61 if (*p ==
'X') c =
'F';
77 char buf[64], *
b = buf +
sizeof buf;
79 unsigned long val = (
unsigned long)num;
95 }
while (val /= base);
98 b = remove_sign_bits(b, base);
100 case 16: d =
'f';
break;
101 case 8: d =
'7';
break;
102 case 2: d =
'1';
break;
103 default: d = 0;
break;
124 #define CHECK(l) do {\
126 while (blen + (l) >= bsiz) {\
129 mrb_str_resize(mrb, result, bsiz);\
131 buf = RSTRING_PTR(result);\
134 #define PUSH(s, l) do { \
136 memcpy(&buf[blen], s, l);\
140 #define FILL(c, l) do { \
142 memset(&buf[blen], c, l);\
146 #define GETARG() (!mrb_undef_p(nextvalue) ? nextvalue : \
148 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with numbered", mrb_fixnum_value(nextarg)), mrb_undef_value()) : \
150 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with named", mrb_fixnum_value(nextarg)), mrb_undef_value()) : \
151 (posarg = nextarg++, GETNTHARG(posarg)))
153 #define GETPOSARG(n) (posarg > 0 ? \
154 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after unnumbered(%S)", mrb_fixnum_value(n), mrb_fixnum_value(posarg)), mrb_undef_value()) : \
156 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after named", mrb_fixnum_value(n)), mrb_undef_value()) : \
158 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid index - %S$", mrb_fixnum_value(n)), mrb_undef_value()) : \
159 (posarg = -1, GETNTHARG(n))))
161 #define GETNTHARG(nth) \
162 ((nth >= argc) ? (mrb_raise(mrb, E_ARGUMENT_ERROR, "too few arguments"), mrb_undef_value()) : argv[nth])
164 #define GETNAMEARG(id, name, len) ( \
166 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after unnumbered(%S)", mrb_str_new(mrb, (name), (len)), mrb_fixnum_value(posarg)), mrb_undef_value()) : \
168 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after numbered", mrb_str_new(mrb, (name), (len))), mrb_undef_value()) : \
169 (posarg = -2, mrb_hash_fetch(mrb, get_hash(mrb, &hash, argc, argv), id, mrb_undef_value())))
171 #define GETNUM(n, val) \
172 for (; p < end && ISDIGIT(*p); p++) {\
173 int next_n = 10 * n + (*p - '0'); \
174 if (next_n / 10 != n) {\
175 mrb_raise(mrb, E_ARGUMENT_ERROR, #val " too big"); \
180 mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed format string - %*[0-9]"); \
183 #define GETASTER(num) do { \
188 tmp = GETPOSARG(n); \
194 num = mrb_fixnum(tmp); \
210 return (*hash = tmp);
484 return mrb_nil_value();
510 #define CHECK_FOR_WIDTH(f) \
511 if ((f) & FWIDTH) { \
512 mrb_raise(mrb, E_ARGUMENT_ERROR, "width given twice"); \
514 if ((f) & FPREC0) { \
515 mrb_raise(mrb, E_ARGUMENT_ERROR, "width after precision"); \
517 #define CHECK_FOR_FLAGS(f) \
518 if ((f) & FWIDTH) { \
519 mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after width"); \
521 if ((f) & FPREC0) { \
522 mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after precision"); \
534 memset(buf, 0, bsiz);
536 for (; p < end; p++) {
540 for (t = p; t < end && *t !=
'%'; t++) ;
548 nextvalue = mrb_undef_value();
586 case '1':
case '2':
case '3':
case '4':
587 case '5':
case '6':
case '7':
case '8':
case '9':
605 const char *start = p;
606 char term = (*p ==
'<') ?
'>' :
'}';
609 for (; p < end && *p != term; )
615 symname =
mrb_str_new(mrb, start + 1, p - start - 1);
617 nextvalue =
GETNAMEARG(mrb_symbol_value(
id), start, (
int)(p - start + 1));
621 if (term ==
'}')
goto format_s;
662 if (flags !=
FNONE) {
693 else if ((flags &
FMINUS)) {
725 if ((flags&
FPREC) && (prec < slen)) {
731 if ((flags&
FWIDTH) && (width > slen)) {
764 char fbuf[32], nbuf[64], *s;
765 const char *prefix = NULL;
766 int sign = 0, dots = 0;
789 case 'o': prefix =
"0";
break;
790 case 'x': prefix =
"0x";
break;
791 case 'X': prefix =
"0X";
break;
792 case 'b': prefix =
"0b";
break;
793 case 'B': prefix =
"0B";
break;
837 if ( v < 0 && !sign ) {
838 val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base);
848 if (c ==
'i') c =
'd';
849 if (base == 2) c =
'd';
855 else if (flags &
FPLUS) {
859 else if (flags &
FSPACE) {
863 snprintf(fbuf,
sizeof(fbuf),
"%%l%c", c);
864 snprintf(nbuf,
sizeof(nbuf), fbuf, v);
869 if (c ==
'X') c =
'x';
870 if (base == 2) c =
'd';
875 snprintf(fbuf,
sizeof(fbuf),
"%%l%c", c);
876 snprintf(++s,
sizeof(nbuf) - 1, fbuf, v);
880 s = remove_sign_bits(s, base);
882 case 16: d =
'f';
break;
883 case 8: d =
'7';
break;
884 case 2: d =
'1';
break;
885 default: d = 0;
break;
908 while ((c = (
int)(
unsigned char)*pp) != 0) {
914 if (prefix && !prefix[1]) {
918 else if (len == 1 && *s ==
'0') {
920 if (flags &
FPREC) prec--;
922 else if ((flags &
FPREC) && (prec > len)) {
926 else if (len == 1 && *s ==
'0') {
932 size = strlen(prefix);
944 if (!prefix && prec == 0 && len == 1 && *s ==
'0') len = 0;
952 while (width-- > 0) {
957 if (sc)
PUSH(&sc, 1);
960 int plen = (int)strlen(prefix);
964 if (dots)
PUSH(
"..", 2);
966 if (v < 0 || (base == 2 && org_v < 0)) {
967 char c = sign_bits(base, p);
968 while (len < prec--) {
972 else if ((flags & (FMINUS|
FPREC)) != FMINUS) {
974 while (len < prec--) {
981 while (width-- > 0) {
1000 if (isnan(fval) || isinf(fval)) {
1011 if ((!isnan(fval) && fval < 0.0) || (flags &
FPLUS))
1013 if ((flags &
FWIDTH) && need < width)
1017 snprintf(&buf[blen], need + 1,
"%*s", need,
"");
1019 if (!isnan(fval) && fval < 0.0)
1021 else if (flags & FPLUS)
1025 memcpy(&buf[blen], expr, elen);
1028 if (!isnan(fval) && fval < 0.0)
1029 buf[blen + need - elen - 1] =
'-';
1030 else if (flags & FPLUS)
1031 buf[blen + need - elen - 1] =
'+';
1032 else if ((flags &
FSPACE) && need > width)
1034 memcpy(&buf[blen + need - elen], expr, elen);
1036 blen += strlen(&buf[blen]);
1040 fmt_setup(fbuf,
sizeof(fbuf), *p, flags, width, prec);
1042 if (*p !=
'e' && *p !=
'E') {
1048 need += (flags&
FPREC) ? prec : 6;
1049 if ((flags&
FWIDTH) && need < width)
1054 n = snprintf(&buf[blen], need, fbuf, fval);
1066 if (posarg >= 0 && nextarg < argc) {
1067 const char *mesg =
"too many arguments for format string";
1078 fmt_setup(
char *buf,
size_t size,
int c,
int flags,
mrb_int width,
mrb_int prec)
1080 char *end = buf + size;
1084 if (flags &
FSHARP) *buf++ =
'#';
1085 if (flags &
FPLUS) *buf++ =
'+';
1086 if (flags &
FMINUS) *buf++ =
'-';
1087 if (flags &
FZERO) *buf++ =
'0';
1088 if (flags &
FSPACE) *buf++ =
' ';
1091 n = snprintf(buf, end - buf,
"%d", (
int)width);
1095 if (flags &
FPREC) {
1096 n = snprintf(buf, end - buf,
".%d", (
int)prec);