chiark / gitweb /
Merge branch 'mdw/rsvr'
[catacomb] / math / mptext.c
1 /* -*-c-*-
2  *
3  * Textual representation of multiprecision numbers
4  *
5  * (c) 1999 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Catacomb.
11  *
12  * Catacomb is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU Library General Public License as
14  * published by the Free Software Foundation; either version 2 of the
15  * License, or (at your option) any later version.
16  *
17  * Catacomb is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with Catacomb; if not, write to the Free
24  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25  * MA 02111-1307, USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <ctype.h>
31 #include <limits.h>
32 #include <stdio.h>
33
34 #include "mp.h"
35 #include "mptext.h"
36 #include "paranoia.h"
37
38 /*----- Magical numbers ---------------------------------------------------*/
39
40 /* --- Maximum recursion depth --- *
41  *
42  * This is the number of bits in a @size_t@ object.  Why?
43  *
44  * To see this, let %$b = \textit{MPW\_MAX} + 1$% and let %$Z$% be the
45  * largest @size_t@ value.  Then the largest possible @mp@ is %$M - 1$% where
46  * %$M = b^Z$%.  Let %$r$% be a radix to read or write.  Since the recursion
47  * squares the radix at each step, the highest number reached by the
48  * recursion is %$d$%, where:
49  *
50  *   %$r^{2^d} = b^Z$%.
51  *
52  * Solving gives that %$d = \lg \log_r b^Z$%.  If %$r = 2$%, this is maximum,
53  * so choosing %$d = \lg \lg b^Z = \lg (Z \lg b) = \lg Z + \lg \lg b$%.
54  *
55  * Expressing %$\lg Z$% as @CHAR_BIT * sizeof(size_t)@ yields an
56  * overestimate, since a @size_t@ representation may contain `holes'.
57  * Choosing to represent %$\lg \lg b$% by 10 is almost certainly sufficient
58  * for `some time to come'.
59  */
60
61 #define DEPTH (CHAR_BIT * sizeof(size_t) + 10)
62
63 /*----- Input -------------------------------------------------------------*/
64
65 /* --- @mp_read@ --- *
66  *
67  * Arguments:   @mp *m@ = destination multiprecision number
68  *              @int radix@ = base to assume for data (or zero to guess)
69  *              @const mptext_ops *ops@ = pointer to operations block
70  *              @void *p@ = data for the operations block
71  *
72  * Returns:     The integer read, or zero if it didn't work.
73  *
74  * Use:         Reads an integer from some source.  If the @radix@ is
75  *              specified, the number is assumed to be given in that radix,
76  *              with the letters `a' (either upper- or lower-case) upwards
77  *              standing for digits greater than 9.  Otherwise, base 10 is
78  *              assumed unless the number starts with `0' (octal), `0x' (hex)
79  *              or `nnn_' (base `nnn').  An arbitrary amount of whitespace
80  *              before the number is ignored.
81  */
82
83 /* --- About the algorithm --- *
84  *
85  * The algorithm here is rather aggressive.  I maintain an array of
86  * successive squarings of the radix, and a stack of partial results, each
87  * with a counter attached indicating which radix square to multiply by.
88  * Once the item at the top of the stack reaches the same counter level as
89  * the next item down, they are combined together and the result is given a
90  * counter level one higher than either of the results.
91  *
92  * Gluing the results together at the end is slightly tricky.  Pay attention
93  * to the code.
94  *
95  * This is more complicated because of the need to handle the slightly
96  * bizarre syntax.
97  */
98
99 static int char_digit(int ch, int radix)
100 {
101   int r = radix < 0 ? -radix : radix;
102   int d;
103
104   if (ch < 0) return (-1);
105   if (radix < 0) d = ch;
106   else if ('0' <= ch && ch <= '9') d = ch - '0';
107   else if ('a' <= ch && ch <= 'z') d = ch - 'a' + 10;
108   else if ('A' <= ch && ch <= 'Z') d = ch - 'A' + (radix > 36 ? 36 : 10);
109   else return (-1);
110   if (d >= r) return (-1);
111   return (d);
112 }
113
114 static mp *read_binary(int radix, unsigned bit, unsigned nf,
115                        const mptext_ops *ops, void *p)
116 {
117   mpw a = 0;
118   unsigned b = MPW_BITS;
119   int any = 0, nz = 0;
120   int ch, d;
121   size_t len, n;
122   mpw *v;
123   mp *m;
124
125   /* --- The fast binary algorithm --- *
126    *
127    * We stack bits up starting at the top end of a word.  When one word is
128    * full, we write it to the integer, and start another with the left-over
129    * bits.  When the array in the integer is full, we resize using low-level
130    * calls and copy the current data to the top end.  Finally, we do a single
131    * bit-shift when we know where the end of the number is.
132    */
133
134   m = mp_dest(MP_NEW, 1, nf);
135   len = n = m->sz;
136   n = len;
137   v = m->v + n;
138
139   for (;;) {
140     ch = ops->get(p);
141     if ((d = char_digit(ch, radix)) < 0) break;
142
143     /* --- Ignore leading zeroes, but notice that the number is valid --- */
144
145     any = 1;
146     if (!d && !nz) continue;
147     nz = 1;
148
149     /* --- Feed the digit into the accumulator --- */
150
151     if (b > bit) {
152       b -= bit;
153       a |= MPW(d) << b;
154     } else {
155       a |= MPW(d) >> (bit - b);
156       b += MPW_BITS - bit;
157       *--v = MPW(a); n--;
158       if (!n) {
159         n = len; len <<= 1;
160         v = mpalloc(m->a, len);
161         memcpy(v + n, m->v, MPWS(n));
162         mpfree(m->a, m->v);
163         m->v = v; v = m->v + n;
164       }
165       a = (b < MPW_BITS) ? MPW(d) << b : 0;
166     }
167   }
168
169   /* --- Finish up --- */
170
171   ops->unget(ch, p);
172   if (!any) { mp_drop(m); return (0); }
173
174   *--v = MPW(a); n--;
175   m->sz = len;
176   m->vl = m->v + len;
177   m->f &= ~MP_UNDEF;
178   m = mp_lsr(m, m, (unsigned long)n * MPW_BITS + b);
179
180   return (m);
181 }
182
183 struct readstate {
184
185   /* --- State for the general-base reader --- *
186    *
187    * There are two arrays.  The @pow@ array is set so that @pow[i]@ contains
188    * %$R^{2^i}$% for @i < pows@.  The stack @s@ contains partial results:
189    * each entry contains a value @m@ corresponding to %$2^i$% digits.
190    * Inductively, an empty stack represents zero; if a stack represents %$x$%
191    * then pushing a new entry on the top causes the stack to represent
192    * %$R^{2^i} x + m$%.
193    *
194    * It is an invariant that each entry has a strictly smaller @i@ than the
195    * items beneath it.  This is achieved by coaslescing entries at the top if
196    * they have equal %$i$% values: if the top items are %$(m, i)$%, and
197    * %$(M', i)$%, and the rest of the stack represents the integer %$x$%,
198    * then %$R^{2^i} (R^{2^i} x + M) + m = R^{2^{i+1}} x + (R^{2^i} M + m)$%,
199    * so we replace the top two items by %$((R^{2^i} M + m), i + 1)$%, and
200    * repeat if necessary.
201    */
202
203   unsigned pows, sp;
204   struct { unsigned i; mp *m; } s[DEPTH];
205   mp *pow[DEPTH];
206 };
207
208 static void ensure_power(struct readstate *rs)
209 {
210   /* --- Make sure we have the necessary %$R^{2^i}$% computed --- */
211
212   if (rs->s[rs->sp].i >= rs->pows) {
213     assert(rs->pows < DEPTH);
214     rs->pow[rs->pows] = mp_sqr(MP_NEW, rs->pow[rs->pows - 1]);
215     rs->pows++;
216   }
217 }
218
219 static void read_digit(struct readstate *rs, unsigned nf, int d)
220 {
221   mp *m = mp_new(1, nf);
222   m->v[0] = d;
223
224   /* --- Put the new digit on top --- */
225
226   assert(rs->sp < DEPTH);
227   rs->s[rs->sp].m = m;
228   rs->s[rs->sp].i = 0;
229
230   /* --- Restore the stack invariant --- */
231
232   while (rs->sp && rs->s[rs->sp - 1].i <= rs->s[rs->sp].i) {
233     assert(rs->sp > 0);
234     ensure_power(rs);
235     rs->sp--;
236
237     m = rs->s[rs->sp].m;
238     m = mp_mul(m, m, rs->pow[rs->s[rs->sp + 1].i]);
239     m = mp_add(m, m, rs->s[rs->sp + 1].m);
240     MP_DROP(rs->s[rs->sp + 1].m);
241     rs->s[rs->sp].m = m;
242     rs->s[rs->sp].i++;
243   }
244
245   /* --- Leave the stack pointer at an empty item --- */
246
247   rs->sp++;
248 }
249
250 static mp *read_general(int radix, unsigned t, unsigned nf,
251                         const mptext_ops *ops, void *p)
252 {
253   struct readstate rs;
254   unsigned char v[4];
255   unsigned i;
256   mpw r;
257   int any = 0;
258   int ch, d;
259   mp rr;
260   mp *m, *z, *n;
261
262   /* --- Prepare the stack --- */
263
264   r = radix < 0 ? -radix : radix;
265   mp_build(&rr, &r, &r + 1);
266   rs.pow[0] = &rr;
267   rs.pows = 1;
268   rs.sp = 0;
269
270   /* --- If we've partially parsed some input then feed it in --- *
271    *
272    * Unfortunately, what we've got is backwards.  Fortunately there's a
273    * fairly tight upper bound on how many digits @t@ might be, since we
274    * aborted that loop once it got too large.
275    */
276
277   if (t) {
278     i = 0;
279     while (t) { assert(i < sizeof(v)); v[i++] = t%r; t /= r; }
280     while (i) read_digit(&rs, nf, v[--i]);
281     any = 1;
282   }
283
284   /* --- Read more stuff --- */
285
286   for (;;) {
287     ch = ops->get(p);
288     if ((d = char_digit(ch, radix)) < 0) break;
289     read_digit(&rs, nf, d); any = 1;
290   }
291   ops->unget(ch, p);
292
293   /* --- Stitch all of the numbers together --- *
294    *
295    * This is not the same code as @read_digit@.  In particular, here we must
296    * cope with the partial result being some inconvenient power of %$R$%,
297    * rather than %$R^{2^i}$%.
298    */
299
300   if (!any) return (0);
301   m = MP_ZERO; z = MP_ONE;
302   while (rs.sp) {
303     rs.sp--;
304     ensure_power(&rs);
305     n = rs.s[rs.sp].m;
306     n = mp_mul(n, n, z);
307     m = mp_add(m, m, n);
308     z = mp_mul(z, z, rs.pow[rs.s[rs.sp].i]);
309     MP_DROP(n);
310   }
311   for (i = 0; i < rs.pows; i++) MP_DROP(rs.pow[i]);
312   MP_DROP(z);
313   return (m);
314 }
315
316 mp *mp_read(mp *m, int radix, const mptext_ops *ops, void *p)
317 {
318   unsigned t = 0;
319   unsigned nf = 0;
320   int ch, d, rd;
321
322   unsigned f = 0;
323 #define f_neg 1u
324 #define f_ok 2u
325
326   /* --- We don't actually need a destination so throw it away --- *
327    *
328    * But note the flags before we lose it entirely.
329    */
330
331   if (m) {
332     nf = m->f & MP_BURN;
333     MP_DROP(m);
334   }
335
336   /* --- Maintain a lookahead character --- */
337
338   ch = ops->get(p);
339
340   /* --- If we're reading text, skip leading space, and maybe a sign --- */
341
342   if (radix >= 0) {
343     while (isspace(ch)) ch = ops->get(p);
344     switch (ch) {
345       case '-': f |= f_neg; /* and on */
346       case '+': do ch = ops->get(p); while (isspace(ch));
347     }
348   }
349
350   /* --- If we don't have a fixed radix, then parse one from the input --- *
351    *
352    * This is moderately easy if the input starts with `0x' or similar.  If it
353    * starts with `0' and something else, then it might be octal, or just a
354    * plain old zero.  Finally, it might start with a leading `NN_', in which
355    * case we carefully collect the decimal number until we're sure it's
356    * either a radix prefix (in which case we accept it and start over) or it
357    * isn't (in which case it's actually the start of a large number we need
358    * to read).
359    */
360
361   if (radix == 0) {
362     if (ch == '0') {
363       ch = ops->get(p);
364       switch (ch) {
365         case 'x': case 'X': radix = 16; goto fetch;
366         case 'o': case 'O': radix = 8; goto fetch;
367         case 'b': case 'B': radix = 2; goto fetch;
368         fetch: ch = ops->get(p); break;
369         default: radix = 8; f |= f_ok; break;
370       }
371     } else {
372       if ((d = char_digit(ch, 10)) < 0) { ops->unget(ch, p); return (0); }
373       for (;;) {
374         t = 10*t + d;
375         ch = ops->get(p);
376         if (t > 52) break;
377         if ((d = char_digit(ch, 10)) < 0) break;
378       }
379       if (ch != '_' || t > 52) radix = 10;
380       else {
381         radix = t; t = 0;
382         ch = ops->get(p);
383       }
384     }
385   }
386
387   /* --- We're now ready to dispatch to the correct handler --- */
388
389   rd = radix < 0 ? -radix : radix;
390   ops->unget(ch, p);
391   switch (rd) {
392     case   2: m = read_binary(radix,  1, nf, ops, p); break;
393     case   4: m = read_binary(radix,  2, nf, ops, p); break;
394     case   8: m = read_binary(radix,  3, nf, ops, p); break;
395     case  16: m = read_binary(radix,  4, nf, ops, p); break;
396     case  32: m = read_binary(radix,  5, nf, ops, p); break;
397     case  64: m = read_binary(radix,  6, nf, ops, p); break;
398     case 128: m = read_binary(radix,  7, nf, ops, p); break;
399     default:  m = read_general(radix, t, nf, ops, p); break;
400   }
401
402   /* --- That didn't work --- *
403    *
404    * If we've already read something then return that.  Otherwise it's an
405    * error.
406    */
407
408   if (!m) {
409     if (f & f_ok) return (MP_ZERO);
410     else return (0);
411   }
412
413   /* --- Negate the result if we should do that --- */
414
415   if (f & f_neg) m = mp_neg(m, m);
416
417   /* --- And we're all done --- */
418
419   return (m);
420
421 #undef f_neg
422 #undef f_ok
423 }
424
425 /*----- Output ------------------------------------------------------------*/
426
427 /* --- @mp_write@ --- *
428  *
429  * Arguments:   @mp *m@ = pointer to a multi-precision integer
430  *              @int radix@ = radix to use when writing the number out
431  *              @const mptext_ops *ops@ = pointer to an operations block
432  *              @void *p@ = data for the operations block
433  *
434  * Returns:     Zero if it worked, nonzero otherwise.
435  *
436  * Use:         Writes a large integer in textual form.
437  */
438
439 static int digit_char(int d, int radix)
440 {
441   if (radix < 0) return (d);
442   else if (d < 10) return (d + '0');
443   else if (d < 26) return (d - 10 + 'a');
444   else return (d - 36 + 'A');
445 }
446
447 /* --- Simple case --- *
448  *
449  * Use a fixed-sized buffer and single-precision arithmetic to pick off
450  * low-order digits.  Put each digit in a buffer, working backwards from the
451  * end.  If the buffer becomes full, recurse to get another one.  Ensure that
452  * there are at least @z@ digits by writing leading zeroes if there aren't
453  * enough real digits.
454  */
455
456 static int write_simple(mpw n, int radix, unsigned z,
457                         const mptext_ops *ops, void *p)
458 {
459   int rc = 0;
460   char buf[64];
461   unsigned i = sizeof(buf);
462   int rd = radix > 0 ? radix : -radix;
463   mpw x;
464
465   do {
466     x = n % rd; n /= rd;
467     buf[--i] = digit_char(x, radix);
468     if (z) z--;
469   } while (i && n);
470
471   if (n)
472     rc = write_simple(n, radix, z, ops, p);
473   else {
474     char zbuf[32];
475     memset(zbuf, (radix < 0) ? 0 : '0', sizeof(zbuf));
476     while (!rc && z >= sizeof(zbuf)) {
477       rc = ops->put(zbuf, sizeof(zbuf), p);
478       z -= sizeof(zbuf);
479     }
480     if (!rc && z) rc = ops->put(zbuf, z, p);
481   }
482   if (!rc) rc = ops->put(buf + i, sizeof(buf) - i, p);
483   BURN(buf);
484   return (rc);
485 }
486
487 /* --- Complicated case --- *
488  *
489  * If the number is small, fall back to the simple case above.  Otherwise
490  * divide and take remainder by current large power of the radix, and emit
491  * each separately.  Don't emit a zero quotient.  Be very careful about
492  * leading zeroes on the remainder part, because they're deeply significant.
493  */
494
495 static int write_complicated(mp *m, int radix, mp **pr,
496                              unsigned i, unsigned z,
497                              const mptext_ops *ops, void *p)
498 {
499   int rc = 0;
500   mp *q = MP_NEW;
501   unsigned d = 1 << i;
502
503   if (MP_LEN(m) < 2)
504     return (write_simple(MP_LEN(m) ? m->v[0] : 0, radix, z, ops, p));
505
506   assert(i);
507   mp_div(&q, &m, m, pr[i]);
508   if (MP_ZEROP(q)) d = z;
509   else {
510     if (z > d) z -= d;
511     else z = 0;
512     rc = write_complicated(q, radix, pr, i - 1, z, ops, p);
513   }
514   if (!rc) rc = write_complicated(m, radix, pr, i - 1, d, ops, p);
515   mp_drop(q);
516   return (rc);
517 }
518
519 /* --- Binary case --- *
520  *
521  * Special case for binary output.  Goes much faster.
522  */
523
524 static int write_binary(mp *m, int bit, int radix,
525                         const mptext_ops *ops, void *p)
526 {
527   mpw *v;
528   mpw a;
529   int rc = 0;
530   unsigned b;
531   unsigned mask;
532   unsigned long n;
533   unsigned f = 0;
534   char buf[8], *q;
535   unsigned x;
536
537 #define f_out 1u
538
539   /* --- Work out where to start --- */
540
541   n = mp_bits(m);
542   if (n % bit) n += bit - (n % bit);
543   b = n % MPW_BITS;
544   n /= MPW_BITS;
545
546   if (n >= MP_LEN(m)) {
547     n--;
548     b += MPW_BITS;
549   }
550
551   v = m->v + n;
552   a = *v;
553   mask = (1 << bit) - 1;
554   q = buf;
555
556   /* --- Main code --- */
557
558   for (;;) {
559     if (b > bit) {
560       b -= bit;
561       x = a >> b;
562     } else {
563       x = a << (bit - b);
564       b += MPW_BITS - bit;
565       if (v == m->v) break;
566       a = *--v;
567       if (b < MPW_BITS) x |= a >> b;
568     }
569     x &= mask;
570     if (!x && !(f & f_out)) continue;
571
572     *q++ = digit_char(x, radix);
573     if (q >= buf + sizeof(buf)) {
574       if ((rc = ops->put(buf, sizeof(buf), p)) != 0) goto done;
575       q = buf;
576     }
577     f |= f_out;
578   }
579
580   x &= mask;
581   *q++ = digit_char(x, radix);
582   rc = ops->put(buf, q - buf, p);
583
584 done:
585   mp_drop(m);
586   return (rc);
587
588 #undef f_out
589 }
590
591 /* --- Main driver code --- */
592
593 int mp_write(mp *m, int radix, const mptext_ops *ops, void *p)
594 {
595   int rc;
596   mp *pr[DEPTH];
597   size_t target;
598   unsigned i = 0;
599   mp *z;
600
601   if (MP_EQ(m, MP_ZERO))
602     return (ops->put(radix > 0 ? "0" : "\0", 1, p));
603
604   /* --- Set various things up --- */
605
606   m = MP_COPY(m);
607   MP_SPLIT(m);
608
609   /* --- Check the radix for sensibleness --- */
610
611   if (radix > 0)
612     assert(((void)"ascii radix must be <= 62", radix <= 62));
613   else if (radix < 0)
614     assert(((void)"binary radix must fit in a byte", -radix <= UCHAR_MAX));
615   else
616     assert(((void)"radix can't be zero in mp_write", 0));
617
618   /* --- If the number is negative, sort that out --- */
619
620   if (MP_NEGP(m)) {
621     assert(radix > 0);
622     if (ops->put("-", 1, p)) return (EOF);
623     m->f &= ~MP_NEG;
624   }
625
626   /* --- Handle binary radix --- */
627
628   switch (radix) {
629     case   2: case   -2: return (write_binary(m, 1, radix, ops, p));
630     case   4: case   -4: return (write_binary(m, 2, radix, ops, p));
631     case   8: case   -8: return (write_binary(m, 3, radix, ops, p));
632     case  16: case  -16: return (write_binary(m, 4, radix, ops, p));
633     case  32: case  -32: return (write_binary(m, 5, radix, ops, p));
634               case  -64: return (write_binary(m, 6, radix, ops, p));
635               case -128: return (write_binary(m, 7, radix, ops, p));
636   }
637
638   /* --- If the number is small, do it the easy way --- */
639
640   if (MP_LEN(m) < 2)
641     rc = write_simple(MP_LEN(m) ? m->v[0] : 0, radix, 0, ops, p);
642
643   /* --- Use a clever algorithm --- *
644    *
645    * Square the radix repeatedly, remembering old results, until I get
646    * something more than half the size of the number @m@.  Use this to divide
647    * the number: the quotient and remainder will be approximately the same
648    * size, and I'll have split them on a digit boundary, so I can just emit
649    * the quotient and remainder recursively, in order.
650    */
651
652   else {
653     target = (MP_LEN(m) + 1) / 2;
654     z = mp_new(1, 0);
655
656     /* --- Set up the exponent table --- */
657
658     z->v[0] = (radix > 0 ? radix : -radix);
659     z->f = 0;
660     for (;;) {
661       assert(((void)"Number is too unimaginably huge", i < DEPTH));
662       pr[i++] = z;
663       if (MP_LEN(z) > target) break;
664       z = mp_sqr(MP_NEW, z);
665     }
666
667     /* --- Write out the answer --- */
668
669     rc = write_complicated(m, radix, pr, i - 1, 0, ops, p);
670
671     /* --- Tidy away the array --- */
672
673     while (i > 0) mp_drop(pr[--i]);
674   }
675
676   /* --- Tidying up code --- */
677
678   MP_DROP(m);
679   return (rc);
680 }
681
682 /*----- Test rig ----------------------------------------------------------*/
683
684 #ifdef TEST_RIG
685
686 #include <mLib/testrig.h>
687
688 static int verify(dstr *v)
689 {
690   int ok = 1;
691   int ib = *(int *)v[0].buf, ob = *(int *)v[2].buf;
692   dstr d = DSTR_INIT;
693   size_t off = 0;
694   mp *m = mp_readdstr(MP_NEW, &v[1], &off, ib);
695   if (m) {
696     if (!ob) {
697       fprintf(stderr, "*** unexpected successful parse\n"
698                       "*** input [%2i] =     ", ib);
699       if (ib < 0)
700         type_hex.dump(&v[1], stderr);
701       else
702         fputs(v[1].buf, stderr);
703       mp_writedstr(m, &d, 10);
704       fprintf(stderr, "\n*** (value = %s)\n", d.buf);
705       ok = 0;
706     } else {
707       mp_writedstr(m, &d, ob);
708       if (d.len != v[3].len || memcmp(d.buf, v[3].buf, d.len) != 0) {
709         fprintf(stderr, "*** failed read or write\n"
710                         "*** input [%2i]      = ", ib);
711         if (ib < 0)
712           type_hex.dump(&v[1], stderr);
713         else
714           fputs(v[1].buf, stderr);
715         fprintf(stderr, "\n*** output [%2i]     = ", ob);
716         if (ob < 0)
717           type_hex.dump(&d, stderr);
718         else
719           fputs(d.buf, stderr);
720         fprintf(stderr, "\n*** expected [%2i]   = ", ob);
721         if (ob < 0)
722           type_hex.dump(&v[3], stderr);
723         else
724           fputs(v[3].buf, stderr);
725         fputc('\n', stderr);
726         ok = 0;
727       }
728     }
729     mp_drop(m);
730   } else {
731     if (ob) {
732       fprintf(stderr, "*** unexpected parse failure\n"
733                       "*** input [%2i]    = ", ib);
734       if (ib < 0)
735         type_hex.dump(&v[1], stderr);
736       else
737         fputs(v[1].buf, stderr);
738       fprintf(stderr, "\n*** expected [%2i]   = ", ob);
739       if (ob < 0)
740         type_hex.dump(&v[3], stderr);
741       else
742         fputs(v[3].buf, stderr);
743       fputc('\n', stderr);
744       ok = 0;
745     }
746   }
747
748   if (v[1].len - off != v[4].len ||
749       memcmp(v[1].buf + off, v[4].buf, v[4].len) != 0) {
750     fprintf(stderr, "*** leftovers incorrect\n"
751                     "*** input [%2i]    = ", ib);
752     if (ib < 0)
753       type_hex.dump(&v[1], stderr);
754     else
755       fputs(v[1].buf, stderr);
756     fprintf(stderr, "\n*** expected `%s'\n"
757                     "*** found `%s'\n",
758             v[4].buf, v[1].buf + off);
759     ok = 0;
760   }
761
762   dstr_destroy(&d);
763   assert(mparena_count(MPARENA_GLOBAL) == 0);
764   return (ok);
765 }
766
767 static test_chunk tests[] = {
768   { "mptext-ascii", verify,
769     { &type_int, &type_string, &type_int, &type_string, &type_string, 0 } },
770   { "mptext-bin-in", verify,
771     { &type_int, &type_hex, &type_int, &type_string, &type_string, 0 } },
772   { "mptext-bin-out", verify,
773     { &type_int, &type_string, &type_int, &type_hex, &type_string, 0 } },
774   { 0, 0, { 0 } }
775 };
776
777 int main(int argc, char *argv[])
778 {
779   sub_init();
780   test_run(argc, argv, tests, SRCDIR "/t/mptext");
781   return (0);
782 }
783
784 #endif
785
786 /*----- That's all, folks -------------------------------------------------*/