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