1
2 /*
3 * M_APM - mapm_set.c
4 *
5 * Copyright (C) 1999 - 2007 Michael C. Ring
6 *
7 * Permission to use, copy, and distribute this software and its
8 * documentation for any purpose with or without fee is hereby granted,
9 * provided that the above copyright notice appear in all copies and
10 * that both that copyright notice and this permission notice appear
11 * in supporting documentation.
12 *
13 * Permission to modify the software is granted. Permission to distribute
14 * the modified code is granted. Modifications are to be distributed by
15 * using the file 'license.txt' as a template to modify the file header.
16 * 'license.txt' is available in the official MAPM distribution.
17 *
18 * This software is provided "as is" without express or implied warranty.
19 */
20
21 /*
22 * $Id: mapm_set.c,v 1.18 2007/12/03 01:47:50 mike Exp $
23 *
24 * This file contains the functions necessary to get C 'longs' and
25 * 'strings' into the MAPM number system. It also contains the function
26 * to get a string from a MAPM number.
27 *
28 * $Log: mapm_set.c,v $
29 * Revision 1.18 2007/12/03 01:47:50 mike
30 * Update license
31 *
32 * Revision 1.17 2003/07/21 20:25:06 mike
33 * Modify error messages to be in a consistent format.
34 *
35 * Revision 1.16 2003/03/31 21:59:52 mike
36 * call generic error handling function
37 *
38 * Revision 1.15 2002/11/05 23:31:54 mike
39 * use new set_to_zero call instead of copy
40 *
41 * Revision 1.14 2002/11/03 22:24:19 mike
42 * Updated function parameters to use the modern style
43 *
44 * Revision 1.13 2001/07/16 19:34:16 mike
45 * add function M_free_all_set
46 *
47 * Revision 1.12 2001/02/11 22:33:27 mike
48 * modify parameters to REALLOC
49 *
50 * Revision 1.11 2001/01/23 21:16:03 mike
51 * use dedicated call to long->ascii instead of sprintf
52 *
53 * Revision 1.10 2000/10/25 22:57:25 mike
54 * add cast which really wasn't needed
55 *
56 * Revision 1.9 2000/10/25 19:57:01 mike
57 * add free call to end of set string if the temp
58 * string gets too big
59 *
60 * Revision 1.8 2000/05/04 23:49:19 mike
61 * put in more efficient set_long function
62 *
63 * Revision 1.7 2000/02/03 22:47:15 mike
64 * use MAPM_* generic memory function
65 *
66 * Revision 1.6 1999/07/12 22:23:17 mike
67 * tweak output string when input == 0
68 *
69 * Revision 1.5 1999/07/12 02:07:56 mike
70 * fix dec_places error (was == -1, should be < 0)
71 *
72 * Revision 1.4 1999/06/19 21:36:57 mike
73 * added some comments
74 *
75 * Revision 1.3 1999/06/19 21:35:19 mike
76 * changed local static variables to MAPM stack variables
77 *
78 * Revision 1.2 1999/05/13 21:32:41 mike
79 * added check for illegal chars in string parse
80 *
81 * Revision 1.1 1999/05/10 20:56:31 mike
82 * Initial revision
83 */
84
85 #include "m_apm_lc.h"
86
87 static char *M_buf = NULL;
88 static int M_lbuf = 0;
89 static char *M_set_string_error_msg = "\'m_apm_set_string\', Out of memory";
90
91 /****************************************************************************/
M_free_all_set()92 void M_free_all_set()
93 {
94 if (M_lbuf != 0)
95 {
96 MAPM_FREE(M_buf);
97 M_buf = NULL;
98 M_lbuf = 0;
99 }
100 }
101 /****************************************************************************/
m_apm_set_long(M_APM atmp,long mm)102 void m_apm_set_long(M_APM atmp, long mm)
103 {
104 int len, ii, nbytes;
105 char *p, *buf, ch, buf2[64];
106
107 /* if zero, return right away */
108
109 if (mm == 0)
110 {
111 M_set_to_zero(atmp);
112 return;
113 }
114
115 M_long_2_ascii(buf2, mm); /* convert long -> ascii in base 10 */
116 buf = buf2;
117
118 if (mm < 0)
119 {
120 atmp->m_apm_sign = -1;
121 buf++; /* get past '-' sign */
122 }
123 else
124 {
125 atmp->m_apm_sign = 1;
126 }
127
128 len = strlen(buf);
129 atmp->m_apm_exponent = len;
130
131 /* least significant nibble of ODD data-length must be 0 */
132
133 if ((len & 1) != 0)
134 {
135 buf[len] = '0';
136 }
137
138 /* remove any trailing '0' ... */
139
140 while (TRUE)
141 {
142 if (buf[--len] != '0')
143 break;
144 }
145
146 atmp->m_apm_datalength = ++len;
147
148 nbytes = (len + 1) >> 1;
149 p = buf;
150
151 for (ii=0; ii < nbytes; ii++)
152 {
153 ch = *p++ - '0';
154 atmp->m_apm_data[ii] = 10 * ch + *p++ - '0';
155 }
156 }
157 /****************************************************************************/
m_apm_set_string(M_APM ctmp,char * s_in)158 void m_apm_set_string(M_APM ctmp, char *s_in)
159 {
160 char ch, *cp, *s, *p;
161 void *vp;
162 int i, j, zflag, exponent, sign;
163
164 if (M_lbuf == 0)
165 {
166 M_lbuf = 256;
167 if ((M_buf = (char *)MAPM_MALLOC(256)) == NULL)
168 {
169 /* fatal, this does not return */
170
171 M_apm_log_error_msg(M_APM_FATAL, M_set_string_error_msg);
172 }
173 }
174
175 if ((i = strlen(s_in)) > (M_lbuf - 4))
176 {
177 M_lbuf = i + 32;
178 if ((vp = MAPM_REALLOC(M_buf, M_lbuf)) == NULL)
179 {
180 /* fatal, this does not return */
181
182 M_apm_log_error_msg(M_APM_FATAL, M_set_string_error_msg);
183 }
184
185 M_buf = (char *)vp;
186 }
187
188 s = M_buf;
189 strcpy(s,s_in);
190
191 /* default == zero ... */
192
193 M_set_to_zero(ctmp);
194
195 p = s;
196
197 while (TRUE)
198 {
199 if (*p == ' ' || *p == '\t')
200 p++;
201 else
202 break;
203 }
204
205 if (*p == '\0')
206 return;
207
208 sign = 1; /* assume number is positive */
209
210 if (*p == '+') /* scan by optional '+' sign */
211 p++;
212 else
213 {
214 if (*p == '-') /* check if number negative */
215 {
216 sign = -1;
217 p++;
218 }
219 }
220
221 M_lowercase(p); /* convert string to lowercase */
222 exponent = 0; /* default */
223
224 if ((cp = strstr(p,"e")) != NULL)
225 {
226 exponent = atoi(cp + sizeof(char));
227 *cp = '\0'; /* erase the exponent now */
228 }
229
230 j = M_strposition(p,"."); /* is there a decimal point ?? */
231 if (j == -1)
232 {
233 strcat(p,"."); /* if not, append one */
234 j = M_strposition(p,"."); /* now find it ... */
235 }
236
237 if (j > 0) /* normalize number and adjust exponent */
238 {
239 exponent += j;
240 memmove((p+1),p,(j * sizeof(char)));
241 }
242
243 p++; /* scan past implied decimal point now in column 1 (index 0) */
244
245 i = strlen(p);
246 ctmp->m_apm_datalength = i;
247
248 if ((i & 1) != 0) /* if odd number of digits, append a '0' to make it even */
249 strcat(p,"0");
250
251 j = strlen(p) >> 1; /* number of bytes in encoded M_APM number */
252
253 /* do we need more memory to hold this number */
254
255 if (j > ctmp->m_apm_malloclength)
256 {
257 if ((vp = MAPM_REALLOC(ctmp->m_apm_data, (j + 32))) == NULL)
258 {
259 /* fatal, this does not return */
260
261 M_apm_log_error_msg(M_APM_FATAL, M_set_string_error_msg);
262 }
263
264 ctmp->m_apm_malloclength = j + 28;
265 ctmp->m_apm_data = (UCHAR *)vp;
266 }
267
268 zflag = TRUE;
269
270 for (i=0; i < j; i++)
271 {
272 ch = *p++ - '0';
273 if ((ch = (10 * ch + *p++ - '0')) != 0)
274 zflag = FALSE;
275
276 if (((int)ch & 0xFF) >= 100)
277 {
278 M_apm_log_error_msg(M_APM_RETURN,
279 "\'m_apm_set_string\', Non-digit char found in parse");
280
281 M_apm_log_error_msg(M_APM_RETURN, "Text =");
282 M_apm_log_error_msg(M_APM_RETURN, s_in);
283
284 M_set_to_zero(ctmp);
285 return;
286 }
287
288 ctmp->m_apm_data[i] = ch;
289 ctmp->m_apm_data[i+1] = 0;
290 }
291
292 ctmp->m_apm_exponent = exponent;
293 ctmp->m_apm_sign = sign;
294
295 if (zflag)
296 {
297 ctmp->m_apm_exponent = 0;
298 ctmp->m_apm_sign = 0;
299 ctmp->m_apm_datalength = 1;
300 }
301 else
302 {
303 M_apm_normalize(ctmp);
304 }
305
306 /*
307 * if our local temp string is getting too big,
308 * release it's memory and start over next time.
309 * (this 1000 byte threshold is quite arbitrary,
310 * it may be more efficient in your app to make
311 * this number bigger).
312 */
313
314 if (M_lbuf > 1000)
315 {
316 MAPM_FREE(M_buf);
317 M_buf = NULL;
318 M_lbuf = 0;
319 }
320 }
321 /****************************************************************************/
m_apm_to_string(char * s,int places,M_APM mtmp)322 void m_apm_to_string(char *s, int places, M_APM mtmp)
323 {
324 M_APM ctmp;
325 char *cp;
326 int i, index, first, max_i, num_digits, dec_places;
327 UCHAR numdiv, numrem;
328
329 ctmp = M_get_stack_var();
330 dec_places = places;
331
332 if (dec_places < 0)
333 m_apm_copy(ctmp, mtmp);
334 else
335 m_apm_round(ctmp, dec_places, mtmp);
336
337 if (ctmp->m_apm_sign == 0)
338 {
339 if (dec_places < 0)
340 strcpy(s,"0.0E+0");
341 else
342 {
343 strcpy(s,"0");
344
345 if (dec_places > 0)
346 strcat(s,".");
347
348 for (i=0; i < dec_places; i++)
349 strcat(s,"0");
350
351 strcat(s,"E+0");
352 }
353
354 M_restore_stack(1);
355 return;
356 }
357
358 max_i = (ctmp->m_apm_datalength + 1) >> 1;
359
360 if (dec_places < 0)
361 num_digits = ctmp->m_apm_datalength;
362 else
363 num_digits = dec_places + 1;
364
365 cp = s;
366
367 if (ctmp->m_apm_sign == -1)
368 *cp++ = '-';
369
370 first = TRUE;
371
372 i = 0;
373 index = 0;
374
375 while (TRUE)
376 {
377 if (index >= max_i)
378 {
379 numdiv = 0;
380 numrem = 0;
381 }
382 else
383 M_get_div_rem_10((int)ctmp->m_apm_data[index],&numdiv,&numrem);
384
385 index++;
386
387 *cp++ = numdiv + '0';
388
389 if (++i == num_digits)
390 break;
391
392 if (first)
393 {
394 first = FALSE;
395 *cp++ = '.';
396 }
397
398 *cp++ = numrem + '0';
399
400 if (++i == num_digits)
401 break;
402 }
403
404 i = ctmp->m_apm_exponent - 1;
405 if (i >= 0)
406 sprintf(cp,"E+%d",i);
407 else
408 sprintf(cp,"E%d",i);
409
410 M_restore_stack(1);
411 }
412 /****************************************************************************/
413