summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/mruby/boxing_nan.h13
-rw-r--r--include/mruby/boxing_word.h5
-rw-r--r--include/mruby/numeric.h1
-rw-r--r--include/mruby/value.h7
-rw-r--r--mrbgems/mruby-bin-config/mrbgem.rake7
-rw-r--r--mrbgems/mruby-io/src/io.c3
-rw-r--r--mrbgems/mruby-pack/src/pack.c125
-rw-r--r--mrbgems/mruby-sprintf/src/sprintf.c78
-rw-r--r--mrbgems/mruby-sprintf/test/sprintf.rb5
-rw-r--r--src/etc.c17
-rw-r--r--src/fmt_fp.c119
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
diff --git a/src/etc.c b/src/etc.c
index 607e82ca1..6e1533e3d 100644
--- a/src/etc.c
+++ b/src/etc.c
@@ -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