X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/a951033da37da66f31d13d4825c562bf7762e213..1589affab225db500965e2cb869c534d6860e6bd:/mptext.c diff --git a/mptext.c b/mptext.c index 57521da..3eb58cf 100644 --- a/mptext.c +++ b/mptext.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: mptext.c,v 1.10 2001/06/16 13:22:39 mdw Exp $ + * $Id: mptext.c,v 1.17 2002/10/19 11:59:04 mdw Exp $ * * Textual representation of multiprecision numbers * @@ -30,6 +30,27 @@ /*----- Revision history --------------------------------------------------* * * $Log: mptext.c,v $ + * Revision 1.17 2002/10/19 11:59:04 mdw + * Fix leftovers bug in reading. + * + * Revision 1.16 2002/10/15 22:57:43 mdw + * Bug fix: prevent negative zero. + * + * Revision 1.15 2002/10/15 19:18:15 mdw + * Fix fencepost bugs in binary radix writing. + * + * Revision 1.14 2002/10/09 00:33:44 mdw + * Allow `0o' and `0b' prefixes for octal and binary (from Haskell) + * + * Revision 1.13 2002/10/09 00:21:06 mdw + * Allow user-specified `r_xx' bases to be up to 62. + * + * Revision 1.12 2002/01/13 19:51:18 mdw + * Extend the textual format to bases up to 62 by distinguishing case. + * + * Revision 1.11 2001/06/16 23:42:17 mdw + * Typesetting fixes. + * * Revision 1.10 2001/06/16 13:22:39 mdw * Added fast-track code for binary output bases, and tests. * @@ -82,7 +103,7 @@ * * This is the number of bits in a @size_t@ object. Why? * - * To see this, let %$b = \mathit{MPW\_MAX} + 1$% and let %$Z$% be the + * To see this, let %$b = \textit{MPW\_MAX} + 1$% and let %$Z$% be the * largest @size_t@ value. Then the largest possible @mp@ is %$M - 1$% where * %$M = b^Z$%. Let %$r$% be a radix to read or write. Since the recursion * squares the radix at each step, the highest number reached by the @@ -189,7 +210,7 @@ mp *mp_read(mp *m, int radix, const mptext_ops *ops, void *p) /* --- If the radix is zero, look for leading zeros --- */ if (radix > 0) { - assert(((void)"ascii radix must be <= 36", radix <= 36)); + assert(((void)"ascii radix must be <= 62", radix <= 62)); rd = radix; r = -1; } else if (radix < 0) { @@ -201,12 +222,22 @@ mp *mp_read(mp *m, int radix, const mptext_ops *ops, void *p) r = 0; } else { ch = ops->get(p); - if (ch == 'x') { - ch = ops->get(p); - rd = 16; - } else { - rd = 8; - f |= f_ok; + switch (ch) { + case 'x': + rd = 16; + goto prefix; + case 'o': + rd = 8; + goto prefix; + case 'b': + rd = 2; + goto prefix; + prefix: + ch = ops->get(p); + break; + default: + rd = 8; + f |= f_ok; } r = -1; } @@ -267,9 +298,12 @@ restart: if (ch >= '0' && ch <= '9') x = ch - '0'; else { - ch = tolower(ch); + if (rd <= 36) + ch = tolower(ch); if (ch >= 'a' && ch <= 'z') /* ASCII dependent! */ x = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'Z') + x = ch - 'A' + 36; else break; } @@ -317,6 +351,7 @@ restart: m->f &= ~MP_UNDEF; m = mp_lsr(m, m, (unsigned long)n * MPW_BITS + b); } + ops->unget(ch, p); goto done; }} @@ -330,7 +365,7 @@ restart: /* --- An underscore indicates a numbered base --- */ - if (ch == '_' && r > 0 && r <= 36) { + if (ch == '_' && r > 0 && r <= 62) { unsigned i; /* --- Clear out the stacks --- */ @@ -361,9 +396,12 @@ restart: if (ch >= '0' && ch <= '9') x = ch - '0'; else { - ch = tolower(ch); + if (rd <= 36) + ch = tolower(ch); if (ch >= 'a' && ch <= 'z') /* ASCII dependent! */ x = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'Z') + x = ch - 'A' + 36; else break; } @@ -470,6 +508,7 @@ done: if (f & f_neg) m->f |= MP_NEG; + MP_SHRINK(m); return (m); #undef f_start @@ -516,8 +555,10 @@ static int simple(mpw n, int radix, unsigned z, ch = x; else if (x < 10) ch = '0' + x; - else + else if (x < 36) /* Ascii specific */ ch = 'a' + x - 10; + else + ch = 'A' + x - 36; buf[--i] = ch; if (z) z--; @@ -599,11 +640,12 @@ static int binary(mp *m, int bit, int radix, const mptext_ops *ops, void *p) /* --- Work out where to start --- */ n = mp_bits(m); - n += bit - (n % bit); + if (n % bit) + n += bit - (n % bit); b = n % MPW_BITS; n /= MPW_BITS; - - if (n > MP_LEN(m)) { + + if (n >= MP_LEN(m)) { n--; b += MPW_BITS; } @@ -636,8 +678,10 @@ static int binary(mp *m, int bit, int radix, const mptext_ops *ops, void *p) ch = x; else if (x < 10) ch = '0' + x; + else if (x < 36) + ch = 'a' + x - 10; /* Ascii specific */ else - ch = 'a' + x - 10; + ch = 'A' + x - 36; *q++ = ch; if (q >= buf + sizeof(buf)) { if ((rc = ops->put(buf, sizeof(buf), p)) != 0) @@ -652,8 +696,10 @@ static int binary(mp *m, int bit, int radix, const mptext_ops *ops, void *p) ch = x; else if (x < 10) ch = '0' + x; + else if (x < 36) + ch = 'a' + x - 10; /* Ascii specific */ else - ch = 'a' + x - 10; + ch = 'A' + x - 36; *q++ = ch; rc = ops->put(buf, q - buf, p); @@ -670,6 +716,9 @@ int mp_write(mp *m, int radix, const mptext_ops *ops, void *p) { int rc; + if (MP_EQ(m, MP_ZERO)) + return (ops->put("0", 1, p)); + /* --- Set various things up --- */ m = MP_COPY(m); @@ -678,7 +727,7 @@ int mp_write(mp *m, int radix, const mptext_ops *ops, void *p) /* --- Check the radix for sensibleness --- */ if (radix > 0) - assert(((void)"ascii radix must be <= 36", radix <= 36)); + assert(((void)"ascii radix must be <= 62", radix <= 62)); else if (radix < 0) assert(((void)"binary radix must fit in a byte", -radix < UCHAR_MAX)); else @@ -763,7 +812,8 @@ static int verify(dstr *v) int ok = 1; int ib = *(int *)v[0].buf, ob = *(int *)v[2].buf; dstr d = DSTR_INIT; - mp *m = mp_readdstr(MP_NEW, &v[1], 0, ib); + size_t off = 0; + mp *m = mp_readdstr(MP_NEW, &v[1], &off, ib); if (m) { if (!ob) { fprintf(stderr, "*** unexpected successful parse\n" @@ -802,12 +852,12 @@ static int verify(dstr *v) } else { if (ob) { fprintf(stderr, "*** unexpected parse failure\n" - "*** input [%i] = ", ib); + "*** input [%2i] = ", ib); if (ib < 0) type_hex.dump(&v[1], stderr); else fputs(v[1].buf, stderr); - fprintf(stderr, "\n*** expected [%i] = ", ob); + fprintf(stderr, "\n*** expected [%2i] = ", ob); if (ob < 0) type_hex.dump(&v[3], stderr); else @@ -817,6 +867,20 @@ static int verify(dstr *v) } } + if (v[1].len - off != v[4].len || + memcmp(v[1].buf + off, v[4].buf, v[4].len) != 0) { + fprintf(stderr, "*** leftovers incorrect\n" + "*** input [%2i] = ", ib); + if (ib < 0) + type_hex.dump(&v[1], stderr); + else + fputs(v[1].buf, stderr); + fprintf(stderr, "\n*** expected `%s'\n" + "*** found `%s'\n", + v[4].buf, v[1].buf + off); + ok = 0; + } + dstr_destroy(&d); assert(mparena_count(MPARENA_GLOBAL) == 0); return (ok); @@ -824,11 +888,11 @@ static int verify(dstr *v) static test_chunk tests[] = { { "mptext-ascii", verify, - { &type_int, &type_string, &type_int, &type_string, 0 } }, + { &type_int, &type_string, &type_int, &type_string, &type_string, 0 } }, { "mptext-bin-in", verify, - { &type_int, &type_hex, &type_int, &type_string, 0 } }, + { &type_int, &type_hex, &type_int, &type_string, &type_string, 0 } }, { "mptext-bin-out", verify, - { &type_int, &type_string, &type_int, &type_hex, 0 } }, + { &type_int, &type_string, &type_int, &type_hex, &type_string, 0 } }, { 0, 0, { 0 } } };