3 * $Id: mptext.c,v 1.1 1999/11/17 18:02:16 mdw Exp $
5 * Textual representation of multiprecision numbers
7 * (c) 1999 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.1 1999/11/17 18:02:16 mdw
34 * New multiprecision integer arithmetic suite.
38 /*----- Header files ------------------------------------------------------*/
43 #include <mLib/darray.h>
48 /*----- Data structures ---------------------------------------------------*/
55 /*----- Main code ---------------------------------------------------------*/
57 /* --- @mp_read@ --- *
59 * Arguments: @mp *m@ = destination multiprecision number
60 * @int radix@ = base to assume for data (or zero to guess)
61 * @const mptext_ops *ops@ = pointer to operations block
62 * @void *p@ = data for the operations block
64 * Returns: The integer read, or zero if it didn't work.
66 * Use: Reads an integer from some source. If the @radix@ is
67 * specified, the number is assumed to be given in that radix,
68 * with the letters `a' (either upper- or lower-case) upwards
69 * standing for digits greater than 9. Otherwise, base 10 is
70 * assumed unless the number starts with `0' (octal), `0x' (hex)
71 * or `nnn_' (base `nnn'). An arbitrary amount of whitespace
72 * before the number is ignored.
75 mp *mp_read(mp *m, int radix, const mptext_ops *ops, void *p)
86 /* --- Initialize the destination number --- */
92 /* --- Read an initial character --- */
98 /* --- Handle an initial sign --- */
107 /* --- If the radix is zero, look for leading zeros --- */
111 else if (ch != '0') {
126 /* --- Time to start --- */
128 for (;; ch = ops->get(p)) {
131 /* --- An underscore indicates a numbered base --- */
133 if (ch == '_' && r > 0 && r <= 36) {
141 /* --- Check that the character is a digit and in range --- */
145 if (ch >= '0' && ch <= '9')
149 if (ch >= 'a' && ch <= 'z') /* ASCII dependent! */
155 /* --- Sort out what to do with the character --- */
157 if (x >= 10 && r >= 0)
165 /* --- Stick the character on the end of my integer --- */
167 MP_ENSURE(m, MP_LEN(m) + 1);
168 MPX_UMULN(m->v, m->vl, m->v, m->vl - 1, radix);
169 MPX_UADDN(m->v, m->vl, x);
176 /* --- Bail out if the number was bad --- */
183 /* --- Set the sign and return --- */
191 /* --- @mp_write@ --- *
193 * Arguments: @mp *m@ = pointer to a multi-precision integer
194 * @int radix@ = radix to use when writing the number out
195 * @const mptext_ops *ops@ = pointer to an operations block
196 * @void *p@ = data for the operations block
198 * Returns: Zero if it worked, nonzero otherwise.
200 * Use: Writes a large integer in textual form.
203 int mp_write(mp *m, int radix, const mptext_ops *ops, void *p)
209 /* --- Set various things up --- */
212 mp_build(&bb, &b, &b + 1);
214 /* --- If the number is negative, sort that out --- */
217 if (ops->put("-", 1, p))
223 /* --- Write digits to a temporary array --- */
226 mp *q = MP_NEW, *r = MP_NEW;
230 mp_div(&q, &r, m, &bb);
240 } while (MP_CMP(m, !=, MP_ZERO));
242 /* --- Finished that --- */
247 int rc = ops->put(DA(&v), DA_LEN(&v), p);
249 return (rc ? EOF : 0);
253 /*----- Test rig ----------------------------------------------------------*/
257 #include <mLib/testrig.h>
259 static int verify(dstr *v)
262 int ib = *(int *)v[0].buf, ob = *(int *)v[2].buf;
264 mp *m = mp_readdstr(MP_NEW, &v[1], 0, ib);
267 fprintf(stderr, "*** unexpected successful parse\n"
268 "*** input [%i] = %s\n",
270 mp_writedstr(m, &d, 10);
271 fprintf(stderr, "*** (value = %s)\n", d.buf);
274 mp_writedstr(m, &d, ob);
275 if (d.len != v[3].len || memcmp(d.buf, v[3].buf, d.len) != 0) {
276 fprintf(stderr, "*** failed read or write\n"
277 "*** input [%i] = %s\n"
278 "*** output [%i] = %s\n"
279 "*** expected [%i] = %s\n",
280 ib, v[1].buf, ob, d.buf, ob, v[3].buf);
287 fprintf(stderr, "*** unexpected parse failure\n"
288 "*** input [%i] = %s\n"
289 "*** expected [%i] = %s\n",
290 ib, v[1].buf, ob, v[3].buf);
299 static test_chunk tests[] = {
301 { &type_int, &type_string, &type_int, &type_string, 0 } },
305 int main(int argc, char *argv[])
308 test_run(argc, argv, tests, SRCDIR "/tests/mptext");
314 /*----- That's all, folks -------------------------------------------------*/