3 * $Id: mptext.c,v 1.3 1999/12/10 23:23:26 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.3 1999/12/10 23:23:26 mdw
34 * Allocate slightly less memory.
36 * Revision 1.2 1999/11/20 22:24:15 mdw
37 * Use function versions of MPX_UMULN and MPX_UADDN.
39 * Revision 1.1 1999/11/17 18:02:16 mdw
40 * New multiprecision integer arithmetic suite.
44 /*----- Header files ------------------------------------------------------*/
49 #include <mLib/darray.h>
54 /*----- Data structures ---------------------------------------------------*/
61 /*----- Main code ---------------------------------------------------------*/
63 /* --- @mp_read@ --- *
65 * Arguments: @mp *m@ = destination multiprecision number
66 * @int radix@ = base to assume for data (or zero to guess)
67 * @const mptext_ops *ops@ = pointer to operations block
68 * @void *p@ = data for the operations block
70 * Returns: The integer read, or zero if it didn't work.
72 * Use: Reads an integer from some source. If the @radix@ is
73 * specified, the number is assumed to be given in that radix,
74 * with the letters `a' (either upper- or lower-case) upwards
75 * standing for digits greater than 9. Otherwise, base 10 is
76 * assumed unless the number starts with `0' (octal), `0x' (hex)
77 * or `nnn_' (base `nnn'). An arbitrary amount of whitespace
78 * before the number is ignored.
81 mp
*mp_read(mp
*m
, int radix
, const mptext_ops
*ops
, void *p
)
92 /* --- Initialize the destination number --- */
98 /* --- Read an initial character --- */
104 /* --- Handle an initial sign --- */
113 /* --- If the radix is zero, look for leading zeros --- */
117 else if (ch
!= '0') {
132 /* --- Time to start --- */
134 for (;; ch
= ops
->get(p
)) {
137 /* --- An underscore indicates a numbered base --- */
139 if (ch
== '_' && r
> 0 && r
<= 36) {
147 /* --- Check that the character is a digit and in range --- */
151 if (ch
>= '0' && ch
<= '9')
155 if (ch
>= 'a' && ch
<= 'z') /* ASCII dependent! */
161 /* --- Sort out what to do with the character --- */
163 if (x
>= 10 && r
>= 0)
171 /* --- Stick the character on the end of my integer --- */
173 mp_ensure(m
, MP_LEN(m
) + 1);
174 mpx_umuln(m
->v
, m
->vl
, m
->v
, m
->vl
- 1, radix
);
175 mpx_uaddn(m
->v
, m
->vl
, x
);
182 /* --- Bail out if the number was bad --- */
189 /* --- Set the sign and return --- */
197 /* --- @mp_write@ --- *
199 * Arguments: @mp *m@ = pointer to a multi-precision integer
200 * @int radix@ = radix to use when writing the number out
201 * @const mptext_ops *ops@ = pointer to an operations block
202 * @void *p@ = data for the operations block
204 * Returns: Zero if it worked, nonzero otherwise.
206 * Use: Writes a large integer in textual form.
209 int mp_write(mp
*m
, int radix
, const mptext_ops
*ops
, void *p
)
215 /* --- Set various things up --- */
218 mp_build(&bb
, &b
, &b
+ 1);
220 /* --- If the number is negative, sort that out --- */
223 if (ops
->put("-", 1, p
))
229 /* --- Write digits to a temporary array --- */
232 mp
*q
= MP_NEW
, *r
= MP_NEW
;
236 mp_div(&q
, &r
, m
, &bb
);
246 } while (MP_CMP(m
, !=, MP_ZERO
));
248 /* --- Finished that --- */
253 int rc
= ops
->put(DA(&v
), DA_LEN(&v
), p
);
255 return (rc ? EOF
: 0);
259 /*----- Test rig ----------------------------------------------------------*/
263 #include <mLib/testrig.h>
265 static int verify(dstr
*v
)
268 int ib
= *(int *)v
[0].buf
, ob
= *(int *)v
[2].buf
;
270 mp
*m
= mp_readdstr(MP_NEW
, &v
[1], 0, ib
);
273 fprintf(stderr
, "*** unexpected successful parse\n"
274 "*** input [%i] = %s\n",
276 mp_writedstr(m
, &d
, 10);
277 fprintf(stderr
, "*** (value = %s)\n", d
.buf
);
280 mp_writedstr(m
, &d
, ob
);
281 if (d
.len
!= v
[3].len
|| memcmp(d
.buf
, v
[3].buf
, d
.len
) != 0) {
282 fprintf(stderr
, "*** failed read or write\n"
283 "*** input [%i] = %s\n"
284 "*** output [%i] = %s\n"
285 "*** expected [%i] = %s\n",
286 ib
, v
[1].buf
, ob
, d
.buf
, ob
, v
[3].buf
);
293 fprintf(stderr
, "*** unexpected parse failure\n"
294 "*** input [%i] = %s\n"
295 "*** expected [%i] = %s\n",
296 ib
, v
[1].buf
, ob
, v
[3].buf
);
302 assert(mparena_count(MPARENA_GLOBAL
) == 0);
306 static test_chunk tests
[] = {
308 { &type_int
, &type_string
, &type_int
, &type_string
, 0 } },
312 int main(int argc
, char *argv
[])
315 test_run(argc
, argv
, tests
, SRCDIR
"/tests/mptext");
321 /*----- That's all, folks -------------------------------------------------*/