3 * $Id: mptext.c,v 1.2 1999/11/20 22:24:15 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.2 1999/11/20 22:24:15 mdw
34 * Use function versions of MPX_UMULN and MPX_UADDN.
36 * Revision 1.1 1999/11/17 18:02:16 mdw
37 * New multiprecision integer arithmetic suite.
41 /*----- Header files ------------------------------------------------------*/
46 #include <mLib/darray.h>
51 /*----- Data structures ---------------------------------------------------*/
58 /*----- Main code ---------------------------------------------------------*/
60 /* --- @mp_read@ --- *
62 * Arguments: @mp *m@ = destination multiprecision number
63 * @int radix@ = base to assume for data (or zero to guess)
64 * @const mptext_ops *ops@ = pointer to operations block
65 * @void *p@ = data for the operations block
67 * Returns: The integer read, or zero if it didn't work.
69 * Use: Reads an integer from some source. If the @radix@ is
70 * specified, the number is assumed to be given in that radix,
71 * with the letters `a' (either upper- or lower-case) upwards
72 * standing for digits greater than 9. Otherwise, base 10 is
73 * assumed unless the number starts with `0' (octal), `0x' (hex)
74 * or `nnn_' (base `nnn'). An arbitrary amount of whitespace
75 * before the number is ignored.
78 mp
*mp_read(mp
*m
, int radix
, const mptext_ops
*ops
, void *p
)
89 /* --- Initialize the destination number --- */
95 /* --- Read an initial character --- */
101 /* --- Handle an initial sign --- */
110 /* --- If the radix is zero, look for leading zeros --- */
114 else if (ch
!= '0') {
129 /* --- Time to start --- */
131 for (;; ch
= ops
->get(p
)) {
134 /* --- An underscore indicates a numbered base --- */
136 if (ch
== '_' && r
> 0 && r
<= 36) {
144 /* --- Check that the character is a digit and in range --- */
148 if (ch
>= '0' && ch
<= '9')
152 if (ch
>= 'a' && ch
<= 'z') /* ASCII dependent! */
158 /* --- Sort out what to do with the character --- */
160 if (x
>= 10 && r
>= 0)
168 /* --- Stick the character on the end of my integer --- */
170 mp_ensure(m
, MP_LEN(m
) + 1);
171 mpx_umuln(m
->v
, m
->vl
, m
->v
, m
->vl
- 1, radix
);
172 mpx_uaddn(m
->v
, m
->vl
, x
);
179 /* --- Bail out if the number was bad --- */
186 /* --- Set the sign and return --- */
194 /* --- @mp_write@ --- *
196 * Arguments: @mp *m@ = pointer to a multi-precision integer
197 * @int radix@ = radix to use when writing the number out
198 * @const mptext_ops *ops@ = pointer to an operations block
199 * @void *p@ = data for the operations block
201 * Returns: Zero if it worked, nonzero otherwise.
203 * Use: Writes a large integer in textual form.
206 int mp_write(mp
*m
, int radix
, const mptext_ops
*ops
, void *p
)
212 /* --- Set various things up --- */
215 mp_build(&bb
, &b
, &b
+ 1);
217 /* --- If the number is negative, sort that out --- */
220 if (ops
->put("-", 1, p
))
226 /* --- Write digits to a temporary array --- */
229 mp
*q
= MP_NEW
, *r
= MP_NEW
;
233 mp_div(&q
, &r
, m
, &bb
);
243 } while (MP_CMP(m
, !=, MP_ZERO
));
245 /* --- Finished that --- */
250 int rc
= ops
->put(DA(&v
), DA_LEN(&v
), p
);
252 return (rc ? EOF
: 0);
256 /*----- Test rig ----------------------------------------------------------*/
260 #include <mLib/testrig.h>
262 static int verify(dstr
*v
)
265 int ib
= *(int *)v
[0].buf
, ob
= *(int *)v
[2].buf
;
267 mp
*m
= mp_readdstr(MP_NEW
, &v
[1], 0, ib
);
270 fprintf(stderr
, "*** unexpected successful parse\n"
271 "*** input [%i] = %s\n",
273 mp_writedstr(m
, &d
, 10);
274 fprintf(stderr
, "*** (value = %s)\n", d
.buf
);
277 mp_writedstr(m
, &d
, ob
);
278 if (d
.len
!= v
[3].len
|| memcmp(d
.buf
, v
[3].buf
, d
.len
) != 0) {
279 fprintf(stderr
, "*** failed read or write\n"
280 "*** input [%i] = %s\n"
281 "*** output [%i] = %s\n"
282 "*** expected [%i] = %s\n",
283 ib
, v
[1].buf
, ob
, d
.buf
, ob
, v
[3].buf
);
290 fprintf(stderr
, "*** unexpected parse failure\n"
291 "*** input [%i] = %s\n"
292 "*** expected [%i] = %s\n",
293 ib
, v
[1].buf
, ob
, v
[3].buf
);
302 static test_chunk tests
[] = {
304 { &type_int
, &type_string
, &type_int
, &type_string
, 0 } },
308 int main(int argc
, char *argv
[])
311 test_run(argc
, argv
, tests
, SRCDIR
"/tests/mptext");
317 /*----- That's all, folks -------------------------------------------------*/