xref: /haiku/src/libs/mapm/mapmutil.c (revision 59d799dabcba86f92658ddb402f634e262d9aae7)
1 
2 /*
3  *  M_APM  -  mapmutil.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: mapmutil.c,v 1.26 2007/12/03 01:58:49 mike Exp $
23  *
24  *      This file contains various utility functions needed by the
25  *	library in addition to some basic user callable functions.
26  *
27  *      $Log: mapmutil.c,v $
28  *      Revision 1.26  2007/12/03 01:58:49  mike
29  *      Update license
30  *
31  *      Revision 1.25  2003/07/21 20:51:34  mike
32  *      Modify error messages to be in a consistent format.
33  *
34  *      Revision 1.24  2003/03/31 22:03:54  mike
35  *      call generic error handling function
36  *
37  *      Revision 1.23  2002/11/04 20:47:02  mike
38  *      change m_apm_init so it compiles clean with a real C++ compiler
39  *
40  *      Revision 1.22  2002/11/03 22:50:58  mike
41  *      Updated function parameters to use the modern style
42  *
43  *      Revision 1.21  2002/05/17 22:26:49  mike
44  *      move some functions into another file
45  *
46  *      Revision 1.20  2002/02/12 20:21:53  mike
47  *      eliminate unneeded working arrays in _scale
48  *      by processing the scaling operation in reverse
49  *
50  *      Revision 1.19  2001/07/24 18:29:18  mike
51  *      add util function to get address of
52  *      the div/rem lookup tables
53  *
54  *      Revision 1.18  2001/07/20 16:14:05  mike
55  *      optimize normalize yet again
56  *
57  *      Revision 1.17  2001/07/17 18:17:56  mike
58  *      another optimization to _normalize
59  *
60  *      Revision 1.16  2001/07/16 22:33:43  mike
61  *      update free_all_util
62  *
63  *      Revision 1.15  2001/07/16 19:56:26  mike
64  *      add function M_free_all_util
65  *
66  *      Revision 1.14  2001/07/16 18:10:21  mike
67  *      optimize M_apm_normalize when moving multiple '00' bytes
68  *
69  *      Revision 1.13  2001/02/11 22:36:43  mike
70  *      modify parameters to REALLOC
71  *
72  *      Revision 1.12  2001/01/23 21:17:38  mike
73  *      add dedicated long->ascii conversion (instead of sprintf)
74  *
75  *      Revision 1.11  2000/08/22 20:21:54  mike
76  *      fix m_apm_exponent with exactly 0 as the input
77  *
78  *      Revision 1.10  2000/08/22 00:01:26  mike
79  *      add zero check in is_integer
80  *
81  *      Revision 1.9  2000/08/21 23:34:44  mike
82  *      add new function _is_integer
83  *
84  *      Revision 1.8  2000/08/01 22:29:02  mike
85  *      add sizeof int function call
86  *
87  *      Revision 1.7  2000/05/19 16:21:03  mike
88  *      delete M_check_dec_places, no longer needed
89  *
90  *      Revision 1.6  2000/04/04 17:06:37  mike
91  *      initialize C++ refcount struct element to 1
92  *
93  *      Revision 1.5  2000/02/03 22:49:56  mike
94  *      use MAPM_* generic memory function
95  *
96  *      Revision 1.4  1999/09/18 03:06:41  mike
97  *      fix m_apm_exponent
98  *
99  *      Revision 1.3  1999/09/18 02:59:11  mike
100  *      added new functions
101  *
102  *      Revision 1.2  1999/05/15 02:21:14  mike
103  *      add check for number of decimal places
104  *
105  *      Revision 1.1  1999/05/10 20:56:31  mike
106  *      Initial revision
107  */
108 
109 #include "m_apm_lc.h"
110 
111 static  UCHAR	*M_mul_div = NULL;
112 static  UCHAR   *M_mul_rem = NULL;
113 
114 static  UCHAR   M_mul_div_10[100];
115 static	UCHAR   M_mul_rem_10[100];
116 
117 static	int	M_util_firsttime = TRUE;
118 static	int     M_firsttime3 = TRUE;
119 
120 static	M_APM	M_work_0_5;
121 
122 static  char    *M_init_error_msg = "\'m_apm_init\', Out of memory";
123 
124 /****************************************************************************/
m_apm_init()125 M_APM	m_apm_init()
126 {
127 M_APM	atmp;
128 
129 if (M_firsttime3)
130   {
131    M_firsttime3 = FALSE;
132    M_init_util_data();
133    M_init_trig_globals();
134   }
135 
136 if ((atmp = (M_APM)MAPM_MALLOC(sizeof(M_APM_struct))) == NULL)
137   {
138    /* fatal, this does not return */
139 
140    M_apm_log_error_msg(M_APM_FATAL, M_init_error_msg);
141   }
142 
143 atmp->m_apm_id           = M_APM_IDENT;
144 atmp->m_apm_malloclength = 80;
145 atmp->m_apm_datalength   = 1;
146 atmp->m_apm_refcount     = 1;           /* not for us, for MAPM C++ class */
147 atmp->m_apm_exponent     = 0;
148 atmp->m_apm_sign         = 0;
149 
150 if ((atmp->m_apm_data = (UCHAR *)MAPM_MALLOC(84)) == NULL)
151   {
152    /* fatal, this does not return */
153 
154    M_apm_log_error_msg(M_APM_FATAL, M_init_error_msg);
155   }
156 
157 atmp->m_apm_data[0] = 0;
158 return(atmp);
159 }
160 /****************************************************************************/
m_apm_free(M_APM atmp)161 void	m_apm_free(M_APM atmp)
162 {
163 if (atmp->m_apm_id == M_APM_IDENT)
164   {
165    atmp->m_apm_id = 0x0FFFFFF0L;
166    MAPM_FREE(atmp->m_apm_data);
167    MAPM_FREE(atmp);
168   }
169 else
170   {
171    M_apm_log_error_msg(M_APM_RETURN, "\'m_apm_free\', Invalid M_APM variable");
172   }
173 }
174 /****************************************************************************/
M_free_all_util()175 void	M_free_all_util()
176 {
177 if (M_util_firsttime == FALSE)
178   {
179    m_apm_free(M_work_0_5);
180    M_util_firsttime = TRUE;
181   }
182 
183 if (M_firsttime3 == FALSE)
184   {
185    MAPM_FREE(M_mul_div);
186    MAPM_FREE(M_mul_rem);
187 
188    M_mul_div    = NULL;
189    M_mul_rem    = NULL;
190    M_firsttime3 = TRUE;
191   }
192 }
193 /****************************************************************************/
194 /*
195  *      just a dummy wrapper to keep some compilers from complaining
196  */
M_get_sizeof_int()197 int 	M_get_sizeof_int()
198 {
199 return(sizeof(int));
200 }
201 /****************************************************************************/
M_init_util_data()202 void	M_init_util_data()
203 {
204 int	k;
205 UCHAR   ndiv, nrem;
206 
207 if (M_mul_div != NULL)
208   return;
209 
210 M_mul_div = (UCHAR *)MAPM_MALLOC(10000 * sizeof(UCHAR));
211 M_mul_rem = (UCHAR *)MAPM_MALLOC(10000 * sizeof(UCHAR));
212 
213 if (M_mul_div == NULL || M_mul_rem == NULL)
214   {
215    /* fatal, this does not return */
216 
217    M_apm_log_error_msg(M_APM_FATAL, "\'M_init_util_data\', Out of memory");
218   }
219 
220 ndiv = 0;
221 nrem = 0;
222 
223 for (k=0; k < 100; k++)
224   {
225    M_mul_div_10[k] = ndiv;
226    M_mul_rem_10[k] = nrem;
227 
228    if (++nrem == 10)
229      {
230       nrem = 0;
231       ndiv++;
232      }
233   }
234 
235 ndiv = 0;
236 nrem = 0;
237 
238 for (k=0; k < 10000; k++)
239   {
240    M_mul_div[k] = ndiv;
241    M_mul_rem[k] = nrem;
242 
243    if (++nrem == 100)
244      {
245       nrem = 0;
246       ndiv++;
247      }
248   }
249 }
250 /****************************************************************************/
M_get_div_rem_addr(UCHAR ** ndivp,UCHAR ** nremp)251 void	M_get_div_rem_addr(UCHAR **ndivp, UCHAR **nremp)
252 {
253 *ndivp = M_mul_div;
254 *nremp = M_mul_rem;
255 }
256 /****************************************************************************/
M_get_div_rem(int tbl_lookup,UCHAR * ndiv,UCHAR * nrem)257 void	M_get_div_rem(int tbl_lookup, UCHAR *ndiv, UCHAR *nrem)
258 {
259 *ndiv = M_mul_div[tbl_lookup];
260 *nrem = M_mul_rem[tbl_lookup];
261 }
262 /****************************************************************************/
M_get_div_rem_10(int tbl_lookup,UCHAR * ndiv,UCHAR * nrem)263 void	M_get_div_rem_10(int tbl_lookup, UCHAR *ndiv, UCHAR *nrem)
264 {
265 *ndiv = M_mul_div_10[tbl_lookup];
266 *nrem = M_mul_rem_10[tbl_lookup];
267 }
268 /****************************************************************************/
m_apm_round(M_APM btmp,int places,M_APM atmp)269 void	m_apm_round(M_APM btmp, int places, M_APM atmp)
270 {
271 int	ii;
272 
273 if (M_util_firsttime)
274   {
275    M_util_firsttime = FALSE;
276 
277    M_work_0_5 = m_apm_init();
278    m_apm_set_string(M_work_0_5, "5");
279   }
280 
281 ii = places + 1;
282 
283 if (atmp->m_apm_datalength <= ii)
284   {
285    m_apm_copy(btmp,atmp);
286    return;
287   }
288 
289 M_work_0_5->m_apm_exponent = atmp->m_apm_exponent - ii;
290 
291 if (atmp->m_apm_sign > 0)
292   m_apm_add(btmp, atmp, M_work_0_5);
293 else
294   m_apm_subtract(btmp, atmp, M_work_0_5);
295 
296 btmp->m_apm_datalength = ii;
297 M_apm_normalize(btmp);
298 }
299 /****************************************************************************/
M_apm_normalize(M_APM atmp)300 void	M_apm_normalize(M_APM atmp)
301 {
302 int	i, index, datalength, exponent;
303 UCHAR   *ucp, numdiv, numrem, numrem2;
304 
305 if (atmp->m_apm_sign == 0)
306   return;
307 
308 datalength = atmp->m_apm_datalength;
309 exponent   = atmp->m_apm_exponent;
310 
311 /* make sure trailing bytes/chars are 0                */
312 /* the following function will adjust the 'datalength' */
313 /* we want the original value and will fix it later    */
314 
315 M_apm_pad(atmp, (datalength + 3));
316 
317 while (TRUE)			/* remove lead-in '0' if any */
318   {
319    M_get_div_rem_10((int)atmp->m_apm_data[0], &numdiv, &numrem);
320 
321    if (numdiv >= 1)      /* number is normalized, done here */
322      break;
323 
324    index = (datalength + 1) >> 1;
325 
326    if (numrem == 0)      /* both nibbles are 0, we can move full bytes */
327      {
328       i = 0;
329       ucp = atmp->m_apm_data;
330 
331       while (TRUE)	 /* find out how many '00' bytes we can move */
332         {
333 	 if (*ucp != 0)
334 	   break;
335 
336          ucp++;
337 	 i++;
338 	}
339 
340       memmove(atmp->m_apm_data, ucp, (index + 1 - i));
341       datalength -= 2 * i;
342       exponent -= 2 * i;
343      }
344    else
345      {
346       for (i=0; i < index; i++)
347         {
348          M_get_div_rem_10((int)atmp->m_apm_data[i+1], &numdiv, &numrem2);
349          atmp->m_apm_data[i] = 10 * numrem + numdiv;
350 	 numrem = numrem2;
351         }
352 
353       datalength--;
354       exponent--;
355      }
356   }
357 
358 while (TRUE)			/* remove trailing '0' if any */
359   {
360    index = ((datalength + 1) >> 1) - 1;
361 
362    if ((datalength & 1) == 0)   /* back-up full bytes at a time if the */
363      {				/* current length is an even number    */
364       ucp = atmp->m_apm_data + index;
365       if (*ucp == 0)
366         {
367 	 while (TRUE)
368 	   {
369 	    datalength -= 2;
370 	    index--;
371 	    ucp--;
372 
373 	    if (*ucp != 0)
374 	      break;
375 	   }
376 	}
377      }
378 
379    M_get_div_rem_10((int)atmp->m_apm_data[index], &numdiv, &numrem);
380 
381    if (numrem != 0)		/* last digit non-zero, all done */
382      break;
383 
384    if ((datalength & 1) != 0)   /* if odd, then first char must be non-zero */
385      {
386       if (numdiv != 0)
387         break;
388      }
389 
390    if (datalength == 1)
391      {
392       atmp->m_apm_sign = 0;
393       exponent = 0;
394       break;
395      }
396 
397    datalength--;
398   }
399 
400 atmp->m_apm_datalength = datalength;
401 atmp->m_apm_exponent   = exponent;
402 }
403 /****************************************************************************/
M_apm_scale(M_APM ctmp,int count)404 void	M_apm_scale(M_APM ctmp, int count)
405 {
406 int	ii, numb, ct;
407 UCHAR	*chp, numdiv, numdiv2, numrem;
408 void	*vp;
409 
410 ct = count;
411 
412 ii = (ctmp->m_apm_datalength + ct + 1) >> 1;
413 if (ii > ctmp->m_apm_malloclength)
414   {
415    if ((vp = MAPM_REALLOC(ctmp->m_apm_data, (ii + 32))) == NULL)
416      {
417       /* fatal, this does not return */
418 
419       M_apm_log_error_msg(M_APM_FATAL, "\'M_apm_scale\', Out of memory");
420      }
421 
422    ctmp->m_apm_malloclength = ii + 28;
423    ctmp->m_apm_data = (UCHAR *)vp;
424   }
425 
426 if ((ct & 1) != 0)          /* move odd number first */
427   {
428    ct--;
429    chp = ctmp->m_apm_data;
430    ii  = ((ctmp->m_apm_datalength + 1) >> 1) - 1;
431 
432    if ((ctmp->m_apm_datalength & 1) == 0)
433      {
434       /*
435        *   original datalength is even:
436        *
437        *   uv  wx  yz   becomes  -->   0u  vw  xy  z0
438        */
439 
440       numdiv = 0;
441 
442       while (TRUE)
443         {
444          M_get_div_rem_10((int)chp[ii], &numdiv2, &numrem);
445 
446 	 chp[ii + 1] = 10 * numrem + numdiv;
447 	 numdiv = numdiv2;
448 
449 	 if (ii == 0)
450 	   break;
451 
452          ii--;
453 	}
454 
455       chp[0] = numdiv2;
456      }
457    else
458      {
459       /*
460        *   original datalength is odd:
461        *
462        *   uv  wx  y0   becomes  -->   0u  vw  xy
463        */
464 
465       M_get_div_rem_10((int)chp[ii], &numdiv2, &numrem);
466 
467       if (ii == 0)
468         {
469          chp[0] = numdiv2;
470         }
471       else
472         {
473          while (TRUE)
474            {
475             M_get_div_rem_10((int)chp[ii - 1], &numdiv, &numrem);
476 
477 	    chp[ii] = 10 * numrem + numdiv2;
478 	    numdiv2 = numdiv;
479 
480 	    if (--ii == 0)
481 	      break;
482 	   }
483 
484          chp[0] = numdiv;
485         }
486      }
487 
488    ctmp->m_apm_exponent++;
489    ctmp->m_apm_datalength++;
490   }
491 
492 /* ct is even here */
493 
494 if (ct > 0)
495   {
496    numb = (ctmp->m_apm_datalength + 1) >> 1;
497    ii   = ct >> 1;
498 
499    memmove((ctmp->m_apm_data + ii), ctmp->m_apm_data, numb);
500    memset(ctmp->m_apm_data, 0, ii);
501 
502    ctmp->m_apm_datalength += ct;
503    ctmp->m_apm_exponent += ct;
504   }
505 }
506 /****************************************************************************/
M_apm_pad(M_APM ctmp,int new_length)507 void	M_apm_pad(M_APM ctmp, int new_length)
508 {
509 int	num1, numb, ct;
510 UCHAR	numdiv, numrem;
511 void	*vp;
512 
513 ct = new_length;
514 if (ctmp->m_apm_datalength >= ct)
515   return;
516 
517 numb = (ct + 1) >> 1;
518 if (numb > ctmp->m_apm_malloclength)
519   {
520    if ((vp = MAPM_REALLOC(ctmp->m_apm_data, (numb + 32))) == NULL)
521      {
522       /* fatal, this does not return */
523 
524       M_apm_log_error_msg(M_APM_FATAL, "\'M_apm_pad\', Out of memory");
525      }
526 
527    ctmp->m_apm_malloclength = numb + 28;
528    ctmp->m_apm_data = (UCHAR *)vp;
529   }
530 
531 num1 = (ctmp->m_apm_datalength + 1) >> 1;
532 
533 if ((ctmp->m_apm_datalength & 1) != 0)
534   {
535    M_get_div_rem_10((int)ctmp->m_apm_data[num1 - 1], &numdiv, &numrem);
536    ctmp->m_apm_data[num1 - 1] = 10 * numdiv;
537   }
538 
539 memset((ctmp->m_apm_data + num1), 0, (numb - num1));
540 ctmp->m_apm_datalength = ct;
541 }
542 /****************************************************************************/
543 
544 /*
545       debug_dsp(cc)
546       M_APM cc;
547       {
548 static char buffer[8192];
549 
550 m_apm_to_string(buffer, -1, cc);
551 printf("(dsp func) = [%s]\n",buffer);
552 
553       }
554 */
555 
556