Make tables of standard encryption schemes etc.
[u/mdw/catacomb] / mptext.c
index f6bc2e3..3eb58cf 100644 (file)
--- a/mptext.c
+++ b/mptext.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: mptext.c,v 1.11 2001/06/16 23:42:17 mdw Exp $
+ * $Id: mptext.c,v 1.17 2002/10/19 11:59:04 mdw Exp $
  *
  * Textual representation of multiprecision numbers
  *
 /*----- 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.
  *
@@ -192,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) {
@@ -204,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;
   }
@@ -270,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;
        }
@@ -320,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;
   }}
 
@@ -333,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 --- */
@@ -364,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;
       }
@@ -473,6 +508,7 @@ done:
 
   if (f & f_neg)
     m->f |= MP_NEG;
+  MP_SHRINK(m);
   return (m);
 
 #undef f_start
@@ -519,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--;
@@ -602,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;
   }
@@ -639,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)
@@ -655,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);
 
@@ -673,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);
@@ -681,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
@@ -766,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"
@@ -805,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
@@ -820,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);
@@ -827,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 } }
 };