diff options
| -rw-r--r-- | include/mruby/boxing_nan.h | 13 | ||||
| -rw-r--r-- | include/mruby/boxing_word.h | 5 | ||||
| -rw-r--r-- | include/mruby/numeric.h | 1 | ||||
| -rw-r--r-- | include/mruby/value.h | 7 | ||||
| -rw-r--r-- | mrbgems/mruby-bin-config/mrbgem.rake | 7 | ||||
| -rw-r--r-- | mrbgems/mruby-io/src/io.c | 3 | ||||
| -rw-r--r-- | mrbgems/mruby-pack/src/pack.c | 125 | ||||
| -rw-r--r-- | mrbgems/mruby-sprintf/src/sprintf.c | 78 | ||||
| -rw-r--r-- | mrbgems/mruby-sprintf/test/sprintf.rb | 5 | ||||
| -rw-r--r-- | src/etc.c | 17 | ||||
| -rw-r--r-- | src/fmt_fp.c | 119 |
11 files changed, 308 insertions, 72 deletions
diff --git a/include/mruby/boxing_nan.h b/include/mruby/boxing_nan.h index e7bc9331c..fae3b7630 100644 --- a/include/mruby/boxing_nan.h +++ b/include/mruby/boxing_nan.h @@ -44,6 +44,9 @@ typedef struct mrb_value { }; ) }; +#ifdef MRB_64BIT + struct RCptr *vp; +#endif } value; }; } mrb_value; @@ -54,13 +57,15 @@ typedef struct mrb_value { #define mrb_type(o) (enum mrb_vtype)((uint32_t)0xfff00000 < (o).value.ttt ? mrb_tt(o) : MRB_TT_FLOAT) #define mrb_ptr(o) ((void*)((((uintptr_t)0x3fffffffffff)&((uintptr_t)((o).value.p)))<<2)) #define mrb_float(o) (o).f -#define mrb_cptr(o) mrb_ptr(o) #define mrb_fixnum(o) (o).value.i #define mrb_symbol(o) (o).value.sym #ifdef MRB_64BIT +MRB_API mrb_value mrb_nan_boxing_cptr_value(struct mrb_state*, void*); +#define mrb_cptr(o) (((struct RCptr*)mrb_ptr(o))->p) #define BOXNAN_SHIFT_LONG_POINTER(v) (((uintptr_t)(v)>>34)&0x3fff) #else +#define mrb_cptr(o) ((o).value.p) #define BOXNAN_SHIFT_LONG_POINTER(v) 0 #endif @@ -90,7 +95,11 @@ typedef struct mrb_value { #define SET_INT_VALUE(r,n) BOXNAN_SET_VALUE(r, MRB_TT_FIXNUM, value.i, (n)) #define SET_SYM_VALUE(r,v) BOXNAN_SET_VALUE(r, MRB_TT_SYMBOL, value.sym, (v)) #define SET_OBJ_VALUE(r,v) BOXNAN_SET_OBJ_VALUE(r, (((struct RObject*)(v))->tt), (v)) -#define SET_CPTR_VALUE(mrb,r,v) BOXNAN_SET_OBJ_VALUE(r, MRB_TT_CPTR, v) +#ifdef MRB_64BIT +#define SET_CPTR_VALUE(mrb,r,v) ((r) = mrb_nan_boxing_cptr_value(mrb, v)) +#else +#define SET_CPTR_VALUE(mrb,r,v) BOXNAN_SET_VALUE(r, MRB_TT_CPTR, value.p, v) +#endif #define SET_UNDEF_VALUE(r) BOXNAN_SET_VALUE(r, MRB_TT_UNDEF, value.i, 0) #endif /* MRUBY_BOXING_NAN_H */ diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 1388bb9f6..c0d7087e0 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -18,11 +18,6 @@ struct RFloat { }; #endif -struct RCptr { - MRB_OBJECT_HEADER; - void *p; -}; - enum mrb_special_consts { MRB_Qnil = 0, MRB_Qfalse = 4, diff --git a/include/mruby/numeric.h b/include/mruby/numeric.h index a176d96cd..06a33cc6f 100644 --- a/include/mruby/numeric.h +++ b/include/mruby/numeric.h @@ -37,6 +37,7 @@ MRB_API mrb_value mrb_fixnum_to_str(mrb_state *mrb, mrb_value x, mrb_int base); /* ArgumentError if format string doesn't match /%(\.[0-9]+)?[aAeEfFgG]/ */ #ifndef MRB_WITHOUT_FLOAT MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value x, const char *fmt); +MRB_API int mrb_float_to_cstr(mrb_state *mrb, char *buf, size_t len, const char *fmt, mrb_float f); MRB_API mrb_float mrb_to_flo(mrb_state *mrb, mrb_value x); MRB_API mrb_value mrb_int_value(mrb_state *mrb, mrb_float f); #endif diff --git a/include/mruby/value.h b/include/mruby/value.h index 232beb1dc..33c70f15a 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -149,6 +149,13 @@ typedef void mrb_value; #endif +#if defined(MRB_WORD_BOXING) || (defined(MRB_NAN_BOXING) && defined(MRB_64BIT)) +struct RCptr { + MRB_OBJECT_HEADER; + void *p; +}; +#endif + #if defined(MRB_NAN_BOXING) #include "boxing_nan.h" #elif defined(MRB_WORD_BOXING) diff --git a/mrbgems/mruby-bin-config/mrbgem.rake b/mrbgems/mruby-bin-config/mrbgem.rake index 6005a876d..c56af435f 100644 --- a/mrbgems/mruby-bin-config/mrbgem.rake +++ b/mrbgems/mruby-bin-config/mrbgem.rake @@ -5,13 +5,16 @@ unless MRuby::Build.current.kind_of?(MRuby::CrossBuild) spec.author = 'mruby developers' spec.summary = "#{name} command" + mruby_config_dir = "#{build.build_dir}/bin" mruby_config = name + (ENV['OS'] == 'Windows_NT' ? '.bat' : '') - mruby_config_path = "#{build.build_dir}/bin/#{mruby_config}" + mruby_config_path = "#{mruby_config_dir}/#{mruby_config}" make_cfg = "#{build.build_dir}/lib/libmruby.flags.mak" tmplt_path = "#{__dir__}/#{mruby_config}" build.bins << mruby_config - file mruby_config_path => [make_cfg, tmplt_path] do |t| + directory mruby_config_dir + + file mruby_config_path => [mruby_config_dir, make_cfg, tmplt_path] do |t| config = Hash[File.readlines(make_cfg).map!(&:chomp).map! {|l| l.gsub('\\"', '"').split(' = ', 2).map! {|s| s.sub(/^(?=.)/, 'echo ')} }] diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index c7273bce8..a79db4f17 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -1193,6 +1193,7 @@ mrb_io_s_select(mrb_state *mrb, mrb_value klass) for (i = 0; i < RARRAY_LEN(read); i++) { read_io = RARRAY_PTR(read)[i]; fptr = io_get_open_fptr(mrb, read_io); + if (fptr->fd >= FD_SETSIZE) continue; FD_SET(fptr->fd, rp); if (mrb_io_read_data_pending(mrb, read_io)) { pending++; @@ -1215,6 +1216,7 @@ mrb_io_s_select(mrb_state *mrb, mrb_value klass) FD_ZERO(wp); for (i = 0; i < RARRAY_LEN(write); i++) { fptr = io_get_open_fptr(mrb, RARRAY_PTR(write)[i]); + if (fptr->fd >= FD_SETSIZE) continue; FD_SET(fptr->fd, wp); if (max < fptr->fd) max = fptr->fd; @@ -1234,6 +1236,7 @@ mrb_io_s_select(mrb_state *mrb, mrb_value klass) FD_ZERO(ep); for (i = 0; i < RARRAY_LEN(except); i++) { fptr = io_get_open_fptr(mrb, RARRAY_PTR(except)[i]); + if (fptr->fd >= FD_SETSIZE) continue; FD_SET(fptr->fd, ep); if (max < fptr->fd) max = fptr->fd; diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index a5cd7efed..3a2c3367a 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -3,11 +3,6 @@ */ #include <mruby.h> - -#ifdef MRB_DISABLE_STDIO -# error pack/unpack conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb' -#endif - #include "mruby/error.h" #include "mruby/array.h" #include "mruby/class.h" @@ -217,6 +212,59 @@ pack_l(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int fl return 4; } +#ifndef MRB_INT64 +static void +u32tostr(char *buf, size_t len, uint32_t n) +{ +#ifdef MRB_DISABLE_STDIO + char *bufend = buf + len; + char *p = bufend - 1; + + if (len < 1) { + return; + } + + *p -- = '\0'; + len --; + + if (n > 0) { + for (; len > 0 && n > 0; len --, n /= 10) { + *p -- = '0' + (n % 10); + } + p ++; + } + else if (len > 0) { + *p = '0'; + len --; + } + + memmove(buf, p, bufend - p); +#else + snprintf(buf, len, "%" PRIu32, n); +#endif /* MRB_DISABLE_STDIO */ +} + +static void +i32tostr(char *buf, size_t len, int32_t n) +{ +#ifdef MRB_DISABLE_STDIO + if (len < 1) { + return; + } + + if (n < 0) { + *buf ++ = '-'; + len --; + n = -n; + } + + u32tostr(buf, len, (uint32_t)n); +#else + snprintf(buf, len, "%" PRId32, n); +#endif /* MRB_DISABLE_STDIO */ +} +#endif /* MRB_INT64 */ + static int unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) { @@ -241,16 +289,16 @@ unpack_l(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un int32_t sl = ul; #ifndef MRB_INT64 if (!FIXABLE(sl)) { - snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %" PRId32, sl); - mrb_raise(mrb, E_RANGE_ERROR, msg); + i32tostr(msg, sizeof(msg), sl); + mrb_raisef(mrb, E_RANGE_ERROR, "cannot unpack to Fixnum: %s", msg); } #endif n = sl; } else { #ifndef MRB_INT64 if (!POSFIXABLE(ul)) { - snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %" PRIu32, ul); - mrb_raise(mrb, E_RANGE_ERROR, msg); + u32tostr(msg, sizeof(msg), ul); + mrb_raisef(mrb, E_RANGE_ERROR, "cannot unpack to Fixnum: %s", msg); } #endif n = ul; @@ -288,6 +336,57 @@ pack_q(mrb_state *mrb, mrb_value o, mrb_value str, mrb_int sidx, unsigned int fl return 8; } +static void +u64tostr(char *buf, size_t len, uint64_t n) +{ +#ifdef MRB_DISABLE_STDIO + char *bufend = buf + len; + char *p = bufend - 1; + + if (len < 1) { + return; + } + + *p -- = '\0'; + len --; + + if (n > 0) { + for (; len > 0 && n > 0; len --, n /= 10) { + *p -- = '0' + (n % 10); + } + p ++; + } + else if (len > 0) { + *p = '0'; + len --; + } + + memmove(buf, p, bufend - p); +#else + snprintf(buf, len, "%" PRIu64, n); +#endif /* MRB_DISABLE_STDIO */ +} + +static void +i64tostr(char *buf, size_t len, int64_t n) +{ +#ifdef MRB_DISABLE_STDIO + if (len < 1) { + return; + } + + if (n < 0) { + *buf ++ = '-'; + len --; + n = -n; + } + + u64tostr(buf, len, (uint64_t)n); +#else + snprintf(buf, len, "%" PRId64, n); +#endif /* MRB_DISABLE_STDIO */ +} + static int unpack_q(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, unsigned int flags) { @@ -311,14 +410,14 @@ unpack_q(mrb_state *mrb, const unsigned char *src, int srclen, mrb_value ary, un if (flags & PACK_FLAG_SIGNED) { int64_t sll = ull; if (!FIXABLE(sll)) { - snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %" PRId64, sll); - mrb_raise(mrb, E_RANGE_ERROR, msg); + i64tostr(msg, sizeof(msg), sll); + mrb_raisef(mrb, E_RANGE_ERROR, "cannot unpack to Fixnum: %s", msg); } n = sll; } else { if (!POSFIXABLE(ull)) { - snprintf(msg, sizeof(msg), "cannot unpack to Fixnum: %" PRIu64, ull); - mrb_raise(mrb, E_RANGE_ERROR, msg); + u64tostr(msg, sizeof(msg), ull); + mrb_raisef(mrb, E_RANGE_ERROR, "cannot unpack to Fixnum: %s", msg); } n = ull; } diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index 558d57173..987ec711f 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -5,11 +5,6 @@ */ #include <mruby.h> - -#ifdef MRB_DISABLE_STDIO -# error sprintf conflicts 'MRB_DISABLE_STDIO' configuration in your 'build_config.rb' -#endif - #include <limits.h> #include <string.h> #include <mruby/string.h> @@ -521,6 +516,50 @@ mrb_f_sprintf(mrb_state *mrb, mrb_value obj) } } +static int +mrb_int2str(char *buf, size_t len, mrb_int n) +{ +#ifdef MRB_DISABLE_STDIO + char *bufend = buf + len; + char *p = bufend - 1; + + if (len < 1) return -1; + + *p -- = '\0'; + len --; + + if (n < 0) { + if (len < 1) return -1; + + *p -- = '-'; + len --; + n = -n; + } + + if (n > 0) { + for (; n > 0; len --, n /= 10) { + if (len < 1) return -1; + + *p -- = '0' + (n % 10); + } + p ++; + } + else if (len > 0) { + *p = '0'; + len --; + } + else { + return -1; + } + + memmove(buf, p, bufend - p); + + return bufend - p - 1; +#else + return snprintf(buf, len, "%" MRB_PRId, n); +#endif /* MRB_DISABLE_STDIO */ +} + mrb_value mrb_str_format(mrb_state *mrb, mrb_int argc, const mrb_value *argv, mrb_value fmt) { @@ -869,7 +908,7 @@ retry: width--; } mrb_assert(base == 10); - snprintf(nbuf, sizeof(nbuf), "%" MRB_PRId, v); + mrb_int2str(nbuf, sizeof(nbuf), v); s = nbuf; if (v < 0) s++; /* skip minus sign */ } @@ -877,24 +916,12 @@ retry: s = nbuf; if (v < 0) { dots = 1; + val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base); } - switch (base) { - case 2: - if (v < 0) { - val = mrb_fix2binstr(mrb, mrb_fixnum_value(v), base); - } - else { - val = mrb_fixnum_to_str(mrb, mrb_fixnum_value(v), base); - } - strncpy(++s, RSTRING_PTR(val), sizeof(nbuf)-1); - break; - case 8: - snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIo, v); - break; - case 16: - snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIx, v); - break; + else { + val = mrb_fixnum_to_str(mrb, mrb_fixnum_value(v), base); } + strncpy(++s, RSTRING_PTR(val), sizeof(nbuf)-1); if (v < 0) { char d; @@ -1071,7 +1098,7 @@ retry: need += 20; CHECK(need); - n = snprintf(&buf[blen], need, fbuf, fval); + n = mrb_float_to_cstr(mrb, &buf[blen], need, fbuf, fval); if (n < 0 || n >= need) { mrb_raise(mrb, E_RUNTIME_ERROR, "formatting error"); } @@ -1113,12 +1140,13 @@ fmt_setup(char *buf, size_t size, int c, int flags, mrb_int width, mrb_int prec) if (flags & FSPACE) *buf++ = ' '; if (flags & FWIDTH) { - n = snprintf(buf, end - buf, "%d", (int)width); + n = mrb_int2str(buf, end - buf, width); buf += n; } if (flags & FPREC) { - n = snprintf(buf, end - buf, ".%d", (int)prec); + *buf ++ = '.'; + n = mrb_int2str(buf, end - buf, prec); buf += n; } diff --git a/mrbgems/mruby-sprintf/test/sprintf.rb b/mrbgems/mruby-sprintf/test/sprintf.rb index 137812ae7..24d01c9be 100644 --- a/mrbgems/mruby-sprintf/test/sprintf.rb +++ b/mrbgems/mruby-sprintf/test/sprintf.rb @@ -8,6 +8,11 @@ assert('String#%') do assert_equal 15, ("%b" % (1<<14)).size skip unless Object.const_defined?(:Float) assert_equal "1.0", "%3.1f" % 1.01 + assert_equal " 123456789.12", "% 4.2f" % 123456789.123456789 + assert_equal "123456789.12", "%-4.2f" % 123456789.123456789 + assert_equal "+123456789.12", "%+4.2f" % 123456789.123456789 + assert_equal "123456789.12", "%04.2f" % 123456789.123456789 + assert_equal "00000000123456789.12", "%020.2f" % 123456789.123456789 end assert('String#% with inf') do @@ -140,7 +140,13 @@ mrb_obj_id(mrb_value obj) } } +#if defined(MRB_NAN_BOXING) && defined(MRB_64BIT) +#define mrb_xxx_boxing_cptr_value mrb_nan_boxing_cptr_value +#endif + #ifdef MRB_WORD_BOXING +#define mrb_xxx_boxing_cptr_value mrb_word_boxing_cptr_value + #ifndef MRB_WITHOUT_FLOAT MRB_API mrb_value mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) @@ -164,17 +170,20 @@ mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) return mrb_obj_value(nf); } #endif /* MRB_WITHOUT_FLOAT */ +#endif /* MRB_WORD_BOXING */ +#if defined(MRB_WORD_BOXING) || (defined(MRB_NAN_BOXING) && defined(MRB_64BIT)) MRB_API mrb_value -mrb_word_boxing_cptr_value(mrb_state *mrb, void *p) +mrb_xxx_boxing_cptr_value(mrb_state *mrb, void *p) { mrb_value v; + struct RCptr *cptr = (struct RCptr*)mrb_obj_alloc(mrb, MRB_TT_CPTR, mrb->object_class); - v.value.p = mrb_obj_alloc(mrb, MRB_TT_CPTR, mrb->object_class); - v.value.vp->p = p; + SET_OBJ_VALUE(v, cptr); + cptr->p = p; return v; } -#endif /* MRB_WORD_BOXING */ +#endif #if defined _MSC_VER && _MSC_VER < 1900 diff --git a/src/fmt_fp.c b/src/fmt_fp.c index b77abe7b5..9ae5dd177 100644 --- a/src/fmt_fp.c +++ b/src/fmt_fp.c @@ -37,9 +37,19 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <mruby.h> #include <mruby/string.h> +struct fmt_args; + +typedef void output_func(struct fmt_args *f, const char *s, size_t l); + struct fmt_args { mrb_state *mrb; - mrb_value str; + output_func *output; + void *opaque; +}; + +struct mrb_cstr { + char *buf; + size_t len; }; #define MAX(a,b) ((a)>(b) ? (a) : (b)) @@ -54,15 +64,44 @@ struct fmt_args { #define PAD_POS (1U<<(' '-' ')) #define MARK_POS (1U<<('+'-' ')) +#define FLAGMASK (ALT_FORM|ZERO_PAD|LEFT_ADJ|PAD_POS|MARK_POS) + +static output_func strcat_value; +static output_func strcat_cstr; + +static void +strcat_value(struct fmt_args *f, const char *s, size_t l) +{ + mrb_value str = *(mrb_value*)f->opaque; + mrb_str_cat(f->mrb, str, s, l); +} + +static void +strcat_cstr(struct fmt_args *f, const char *s, size_t l) +{ + struct mrb_cstr *cstr = (struct mrb_cstr*)f->opaque; + + if (l > cstr->len) { + mrb_state *mrb = f->mrb; + + mrb_raise(mrb, E_ARGUMENT_ERROR, "string buffer too small"); + } + + memcpy(cstr->buf, s, l); + + cstr->buf += l; + cstr->len -= l; +} + static void out(struct fmt_args *f, const char *s, size_t l) { - mrb_str_cat(f->mrb, f->str, s, l); + f->output(f, s, l); } #define PAD_SIZE 256 static void -pad(struct fmt_args *f, char c, ptrdiff_t w, ptrdiff_t l, uint8_t fl) +pad(struct fmt_args *f, char c, ptrdiff_t w, ptrdiff_t l, uint32_t fl) { char pad[PAD_SIZE]; if (fl & (LEFT_ADJ | ZERO_PAD) || l >= w) return; @@ -92,7 +131,7 @@ typedef char compiler_defines_long_double_incorrectly[9-(int)sizeof(long double) #endif static int -fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t) +fmt_fp(struct fmt_args *f, long double y, ptrdiff_t w, ptrdiff_t p, uint32_t fl, int t) { uint32_t big[(LDBL_MANT_DIG+28)/29 + 1 // mantissa expansion + (LDBL_MAX_EXP+LDBL_MANT_DIG+28+8)/9]; // exponent expansion @@ -117,11 +156,11 @@ fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t) if (!isfinite(y)) { const char *ss = (t&32)?"inf":"INF"; if (y!=y) ss=(t&32)?"nan":"NAN"; - pad(f, ' ', 0, 3+pl, fl&~ZERO_PAD); + pad(f, ' ', w, 3+pl, fl&~ZERO_PAD); out(f, prefix, pl); out(f, ss, 3); - pad(f, ' ', 0, 3+pl, fl^LEFT_ADJ); - return 3+(int)pl; + pad(f, ' ', w, 3+pl, fl^LEFT_ADJ); + return MAX(w, 3+(int)pl); } y = frexp((double)y, &e2) * 2; @@ -169,14 +208,14 @@ fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t) else l = (s-buf) + (ebuf-estr); - pad(f, ' ', 0, pl+l, fl); + pad(f, ' ', w, pl+l, fl); out(f, prefix, pl); - pad(f, '0', 0, pl+l, fl^ZERO_PAD); + pad(f, '0', w, pl+l, fl^ZERO_PAD); out(f, buf, s-buf); pad(f, '0', l-(ebuf-estr)-(s-buf), 0, 0); out(f, estr, ebuf-estr); - pad(f, ' ', 0, pl+l, fl^LEFT_ADJ); - return (int)pl+(int)l; + pad(f, ' ', w, pl+l, fl^LEFT_ADJ); + return MAX(w, (int)pl+(int)l); } if (p<0) p=6; @@ -288,9 +327,9 @@ fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t) l += ebuf-estr; } - pad(f, ' ', 0, pl+l, fl); + pad(f, ' ', w, pl+l, fl); out(f, prefix, pl); - pad(f, '0', 0, pl+l, fl^ZERO_PAD); + pad(f, '0', w, pl+l, fl^ZERO_PAD); if ((t|32)=='f') { if (a>r) a=r; @@ -325,21 +364,33 @@ fmt_fp(struct fmt_args *f, long double y, ptrdiff_t p, uint8_t fl, int t) out(f, estr, ebuf-estr); } - pad(f, ' ', 0, pl+l, fl^LEFT_ADJ); + pad(f, ' ', w, pl+l, fl^LEFT_ADJ); - return (int)pl+(int)l; + return MAX(w, (int)pl+(int)l); } static int fmt_core(struct fmt_args *f, const char *fmt, mrb_float flo) { - ptrdiff_t p; + ptrdiff_t w, p; + uint32_t fl; if (*fmt != '%') { return -1; } ++fmt; + /* Read modifier flags */ + for (fl=0; (unsigned)*fmt-' '<32 && (FLAGMASK&(1U<<(*fmt-' '))); fmt++) + fl |= 1U<<(*fmt-' '); + + /* - and 0 flags are mutually exclusive */ + if (fl & LEFT_ADJ) fl &= ~ZERO_PAD; + + for (w = 0; ISDIGIT(*fmt); ++fmt) { + w = 10 * w + (*fmt - '0'); + } + if (*fmt == '.') { ++fmt; for (p = 0; ISDIGIT(*fmt); ++fmt) { @@ -353,29 +404,49 @@ fmt_core(struct fmt_args *f, const char *fmt, mrb_float flo) switch (*fmt) { case 'e': case 'f': case 'g': case 'a': case 'E': case 'F': case 'G': case 'A': - return fmt_fp(f, flo, p, 0, *fmt); + return fmt_fp(f, flo, w, p, fl, *fmt); default: return -1; } } -mrb_value +MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) { struct fmt_args f; + mrb_value str = mrb_str_new_capa(mrb, 24); f.mrb = mrb; - f.str = mrb_str_new_capa(mrb, 24); + f.output = strcat_value; + f.opaque = (void*)&str; if (fmt_core(&f, fmt, mrb_float(flo)) < 0) { mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format string"); } - return f.str; + return str; +} + +MRB_API int +mrb_float_to_cstr(mrb_state *mrb, char *buf, size_t len, const char *fmt, mrb_float fval) +{ + struct fmt_args f; + struct mrb_cstr cstr; + + cstr.buf = buf; + cstr.len = len - 1; /* reserve NUL terminator */ + f.mrb = mrb; + f.output = strcat_cstr; + f.opaque = (void*)&cstr; + if (fmt_core(&f, fmt, fval) < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid format string"); + } + *cstr.buf = '\0'; + return cstr.buf - buf; } #else /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #include <mruby.h> #include <stdio.h> -mrb_value +MRB_API mrb_value mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) { char buf[25]; @@ -383,5 +454,11 @@ mrb_float_to_str(mrb_state *mrb, mrb_value flo, const char *fmt) snprintf(buf, sizeof(buf), fmt, mrb_float(flo)); return mrb_str_new_cstr(mrb, buf); } + +MRB_API int +mrb_float_to_cstr(mrb_state *mrb, char *buf, size_t len, const char *fmt, mrb_float fval) +{ + return snprintf(buf, len, fmt, fval); +} #endif /* MRB_DISABLE_STDIO || _WIN32 || _WIN64 */ #endif |
