From 054313b96c4ed7154e001f950a8e05baecc7fa35 Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Wed, 29 May 2019 01:35:13 +0000 Subject: [PATCH] renamed moo_sprintfmtfromstack() to moo_strfmtcallstack(). refactored related functions --- moo/kernel/Collect.moo | 1 + moo/lib/exec.c | 26 +- moo/lib/fmt.c | 685 +++++++++++++++++++++++++++++++++++++++++ moo/lib/fmtout.c | 25 +- moo/lib/moo-prv.h | 5 +- moo/lib/moo-utl.h | 8 +- moo/t/Makefile.in | 1 + moo/t/t-003.c | 8 +- 8 files changed, 741 insertions(+), 18 deletions(-) diff --git a/moo/kernel/Collect.moo b/moo/kernel/Collect.moo index 9ba8c2d..6345e71 100644 --- a/moo/kernel/Collect.moo +++ b/moo/kernel/Collect.moo @@ -285,6 +285,7 @@ class(#character) String(Array) method(#primitive) strlen. method(#primitive,#variadic) strfmt(). + method(#primitive,#variadic,#class) format(fmt). } ## ------------------------------------------------------------------------------- diff --git a/moo/lib/exec.c b/moo/lib/exec.c index a3ed6e2..afe0ac4 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -3637,6 +3637,29 @@ static moo_pfrc_t pf_error_as_string (moo_t* moo, moo_mod_t* mod, moo_ooi_t narg return MOO_PF_SUCCESS; } +static moo_pfrc_t pf_string_format (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) +{ + /* ignore the receiver. the first argument is the format string. */ + /*moo_oop_t rcv; + rcv = MOO_STACK_GETRCV(moo, nargs); + MOO_PF_CHECK_RCV (moo, MOO_OBJ_IS_CHAR_POINTER(rcv));*/ + + if (moo_strfmtcallstack(moo, nargs, 0) <= -1) + { + MOO_STACK_SETRETTOERRNUM (moo, nargs); + } + else + { + moo_oop_t str; + str = moo_makestring(moo, moo->sprintf.xbuf.ptr, moo->sprintf.xbuf.len); + if (!str) return MOO_PF_FAILURE; + + MOO_STACK_SETRET (moo, nargs, str); + } + + return MOO_PF_SUCCESS; +} + static moo_pfrc_t pf_strfmt (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) { moo_oop_t rcv; @@ -3644,7 +3667,7 @@ static moo_pfrc_t pf_strfmt (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) rcv = MOO_STACK_GETRCV(moo, nargs); MOO_PF_CHECK_RCV (moo, MOO_OBJ_IS_CHAR_POINTER(rcv)); - if (moo_sprintfmtst(moo, nargs) <= -1) + if (moo_strfmtcallstack(moo, nargs, 1) <= -1) { MOO_STACK_SETRETTOERRNUM (moo, nargs); } @@ -3870,6 +3893,7 @@ static pf_t pftab[] = { "SmallPointer_putUint64", { moo_pf_smptr_put_uint64, 2, 2 } }, { "SmallPointer_putUint8", { moo_pf_smptr_put_uint8, 2, 2 } }, + { "String_format", { pf_string_format, 1, MA } }, { "String_strfmt", { pf_strfmt, 0, MA } }, { "String_strlen", { pf_strlen, 0, 0 } }, diff --git a/moo/lib/fmt.c b/moo/lib/fmt.c index 21f8152..59df2a6 100644 --- a/moo/lib/fmt.c +++ b/moo/lib/fmt.c @@ -1759,3 +1759,688 @@ moo_ooi_t moo_logufmt (moo_t* moo, moo_bitmask_t mask, const moo_uch_t* fmt, ... } return (x <= -1)? -1: fo.count; } + + +/* -------------------------------------------------------------------------- + * SUPPORT FOR FORMATTED OUTPUT TO BE USED BY BUILTIN PRIMITIVE FUNCTIONS + * -------------------------------------------------------------------------- */ +static int sprint_bcs (moo_fmtout_t* fmtout, const moo_bch_t* ptr, moo_oow_t len) +{ + moo_t* moo = (moo_t*)fmtout->ctx; + moo_oow_t unused, oolen, blen; + + unused = moo->sprintf.xbuf.capa - moo->sprintf.xbuf.len; + +#if defined(MOO_OOCH_IS_UCH) + blen = len; + moo_conv_bchars_to_uchars_with_cmgr (ptr, &blen, MOO_NULL, &oolen, moo->cmgr, 1); +#else + oolen = len; +#endif + + if (oolen > unused) + { + moo_ooch_t* tmp; + moo_oow_t newcapa; + + newcapa = moo->sprintf.xbuf.len + oolen + 1; + newcapa = MOO_ALIGN_POW2(newcapa, 256); + + tmp = (moo_ooch_t*)moo_reallocmem(moo, moo->sprintf.xbuf.ptr, newcapa * MOO_SIZEOF(*tmp)); + if (!tmp) return -1; + + moo->sprintf.xbuf.ptr = tmp; + moo->sprintf.xbuf.capa = newcapa; + } + +#if defined(MOO_OOCH_IS_UCH) + moo_conv_bchars_to_uchars_with_cmgr (ptr, &len, &moo->sprintf.xbuf.ptr[moo->sprintf.xbuf.len], &oolen, moo->cmgr, 1); +#else + MOO_MEMCPY (&moo->sprintf.xbuf.ptr[moo->sprintf.xbuf.len], ptr, len * MOO_SIZEOF(*ptr)); +#endif + moo->sprintf.xbuf.len += oolen; + + return 1; /* success */ +} + +static int sprint_ucs (moo_fmtout_t* fmtout, const moo_uch_t* ptr, moo_oow_t len) +{ + moo_t* moo = (moo_t*)fmtout->ctx; + moo_oow_t unused, oolen, ulen; + + unused = moo->sprintf.xbuf.capa - moo->sprintf.xbuf.len; + +#if defined(MOO_OOCH_IS_UCH) + oolen = len; +#else + ulen = len; + moo_conv_uchars_to_bchars_with_cmgr (ptr, &ulen, MOO_NULL, &oolen, moo->cmgr); +#endif + + if (oolen > unused) + { + moo_ooch_t* tmp; + moo_oow_t newcapa; + + newcapa = moo->sprintf.xbuf.len + oolen + 1; + newcapa = MOO_ALIGN_POW2(newcapa, 256); + + tmp = (moo_ooch_t*)moo_reallocmem(moo, moo->sprintf.xbuf.ptr, newcapa * MOO_SIZEOF(*tmp)); + if (!tmp) return -1; + + moo->sprintf.xbuf.ptr = tmp; + moo->sprintf.xbuf.capa = newcapa; + } + +#if defined(MOO_OOCH_IS_UCH) + MOO_MEMCPY (&moo->sprintf.xbuf.ptr[moo->sprintf.xbuf.len], ptr, len * MOO_SIZEOF(*ptr)); +#else + moo_conv_uchars_to_bchars_with_cmgr (ptr, &len, &moo->sprintf.xbuf.ptr[moo->sprintf.xbuf.len], &oolen, moo->cmgr); +#endif + moo->sprintf.xbuf.len += oolen; + + return 1; /* success */ +} + + +moo_ooi_t moo_sproutbfmt (moo_t* moo, moo_bitmask_t mask, const moo_bch_t* fmt, ...) +{ + int x; + va_list ap; + moo_fmtout_t fo; + + MOO_MEMSET (&fo, 0, MOO_SIZEOF(fo)); + fo.fmt_type = MOO_FMTOUT_FMT_TYPE_BCH; + fo.fmt_str = fmt; + fo.mask = mask; + fo.putbcs = sprint_bcs; + fo.putucs = sprint_ucs; + fo.putobj = moo_fmt_object_; + + va_start (ap, fmt); + x = fmt_outv(&fo, ap); + va_end (ap); + + return (x <= -1)? -1: fo.count; +} + +moo_ooi_t moo_sproutufmt (moo_t* moo, moo_bitmask_t mask, const moo_uch_t* fmt, ...) +{ + int x; + va_list ap; + moo_fmtout_t fo; + + MOO_MEMSET (&fo, 0, MOO_SIZEOF(fo)); + fo.fmt_type = MOO_FMTOUT_FMT_TYPE_UCH; + fo.fmt_str = fmt; + fo.mask = mask; + fo.putbcs = sprint_bcs; + fo.putucs = sprint_ucs; + fo.putobj = moo_fmt_object_; + + va_start (ap, fmt); + x = fmt_outv(&fo, ap); + va_end (ap); + + return (x <= -1)? -1: fo.count; +} + + + +#define GET_NEXT_ARG_TO(moo,nargs,arg_state,arg) do { \ + if ((arg_state)->idx >= nargs) { (arg_state)->stop = 1; goto invalid_format; } \ + arg = MOO_STACK_GETARG(moo, nargs, (arg_state)->idx); \ + (arg_state)->idx++; \ +} while(0) + +#define GET_NEXT_CHAR_TO(moo,fmt,fmtend,ch) do { \ + if (fmt >= fmtend) ch = MOO_OOCI_EOF; \ + else { ch = *(fmt); (fmt)++; }\ +} while(0) + +static MOO_INLINE int format_stack_args (moo_fmtout_t* fmtout, moo_ooi_t nargs, int rcv_is_fmtstr) +{ + moo_t* moo = (moo_t*)fmtout->ctx; + + const moo_ooch_t* fmtptr, * fmtend; + const moo_ooch_t* checkpoint, * percent; + + int n, radix, neg, sign, radix_flags; + moo_ooi_t extra, width, precision; + moo_ooch_t padc, ooch; + moo_ooci_t ch; + int flagc; + + struct + { + moo_ooi_t idx; + int stop; + } arg_state; + moo_oop_t arg; + + MOO_ASSERT (moo, fmtout->putobj != MOO_NULL); + + fmtout->count = 0; + + if (rcv_is_fmtstr) + { + arg = MOO_STACK_GETRCV(moo, nargs); + arg_state.idx = 0; + } + else + { + arg = MOO_STACK_GETARG(moo, nargs, 0); + arg_state.idx = 1; + } + + if (!MOO_OOP_IS_POINTER(arg) || MOO_OBJ_GET_FLAGS_TYPE(arg) != MOO_OBJ_TYPE_CHAR) + { + moo_ooi_t i; + /* if the first argument is not a valid formatting string, + * print all arguments as objects */ + if (fmtout->putobj(fmtout, arg) <= -1) goto oops; + for (i = arg_state.idx; i < nargs; i++) + { + arg = MOO_STACK_GETARG(moo, nargs, i); + if (fmtout->putobj(fmtout, arg) <= -1) goto oops; + } + return 0; + } + + arg_state.stop = 0; + + fmtptr = MOO_OBJ_GET_CHAR_SLOT(arg); + fmtend = fmtptr + MOO_OBJ_GET_SIZE(arg); + + while (1) + { + checkpoint = fmtptr; + + while (1) + { + GET_NEXT_CHAR_TO (moo, fmtptr, fmtend, ch); + if (ch == '%' && !arg_state.stop) break; + + if (ch == MOO_OOCI_EOF) + { + /* fmt is not advanced when it is length-bounded. + * so not fmt - checkpoint - 1 */ + PUT_OOCS (fmtout, checkpoint, fmtptr - checkpoint); + goto done; + } + } + PUT_OOCS (fmtout, checkpoint, fmtptr - checkpoint - 1); + + percent = fmtptr - 1; + + padc = ' '; + width = 0; precision = 0; + neg = 0; sign = 0; + + flagc = 0; + radix_flags = MOO_INTTOSTR_NONEWOBJ; + + reswitch: + GET_NEXT_CHAR_TO (moo, fmtptr, fmtend, ch); + switch (ch) + { + case '%': /* %% */ + ooch = ch; + goto print_char; + + /* flag characters */ + case '.': + if (flagc & FLAGC_DOT) goto invalid_format; + flagc |= FLAGC_DOT; + goto reswitch; + + case '#': + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + flagc |= FLAGC_SHARP; + goto reswitch; + + case ' ': + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + flagc |= FLAGC_SPACE; + goto reswitch; + + case '+': /* place sign for signed conversion */ + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + flagc |= FLAGC_SIGN; + goto reswitch; + + case '-': /* left adjusted */ + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + if (flagc & FLAGC_DOT) + { + goto invalid_format; + } + else + { + flagc |= FLAGC_LEFTADJ; + if (flagc & FLAGC_ZEROPAD) + { + padc = ' '; + flagc &= ~FLAGC_ZEROPAD; + } + } + + goto reswitch; + + case '*': /* take the length from the parameter */ + if (flagc & FLAGC_DOT) + { + if (flagc & (FLAGC_STAR2 | FLAGC_PRECISION)) goto invalid_format; + flagc |= FLAGC_STAR2; + + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (moo_inttoooi(moo, arg, &precision) <= -1) goto invalid_format; + if (precision < 0) + { + /* if precision is less than 0, + * treat it as if no .precision is specified */ + flagc &= ~FLAGC_DOT; + precision = 0; + } + } + else + { + if (flagc & (FLAGC_STAR1 | FLAGC_WIDTH)) goto invalid_format; + flagc |= FLAGC_STAR1; + + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (moo_inttoooi(moo, arg, &width) <= -1) goto invalid_format; + if (width < 0) + { + flagc |= FLAGC_LEFTADJ; + width = -width; + } + } + goto reswitch; + + case '0': /* zero pad */ + if (flagc & FLAGC_LENMOD) goto invalid_format; + if (!(flagc & (FLAGC_DOT | FLAGC_LEFTADJ))) + { + padc = '0'; + flagc |= FLAGC_ZEROPAD; + goto reswitch; + } + /* end of flags characters */ + + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (flagc & FLAGC_LENMOD) goto invalid_format; + for (n = 0;; ++fmtptr) + { + n = n * 10 + ch - '0'; + ch = *fmtptr; + if (ch < '0' || ch > '9') break; + } + if (flagc & FLAGC_DOT) + { + if (flagc & FLAGC_STAR2) goto invalid_format; + precision = n; + flagc |= FLAGC_PRECISION; + } + else + { + if (flagc & FLAGC_STAR1) goto invalid_format; + width = n; + flagc |= FLAGC_WIDTH; + } + goto reswitch; + + /* integer conversions */ + case 'd': + case 'i': /* signed conversion */ + radix = 10; + sign = 1; + goto print_integer; + case 'o': + radix = 8; + goto print_integer; + case 'u': + radix = 10; + goto print_integer; + case 'x': + radix_flags |= MOO_INTTOSTR_LOWERCASE; + case 'X': + radix = 16; + goto print_integer; + case 'b': + radix = 2; + goto print_integer; + /* end of integer conversions */ + + case 'f': + { + const moo_ooch_t* nsptr; + moo_oow_t nslen; + moo_oow_t scale = 0; + + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (MOO_OOP_IS_CHAR(arg)) + { + arg = MOO_SMOOI_TO_OOP(MOO_OOP_TO_CHAR(arg)); + } + else if (MOO_OOP_IS_FPDEC(moo, arg)) + { + moo_oop_fpdec_t fa = (moo_oop_fpdec_t)arg; + scale = MOO_OOP_TO_SMOOI(fa->scale); + arg = fa->value; + } + + if (!moo_inttostr(moo, arg, 10 | MOO_INTTOSTR_NONEWOBJ)) + { + MOO_LOG1 (moo, MOO_LOG_WARN | MOO_LOG_UNTYPED, "unable to convert %O to string \n", arg); + goto invalid_format; + } + + nsptr = moo->inttostr.xbuf.ptr; + nslen = moo->inttostr.xbuf.len; + MOO_ASSERT (moo, nslen > 0); + + if (nsptr[0] == '-') + { + MOO_ASSERT (moo, (MOO_OOP_IS_SMOOI(arg) && MOO_OOP_TO_SMOOI(arg) < 0) || MOO_OOP_IS_NBIGINT(moo,arg)); + nsptr++; + nslen--; + neg = 1; + } + + if (!(flagc & FLAGC_DOT)) + { + precision = scale; + if (precision <= 0) precision = 1; + } + + if ((flagc & FLAGC_DOT) && precision < scale) + { + moo_oow_t diff = scale - precision; + scale = precision; + nslen = (nslen < diff)? 0: (nslen - diff); + } + + if (nslen < scale + 1) + { + extra = 1; + if (precision > 0) extra += 1 + scale; + } + else + { + extra = 0; + if (nslen > 0) extra += nslen - scale; + if (precision > 0) + { + extra += 1; + if (nslen > 0) extra += scale; + } + } + + if (neg) extra++; + else if (flagc & FLAGC_SIGN) extra++; + else if (flagc & FLAGC_SPACE) extra++; + + if ((flagc & FLAGC_DOT) && precision > scale) + { + /* trailing zeros in the fractional part */ + extra += precision - scale; + } + + if (!(flagc & FLAGC_LEFTADJ) && !(flagc & FLAGC_ZEROPAD) && width > extra) + { + width -= extra; + PUT_OOCH (fmtout, padc, width); + width = 0; + } + if (neg) PUT_OOCH (fmtout, '-', 1); + else if (flagc & FLAGC_SIGN) PUT_OOCH (fmtout, '+', 1); + else if (flagc & FLAGC_SPACE) PUT_OOCH (fmtout, ' ', 1); + + if (!(flagc & FLAGC_LEFTADJ) && width > extra) + { + width -= extra; + PUT_OOCH (fmtout, padc, width); + } + + if (nslen < scale + 1) + { + PUT_OOCH (fmtout, '0', 1); + if (precision > 0) + { + PUT_OOCH (fmtout, '.', 1); + PUT_OOCH (fmtout, '0', scale - nslen); + PUT_OOCS (fmtout, nsptr, nslen); + } + } + else + { + if (nslen > 0) PUT_OOCS (fmtout, nsptr, nslen - scale); + if (precision > 0) + { + PUT_OOCH (fmtout, '.', 1); + if (nslen > 0) PUT_OOCS (fmtout, &nsptr[nslen - scale], scale); + } + } + if (precision > scale) + { + /* trailing zeros in the fractional part */ + PUT_OOCH (fmtout, '0', precision - scale); + } + + if ((flagc & FLAGC_LEFTADJ) && width > extra) + { + width -= extra; + PUT_OOCH (fmtout, padc, width); + } + break; + } + + case 'c': + case 'C': + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (MOO_OOP_IS_SMOOI(arg)) arg = MOO_CHAR_TO_OOP(MOO_OOP_TO_SMOOI(arg)); + if (!MOO_OOP_IS_CHAR(arg)) goto invalid_format; + ooch = MOO_OOP_TO_CHAR(arg); + + print_char: + /* zeropad must not take effect for 'c' */ + if (flagc & FLAGC_ZEROPAD) padc = ' '; + + /* precision 0 doesn't kill the letter */ + width--; + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (fmtout, padc, width); + PUT_OOCH (fmtout, ooch, 1); + if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (fmtout, padc, width); + break; + + case 's': + case 'S': + { + const moo_ooch_t* oosp; + moo_oow_t oosl; + + /* zeropad must not take effect for 'S' */ + if (flagc & FLAGC_ZEROPAD) padc = ' '; + + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (!MOO_OOP_IS_POINTER(arg) || MOO_OBJ_GET_FLAGS_TYPE(arg) != MOO_OBJ_TYPE_CHAR) goto invalid_format; + + oosp = MOO_OBJ_GET_CHAR_SLOT(arg); + oosl = MOO_OBJ_GET_SIZE(arg); + + if (flagc & FLAGC_DOT) + { + if (oosl > precision) oosl = precision; + } + width -= oosl; + + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (fmtout, padc, width); + PUT_OOCS (fmtout, oosp, oosl); + if ((flagc & FLAGC_LEFTADJ) && width > 0) PUT_OOCH (fmtout, padc, width); + break; + } + + case 'O': /* object - ignore precision, width, adjustment */ + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (fmtout->putobj(fmtout, arg) <= -1) goto oops; + break; + + print_integer: + { + const moo_ooch_t* nsptr; + moo_oow_t nslen; + + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (MOO_OOP_IS_CHAR(arg)) + { + arg = MOO_SMOOI_TO_OOP(MOO_OOP_TO_CHAR(arg)); + } + else if (MOO_OOP_IS_FPDEC(moo, arg)) + { + moo_oop_t nv; + moo_oop_fpdec_t fa = (moo_oop_fpdec_t)arg; + + /* the given number for integer output is a fixed-point decimal. + * i will drop all digits after the fixed point */ + moo_pushvolat (moo, &arg); + nv = moo_truncfpdecval(moo, fa->value, MOO_OOP_TO_SMOOI(fa->scale), 0); + moo_popvolat (moo); + if (!nv) + { + MOO_LOG1 (moo, MOO_LOG_WARN | MOO_LOG_UNTYPED, "unable to truncate a fixed-point number %O to an integer for output\n", arg); + goto invalid_format; + } + + arg = nv; + } + + if (!moo_inttostr(moo, arg, radix | radix_flags)) + { + /*moo_seterrbfmt (moo, MOO_EINVAL, "not a valid number - %O", arg); + goto oops;*/ + MOO_LOG1 (moo, MOO_LOG_WARN | MOO_LOG_UNTYPED, "unable to convert integer %O to string \n", arg); + goto invalid_format; + } + + nsptr = moo->inttostr.xbuf.ptr; + nslen = moo->inttostr.xbuf.len; + + MOO_ASSERT (moo, nslen > 0); + if (nsptr[0] == '-') + { + /* a negative number was given. i must skip the minus sign + * added by moo_inttostr() for a negative number. */ + MOO_ASSERT (moo, (MOO_OOP_IS_SMOOI(arg) && MOO_OOP_TO_SMOOI(arg) < 0) || MOO_OOP_IS_NBIGINT(moo,arg)); + nsptr++; + nslen--; + } + + extra = nslen; + if (sign && ((MOO_OOP_IS_SMOOI(arg) && MOO_OOP_TO_SMOOI(arg) < 0) || MOO_OOP_IS_NBIGINT(moo,arg))) neg = 1; + + if ((flagc & FLAGC_SHARP) && arg != MOO_SMOOI_TO_OOP(0)) + { + if (radix == 2 || radix == 8 || radix == 16) extra += 2; + } + if (neg) extra++; + else if (flagc & FLAGC_SIGN) extra++; + else if (flagc & FLAGC_SPACE) extra++; + + if ((flagc & FLAGC_DOT) && precision > nslen) + { + /* extra zeros for precision specified */ + extra += (precision - nslen); + } + + if (!(flagc & FLAGC_LEFTADJ) && !(flagc & FLAGC_ZEROPAD) && width > 0 && (width -= extra) > 0) + { + PUT_OOCH (fmtout, padc, width); + width = 0; + } + + if (neg) PUT_OOCH (fmtout, '-', 1); + else if (flagc & FLAGC_SIGN) PUT_OOCH (fmtout, '+', 1); + else if (flagc & FLAGC_SPACE) PUT_OOCH (fmtout, ' ', 1); + + if ((flagc & FLAGC_SHARP) && arg != MOO_SMOOI_TO_OOP(0)) + { + if (radix == 2) + { + PUT_OOCH (fmtout, '2', 1); + PUT_OOCH (fmtout, 'r', 1); + } + if (radix == 8) + { + PUT_OOCH (fmtout, '8', 1); + PUT_OOCH (fmtout, 'r', 1); + } + else if (radix == 16) + { + PUT_OOCH (fmtout, '1', 1); + PUT_OOCH (fmtout, '6', 1); + PUT_OOCH (fmtout, 'r', 1); + } + } + + if ((flagc & FLAGC_DOT) && precision > nslen) + { + /* extra zeros for precision specified */ + PUT_OOCH (fmtout, '0', precision - nslen); + } + + if (!(flagc & FLAGC_LEFTADJ) && width > 0 && (width -= extra) > 0) + { + PUT_OOCH (fmtout, padc, width); + } + + PUT_OOCS (fmtout, nsptr, nslen); + + if ((flagc & FLAGC_LEFTADJ) && width > 0 && (width -= extra) > 0) + { + PUT_OOCH (fmtout, padc, width); + } + break; + } + + invalid_format: + PUT_OOCS (fmtout, percent, fmtptr - percent); + break; + + default: + PUT_OOCS (fmtout, percent, fmtptr - percent); + /* + * Since we ignore an formatting argument it is no + * longer safe to obey the remaining formatting + * arguments as the arguments will no longer match + * the format specs. + */ + arg_state.stop = 1; + break; + } + } + +done: + return 0; + +oops: + return -1; +} + +int moo_strfmtcallstack (moo_t* moo, moo_ooi_t nargs, int rcv_is_fmtstr) +{ + /* format a string using the receiver and arguments on the stack */ + moo_fmtout_t fo; + + MOO_MEMSET (&fo, 0, MOO_SIZEOF(fo)); + fo.ctx = moo; + fo.putbcs = sprint_bcs; + fo.putucs = sprint_ucs; + fo.putobj = moo_fmt_object_; + /* format_stack_args doesn't use fmt_str and fmt_type. + * it takes the format string from the stack. */ + + moo->sprintf.xbuf.len = 0; + return format_stack_args(&fo, nargs, rcv_is_fmtstr); +} diff --git a/moo/lib/fmtout.c b/moo/lib/fmtout.c index 5b3e52f..af55c6a 100644 --- a/moo/lib/fmtout.c +++ b/moo/lib/fmtout.c @@ -26,6 +26,8 @@ #include "moo-prv.h" +#if 0 + /*#include */ /* for snrintf(). used for floating-point number formatting */ #if defined(_MSC_VER) || defined(__BORLANDC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1200)) @@ -729,7 +731,7 @@ moo_ooi_t moo_logufmt (moo_t* moo, moo_bitmask_t mask, const moo_uch_t* fmt, ... else { ch = *(fmt); (fmt)++; }\ } while(0) -static MOO_INLINE int print_formatted (moo_t* moo, moo_ooi_t nargs, moo_fmtout_data_t* data, moo_outbfmt_t outbfmt, int ignore_rcv) +static MOO_INLINE int print_formatted (moo_t* moo, moo_ooi_t nargs, moo_fmtout_data_t* data, moo_outbfmt_t outbfmt, int rcv_is_fmtstr) { const moo_ooch_t* fmt, * fmtend; const moo_ooch_t* checkpoint, * percent; @@ -747,16 +749,16 @@ static MOO_INLINE int print_formatted (moo_t* moo, moo_ooi_t nargs, moo_fmtout_d } arg_state; moo_oop_t arg; - if (ignore_rcv) - { - arg = MOO_STACK_GETARG(moo, nargs, 0); - arg_state.idx = 1; - } - else + if (rcv_is_fmtstr) { arg = MOO_STACK_GETRCV(moo, nargs); arg_state.idx = 0; } + else + { + arg = MOO_STACK_GETARG(moo, nargs, 0); + arg_state.idx = 1; + } if (!MOO_OOP_IS_POINTER(arg) || MOO_OBJ_GET_FLAGS_TYPE(arg) != MOO_OBJ_TYPE_CHAR) { @@ -1377,6 +1379,7 @@ static moo_ooi_t __sprbfmtv(moo_t* moo, moo_bitmask_t mask, const moo_bch_t* fmt return fo.count; } +#if 0 moo_ooi_t moo_sproutbfmt (moo_t* moo, moo_bitmask_t mask, const moo_bch_t* fmt, ...) { int x; @@ -1393,7 +1396,7 @@ moo_ooi_t moo_sproutbfmt (moo_t* moo, moo_bitmask_t mask, const moo_bch_t* fmt, return (x <= -1)? -1: fo.count; } - +#endif /* moo_ooi_t moo_sproutufmt (moo_t* moo, moo_bitmask_t mask, const moo_uch_t* fmt, ...) { @@ -1413,7 +1416,7 @@ moo_ooi_t moo_sproutufmt (moo_t* moo, moo_bitmask_t mask, const moo_uch_t* fmt, }*/ -int moo_sprintfmtst (moo_t* moo, moo_ooi_t nargs) +int moo_strfmtcallstack (moo_t* moo, moo_ooi_t nargs) { /* format a string using the receiver and arguments on the stack */ moo_fmtout_data_t fo; @@ -1421,5 +1424,7 @@ int moo_sprintfmtst (moo_t* moo, moo_ooi_t nargs) fo.putch = put_sprch; fo.putcs = put_sprcs; moo->sprintf.xbuf.len = 0; - return print_formatted(moo, nargs, &fo, moo_sproutbfmt, 0); + return print_formatted(moo, nargs, &fo, moo_sproutbfmt, 1); } + +#endif diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index 19aaf8b..f595631 100644 --- a/moo/lib/moo-prv.h +++ b/moo/lib/moo-prv.h @@ -1501,9 +1501,10 @@ moo_ooi_t moo_sproutbfmt ( ... ); -int moo_sprintfmtst ( +int moo_strfmtcallstack ( moo_t* moo, - moo_ooi_t nargs + moo_ooi_t nargs, + int rcv_is_fmtstr ); /* ========================================================================= */ diff --git a/moo/lib/moo-utl.h b/moo/lib/moo-utl.h index 669cb3c..a93e156 100644 --- a/moo/lib/moo-utl.h +++ b/moo/lib/moo-utl.h @@ -381,10 +381,10 @@ MOO_EXPORT moo_oow_t moo_hash_bytes_ ( } #else # define moo_hash_bytes(ptr,len) moo_hash_bytes_(ptr, len) -# define moo_hash_bchars(ptr,len) moo_hash_bytes((const moo_oob_t*)(ptr), (len) * MOO_SIZEOF(moo_bch_t)) -# define moo_hash_uchars(ptr,len) moo_hash_bytes((const moo_oob_t*)(ptr), (len) * MOO_SIZEOF(moo_uch_t)) -# define moo_hash_words(ptr,len) moo_hash_bytes((const moo_oob_t*)(ptr), (len) * MOO_SIZEOF(moo_oow_t)) -# define moo_hash_halfwords(ptr,len) moo_hash_bytes((const moo_oob_t*)(ptr), (len) * MOO_SIZEOF(moo_oohw_t)) +# define moo_hash_bchars(ptr,len) moo_hash_bytes_((const moo_oob_t*)(ptr), (len) * MOO_SIZEOF(moo_bch_t)) +# define moo_hash_uchars(ptr,len) moo_hash_bytes_((const moo_oob_t*)(ptr), (len) * MOO_SIZEOF(moo_uch_t)) +# define moo_hash_words(ptr,len) moo_hash_bytes_((const moo_oob_t*)(ptr), (len) * MOO_SIZEOF(moo_oow_t)) +# define moo_hash_halfwords(ptr,len) moo_hash_bytes_((const moo_oob_t*)(ptr), (len) * MOO_SIZEOF(moo_oohw_t)) #endif #if defined(MOO_OOCH_IS_UCH) diff --git a/moo/t/Makefile.in b/moo/t/Makefile.in index 7fe368c..ce24e11 100644 --- a/moo/t/Makefile.in +++ b/moo/t/Makefile.in @@ -332,6 +332,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/moo/t/t-003.c b/moo/t/t-003.c index 656cf26..2afa833 100644 --- a/moo/t/t-003.c +++ b/moo/t/t-003.c @@ -3,6 +3,7 @@ #include #include #include +#include "t.h" static int put_bcs (moo_fmtout_t* fmtout, const moo_bch_t* c, moo_oow_t len) { @@ -59,6 +60,11 @@ int main () /* this unit is the number of characters written. but some are written as bch and some other as uch. * if uch and bch data are mixed, the count returned doesn't really tell how many bytes or characters written */ - cnt = bfmt_out ("wrote [%ld] units\n", cnt); + bfmt_out ("wrote [%ld] units\n", cnt); + T_ASSERT1 (cnt == 98, "bfmt_out test #1"); + return 0; + +oops: + return -1; }