mbed I/F binding for mruby

Dependents:   mruby_mbed_web mirb_mbed

mbed-mruby

How to use

Class

Committer:
mzta
Date:
Mon Apr 13 05:20:15 2015 +0000
Revision:
1:8ccd1d494a4b
Parent:
0:158c61bb030f
- code refactoring.; - add SPI, SPISlave, I2C class to mruby-mbed (Incomplete).

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mzta 0:158c61bb030f 1 /*
mzta 0:158c61bb030f 2 ** sprintf.c - Kernel.#sprintf
mzta 0:158c61bb030f 3 **
mzta 0:158c61bb030f 4 ** See Copyright Notice in mruby.h
mzta 0:158c61bb030f 5 */
mzta 0:158c61bb030f 6
mzta 0:158c61bb030f 7 #include "mruby.h"
mzta 0:158c61bb030f 8
mzta 0:158c61bb030f 9 #include <limits.h>
mzta 0:158c61bb030f 10 #include <stdio.h>
mzta 0:158c61bb030f 11 #include <string.h>
mzta 0:158c61bb030f 12 #include "mruby/string.h"
mzta 0:158c61bb030f 13 #include "mruby/hash.h"
mzta 0:158c61bb030f 14 #include "mruby/numeric.h"
mzta 0:158c61bb030f 15 #include <math.h>
mzta 0:158c61bb030f 16 #include <ctype.h>
mzta 0:158c61bb030f 17
mzta 0:158c61bb030f 18 #define BIT_DIGITS(N) (((N)*146)/485 + 1) /* log2(10) =~ 146/485 */
mzta 0:158c61bb030f 19 #define BITSPERDIG MRB_INT_BIT
mzta 0:158c61bb030f 20 #define EXTENDSIGN(n, l) (((~0 << (n)) >> (((n)*(l)) % BITSPERDIG)) & ~(~0 << (n)))
mzta 0:158c61bb030f 21
mzta 0:158c61bb030f 22 mrb_value mrb_str_format(mrb_state *, int, const mrb_value *, mrb_value);
mzta 0:158c61bb030f 23 static void fmt_setup(char*,size_t,int,int,mrb_int,mrb_int);
mzta 0:158c61bb030f 24
mzta 0:158c61bb030f 25 static char*
mzta 0:158c61bb030f 26 remove_sign_bits(char *str, int base)
mzta 0:158c61bb030f 27 {
mzta 0:158c61bb030f 28 char *t;
mzta 0:158c61bb030f 29
mzta 0:158c61bb030f 30 t = str;
mzta 0:158c61bb030f 31 if (base == 16) {
mzta 0:158c61bb030f 32 while (*t == 'f') {
mzta 0:158c61bb030f 33 t++;
mzta 0:158c61bb030f 34 }
mzta 0:158c61bb030f 35 }
mzta 0:158c61bb030f 36 else if (base == 8) {
mzta 0:158c61bb030f 37 *t |= EXTENDSIGN(3, strlen(t));
mzta 0:158c61bb030f 38 while (*t == '7') {
mzta 0:158c61bb030f 39 t++;
mzta 0:158c61bb030f 40 }
mzta 0:158c61bb030f 41 }
mzta 0:158c61bb030f 42 else if (base == 2) {
mzta 0:158c61bb030f 43 while (*t == '1') {
mzta 0:158c61bb030f 44 t++;
mzta 0:158c61bb030f 45 }
mzta 0:158c61bb030f 46 }
mzta 0:158c61bb030f 47
mzta 0:158c61bb030f 48 return t;
mzta 0:158c61bb030f 49 }
mzta 0:158c61bb030f 50
mzta 0:158c61bb030f 51 static char
mzta 0:158c61bb030f 52 sign_bits(int base, const char *p)
mzta 0:158c61bb030f 53 {
mzta 0:158c61bb030f 54 char c;
mzta 0:158c61bb030f 55
mzta 0:158c61bb030f 56 switch (base) {
mzta 0:158c61bb030f 57 case 16:
mzta 0:158c61bb030f 58 if (*p == 'X') c = 'F';
mzta 0:158c61bb030f 59 else c = 'f';
mzta 0:158c61bb030f 60 break;
mzta 0:158c61bb030f 61 case 8:
mzta 0:158c61bb030f 62 c = '7'; break;
mzta 0:158c61bb030f 63 case 2:
mzta 0:158c61bb030f 64 c = '1'; break;
mzta 0:158c61bb030f 65 default:
mzta 0:158c61bb030f 66 c = '.'; break;
mzta 0:158c61bb030f 67 }
mzta 0:158c61bb030f 68 return c;
mzta 0:158c61bb030f 69 }
mzta 0:158c61bb030f 70
mzta 0:158c61bb030f 71 static mrb_value
mzta 0:158c61bb030f 72 mrb_fix2binstr(mrb_state *mrb, mrb_value x, int base)
mzta 0:158c61bb030f 73 {
mzta 0:158c61bb030f 74 char buf[64], *b = buf + sizeof buf;
mzta 0:158c61bb030f 75 mrb_int num = mrb_fixnum(x);
mzta 0:158c61bb030f 76 unsigned long val = (unsigned long)num;
mzta 0:158c61bb030f 77 char d;
mzta 0:158c61bb030f 78
mzta 0:158c61bb030f 79 if (base != 2) {
mzta 0:158c61bb030f 80 mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %S", mrb_fixnum_value(base));
mzta 0:158c61bb030f 81 }
mzta 0:158c61bb030f 82
mzta 0:158c61bb030f 83 if (val >= (1 << 10))
mzta 0:158c61bb030f 84 val &= 0x3ff;
mzta 0:158c61bb030f 85
mzta 0:158c61bb030f 86 if (val == 0) {
mzta 0:158c61bb030f 87 return mrb_str_new_lit(mrb, "0");
mzta 0:158c61bb030f 88 }
mzta 0:158c61bb030f 89 *--b = '\0';
mzta 0:158c61bb030f 90 do {
mzta 0:158c61bb030f 91 *--b = mrb_digitmap[(int)(val % base)];
mzta 0:158c61bb030f 92 } while (val /= base);
mzta 0:158c61bb030f 93
mzta 0:158c61bb030f 94 if (num < 0) {
mzta 0:158c61bb030f 95 b = remove_sign_bits(b, base);
mzta 0:158c61bb030f 96 switch (base) {
mzta 0:158c61bb030f 97 case 16: d = 'f'; break;
mzta 0:158c61bb030f 98 case 8: d = '7'; break;
mzta 0:158c61bb030f 99 case 2: d = '1'; break;
mzta 0:158c61bb030f 100 default: d = 0; break;
mzta 0:158c61bb030f 101 }
mzta 0:158c61bb030f 102
mzta 0:158c61bb030f 103 if (d && *b != d) {
mzta 0:158c61bb030f 104 *--b = d;
mzta 0:158c61bb030f 105 }
mzta 0:158c61bb030f 106 }
mzta 0:158c61bb030f 107
mzta 0:158c61bb030f 108 return mrb_str_new_cstr(mrb, b);
mzta 0:158c61bb030f 109 }
mzta 0:158c61bb030f 110
mzta 0:158c61bb030f 111 #define FNONE 0
mzta 0:158c61bb030f 112 #define FSHARP 1
mzta 0:158c61bb030f 113 #define FMINUS 2
mzta 0:158c61bb030f 114 #define FPLUS 4
mzta 0:158c61bb030f 115 #define FZERO 8
mzta 0:158c61bb030f 116 #define FSPACE 16
mzta 0:158c61bb030f 117 #define FWIDTH 32
mzta 0:158c61bb030f 118 #define FPREC 64
mzta 0:158c61bb030f 119 #define FPREC0 128
mzta 0:158c61bb030f 120
mzta 0:158c61bb030f 121 #define CHECK(l) do {\
mzta 0:158c61bb030f 122 /* int cr = ENC_CODERANGE(result);*/\
mzta 0:158c61bb030f 123 while (blen + (l) >= bsiz) {\
mzta 0:158c61bb030f 124 bsiz*=2;\
mzta 0:158c61bb030f 125 }\
mzta 0:158c61bb030f 126 mrb_str_resize(mrb, result, bsiz);\
mzta 0:158c61bb030f 127 /* ENC_CODERANGE_SET(result, cr);*/\
mzta 0:158c61bb030f 128 buf = RSTRING_PTR(result);\
mzta 0:158c61bb030f 129 } while (0)
mzta 0:158c61bb030f 130
mzta 0:158c61bb030f 131 #define PUSH(s, l) do { \
mzta 0:158c61bb030f 132 CHECK(l);\
mzta 0:158c61bb030f 133 memcpy(&buf[blen], s, l);\
mzta 0:158c61bb030f 134 blen += (l);\
mzta 0:158c61bb030f 135 } while (0)
mzta 0:158c61bb030f 136
mzta 0:158c61bb030f 137 #define FILL(c, l) do { \
mzta 0:158c61bb030f 138 CHECK(l);\
mzta 0:158c61bb030f 139 memset(&buf[blen], c, l);\
mzta 0:158c61bb030f 140 blen += (l);\
mzta 0:158c61bb030f 141 } while (0)
mzta 0:158c61bb030f 142
mzta 0:158c61bb030f 143 #define GETARG() (!mrb_undef_p(nextvalue) ? nextvalue : \
mzta 0:158c61bb030f 144 posarg == -1 ? \
mzta 0:158c61bb030f 145 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with numbered", mrb_fixnum_value(nextarg)), mrb_undef_value()) : \
mzta 0:158c61bb030f 146 posarg == -2 ? \
mzta 0:158c61bb030f 147 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "unnumbered(%S) mixed with named", mrb_fixnum_value(nextarg)), mrb_undef_value()) : \
mzta 0:158c61bb030f 148 (posarg = nextarg++, GETNTHARG(posarg)))
mzta 0:158c61bb030f 149
mzta 0:158c61bb030f 150 #define GETPOSARG(n) (posarg > 0 ? \
mzta 0:158c61bb030f 151 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after unnumbered(%S)", mrb_fixnum_value(n), mrb_fixnum_value(posarg)), mrb_undef_value()) : \
mzta 0:158c61bb030f 152 posarg == -2 ? \
mzta 0:158c61bb030f 153 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "numbered(%S) after named", mrb_fixnum_value(n)), mrb_undef_value()) : \
mzta 0:158c61bb030f 154 ((n < 1) ? \
mzta 0:158c61bb030f 155 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid index - %S$", mrb_fixnum_value(n)), mrb_undef_value()) : \
mzta 0:158c61bb030f 156 (posarg = -1, GETNTHARG(n))))
mzta 0:158c61bb030f 157
mzta 0:158c61bb030f 158 #define GETNTHARG(nth) \
mzta 0:158c61bb030f 159 ((nth >= argc) ? (mrb_raise(mrb, E_ARGUMENT_ERROR, "too few arguments"), mrb_undef_value()) : argv[nth])
mzta 0:158c61bb030f 160
mzta 0:158c61bb030f 161 #define GETNAMEARG(id, name, len) ( \
mzta 0:158c61bb030f 162 posarg > 0 ? \
mzta 0:158c61bb030f 163 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after unnumbered(%S)", mrb_str_new(mrb, (name), (len)), mrb_fixnum_value(posarg)), mrb_undef_value()) : \
mzta 0:158c61bb030f 164 posarg == -1 ? \
mzta 0:158c61bb030f 165 (mrb_raisef(mrb, E_ARGUMENT_ERROR, "named%S after numbered", mrb_str_new(mrb, (name), (len))), mrb_undef_value()) : \
mzta 0:158c61bb030f 166 (posarg = -2, mrb_hash_fetch(mrb, get_hash(mrb, &hash, argc, argv), id, mrb_undef_value())))
mzta 0:158c61bb030f 167
mzta 0:158c61bb030f 168 #define GETNUM(n, val) \
mzta 0:158c61bb030f 169 for (; p < end && ISDIGIT(*p); p++) {\
mzta 0:158c61bb030f 170 int next_n = 10 * n + (*p - '0'); \
mzta 0:158c61bb030f 171 if (next_n / 10 != n) {\
mzta 0:158c61bb030f 172 mrb_raise(mrb, E_ARGUMENT_ERROR, #val " too big"); \
mzta 0:158c61bb030f 173 } \
mzta 0:158c61bb030f 174 n = next_n; \
mzta 0:158c61bb030f 175 } \
mzta 0:158c61bb030f 176 if (p >= end) { \
mzta 0:158c61bb030f 177 mrb_raise(mrb, E_ARGUMENT_ERROR, "malformed format string - %*[0-9]"); \
mzta 0:158c61bb030f 178 }
mzta 0:158c61bb030f 179
mzta 0:158c61bb030f 180 #define GETASTER(num) do { \
mzta 0:158c61bb030f 181 mrb_value tmp_v; \
mzta 0:158c61bb030f 182 t = p++; \
mzta 0:158c61bb030f 183 n = 0; \
mzta 0:158c61bb030f 184 GETNUM(n, val); \
mzta 0:158c61bb030f 185 if (*p == '$') { \
mzta 0:158c61bb030f 186 tmp_v = GETPOSARG(n); \
mzta 0:158c61bb030f 187 } \
mzta 0:158c61bb030f 188 else { \
mzta 0:158c61bb030f 189 tmp_v = GETARG(); \
mzta 0:158c61bb030f 190 p = t; \
mzta 0:158c61bb030f 191 } \
mzta 0:158c61bb030f 192 num = mrb_fixnum(tmp_v); \
mzta 0:158c61bb030f 193 } while (0)
mzta 0:158c61bb030f 194
mzta 0:158c61bb030f 195 static mrb_value
mzta 0:158c61bb030f 196 get_hash(mrb_state *mrb, mrb_value *hash, int argc, const mrb_value *argv)
mzta 0:158c61bb030f 197 {
mzta 0:158c61bb030f 198 mrb_value tmp;
mzta 0:158c61bb030f 199
mzta 0:158c61bb030f 200 if (!mrb_undef_p(*hash)) return *hash;
mzta 0:158c61bb030f 201 if (argc != 2) {
mzta 0:158c61bb030f 202 mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required");
mzta 0:158c61bb030f 203 }
mzta 0:158c61bb030f 204 tmp = mrb_check_convert_type(mrb, argv[1], MRB_TT_HASH, "Hash", "to_hash");
mzta 0:158c61bb030f 205 if (mrb_nil_p(tmp)) {
mzta 0:158c61bb030f 206 mrb_raise(mrb, E_ARGUMENT_ERROR, "one hash required");
mzta 0:158c61bb030f 207 }
mzta 0:158c61bb030f 208 return (*hash = tmp);
mzta 0:158c61bb030f 209 }
mzta 0:158c61bb030f 210
mzta 0:158c61bb030f 211 /*
mzta 0:158c61bb030f 212 * call-seq:
mzta 0:158c61bb030f 213 * format(format_string [, arguments...] ) -> string
mzta 0:158c61bb030f 214 * sprintf(format_string [, arguments...] ) -> string
mzta 0:158c61bb030f 215 *
mzta 0:158c61bb030f 216 * Returns the string resulting from applying <i>format_string</i> to
mzta 0:158c61bb030f 217 * any additional arguments. Within the format string, any characters
mzta 0:158c61bb030f 218 * other than format sequences are copied to the result.
mzta 0:158c61bb030f 219 *
mzta 0:158c61bb030f 220 * The syntax of a format sequence is follows.
mzta 0:158c61bb030f 221 *
mzta 0:158c61bb030f 222 * %[flags][width][.precision]type
mzta 0:158c61bb030f 223 *
mzta 0:158c61bb030f 224 * A format
mzta 0:158c61bb030f 225 * sequence consists of a percent sign, followed by optional flags,
mzta 0:158c61bb030f 226 * width, and precision indicators, then terminated with a field type
mzta 0:158c61bb030f 227 * character. The field type controls how the corresponding
mzta 0:158c61bb030f 228 * <code>sprintf</code> argument is to be interpreted, while the flags
mzta 0:158c61bb030f 229 * modify that interpretation.
mzta 0:158c61bb030f 230 *
mzta 0:158c61bb030f 231 * The field type characters are:
mzta 0:158c61bb030f 232 *
mzta 0:158c61bb030f 233 * Field | Integer Format
mzta 0:158c61bb030f 234 * ------+--------------------------------------------------------------
mzta 0:158c61bb030f 235 * b | Convert argument as a binary number.
mzta 0:158c61bb030f 236 * | Negative numbers will be displayed as a two's complement
mzta 0:158c61bb030f 237 * | prefixed with `..1'.
mzta 0:158c61bb030f 238 * B | Equivalent to `b', but uses an uppercase 0B for prefix
mzta 0:158c61bb030f 239 * | in the alternative format by #.
mzta 0:158c61bb030f 240 * d | Convert argument as a decimal number.
mzta 0:158c61bb030f 241 * i | Identical to `d'.
mzta 0:158c61bb030f 242 * o | Convert argument as an octal number.
mzta 0:158c61bb030f 243 * | Negative numbers will be displayed as a two's complement
mzta 0:158c61bb030f 244 * | prefixed with `..7'.
mzta 0:158c61bb030f 245 * u | Identical to `d'.
mzta 0:158c61bb030f 246 * x | Convert argument as a hexadecimal number.
mzta 0:158c61bb030f 247 * | Negative numbers will be displayed as a two's complement
mzta 0:158c61bb030f 248 * | prefixed with `..f' (representing an infinite string of
mzta 0:158c61bb030f 249 * | leading 'ff's).
mzta 0:158c61bb030f 250 * X | Equivalent to `x', but uses uppercase letters.
mzta 0:158c61bb030f 251 *
mzta 0:158c61bb030f 252 * Field | Float Format
mzta 0:158c61bb030f 253 * ------+--------------------------------------------------------------
mzta 0:158c61bb030f 254 * e | Convert floating point argument into exponential notation
mzta 0:158c61bb030f 255 * | with one digit before the decimal point as [-]d.dddddde[+-]dd.
mzta 0:158c61bb030f 256 * | The precision specifies the number of digits after the decimal
mzta 0:158c61bb030f 257 * | point (defaulting to six).
mzta 0:158c61bb030f 258 * E | Equivalent to `e', but uses an uppercase E to indicate
mzta 0:158c61bb030f 259 * | the exponent.
mzta 0:158c61bb030f 260 * f | Convert floating point argument as [-]ddd.dddddd,
mzta 0:158c61bb030f 261 * | where the precision specifies the number of digits after
mzta 0:158c61bb030f 262 * | the decimal point.
mzta 0:158c61bb030f 263 * g | Convert a floating point number using exponential form
mzta 0:158c61bb030f 264 * | if the exponent is less than -4 or greater than or
mzta 0:158c61bb030f 265 * | equal to the precision, or in dd.dddd form otherwise.
mzta 0:158c61bb030f 266 * | The precision specifies the number of significant digits.
mzta 0:158c61bb030f 267 * G | Equivalent to `g', but use an uppercase `E' in exponent form.
mzta 0:158c61bb030f 268 * a | Convert floating point argument as [-]0xh.hhhhp[+-]dd,
mzta 0:158c61bb030f 269 * | which is consisted from optional sign, "0x", fraction part
mzta 0:158c61bb030f 270 * | as hexadecimal, "p", and exponential part as decimal.
mzta 0:158c61bb030f 271 * A | Equivalent to `a', but use uppercase `X' and `P'.
mzta 0:158c61bb030f 272 *
mzta 0:158c61bb030f 273 * Field | Other Format
mzta 0:158c61bb030f 274 * ------+--------------------------------------------------------------
mzta 0:158c61bb030f 275 * c | Argument is the numeric code for a single character or
mzta 0:158c61bb030f 276 * | a single character string itself.
mzta 0:158c61bb030f 277 * p | The valuing of argument.inspect.
mzta 0:158c61bb030f 278 * s | Argument is a string to be substituted. If the format
mzta 0:158c61bb030f 279 * | sequence contains a precision, at most that many characters
mzta 0:158c61bb030f 280 * | will be copied.
mzta 0:158c61bb030f 281 * % | A percent sign itself will be displayed. No argument taken.
mzta 0:158c61bb030f 282 *
mzta 0:158c61bb030f 283 * The flags modifies the behavior of the formats.
mzta 0:158c61bb030f 284 * The flag characters are:
mzta 0:158c61bb030f 285 *
mzta 0:158c61bb030f 286 * Flag | Applies to | Meaning
mzta 0:158c61bb030f 287 * ---------+---------------+-----------------------------------------
mzta 0:158c61bb030f 288 * space | bBdiouxX | Leave a space at the start of
mzta 0:158c61bb030f 289 * | aAeEfgG | non-negative numbers.
mzta 0:158c61bb030f 290 * | (numeric fmt) | For `o', `x', `X', `b' and `B', use
mzta 0:158c61bb030f 291 * | | a minus sign with absolute value for
mzta 0:158c61bb030f 292 * | | negative values.
mzta 0:158c61bb030f 293 * ---------+---------------+-----------------------------------------
mzta 0:158c61bb030f 294 * (digit)$ | all | Specifies the absolute argument number
mzta 0:158c61bb030f 295 * | | for this field. Absolute and relative
mzta 0:158c61bb030f 296 * | | argument numbers cannot be mixed in a
mzta 0:158c61bb030f 297 * | | sprintf string.
mzta 0:158c61bb030f 298 * ---------+---------------+-----------------------------------------
mzta 0:158c61bb030f 299 * # | bBoxX | Use an alternative format.
mzta 0:158c61bb030f 300 * | aAeEfgG | For the conversions `o', increase the precision
mzta 0:158c61bb030f 301 * | | until the first digit will be `0' if
mzta 0:158c61bb030f 302 * | | it is not formatted as complements.
mzta 0:158c61bb030f 303 * | | For the conversions `x', `X', `b' and `B'
mzta 0:158c61bb030f 304 * | | on non-zero, prefix the result with ``0x'',
mzta 0:158c61bb030f 305 * | | ``0X'', ``0b'' and ``0B'', respectively.
mzta 0:158c61bb030f 306 * | | For `a', `A', `e', `E', `f', `g', and 'G',
mzta 0:158c61bb030f 307 * | | force a decimal point to be added,
mzta 0:158c61bb030f 308 * | | even if no digits follow.
mzta 0:158c61bb030f 309 * | | For `g' and 'G', do not remove trailing zeros.
mzta 0:158c61bb030f 310 * ---------+---------------+-----------------------------------------
mzta 0:158c61bb030f 311 * + | bBdiouxX | Add a leading plus sign to non-negative
mzta 0:158c61bb030f 312 * | aAeEfgG | numbers.
mzta 0:158c61bb030f 313 * | (numeric fmt) | For `o', `x', `X', `b' and `B', use
mzta 0:158c61bb030f 314 * | | a minus sign with absolute value for
mzta 0:158c61bb030f 315 * | | negative values.
mzta 0:158c61bb030f 316 * ---------+---------------+-----------------------------------------
mzta 0:158c61bb030f 317 * - | all | Left-justify the result of this conversion.
mzta 0:158c61bb030f 318 * ---------+---------------+-----------------------------------------
mzta 0:158c61bb030f 319 * 0 (zero) | bBdiouxX | Pad with zeros, not spaces.
mzta 0:158c61bb030f 320 * | aAeEfgG | For `o', `x', `X', `b' and `B', radix-1
mzta 0:158c61bb030f 321 * | (numeric fmt) | is used for negative numbers formatted as
mzta 0:158c61bb030f 322 * | | complements.
mzta 0:158c61bb030f 323 * ---------+---------------+-----------------------------------------
mzta 0:158c61bb030f 324 * * | all | Use the next argument as the field width.
mzta 0:158c61bb030f 325 * | | If negative, left-justify the result. If the
mzta 0:158c61bb030f 326 * | | asterisk is followed by a number and a dollar
mzta 0:158c61bb030f 327 * | | sign, use the indicated argument as the width.
mzta 0:158c61bb030f 328 *
mzta 0:158c61bb030f 329 * Examples of flags:
mzta 0:158c61bb030f 330 *
mzta 0:158c61bb030f 331 * # `+' and space flag specifies the sign of non-negative numbers.
mzta 0:158c61bb030f 332 * sprintf("%d", 123) #=> "123"
mzta 0:158c61bb030f 333 * sprintf("%+d", 123) #=> "+123"
mzta 0:158c61bb030f 334 * sprintf("% d", 123) #=> " 123"
mzta 0:158c61bb030f 335 *
mzta 0:158c61bb030f 336 * # `#' flag for `o' increases number of digits to show `0'.
mzta 0:158c61bb030f 337 * # `+' and space flag changes format of negative numbers.
mzta 0:158c61bb030f 338 * sprintf("%o", 123) #=> "173"
mzta 0:158c61bb030f 339 * sprintf("%#o", 123) #=> "0173"
mzta 0:158c61bb030f 340 * sprintf("%+o", -123) #=> "-173"
mzta 0:158c61bb030f 341 * sprintf("%o", -123) #=> "..7605"
mzta 0:158c61bb030f 342 * sprintf("%#o", -123) #=> "..7605"
mzta 0:158c61bb030f 343 *
mzta 0:158c61bb030f 344 * # `#' flag for `x' add a prefix `0x' for non-zero numbers.
mzta 0:158c61bb030f 345 * # `+' and space flag disables complements for negative numbers.
mzta 0:158c61bb030f 346 * sprintf("%x", 123) #=> "7b"
mzta 0:158c61bb030f 347 * sprintf("%#x", 123) #=> "0x7b"
mzta 0:158c61bb030f 348 * sprintf("%+x", -123) #=> "-7b"
mzta 0:158c61bb030f 349 * sprintf("%x", -123) #=> "..f85"
mzta 0:158c61bb030f 350 * sprintf("%#x", -123) #=> "0x..f85"
mzta 0:158c61bb030f 351 * sprintf("%#x", 0) #=> "0"
mzta 0:158c61bb030f 352 *
mzta 0:158c61bb030f 353 * # `#' for `X' uses the prefix `0X'.
mzta 0:158c61bb030f 354 * sprintf("%X", 123) #=> "7B"
mzta 0:158c61bb030f 355 * sprintf("%#X", 123) #=> "0X7B"
mzta 0:158c61bb030f 356 *
mzta 0:158c61bb030f 357 * # `#' flag for `b' add a prefix `0b' for non-zero numbers.
mzta 0:158c61bb030f 358 * # `+' and space flag disables complements for negative numbers.
mzta 0:158c61bb030f 359 * sprintf("%b", 123) #=> "1111011"
mzta 0:158c61bb030f 360 * sprintf("%#b", 123) #=> "0b1111011"
mzta 0:158c61bb030f 361 * sprintf("%+b", -123) #=> "-1111011"
mzta 0:158c61bb030f 362 * sprintf("%b", -123) #=> "..10000101"
mzta 0:158c61bb030f 363 * sprintf("%#b", -123) #=> "0b..10000101"
mzta 0:158c61bb030f 364 * sprintf("%#b", 0) #=> "0"
mzta 0:158c61bb030f 365 *
mzta 0:158c61bb030f 366 * # `#' for `B' uses the prefix `0B'.
mzta 0:158c61bb030f 367 * sprintf("%B", 123) #=> "1111011"
mzta 0:158c61bb030f 368 * sprintf("%#B", 123) #=> "0B1111011"
mzta 0:158c61bb030f 369 *
mzta 0:158c61bb030f 370 * # `#' for `e' forces to show the decimal point.
mzta 0:158c61bb030f 371 * sprintf("%.0e", 1) #=> "1e+00"
mzta 0:158c61bb030f 372 * sprintf("%#.0e", 1) #=> "1.e+00"
mzta 0:158c61bb030f 373 *
mzta 0:158c61bb030f 374 * # `#' for `f' forces to show the decimal point.
mzta 0:158c61bb030f 375 * sprintf("%.0f", 1234) #=> "1234"
mzta 0:158c61bb030f 376 * sprintf("%#.0f", 1234) #=> "1234."
mzta 0:158c61bb030f 377 *
mzta 0:158c61bb030f 378 * # `#' for `g' forces to show the decimal point.
mzta 0:158c61bb030f 379 * # It also disables stripping lowest zeros.
mzta 0:158c61bb030f 380 * sprintf("%g", 123.4) #=> "123.4"
mzta 0:158c61bb030f 381 * sprintf("%#g", 123.4) #=> "123.400"
mzta 0:158c61bb030f 382 * sprintf("%g", 123456) #=> "123456"
mzta 0:158c61bb030f 383 * sprintf("%#g", 123456) #=> "123456."
mzta 0:158c61bb030f 384 *
mzta 0:158c61bb030f 385 * The field width is an optional integer, followed optionally by a
mzta 0:158c61bb030f 386 * period and a precision. The width specifies the minimum number of
mzta 0:158c61bb030f 387 * characters that will be written to the result for this field.
mzta 0:158c61bb030f 388 *
mzta 0:158c61bb030f 389 * Examples of width:
mzta 0:158c61bb030f 390 *
mzta 0:158c61bb030f 391 * # padding is done by spaces, width=20
mzta 0:158c61bb030f 392 * # 0 or radix-1. <------------------>
mzta 0:158c61bb030f 393 * sprintf("%20d", 123) #=> " 123"
mzta 0:158c61bb030f 394 * sprintf("%+20d", 123) #=> " +123"
mzta 0:158c61bb030f 395 * sprintf("%020d", 123) #=> "00000000000000000123"
mzta 0:158c61bb030f 396 * sprintf("%+020d", 123) #=> "+0000000000000000123"
mzta 0:158c61bb030f 397 * sprintf("% 020d", 123) #=> " 0000000000000000123"
mzta 0:158c61bb030f 398 * sprintf("%-20d", 123) #=> "123 "
mzta 0:158c61bb030f 399 * sprintf("%-+20d", 123) #=> "+123 "
mzta 0:158c61bb030f 400 * sprintf("%- 20d", 123) #=> " 123 "
mzta 0:158c61bb030f 401 * sprintf("%020x", -123) #=> "..ffffffffffffffff85"
mzta 0:158c61bb030f 402 *
mzta 0:158c61bb030f 403 * For
mzta 0:158c61bb030f 404 * numeric fields, the precision controls the number of decimal places
mzta 0:158c61bb030f 405 * displayed. For string fields, the precision determines the maximum
mzta 0:158c61bb030f 406 * number of characters to be copied from the string. (Thus, the format
mzta 0:158c61bb030f 407 * sequence <code>%10.10s</code> will always contribute exactly ten
mzta 0:158c61bb030f 408 * characters to the result.)
mzta 0:158c61bb030f 409 *
mzta 0:158c61bb030f 410 * Examples of precisions:
mzta 0:158c61bb030f 411 *
mzta 0:158c61bb030f 412 * # precision for `d', 'o', 'x' and 'b' is
mzta 0:158c61bb030f 413 * # minimum number of digits <------>
mzta 0:158c61bb030f 414 * sprintf("%20.8d", 123) #=> " 00000123"
mzta 0:158c61bb030f 415 * sprintf("%20.8o", 123) #=> " 00000173"
mzta 0:158c61bb030f 416 * sprintf("%20.8x", 123) #=> " 0000007b"
mzta 0:158c61bb030f 417 * sprintf("%20.8b", 123) #=> " 01111011"
mzta 0:158c61bb030f 418 * sprintf("%20.8d", -123) #=> " -00000123"
mzta 0:158c61bb030f 419 * sprintf("%20.8o", -123) #=> " ..777605"
mzta 0:158c61bb030f 420 * sprintf("%20.8x", -123) #=> " ..ffff85"
mzta 0:158c61bb030f 421 * sprintf("%20.8b", -11) #=> " ..110101"
mzta 0:158c61bb030f 422 *
mzta 0:158c61bb030f 423 * # "0x" and "0b" for `#x' and `#b' is not counted for
mzta 0:158c61bb030f 424 * # precision but "0" for `#o' is counted. <------>
mzta 0:158c61bb030f 425 * sprintf("%#20.8d", 123) #=> " 00000123"
mzta 0:158c61bb030f 426 * sprintf("%#20.8o", 123) #=> " 00000173"
mzta 0:158c61bb030f 427 * sprintf("%#20.8x", 123) #=> " 0x0000007b"
mzta 0:158c61bb030f 428 * sprintf("%#20.8b", 123) #=> " 0b01111011"
mzta 0:158c61bb030f 429 * sprintf("%#20.8d", -123) #=> " -00000123"
mzta 0:158c61bb030f 430 * sprintf("%#20.8o", -123) #=> " ..777605"
mzta 0:158c61bb030f 431 * sprintf("%#20.8x", -123) #=> " 0x..ffff85"
mzta 0:158c61bb030f 432 * sprintf("%#20.8b", -11) #=> " 0b..110101"
mzta 0:158c61bb030f 433 *
mzta 0:158c61bb030f 434 * # precision for `e' is number of
mzta 0:158c61bb030f 435 * # digits after the decimal point <------>
mzta 0:158c61bb030f 436 * sprintf("%20.8e", 1234.56789) #=> " 1.23456789e+03"
mzta 0:158c61bb030f 437 *
mzta 0:158c61bb030f 438 * # precision for `f' is number of
mzta 0:158c61bb030f 439 * # digits after the decimal point <------>
mzta 0:158c61bb030f 440 * sprintf("%20.8f", 1234.56789) #=> " 1234.56789000"
mzta 0:158c61bb030f 441 *
mzta 0:158c61bb030f 442 * # precision for `g' is number of
mzta 0:158c61bb030f 443 * # significant digits <------->
mzta 0:158c61bb030f 444 * sprintf("%20.8g", 1234.56789) #=> " 1234.5679"
mzta 0:158c61bb030f 445 *
mzta 0:158c61bb030f 446 * # <------->
mzta 0:158c61bb030f 447 * sprintf("%20.8g", 123456789) #=> " 1.2345679e+08"
mzta 0:158c61bb030f 448 *
mzta 0:158c61bb030f 449 * # precision for `s' is
mzta 0:158c61bb030f 450 * # maximum number of characters <------>
mzta 0:158c61bb030f 451 * sprintf("%20.8s", "string test") #=> " string t"
mzta 0:158c61bb030f 452 *
mzta 0:158c61bb030f 453 * Examples:
mzta 0:158c61bb030f 454 *
mzta 0:158c61bb030f 455 * sprintf("%d %04x", 123, 123) #=> "123 007b"
mzta 0:158c61bb030f 456 * sprintf("%08b '%4s'", 123, 123) #=> "01111011 ' 123'"
mzta 0:158c61bb030f 457 * sprintf("%1$*2$s %2$d %1$s", "hello", 8) #=> " hello 8 hello"
mzta 0:158c61bb030f 458 * sprintf("%1$*2$s %2$d", "hello", -8) #=> "hello -8"
mzta 0:158c61bb030f 459 * sprintf("%+g:% g:%-g", 1.23, 1.23, 1.23) #=> "+1.23: 1.23:1.23"
mzta 0:158c61bb030f 460 * sprintf("%u", -123) #=> "-123"
mzta 0:158c61bb030f 461 *
mzta 0:158c61bb030f 462 * For more complex formatting, Ruby supports a reference by name.
mzta 0:158c61bb030f 463 * %<name>s style uses format style, but %{name} style doesn't.
mzta 0:158c61bb030f 464 *
mzta 0:158c61bb030f 465 * Exapmles:
mzta 0:158c61bb030f 466 * sprintf("%<foo>d : %<bar>f", { :foo => 1, :bar => 2 })
mzta 0:158c61bb030f 467 * #=> 1 : 2.000000
mzta 0:158c61bb030f 468 * sprintf("%{foo}f", { :foo => 1 })
mzta 0:158c61bb030f 469 * # => "1f"
mzta 0:158c61bb030f 470 */
mzta 0:158c61bb030f 471
mzta 0:158c61bb030f 472 mrb_value
mzta 0:158c61bb030f 473 mrb_f_sprintf(mrb_state *mrb, mrb_value obj)
mzta 0:158c61bb030f 474 {
mzta 0:158c61bb030f 475 mrb_int argc;
mzta 0:158c61bb030f 476 mrb_value *argv;
mzta 0:158c61bb030f 477
mzta 0:158c61bb030f 478 mrb_get_args(mrb, "*", &argv, &argc);
mzta 0:158c61bb030f 479
mzta 0:158c61bb030f 480 if (argc <= 0) {
mzta 0:158c61bb030f 481 mrb_raise(mrb, E_ARGUMENT_ERROR, "too few arguments");
mzta 0:158c61bb030f 482 return mrb_nil_value();
mzta 0:158c61bb030f 483 }
mzta 0:158c61bb030f 484 else {
mzta 0:158c61bb030f 485 return mrb_str_format(mrb, argc - 1, argv + 1, argv[0]);
mzta 0:158c61bb030f 486 }
mzta 0:158c61bb030f 487 }
mzta 0:158c61bb030f 488
mzta 0:158c61bb030f 489 mrb_value
mzta 0:158c61bb030f 490 mrb_str_format(mrb_state *mrb, int argc, const mrb_value *argv, mrb_value fmt)
mzta 0:158c61bb030f 491 {
mzta 0:158c61bb030f 492 const char *p, *end;
mzta 0:158c61bb030f 493 char *buf;
mzta 0:158c61bb030f 494 mrb_int blen;
mzta 0:158c61bb030f 495 mrb_int bsiz;
mzta 0:158c61bb030f 496 mrb_value result;
mzta 0:158c61bb030f 497 mrb_int n;
mzta 0:158c61bb030f 498 mrb_int width;
mzta 0:158c61bb030f 499 mrb_int prec;
mzta 0:158c61bb030f 500 int flags = FNONE;
mzta 0:158c61bb030f 501 int nextarg = 1;
mzta 0:158c61bb030f 502 int posarg = 0;
mzta 0:158c61bb030f 503 mrb_value nextvalue;
mzta 0:158c61bb030f 504 mrb_value str;
mzta 0:158c61bb030f 505 mrb_value hash = mrb_undef_value();
mzta 0:158c61bb030f 506
mzta 0:158c61bb030f 507 #define CHECK_FOR_WIDTH(f) \
mzta 0:158c61bb030f 508 if ((f) & FWIDTH) { \
mzta 0:158c61bb030f 509 mrb_raise(mrb, E_ARGUMENT_ERROR, "width given twice"); \
mzta 0:158c61bb030f 510 } \
mzta 0:158c61bb030f 511 if ((f) & FPREC0) { \
mzta 0:158c61bb030f 512 mrb_raise(mrb, E_ARGUMENT_ERROR, "width after precision"); \
mzta 0:158c61bb030f 513 }
mzta 0:158c61bb030f 514 #define CHECK_FOR_FLAGS(f) \
mzta 0:158c61bb030f 515 if ((f) & FWIDTH) { \
mzta 0:158c61bb030f 516 mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after width"); \
mzta 0:158c61bb030f 517 } \
mzta 0:158c61bb030f 518 if ((f) & FPREC0) { \
mzta 0:158c61bb030f 519 mrb_raise(mrb, E_ARGUMENT_ERROR, "flag after precision"); \
mzta 0:158c61bb030f 520 }
mzta 0:158c61bb030f 521
mzta 0:158c61bb030f 522 ++argc;
mzta 0:158c61bb030f 523 --argv;
mzta 0:158c61bb030f 524 fmt = mrb_str_to_str(mrb, fmt);
mzta 0:158c61bb030f 525 p = RSTRING_PTR(fmt);
mzta 0:158c61bb030f 526 end = p + RSTRING_LEN(fmt);
mzta 0:158c61bb030f 527 blen = 0;
mzta 0:158c61bb030f 528 bsiz = 120;
mzta 0:158c61bb030f 529 result = mrb_str_buf_new(mrb, bsiz);
mzta 0:158c61bb030f 530 buf = RSTRING_PTR(result);
mzta 0:158c61bb030f 531 memset(buf, 0, bsiz);
mzta 0:158c61bb030f 532
mzta 0:158c61bb030f 533 for (; p < end; p++) {
mzta 0:158c61bb030f 534 const char *t;
mzta 0:158c61bb030f 535 mrb_sym id = 0;
mzta 0:158c61bb030f 536
mzta 0:158c61bb030f 537 for (t = p; t < end && *t != '%'; t++) ;
mzta 0:158c61bb030f 538 PUSH(p, t - p);
mzta 0:158c61bb030f 539 if (t >= end)
mzta 0:158c61bb030f 540 goto sprint_exit; /* end of fmt string */
mzta 0:158c61bb030f 541
mzta 0:158c61bb030f 542 p = t + 1; /* skip `%' */
mzta 0:158c61bb030f 543
mzta 0:158c61bb030f 544 width = prec = -1;
mzta 0:158c61bb030f 545 nextvalue = mrb_undef_value();
mzta 0:158c61bb030f 546
mzta 0:158c61bb030f 547 retry:
mzta 0:158c61bb030f 548 switch (*p) {
mzta 0:158c61bb030f 549 default:
mzta 0:158c61bb030f 550 mrb_raisef(mrb, E_ARGUMENT_ERROR, "malformed format string - \\%%S", mrb_str_new(mrb, p, 1));
mzta 0:158c61bb030f 551 break;
mzta 0:158c61bb030f 552
mzta 0:158c61bb030f 553 case ' ':
mzta 0:158c61bb030f 554 CHECK_FOR_FLAGS(flags);
mzta 0:158c61bb030f 555 flags |= FSPACE;
mzta 0:158c61bb030f 556 p++;
mzta 0:158c61bb030f 557 goto retry;
mzta 0:158c61bb030f 558
mzta 0:158c61bb030f 559 case '#':
mzta 0:158c61bb030f 560 CHECK_FOR_FLAGS(flags);
mzta 0:158c61bb030f 561 flags |= FSHARP;
mzta 0:158c61bb030f 562 p++;
mzta 0:158c61bb030f 563 goto retry;
mzta 0:158c61bb030f 564
mzta 0:158c61bb030f 565 case '+':
mzta 0:158c61bb030f 566 CHECK_FOR_FLAGS(flags);
mzta 0:158c61bb030f 567 flags |= FPLUS;
mzta 0:158c61bb030f 568 p++;
mzta 0:158c61bb030f 569 goto retry;
mzta 0:158c61bb030f 570
mzta 0:158c61bb030f 571 case '-':
mzta 0:158c61bb030f 572 CHECK_FOR_FLAGS(flags);
mzta 0:158c61bb030f 573 flags |= FMINUS;
mzta 0:158c61bb030f 574 p++;
mzta 0:158c61bb030f 575 goto retry;
mzta 0:158c61bb030f 576
mzta 0:158c61bb030f 577 case '0':
mzta 0:158c61bb030f 578 CHECK_FOR_FLAGS(flags);
mzta 0:158c61bb030f 579 flags |= FZERO;
mzta 0:158c61bb030f 580 p++;
mzta 0:158c61bb030f 581 goto retry;
mzta 0:158c61bb030f 582
mzta 0:158c61bb030f 583 case '1': case '2': case '3': case '4':
mzta 0:158c61bb030f 584 case '5': case '6': case '7': case '8': case '9':
mzta 0:158c61bb030f 585 n = 0;
mzta 0:158c61bb030f 586 GETNUM(n, width);
mzta 0:158c61bb030f 587 if (*p == '$') {
mzta 0:158c61bb030f 588 if (!mrb_undef_p(nextvalue)) {
mzta 0:158c61bb030f 589 mrb_raisef(mrb, E_ARGUMENT_ERROR, "value given twice - %S$", mrb_fixnum_value(n));
mzta 0:158c61bb030f 590 }
mzta 0:158c61bb030f 591 nextvalue = GETPOSARG(n);
mzta 0:158c61bb030f 592 p++;
mzta 0:158c61bb030f 593 goto retry;
mzta 0:158c61bb030f 594 }
mzta 0:158c61bb030f 595 CHECK_FOR_WIDTH(flags);
mzta 0:158c61bb030f 596 width = n;
mzta 0:158c61bb030f 597 flags |= FWIDTH;
mzta 0:158c61bb030f 598 goto retry;
mzta 0:158c61bb030f 599
mzta 0:158c61bb030f 600 case '<':
mzta 0:158c61bb030f 601 case '{': {
mzta 0:158c61bb030f 602 const char *start = p;
mzta 0:158c61bb030f 603 char term = (*p == '<') ? '>' : '}';
mzta 0:158c61bb030f 604 mrb_value symname;
mzta 0:158c61bb030f 605
mzta 0:158c61bb030f 606 for (; p < end && *p != term; )
mzta 0:158c61bb030f 607 p++;
mzta 0:158c61bb030f 608 if (id) {
mzta 0:158c61bb030f 609 mrb_raisef(mrb, E_ARGUMENT_ERROR, "name%S after <%S>",
mzta 0:158c61bb030f 610 mrb_str_new(mrb, start, p - start + 1), mrb_sym2str(mrb, id));
mzta 0:158c61bb030f 611 }
mzta 0:158c61bb030f 612 symname = mrb_str_new(mrb, start + 1, p - start - 1);
mzta 0:158c61bb030f 613 id = mrb_intern_str(mrb, symname);
mzta 0:158c61bb030f 614 nextvalue = GETNAMEARG(mrb_symbol_value(id), start, (int)(p - start + 1));
mzta 0:158c61bb030f 615 if (mrb_undef_p(nextvalue)) {
mzta 0:158c61bb030f 616 mrb_raisef(mrb, E_KEY_ERROR, "key%S not found", mrb_str_new(mrb, start, p - start + 1));
mzta 0:158c61bb030f 617 }
mzta 0:158c61bb030f 618 if (term == '}') goto format_s;
mzta 0:158c61bb030f 619 p++;
mzta 0:158c61bb030f 620 goto retry;
mzta 0:158c61bb030f 621 }
mzta 0:158c61bb030f 622
mzta 0:158c61bb030f 623 case '*':
mzta 0:158c61bb030f 624 CHECK_FOR_WIDTH(flags);
mzta 0:158c61bb030f 625 flags |= FWIDTH;
mzta 0:158c61bb030f 626 GETASTER(width);
mzta 0:158c61bb030f 627 if (width < 0) {
mzta 0:158c61bb030f 628 flags |= FMINUS;
mzta 0:158c61bb030f 629 width = -width;
mzta 0:158c61bb030f 630 }
mzta 0:158c61bb030f 631 p++;
mzta 0:158c61bb030f 632 goto retry;
mzta 0:158c61bb030f 633
mzta 0:158c61bb030f 634 case '.':
mzta 0:158c61bb030f 635 if (flags & FPREC0) {
mzta 0:158c61bb030f 636 mrb_raise(mrb, E_ARGUMENT_ERROR, "precision given twice");
mzta 0:158c61bb030f 637 }
mzta 0:158c61bb030f 638 flags |= FPREC|FPREC0;
mzta 0:158c61bb030f 639
mzta 0:158c61bb030f 640 prec = 0;
mzta 0:158c61bb030f 641 p++;
mzta 0:158c61bb030f 642 if (*p == '*') {
mzta 0:158c61bb030f 643 GETASTER(prec);
mzta 0:158c61bb030f 644 if (prec < 0) { /* ignore negative precision */
mzta 0:158c61bb030f 645 flags &= ~FPREC;
mzta 0:158c61bb030f 646 }
mzta 0:158c61bb030f 647 p++;
mzta 0:158c61bb030f 648 goto retry;
mzta 0:158c61bb030f 649 }
mzta 0:158c61bb030f 650
mzta 0:158c61bb030f 651 GETNUM(prec, precision);
mzta 0:158c61bb030f 652 goto retry;
mzta 0:158c61bb030f 653
mzta 0:158c61bb030f 654 case '\n':
mzta 0:158c61bb030f 655 case '\0':
mzta 0:158c61bb030f 656 p--;
mzta 0:158c61bb030f 657 /* fallthrough */
mzta 0:158c61bb030f 658 case '%':
mzta 0:158c61bb030f 659 if (flags != FNONE) {
mzta 0:158c61bb030f 660 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format character - %");
mzta 0:158c61bb030f 661 }
mzta 0:158c61bb030f 662 PUSH("%", 1);
mzta 0:158c61bb030f 663 break;
mzta 0:158c61bb030f 664
mzta 0:158c61bb030f 665 case 'c': {
mzta 0:158c61bb030f 666 mrb_value val = GETARG();
mzta 0:158c61bb030f 667 mrb_value tmp;
mzta 0:158c61bb030f 668 char *c;
mzta 0:158c61bb030f 669
mzta 0:158c61bb030f 670 tmp = mrb_check_string_type(mrb, val);
mzta 0:158c61bb030f 671 if (!mrb_nil_p(tmp)) {
mzta 0:158c61bb030f 672 if (mrb_fixnum(mrb_funcall(mrb, tmp, "size", 0)) != 1 ) {
mzta 0:158c61bb030f 673 mrb_raise(mrb, E_ARGUMENT_ERROR, "%c requires a character");
mzta 0:158c61bb030f 674 }
mzta 0:158c61bb030f 675 }
mzta 0:158c61bb030f 676 else if (mrb_fixnum_p(val)) {
mzta 0:158c61bb030f 677 tmp = mrb_funcall(mrb, val, "chr", 0);
mzta 0:158c61bb030f 678 }
mzta 0:158c61bb030f 679 else {
mzta 0:158c61bb030f 680 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid character");
mzta 0:158c61bb030f 681 }
mzta 0:158c61bb030f 682 c = RSTRING_PTR(tmp);
mzta 0:158c61bb030f 683 n = RSTRING_LEN(tmp);
mzta 0:158c61bb030f 684 if (!(flags & FWIDTH)) {
mzta 0:158c61bb030f 685 CHECK(n);
mzta 0:158c61bb030f 686 memcpy(buf+blen, c, n);
mzta 0:158c61bb030f 687 blen += n;
mzta 0:158c61bb030f 688 }
mzta 0:158c61bb030f 689 else if ((flags & FMINUS)) {
mzta 0:158c61bb030f 690 CHECK(n);
mzta 0:158c61bb030f 691 memcpy(buf+blen, c, n);
mzta 0:158c61bb030f 692 blen += n;
mzta 0:158c61bb030f 693 FILL(' ', width-1);
mzta 0:158c61bb030f 694 }
mzta 0:158c61bb030f 695 else {
mzta 0:158c61bb030f 696 FILL(' ', width-1);
mzta 0:158c61bb030f 697 CHECK(n);
mzta 0:158c61bb030f 698 memcpy(buf+blen, c, n);
mzta 0:158c61bb030f 699 blen += n;
mzta 0:158c61bb030f 700 }
mzta 0:158c61bb030f 701 }
mzta 0:158c61bb030f 702 break;
mzta 0:158c61bb030f 703
mzta 0:158c61bb030f 704 case 's':
mzta 0:158c61bb030f 705 case 'p':
mzta 0:158c61bb030f 706 format_s:
mzta 0:158c61bb030f 707 {
mzta 0:158c61bb030f 708 mrb_value arg = GETARG();
mzta 0:158c61bb030f 709 mrb_int len;
mzta 0:158c61bb030f 710 mrb_int slen;
mzta 0:158c61bb030f 711
mzta 0:158c61bb030f 712 if (*p == 'p') arg = mrb_inspect(mrb, arg);
mzta 0:158c61bb030f 713 str = mrb_obj_as_string(mrb, arg);
mzta 0:158c61bb030f 714 len = RSTRING_LEN(str);
mzta 0:158c61bb030f 715 if (RSTRING(result)->flags & MRB_STR_EMBED) {
mzta 0:158c61bb030f 716 mrb_int tmp_n = len;
mzta 0:158c61bb030f 717 RSTRING(result)->flags &= ~MRB_STR_EMBED_LEN_MASK;
mzta 0:158c61bb030f 718 RSTRING(result)->flags |= tmp_n << MRB_STR_EMBED_LEN_SHIFT;
mzta 0:158c61bb030f 719 } else {
mzta 0:158c61bb030f 720 RSTRING(result)->as.heap.len = blen;
mzta 0:158c61bb030f 721 }
mzta 0:158c61bb030f 722 if (flags&(FPREC|FWIDTH)) {
mzta 0:158c61bb030f 723 slen = RSTRING_LEN(str);
mzta 0:158c61bb030f 724 if (slen < 0) {
mzta 0:158c61bb030f 725 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid mbstring sequence");
mzta 0:158c61bb030f 726 }
mzta 0:158c61bb030f 727 if ((flags&FPREC) && (prec < slen)) {
mzta 0:158c61bb030f 728 char *p = RSTRING_PTR(str) + prec;
mzta 0:158c61bb030f 729 slen = prec;
mzta 0:158c61bb030f 730 len = p - RSTRING_PTR(str);
mzta 0:158c61bb030f 731 }
mzta 0:158c61bb030f 732 /* need to adjust multi-byte string pos */
mzta 0:158c61bb030f 733 if ((flags&FWIDTH) && (width > slen)) {
mzta 0:158c61bb030f 734 width -= (int)slen;
mzta 0:158c61bb030f 735 if (!(flags&FMINUS)) {
mzta 0:158c61bb030f 736 CHECK(width);
mzta 0:158c61bb030f 737 while (width--) {
mzta 0:158c61bb030f 738 buf[blen++] = ' ';
mzta 0:158c61bb030f 739 }
mzta 0:158c61bb030f 740 }
mzta 0:158c61bb030f 741 CHECK(len);
mzta 0:158c61bb030f 742 memcpy(&buf[blen], RSTRING_PTR(str), len);
mzta 0:158c61bb030f 743 blen += len;
mzta 0:158c61bb030f 744 if (flags&FMINUS) {
mzta 0:158c61bb030f 745 CHECK(width);
mzta 0:158c61bb030f 746 while (width--) {
mzta 0:158c61bb030f 747 buf[blen++] = ' ';
mzta 0:158c61bb030f 748 }
mzta 0:158c61bb030f 749 }
mzta 0:158c61bb030f 750 break;
mzta 0:158c61bb030f 751 }
mzta 0:158c61bb030f 752 }
mzta 0:158c61bb030f 753 PUSH(RSTRING_PTR(str), len);
mzta 0:158c61bb030f 754 }
mzta 0:158c61bb030f 755 break;
mzta 0:158c61bb030f 756
mzta 0:158c61bb030f 757 case 'd':
mzta 0:158c61bb030f 758 case 'i':
mzta 0:158c61bb030f 759 case 'o':
mzta 0:158c61bb030f 760 case 'x':
mzta 0:158c61bb030f 761 case 'X':
mzta 0:158c61bb030f 762 case 'b':
mzta 0:158c61bb030f 763 case 'B':
mzta 0:158c61bb030f 764 case 'u': {
mzta 0:158c61bb030f 765 mrb_value val = GETARG();
mzta 0:158c61bb030f 766 char fbuf[32], nbuf[64], *s;
mzta 0:158c61bb030f 767 const char *prefix = NULL;
mzta 0:158c61bb030f 768 int sign = 0, dots = 0;
mzta 0:158c61bb030f 769 char sc = 0;
mzta 0:158c61bb030f 770 mrb_int v = 0, org_v = 0;
mzta 0:158c61bb030f 771 int base;
mzta 0:158c61bb030f 772 mrb_int len;
mzta 0:158c61bb030f 773
mzta 0:158c61bb030f 774 switch (*p) {
mzta 0:158c61bb030f 775 case 'd':
mzta 0:158c61bb030f 776 case 'i':
mzta 0:158c61bb030f 777 case 'u':
mzta 0:158c61bb030f 778 sign = 1; break;
mzta 0:158c61bb030f 779 case 'o':
mzta 0:158c61bb030f 780 case 'x':
mzta 0:158c61bb030f 781 case 'X':
mzta 0:158c61bb030f 782 case 'b':
mzta 0:158c61bb030f 783 case 'B':
mzta 0:158c61bb030f 784 if (flags&(FPLUS|FSPACE)) sign = 1;
mzta 0:158c61bb030f 785 break;
mzta 0:158c61bb030f 786 default:
mzta 0:158c61bb030f 787 break;
mzta 0:158c61bb030f 788 }
mzta 0:158c61bb030f 789 if (flags & FSHARP) {
mzta 0:158c61bb030f 790 switch (*p) {
mzta 0:158c61bb030f 791 case 'o': prefix = "0"; break;
mzta 0:158c61bb030f 792 case 'x': prefix = "0x"; break;
mzta 0:158c61bb030f 793 case 'X': prefix = "0X"; break;
mzta 0:158c61bb030f 794 case 'b': prefix = "0b"; break;
mzta 0:158c61bb030f 795 case 'B': prefix = "0B"; break;
mzta 0:158c61bb030f 796 default: break;
mzta 0:158c61bb030f 797 }
mzta 0:158c61bb030f 798 }
mzta 0:158c61bb030f 799
mzta 0:158c61bb030f 800 bin_retry:
mzta 0:158c61bb030f 801 switch (mrb_type(val)) {
mzta 0:158c61bb030f 802 case MRB_TT_FLOAT:
mzta 0:158c61bb030f 803 if (FIXABLE(mrb_float(val))) {
mzta 0:158c61bb030f 804 val = mrb_fixnum_value((mrb_int)mrb_float(val));
mzta 0:158c61bb030f 805 goto bin_retry;
mzta 0:158c61bb030f 806 }
mzta 0:158c61bb030f 807 val = mrb_flo_to_fixnum(mrb, val);
mzta 0:158c61bb030f 808 if (mrb_fixnum_p(val)) goto bin_retry;
mzta 0:158c61bb030f 809 break;
mzta 0:158c61bb030f 810 case MRB_TT_STRING:
mzta 0:158c61bb030f 811 val = mrb_str_to_inum(mrb, val, 0, TRUE);
mzta 0:158c61bb030f 812 goto bin_retry;
mzta 0:158c61bb030f 813 case MRB_TT_FIXNUM:
mzta 0:158c61bb030f 814 v = mrb_fixnum(val);
mzta 0:158c61bb030f 815 break;
mzta 0:158c61bb030f 816 default:
mzta 0:158c61bb030f 817 val = mrb_Integer(mrb, val);
mzta 0:158c61bb030f 818 goto bin_retry;
mzta 0:158c61bb030f 819 }
mzta 0:158c61bb030f 820
mzta 0:158c61bb030f 821 switch (*p) {
mzta 0:158c61bb030f 822 case 'o':
mzta 0:158c61bb030f 823 base = 8; break;
mzta 0:158c61bb030f 824 case 'x':
mzta 0:158c61bb030f 825 case 'X':
mzta 0:158c61bb030f 826 base = 16; break;
mzta 0:158c61bb030f 827 case 'b':
mzta 0:158c61bb030f 828 case 'B':
mzta 0:158c61bb030f 829 base = 2; break;
mzta 0:158c61bb030f 830 case 'u':
mzta 0:158c61bb030f 831 case 'd':
mzta 0:158c61bb030f 832 case 'i':
mzta 0:158c61bb030f 833 default:
mzta 0:158c61bb030f 834 base = 10; break;
mzta 0:158c61bb030f 835 }
mzta 0:158c61bb030f 836
mzta 0:158c61bb030f 837 if (base == 2) {
mzta 0:158c61bb030f 838 org_v = v;
mzta 0:158c61bb030f 839 if (v < 0 && !sign) {
mzta 0:158c61bb030f 840 val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base);
mzta 0:158c61bb030f 841 dots = 1;
mzta 0:158c61bb030f 842 }
mzta 0:158c61bb030f 843 else {
mzta 0:158c61bb030f 844 val = mrb_fixnum_to_str(mrb, mrb_fixnum_value(v), base);
mzta 0:158c61bb030f 845 }
mzta 0:158c61bb030f 846 v = mrb_fixnum(mrb_str_to_inum(mrb, val, 10, FALSE));
mzta 0:158c61bb030f 847 }
mzta 0:158c61bb030f 848 if (sign) {
mzta 0:158c61bb030f 849 char c = *p;
mzta 0:158c61bb030f 850 if (c == 'i') c = 'd'; /* %d and %i are identical */
mzta 0:158c61bb030f 851 if (base == 2) c = 'd';
mzta 0:158c61bb030f 852 if (v < 0) {
mzta 0:158c61bb030f 853 v = -v;
mzta 0:158c61bb030f 854 sc = '-';
mzta 0:158c61bb030f 855 width--;
mzta 0:158c61bb030f 856 }
mzta 0:158c61bb030f 857 else if (flags & FPLUS) {
mzta 0:158c61bb030f 858 sc = '+';
mzta 0:158c61bb030f 859 width--;
mzta 0:158c61bb030f 860 }
mzta 0:158c61bb030f 861 else if (flags & FSPACE) {
mzta 0:158c61bb030f 862 sc = ' ';
mzta 0:158c61bb030f 863 width--;
mzta 0:158c61bb030f 864 }
mzta 0:158c61bb030f 865 snprintf(fbuf, sizeof(fbuf), "%%l%c", c);
mzta 0:158c61bb030f 866 snprintf(nbuf, sizeof(nbuf), fbuf, v);
mzta 0:158c61bb030f 867 s = nbuf;
mzta 0:158c61bb030f 868 }
mzta 0:158c61bb030f 869 else {
mzta 0:158c61bb030f 870 char c = *p;
mzta 0:158c61bb030f 871 if (c == 'X') c = 'x';
mzta 0:158c61bb030f 872 if (base == 2) c = 'd';
mzta 0:158c61bb030f 873 s = nbuf;
mzta 0:158c61bb030f 874 if (v < 0) {
mzta 0:158c61bb030f 875 dots = 1;
mzta 0:158c61bb030f 876 }
mzta 0:158c61bb030f 877 snprintf(fbuf, sizeof(fbuf), "%%l%c", c);
mzta 0:158c61bb030f 878 snprintf(++s, sizeof(nbuf) - 1, fbuf, v);
mzta 0:158c61bb030f 879 if (v < 0) {
mzta 0:158c61bb030f 880 char d;
mzta 0:158c61bb030f 881
mzta 0:158c61bb030f 882 s = remove_sign_bits(s, base);
mzta 0:158c61bb030f 883 switch (base) {
mzta 0:158c61bb030f 884 case 16: d = 'f'; break;
mzta 0:158c61bb030f 885 case 8: d = '7'; break;
mzta 0:158c61bb030f 886 case 2: d = '1'; break;
mzta 0:158c61bb030f 887 default: d = 0; break;
mzta 0:158c61bb030f 888 }
mzta 0:158c61bb030f 889
mzta 0:158c61bb030f 890 if (d && *s != d) {
mzta 0:158c61bb030f 891 *--s = d;
mzta 0:158c61bb030f 892 }
mzta 0:158c61bb030f 893 }
mzta 0:158c61bb030f 894 }
mzta 0:158c61bb030f 895 {
mzta 0:158c61bb030f 896 size_t size;
mzta 0:158c61bb030f 897 size = strlen(s);
mzta 0:158c61bb030f 898 /* PARANOID: assert(size <= MRB_INT_MAX) */
mzta 0:158c61bb030f 899 len = (mrb_int)size;
mzta 0:158c61bb030f 900 }
mzta 0:158c61bb030f 901
mzta 0:158c61bb030f 902 if (dots) {
mzta 0:158c61bb030f 903 prec -= 2;
mzta 0:158c61bb030f 904 width -= 2;
mzta 0:158c61bb030f 905 }
mzta 0:158c61bb030f 906
mzta 0:158c61bb030f 907 if (*p == 'X') {
mzta 0:158c61bb030f 908 char *pp = s;
mzta 0:158c61bb030f 909 int c;
mzta 0:158c61bb030f 910 while ((c = (int)(unsigned char)*pp) != 0) {
mzta 0:158c61bb030f 911 *pp = toupper(c);
mzta 0:158c61bb030f 912 pp++;
mzta 0:158c61bb030f 913 }
mzta 0:158c61bb030f 914 }
mzta 0:158c61bb030f 915
mzta 0:158c61bb030f 916 if (prefix && !prefix[1]) { /* octal */
mzta 0:158c61bb030f 917 if (dots) {
mzta 0:158c61bb030f 918 prefix = NULL;
mzta 0:158c61bb030f 919 }
mzta 0:158c61bb030f 920 else if (len == 1 && *s == '0') {
mzta 0:158c61bb030f 921 len = 0;
mzta 0:158c61bb030f 922 if (flags & FPREC) prec--;
mzta 0:158c61bb030f 923 }
mzta 0:158c61bb030f 924 else if ((flags & FPREC) && (prec > len)) {
mzta 0:158c61bb030f 925 prefix = NULL;
mzta 0:158c61bb030f 926 }
mzta 0:158c61bb030f 927 }
mzta 0:158c61bb030f 928 else if (len == 1 && *s == '0') {
mzta 0:158c61bb030f 929 prefix = NULL;
mzta 0:158c61bb030f 930 }
mzta 0:158c61bb030f 931
mzta 0:158c61bb030f 932 if (prefix) {
mzta 0:158c61bb030f 933 size_t size;
mzta 0:158c61bb030f 934 size = strlen(prefix);
mzta 0:158c61bb030f 935 /* PARANOID: assert(size <= MRB_INT_MAX).
mzta 0:158c61bb030f 936 * this check is absolutely paranoid. */
mzta 0:158c61bb030f 937 width -= (mrb_int)size;
mzta 0:158c61bb030f 938 }
mzta 0:158c61bb030f 939
mzta 0:158c61bb030f 940 if ((flags & (FZERO|FMINUS|FPREC)) == FZERO) {
mzta 0:158c61bb030f 941 prec = width;
mzta 0:158c61bb030f 942 width = 0;
mzta 0:158c61bb030f 943 }
mzta 0:158c61bb030f 944 else {
mzta 0:158c61bb030f 945 if (prec < len) {
mzta 0:158c61bb030f 946 if (!prefix && prec == 0 && len == 1 && *s == '0') len = 0;
mzta 0:158c61bb030f 947 prec = len;
mzta 0:158c61bb030f 948 }
mzta 0:158c61bb030f 949 width -= prec;
mzta 0:158c61bb030f 950 }
mzta 0:158c61bb030f 951
mzta 0:158c61bb030f 952 if (!(flags&FMINUS)) {
mzta 0:158c61bb030f 953 CHECK(width);
mzta 0:158c61bb030f 954 while (width-- > 0) {
mzta 0:158c61bb030f 955 buf[blen++] = ' ';
mzta 0:158c61bb030f 956 }
mzta 0:158c61bb030f 957 }
mzta 0:158c61bb030f 958
mzta 0:158c61bb030f 959 if (sc) PUSH(&sc, 1);
mzta 0:158c61bb030f 960
mzta 0:158c61bb030f 961 if (prefix) {
mzta 0:158c61bb030f 962 int plen = (int)strlen(prefix);
mzta 0:158c61bb030f 963 PUSH(prefix, plen);
mzta 0:158c61bb030f 964 }
mzta 0:158c61bb030f 965 CHECK(prec - len);
mzta 0:158c61bb030f 966 if (dots) PUSH("..", 2);
mzta 0:158c61bb030f 967
mzta 0:158c61bb030f 968 if (v < 0 || (base == 2 && org_v < 0)) {
mzta 0:158c61bb030f 969 char c = sign_bits(base, p);
mzta 0:158c61bb030f 970 while (len < prec--) {
mzta 0:158c61bb030f 971 buf[blen++] = c;
mzta 0:158c61bb030f 972 }
mzta 0:158c61bb030f 973 }
mzta 0:158c61bb030f 974 else if ((flags & (FMINUS|FPREC)) != FMINUS) {
mzta 0:158c61bb030f 975 char c = '0';
mzta 0:158c61bb030f 976 while (len < prec--) {
mzta 0:158c61bb030f 977 buf[blen++] = c;
mzta 0:158c61bb030f 978 }
mzta 0:158c61bb030f 979 }
mzta 0:158c61bb030f 980
mzta 0:158c61bb030f 981 PUSH(s, len);
mzta 0:158c61bb030f 982 CHECK(width);
mzta 0:158c61bb030f 983 while (width-- > 0) {
mzta 0:158c61bb030f 984 buf[blen++] = ' ';
mzta 0:158c61bb030f 985 }
mzta 0:158c61bb030f 986 }
mzta 0:158c61bb030f 987 break;
mzta 0:158c61bb030f 988
mzta 0:158c61bb030f 989 case 'f':
mzta 0:158c61bb030f 990 case 'g':
mzta 0:158c61bb030f 991 case 'G':
mzta 0:158c61bb030f 992 case 'e':
mzta 0:158c61bb030f 993 case 'E':
mzta 0:158c61bb030f 994 case 'a':
mzta 0:158c61bb030f 995 case 'A': {
mzta 0:158c61bb030f 996 mrb_value val = GETARG();
mzta 0:158c61bb030f 997 double fval;
mzta 0:158c61bb030f 998 int i, need = 6;
mzta 0:158c61bb030f 999 char fbuf[32];
mzta 0:158c61bb030f 1000
mzta 0:158c61bb030f 1001 fval = mrb_float(mrb_Float(mrb, val));
mzta 0:158c61bb030f 1002 if (!isfinite(fval)) {
mzta 0:158c61bb030f 1003 const char *expr;
mzta 0:158c61bb030f 1004 const int elen = 3;
mzta 0:158c61bb030f 1005
mzta 0:158c61bb030f 1006 if (isnan(fval)) {
mzta 0:158c61bb030f 1007 expr = "NaN";
mzta 0:158c61bb030f 1008 }
mzta 0:158c61bb030f 1009 else {
mzta 0:158c61bb030f 1010 expr = "Inf";
mzta 0:158c61bb030f 1011 }
mzta 0:158c61bb030f 1012 need = elen;
mzta 0:158c61bb030f 1013 if ((!isnan(fval) && fval < 0.0) || (flags & FPLUS))
mzta 0:158c61bb030f 1014 need++;
mzta 0:158c61bb030f 1015 if ((flags & FWIDTH) && need < width)
mzta 0:158c61bb030f 1016 need = width;
mzta 0:158c61bb030f 1017
mzta 0:158c61bb030f 1018 CHECK(need + 1);
mzta 0:158c61bb030f 1019 snprintf(&buf[blen], need + 1, "%*s", need, "");
mzta 0:158c61bb030f 1020 if (flags & FMINUS) {
mzta 0:158c61bb030f 1021 if (!isnan(fval) && fval < 0.0)
mzta 0:158c61bb030f 1022 buf[blen++] = '-';
mzta 0:158c61bb030f 1023 else if (flags & FPLUS)
mzta 0:158c61bb030f 1024 buf[blen++] = '+';
mzta 0:158c61bb030f 1025 else if (flags & FSPACE)
mzta 0:158c61bb030f 1026 blen++;
mzta 0:158c61bb030f 1027 memcpy(&buf[blen], expr, elen);
mzta 0:158c61bb030f 1028 }
mzta 0:158c61bb030f 1029 else {
mzta 0:158c61bb030f 1030 if (!isnan(fval) && fval < 0.0)
mzta 0:158c61bb030f 1031 buf[blen + need - elen - 1] = '-';
mzta 0:158c61bb030f 1032 else if (flags & FPLUS)
mzta 0:158c61bb030f 1033 buf[blen + need - elen - 1] = '+';
mzta 0:158c61bb030f 1034 else if ((flags & FSPACE) && need > width)
mzta 0:158c61bb030f 1035 blen++;
mzta 0:158c61bb030f 1036 memcpy(&buf[blen + need - elen], expr, elen);
mzta 0:158c61bb030f 1037 }
mzta 0:158c61bb030f 1038 blen += strlen(&buf[blen]);
mzta 0:158c61bb030f 1039 break;
mzta 0:158c61bb030f 1040 }
mzta 0:158c61bb030f 1041
mzta 0:158c61bb030f 1042 fmt_setup(fbuf, sizeof(fbuf), *p, flags, width, prec);
mzta 0:158c61bb030f 1043 need = 0;
mzta 0:158c61bb030f 1044 if (*p != 'e' && *p != 'E') {
mzta 0:158c61bb030f 1045 i = INT_MIN;
mzta 0:158c61bb030f 1046 frexp(fval, &i);
mzta 0:158c61bb030f 1047 if (i > 0)
mzta 0:158c61bb030f 1048 need = BIT_DIGITS(i);
mzta 0:158c61bb030f 1049 }
mzta 0:158c61bb030f 1050 need += (flags&FPREC) ? prec : 6;
mzta 0:158c61bb030f 1051 if ((flags&FWIDTH) && need < width)
mzta 0:158c61bb030f 1052 need = width;
mzta 0:158c61bb030f 1053 need += 20;
mzta 0:158c61bb030f 1054
mzta 0:158c61bb030f 1055 CHECK(need);
mzta 0:158c61bb030f 1056 n = snprintf(&buf[blen], need, fbuf, fval);
mzta 0:158c61bb030f 1057 blen += n;
mzta 0:158c61bb030f 1058 }
mzta 0:158c61bb030f 1059 break;
mzta 0:158c61bb030f 1060 }
mzta 0:158c61bb030f 1061 flags = FNONE;
mzta 0:158c61bb030f 1062 }
mzta 0:158c61bb030f 1063
mzta 0:158c61bb030f 1064 sprint_exit:
mzta 0:158c61bb030f 1065 #if 0
mzta 0:158c61bb030f 1066 /* XXX - We cannot validate the number of arguments if (digit)$ style used.
mzta 0:158c61bb030f 1067 */
mzta 0:158c61bb030f 1068 if (posarg >= 0 && nextarg < argc) {
mzta 0:158c61bb030f 1069 const char *mesg = "too many arguments for format string";
mzta 0:158c61bb030f 1070 if (mrb_test(ruby_debug)) mrb_raise(mrb, E_ARGUMENT_ERROR, mesg);
mzta 0:158c61bb030f 1071 if (mrb_test(ruby_verbose)) mrb_warn(mrb, "%S", mrb_str_new_cstr(mrb, mesg));
mzta 0:158c61bb030f 1072 }
mzta 0:158c61bb030f 1073 #endif
mzta 0:158c61bb030f 1074 mrb_str_resize(mrb, result, blen);
mzta 0:158c61bb030f 1075
mzta 0:158c61bb030f 1076 return result;
mzta 0:158c61bb030f 1077 }
mzta 0:158c61bb030f 1078
mzta 0:158c61bb030f 1079 static void
mzta 0:158c61bb030f 1080 fmt_setup(char *buf, size_t size, int c, int flags, mrb_int width, mrb_int prec)
mzta 0:158c61bb030f 1081 {
mzta 0:158c61bb030f 1082 char *end = buf + size;
mzta 0:158c61bb030f 1083 int n;
mzta 0:158c61bb030f 1084
mzta 0:158c61bb030f 1085 *buf++ = '%';
mzta 0:158c61bb030f 1086 if (flags & FSHARP) *buf++ = '#';
mzta 0:158c61bb030f 1087 if (flags & FPLUS) *buf++ = '+';
mzta 0:158c61bb030f 1088 if (flags & FMINUS) *buf++ = '-';
mzta 0:158c61bb030f 1089 if (flags & FZERO) *buf++ = '0';
mzta 0:158c61bb030f 1090 if (flags & FSPACE) *buf++ = ' ';
mzta 0:158c61bb030f 1091
mzta 0:158c61bb030f 1092 if (flags & FWIDTH) {
mzta 0:158c61bb030f 1093 n = snprintf(buf, end - buf, "%d", (int)width);
mzta 0:158c61bb030f 1094 buf += n;
mzta 0:158c61bb030f 1095 }
mzta 0:158c61bb030f 1096
mzta 0:158c61bb030f 1097 if (flags & FPREC) {
mzta 0:158c61bb030f 1098 n = snprintf(buf, end - buf, ".%d", (int)prec);
mzta 0:158c61bb030f 1099 buf += n;
mzta 0:158c61bb030f 1100 }
mzta 0:158c61bb030f 1101
mzta 0:158c61bb030f 1102 *buf++ = c;
mzta 0:158c61bb030f 1103 *buf = '\0';
mzta 0:158c61bb030f 1104 }
mzta 0:158c61bb030f 1105