xref: /haiku/src/libs/mapm/mapm_set.c (revision 59d799dabcba86f92658ddb402f634e262d9aae7)
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