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 -------------------------------------------------*/