home *** CD-ROM | disk | FTP | other *** search
/ Boston 2 / boston-2.iso / DOS / PROGRAM / C / APMTEST / UTILS.C < prev   
Text File  |  1993-12-01  |  27KB  |  1,291 lines

  1. /******************************************************************************
  2.  
  3.     Arbitrary Precision Math Library General Public License
  4.             (Written October 5, 1988)
  5.  
  6.  Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
  7.  Gatos, California.  Everyone is permitted to copy and distribute
  8.  verbatim copies of this license, but changing it is not allowed.
  9.  You can also use this wording to make the terms for other programs.
  10.  
  11.  The wording of this license is based on that of the
  12.  "GNU EMACS GENERAL PUBLIC LICENSE" by Richard Stallman,
  13.  Copyright (C) 1985, 1987, 1988, version of February 11, 1988,
  14.  but since some of the text has been changed, please be sure to
  15.  READ THIS CAREFULLY!
  16.  
  17.   This general public license is intended to give everyone the right
  18. to share the Arbitrary Precision Math Library (hereinafter referred to
  19. as the "APM Library").  To make sure that you get the rights we want
  20. you to have, I need to make restrictions that forbid anyone to deny
  21. you these rights or to ask you to surrender the rights.
  22.  
  23.   Specifically, we want to make sure that you have the right to give
  24. away copies of the APM Library, that you receive source code or else
  25. can get it if you want it, that you can change the APM Library or use
  26. pieces of it in new programs, and that you know you can do these
  27. things.
  28.  
  29.   To make sure that everyone has such rights, we have to forbid you to
  30. deprive anyone else of these rights.  For example, if you distribute
  31. copies of the APM Library, you must give the recipients all the
  32. rights that you have.  You must make sure that they, too, receive or
  33. can get the source code.  And you must tell them their rights.
  34.  
  35.   Also, for our own protection, we must make certain that everyone
  36. finds out that there is no warranty for the APM Library.  If the APM
  37. Library is modified by someone else and passed on, we want its
  38. recipients to know that what they have is not what we distributed, so
  39. that any problems introduced by others will not reflect on our
  40. reputation.
  41.  
  42.   Therefore we (Lloyd Zusman and Master Byte Software) make the
  43. following terms which say what you must do to be allowed to
  44. distribute or change the APM Library.
  45.  
  46.             COPYING POLICIES
  47.  
  48. 1. You may copy and distribute verbatim copies of the APM Library
  49. source code as you receive it, in any medium, provided that you
  50. conspicuously and appropriately publish on each copy a valid copyright
  51. notice "Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
  52. Gatos, California" (or with whatever year is appropriate); keep intact
  53. the notices on all files that refer to this License Agreement and to
  54. the absence of any warranty; and give any other recipients of the the
  55. APM Library program a copy of this License Agreement along with the
  56. program.  You may charge a distribution fee for the physical act of
  57. transferring a copy.
  58.  
  59.   2. You may modify your copy or copies of the APM Library source code or
  60. any portion of it, and copy and distribute such modifications under
  61. the terms of Paragraph 1 above, provided that you also do the following:
  62.  
  63.     a) cause the modified files to carry prominent notices stating
  64.     that you changed the files and the date of any change; and
  65.  
  66.     b) cause the whole of any work that you distribute or publish, that in
  67.     whole or in part contains or is a derivative of the APM Library or any
  68.     part thereof, to be licensed to all third parties on terms identical
  69.     to those contained in this License Agreement (except that you may
  70.     choose to grant more extensive warranty protection to some or all
  71.     third parties, at your option).
  72.  
  73.     c) You may charge a distribution fee for the physical act of
  74.     transferring a copy, and you may at your option offer warranty
  75.     protection in exchange for a fee.
  76.  
  77.     d) You may not charge a license fee for the whole of any work that
  78.     you distribute or publish, that in whole or in part contains or is
  79.     a derivative of the APM library or any part thereof, without the
  80.     express written permission of Lloyd Zusman and Master Byte Software;
  81.     whether this permission is granted for free or in return for goods
  82.     services, royalties, or other compensation will be determined
  83.     solely by Lloyd Zusman and Master Byte Software.
  84.  
  85. Mere aggregation of another unrelated program with this program (or its
  86. derivative) on a volume of a storage or distribution medium does not bring
  87. the other program under the scope of these terms.
  88.  
  89.   3. You may copy and distribute the APM Library (or a portion or
  90. derivative of it, under Paragraph 2) in object code or executable form
  91. under all the terms of Paragraphs 1 and 2 above provided that you also
  92. do one of the following:
  93.  
  94.     a) accompany it with the complete corresponding machine-readable
  95.     source code, which must be distributed under the terms of
  96.     Paragraphs 1 and 2 above; or,
  97.  
  98.     b) accompany it with a written offer, valid for at least three
  99.     years, to give any third party free (except for a nominal
  100.     shipping charge) a complete machine-readable copy of the
  101.     corresponding source code, to be distributed under the terms of
  102.     Paragraphs 1 and 2 above; or,
  103.  
  104.     c) accompany it with the information you received as to where the
  105.     corresponding source code may be obtained.  (This alternative is
  106.     allowed only for noncommercial distribution and only if you
  107.     received the program in object code or executable form alone.)
  108.  
  109. For an executable file, complete source code means all the source code
  110. for all modules it contains; but, as a special exception, it need not
  111. include source code for modules which are standard libraries that
  112. accompany the operating system on which the executable file runs.
  113.  
  114.   4. You may not copy, sublicense, distribute or transfer the APM
  115. Library except as expressly provided under this License Agreement.
  116. Any attempt otherwise to copy, sublicense, distribute or transfer the
  117. APM Library is void and your rights to use the APM Library under this
  118. License agreement shall be automatically terminated.  However, parties
  119. who have received computer software programs from you with this
  120. License Agreement will not have their licenses terminated so long as
  121. such parties remain in full compliance.
  122.  
  123.   5. If you wish to incorporate parts of the APM Library into other
  124. programs whose distribution conditions are different, write to Lloyd
  125. Zusman at Master Byte Software.  We have not yet worked out a simple
  126. rule that can be stated here, but we will often permit this.  We will
  127. be guided by the goals of (1) preserving the free status of all
  128. derivatives of our free software; of (2) promoting the sharing and
  129. reuse of software; and of (3) not allowing anyone to profit from the
  130. use of our software without us also having the opportunity to share
  131. in these profits.
  132.  
  133. Your comments and suggestions about our licensing policies and our
  134. software are welcome!  Please contact Lloyd Zusman, Master Byte
  135. Software, 127 Wilder Ave., Los Gatos, California 95030, or call
  136. (408) 395-5693.
  137.  
  138.                NO WARRANTY
  139.  
  140.   BECAUSE THE APM LIBRARY IS LICENSED FREE OF CHARGE, WE PROVIDE
  141. ABSOLUTELY NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE
  142. LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING, MASTER BYTE SOFTWARE,
  143. LLOYD ZUSMAN AND/OR OTHER PARTIES PROVIDE THE APM LIBRARY "AS IS"
  144. WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
  145. BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  146. FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
  147. AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE THE APM
  148. LIBRARY PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
  149. SERVICING, REPAIR OR CORRECTION.
  150.  
  151.   IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL MASTER BYTE
  152. SOFTWARE, LLOYD ZUSMAN, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND
  153. REDISTRIBUTE THE APM LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
  154. DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL,
  155. INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
  156. INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
  157. BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
  158. FAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
  159. MASTER BYTE SOFTWARE) THE PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF
  160. THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
  161.  
  162. ******************************************************************************/
  163.  
  164.  
  165. /*
  166.  * Low level utilities for the APM library.  The user never should call
  167.  * any of these directly.
  168.  *
  169.  * $Log:    utils.c,v $
  170.  * Revision 1.0  88/10/05  12:38:16  ljz
  171.  * Initial release.
  172.  * 
  173.  */
  174. #ifndef lint
  175. static char rcsid[] = "$Header: utils.c,v 1.0 88/10/05 12:38:16 ljz Exp $";
  176. #endif /* ! lint */
  177.  
  178. #include <stdio.h>
  179. #include <varargs.h>
  180. #include "apm.h"
  181. #include "apmlocal.h"
  182.  
  183. int apm_errno = APM_OK;
  184. int (*APM_error_func)() = (int (*)())NULL;
  185. int APM_line = 0;
  186. char *APM_file = "";
  187. char *APM_func_name = "";
  188.  
  189. static char APM_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
  190.  
  191. #define MAX_BASE    ((sizeof (APM_digits) / sizeof (APM_digits[0])) - 1)
  192.  
  193. char *
  194. APM_error_message(code)
  195. int code;
  196. {
  197.     static char localMessage[80];
  198.     char *message;
  199.  
  200.     switch (code) {
  201.     case APM_ENOMEM:
  202.         message = "memory allocation failed";
  203.         break;
  204.     case APM_WNULL:
  205.         message = "null argument";
  206.         break;
  207.     case APM_WDIVBYZERO:
  208.         message = "division by zero";
  209.         break;
  210.     case APM_WTRUNC:
  211.         message = "result truncated";
  212.         break;
  213.     case APM_WNOALLOC:
  214.         message = "attempt to free unallocated APM value";
  215.         break;
  216.     case APM_EPARM:
  217.         message = "invalid function parameter";
  218.         break;
  219.     case APM_ENULL:
  220.         message = "null APM value";
  221.         break;
  222.     case APM_EBADVAL:
  223.         message = "bad APM value";
  224.         break;
  225.     case APM_ENULLVAL:
  226.         message = "null value";
  227.         break;
  228.     case APM_EFMT:
  229.         message = "invalid string format";
  230.         break;
  231.     case APM_EBASE:
  232.         message = "invalid base";
  233.         break;
  234.     case APM_ESIZE:
  235.         message = "destination size is too small";
  236.         break;
  237.     case APM_EOVERLAP:
  238.         message = "result overlaps one or more operands";
  239.         break;
  240.     default:
  241.         sprintf(localMessage, "unknown error code: %d", code);
  242.         message = localMessage;
  243.         break;
  244.     }
  245.  
  246.     return (message);
  247. }
  248.  
  249. int
  250. APM_set_errno(code)
  251. int code;
  252. {
  253.     apm_errno = code;
  254.     return (code);
  255. }
  256.  
  257. int
  258. APM_error(code)
  259. int code;
  260. {
  261.     code = APM_set_errno(code);
  262.  
  263.     if (code != APM_OK && APM_error_func != (int (*)())NULL) {
  264.         code = (*APM_error_func)(code,
  265.                      APM_error_message(code),
  266.                      APM_file, APM_line,
  267.                      APM_func_name);
  268.     }
  269.     return (code);
  270. }
  271.  
  272. char *
  273. APM_trim_string(string)
  274. char *string;
  275. {
  276.     char *orig = string;
  277.     char *sp = string;
  278.  
  279.     if (string != NULL) {
  280.         for (; *string != '\0'; ++string) {
  281.             if (*string != ' ' && *string != '\t') {
  282.                 sp = string + 1;
  283.             }
  284.         }
  285.         *sp = '\0';
  286.     }
  287.  
  288.     return (orig);
  289. }
  290.  
  291. char *
  292. APM_left_justify(string, ignore)
  293. char *string;
  294. char *ignore;
  295. {
  296.     if (string != NULL && ignore != NULL) {
  297.         for (; *string != '\0'; ++string) {
  298.             if (APM_index(ignore, *string) == NULL) {
  299.                 break;
  300.             }
  301.         }
  302.     }
  303.  
  304.     return (string);
  305. }
  306.  
  307. int
  308. APM_val_format(apm)
  309. APM apm;
  310. {
  311.     apm_errno = APM_OK;
  312.  
  313.     if (apm == (APM)NULL) {
  314.         return (APM_set_errno(APM_ENULL));
  315.     }
  316.     if (apm->magic != APM_MAGIC) {
  317.         return (APM_set_errno(APM_EBADVAL));
  318.     }
  319.     return (APM_OK);
  320. }
  321.  
  322. int
  323. APM_val_base(base)
  324. short base;
  325. {
  326.     apm_errno = APM_OK;
  327.  
  328.     if (base == SPECIAL_BASE) {
  329.         return (APM_OK);
  330.     }
  331.  
  332.     if (base < 2 || base > MAX_BASE) {
  333.         return (APM_set_errno(APM_EBASE));
  334.     }
  335.  
  336.     return (APM_OK);
  337. }
  338.  
  339. short
  340. APM_get_digit(ch, base)
  341. char ch;
  342. short base;
  343. {
  344.     int ercode;
  345.     short idx;
  346.  
  347.     ercode = APM_val_base(base);
  348.     if (ercode < APM_OK) {
  349.         return (APM_set_errno(ercode));
  350.     }
  351.  
  352.     if (base == SPECIAL_BASE) {
  353.         base = 10;
  354.     }
  355.  
  356.     for (idx = 0; idx < base; ++idx) {
  357.         if (ch == APM_digits[idx]) {
  358.             return (idx);
  359.         }
  360.     }
  361.  
  362.     return (APM_set_errno(APM_EBASE));
  363. }
  364.  
  365. int
  366. APM_radix_pos(string, base)
  367. char *string;
  368. short base;
  369. {
  370.     int dp = -1;
  371.     int nodigits = 1;
  372.     int pos = 0;
  373.     int ercode;
  374.  
  375.     if (string == NULL) {
  376.         return (APM_set_errno(APM_ENULLVAL));
  377.     }
  378.     ercode = APM_val_base(base);
  379.     if (ercode < APM_OK) {
  380.         return (ercode);
  381.     }
  382.  
  383.     for (; string[pos] != '\0'; ++pos) {
  384.         if (string[pos] == '.') {
  385.             if (dp >= 0) {
  386.                 return (APM_set_errno(APM_EFMT));
  387.             }
  388.             else {
  389.                 dp = pos;
  390.             }
  391.         }
  392.         else if (APM_get_digit(string[pos], base) < 0) {
  393.             return (APM_set_errno(APM_EFMT));
  394.         }
  395.         else {
  396.             nodigits = 0;
  397.         }
  398.     }
  399.  
  400.     if (nodigits) {
  401.         return (APM_set_errno(APM_EFMT));
  402.     }
  403.  
  404.     return (dp + 1);
  405. }
  406.  
  407. int
  408. APM_shift(num, scaleFactor)
  409. APM num;
  410. int scaleFactor;
  411. {
  412.     int ercode;
  413.  
  414.     apm_errno = APM_OK;
  415.  
  416.     if (scaleFactor == 0) {
  417.         return (APM_OK);
  418.     }
  419.     if (num->base != 0 && num->base != SPECIAL_BASE) {
  420.         num->dp -= scaleFactor;
  421.     }
  422.     else {
  423.         /*
  424.          * The following code assumes that
  425.          * (-X) % Y == -(X % Y).
  426.          */
  427.         int factor = scaleFactor / SPECIAL_SCALE;
  428.         int n = scaleFactor % SPECIAL_SCALE;
  429.  
  430.         if (scaleFactor < 0) {
  431.             --factor;
  432.             n += SPECIAL_SCALE;
  433.         }
  434.         num->dp -= factor;
  435.         if (n > 0) {
  436.             int multiplier = 1;
  437.             while (n-- > 0) {
  438.                 multiplier *= 10;
  439.             }
  440.             n = (num->length)++;
  441.             ercode = APM_size(num, num->length);
  442.             if (ercode < APM_OK) {
  443.                 return (ercode);
  444.             }
  445.             num->data[n] = APM_scalar_mul(num->data,
  446.                                num->data, n,
  447.                                multiplier,
  448.                                num->base);
  449.         }
  450.     }
  451.     return (APM_trim(num, 1, 1));
  452. }
  453.  
  454. int
  455. APM_trimlead(apm)
  456. APM apm;
  457. {
  458.     int n;
  459.     int ercode;
  460.  
  461.     apm_errno = APM_OK;
  462.  
  463.     if (apm == (APM)NULL) {
  464.         return (APM_set_errno(APM_ENULL));
  465.     }
  466.  
  467.     if (apm->data == NULL) {
  468.         apm->length = 0;
  469.         return (APM_OK);
  470.     }
  471.  
  472.     ercode = APM_normalize(apm);
  473.     if (ercode < APM_OK) {
  474.         return (APM_set_errno(ercode));
  475.     }
  476.  
  477.     for (n = apm->length; n > 0; --n) {
  478.         if (apm->data[n - 1] != 0) {
  479.             break;
  480.         }
  481.     }
  482.  
  483.     if (n < apm->length) {
  484.         apm->length = n;
  485.     }
  486.  
  487.     return (APM_OK);
  488. }
  489.  
  490. int
  491. APM_trimtrail(apm)
  492. APM apm;
  493. {
  494.     int n;
  495.     int ercode;
  496.  
  497.     apm_errno = APM_OK;
  498.  
  499.     if (apm == (APM)NULL) {
  500.         return (APM_set_errno(APM_ENULL));
  501.     }
  502.  
  503.     if (apm->data == NULL) {
  504.         apm->length = 0;
  505.         apm->dp = 0;
  506.         return (APM_OK);
  507.     }
  508.  
  509.     ercode = APM_normalize(apm);
  510.     if (ercode < APM_OK) {
  511.         return (APM_set_errno(ercode));
  512.     }
  513.  
  514.     for (n = 0; n < apm->dp; ++n) {
  515.         if (apm->data[n] != 0) {
  516.             break;
  517.         }
  518.     }
  519.  
  520.     if (n == 0) {    /* no trailing zeros */
  521.         return (APM_OK);
  522.     }
  523.  
  524.     /*
  525.      * Shift down by 'n', subtracting this from apm->length and
  526.      * apm->dp.
  527.      */
  528.     apm->length -= n;
  529.     apm->dp -= n;
  530.     APM_copy_shorts(apm->data, &(apm->data[n]), apm->length);
  531.     APM_zero_shorts(&(apm->data[apm->length]), n);
  532.  
  533.     return (APM_OK);
  534. }
  535.  
  536. int
  537. APM_trim(apm, lead, trail)
  538. APM apm;
  539. int lead;
  540. int trail;
  541. {
  542.     int ercode = APM_OK;
  543.  
  544.     apm_errno = APM_OK;
  545.  
  546.     if (apm == (APM)NULL) {
  547.         return (APM_set_errno(APM_ENULL));
  548.     }
  549.  
  550.     if (ercode >= APM_OK && lead) {
  551.         ercode = APM_trimlead(apm);
  552.     }
  553.  
  554.     if (ercode >= APM_OK && trail) {
  555.         ercode = APM_trimtrail(apm);
  556.     }
  557.  
  558.     if (ercode >= APM_OK) {
  559.         ercode = APM_normalize(apm);
  560.     }
  561.  
  562.     return (APM_set_errno(ercode));
  563. }
  564.  
  565. int
  566. APM_normalize(value)
  567. APM value;
  568. {
  569.     static short *localData = (short *)NULL;
  570.     static int localLen = 0;
  571.     int len;
  572.     int dp;
  573.     int offset;
  574.     int ercode;
  575.  
  576.     apm_errno = APM_OK;
  577.  
  578.     ercode = APM_val_format(value);
  579.     if (ercode < APM_OK) {
  580.         return (ercode);
  581.     }
  582.     ercode = APM_val_base(value->base);
  583.     if (ercode < APM_OK) {
  584.         return (ercode);
  585.     }
  586.  
  587.     if (value->dp >= 0 && value->length >= value->dp) {
  588.         return (APM_OK);
  589.     }
  590.  
  591.     len = value->length;
  592.     if (value->length < value->dp) {
  593.         len = value->dp;
  594.         dp = value->dp;
  595.         offset = 0;
  596.     }
  597.     else if (value->dp < 0) {
  598.         len = value->length - value->dp;
  599.         dp = 0;
  600.         offset = -(value->dp);
  601.     }
  602.     else {
  603.         len = value->length;
  604.         dp = value->dp;
  605.         offset = 0;
  606.     }
  607.  
  608.     if (len > localLen) {
  609.         int xlen = len;
  610.         if (xlen < 8) {
  611.             xlen = 8;
  612.         }
  613.         localData = (short *)APM_alloc_mem(localLen < 1 ?
  614.                         NULL : localData,
  615.                         xlen, sizeof (short));
  616.         if (localData == (short *)NULL) {
  617.             return (APM_set_errno(APM_ENOMEM));
  618.         }
  619.         localLen = xlen;
  620.     }
  621.  
  622.     APM_zero_shorts(localData, len);
  623.     APM_copy_shorts(localData + offset, value->data, value->length);
  624.  
  625.     ercode = APM_size(value, len);
  626.     if (ercode < APM_OK) {
  627.         return (ercode);
  628.     }
  629.  
  630.     APM_copy_shorts(value->data, localData, len);
  631.  
  632.     value->length = len;
  633.     value->dp = dp;
  634.  
  635.     return (APM_OK);
  636. }
  637.  
  638. int
  639. APM_setdp(result, value, dp)
  640. APM result;
  641. APM value;
  642. int dp;
  643. {
  644.     int oldlen;
  645.     int newlen;
  646.     int voffset;
  647.     int roffset;
  648.     int ercode;
  649.  
  650.     apm_errno = APM_OK;
  651.  
  652.     ercode = APM_val_format(value);
  653.     if (ercode < APM_OK) {
  654.         return (ercode);
  655.     }
  656.     ercode = APM_val_base(value->base);
  657.     if (ercode < APM_OK) {
  658.         return (ercode);
  659.     }
  660.     if (result == value) {
  661.         return (APM_set_errno(APM_EOVERLAP));
  662.     }
  663.  
  664.     ercode = APM_normalize(value);
  665.     if (ercode < APM_OK) {
  666.         return (ercode);
  667.     }
  668.  
  669.     if (dp < 0) {
  670.         dp = value->dp;
  671.     }
  672.  
  673.     oldlen = newlen = value->length;
  674.  
  675.     if (dp <= value->dp) {
  676.         voffset = value->dp - dp;
  677.         roffset = 0;
  678.         oldlen -= voffset;
  679.     }
  680.     else {
  681.         voffset = 0;
  682.         roffset = dp - value->dp;
  683.         newlen += roffset;
  684.     }
  685.  
  686.     ercode = APM_size(result, newlen);
  687.     if (ercode < APM_OK) {
  688.         return(ercode);
  689.     }
  690.  
  691.     APM_zero_shorts(result->data, newlen);
  692.     APM_copy_shorts(result->data + roffset, value->data + voffset, oldlen);
  693.  
  694.     result->sign = SIGNOF(value->sign);
  695.     result->base = value->base;
  696.     result->length = newlen;
  697.     result->dp = dp;
  698.     return (APM_OK);
  699. }
  700.  
  701. int
  702. APM_norm_to_spec(apm)
  703. APM apm;
  704. {
  705.     static APM localApm = (APM)NULL;
  706.     int length;
  707.     int locallen;
  708.     int localdp;
  709.     int ercode;
  710.     int n;
  711.     short sign;
  712.  
  713.     apm_errno = APM_OK;
  714.  
  715.     if (apm == (APM)NULL) {
  716.         return (APM_set_errno(APM_ENULL));
  717.     }
  718.  
  719.     if (apm->base != 10) {
  720.         return (APM_set_errno(APM_EFMT));
  721.     }
  722.  
  723.     length = apm->length;
  724.     sign = SIGNOF(apm->sign);
  725.     locallen = length;
  726.     localdp = ((apm->dp + (SPECIAL_SCALE - 1)) / SPECIAL_SCALE)
  727.              * SPECIAL_SCALE;
  728.     locallen += (localdp - apm->dp);
  729.     locallen = ((locallen + (SPECIAL_SCALE - 1)) / SPECIAL_SCALE)
  730.               * SPECIAL_SCALE;
  731.  
  732.     if (localApm == (APM)NULL) {
  733.         localApm = APM_alloc();
  734.         if (localApm == (APM)NULL) {
  735.             return (APM_set_errno(APM_ENOMEM));
  736.         }
  737.     }
  738.     ercode = APM_size(localApm, locallen / SPECIAL_SCALE);
  739.     if (ercode < APM_OK) {
  740.         return (ercode);
  741.     }
  742.  
  743.     for (n = 0; n < locallen; n += SPECIAL_SCALE) {
  744.         int value = 0;
  745.         int tn = n + (apm->dp - localdp);
  746.         if (tn >= 0 && tn < length) {
  747.             value += apm->data[tn];
  748.         }
  749.         ++tn;
  750.         if (tn >= 0 && tn < length) {
  751.             value += apm->data[tn] * 10;
  752.         }
  753.         ++tn;
  754.         if (tn >= 0 && tn < length) {
  755.             value += apm->data[tn] * 100;
  756.         }
  757.         ++tn;
  758.         if (tn >= 0 && tn < length) {
  759.             value += apm->data[tn] * 1000;
  760.         }
  761.         localApm->data[n / SPECIAL_SCALE] = value;
  762.     }
  763.     localApm->length = locallen / SPECIAL_SCALE;
  764.     localApm->dp = localdp / SPECIAL_SCALE;
  765.     localApm->sign = sign;
  766.     localApm->base = SPECIAL_BASE;
  767.  
  768.     ercode = apm_assign(apm, localApm);
  769.  
  770.     return (ercode);
  771. }
  772.  
  773. int
  774. APM_spec_to_norm(apm)
  775. APM apm;
  776. {
  777.     static APM localApm = (APM)NULL;
  778.     int length;
  779.     int locallen;
  780.     int n;
  781.     int ercode;
  782.     short sign;
  783.  
  784.     apm_errno = APM_OK;
  785.  
  786.     if (apm == (APM)NULL) {
  787.         return (APM_set_errno(APM_ENULL));
  788.     }
  789.  
  790.     if (apm->base != SPECIAL_BASE) {
  791.         return (APM_set_errno(APM_EFMT));
  792.     }
  793.  
  794.     ercode = APM_trim(apm, 1, 1);
  795.     if (ercode < APM_OK) {
  796.         return (APM_set_errno(APM_EFMT));
  797.     }
  798.  
  799.     length = apm->length;
  800.     sign = SIGNOF(apm->sign);
  801.     if (localApm == (APM)NULL) {
  802.         localApm = APM_alloc();
  803.         if (localApm == (APM)NULL) {
  804.             return (APM_set_errno(APM_ENOMEM));
  805.         }
  806.     }
  807.     locallen = length * SPECIAL_SCALE;
  808.     ercode = APM_size(localApm, locallen);
  809.     if (ercode < APM_OK) {
  810.         return (ercode);
  811.     }
  812.     localApm->length = locallen;
  813.     localApm->sign = sign;
  814.     localApm->dp = apm->dp * SPECIAL_SCALE;
  815.     localApm->base = 10;
  816.  
  817.     for (n = 0; n < length; ++n) {
  818.         int tn = n * SPECIAL_SCALE;
  819.         int value = apm->data[n];
  820.         int newvalue = value / 10;
  821.         localApm->data[tn] = value - (newvalue * 10);
  822.         value = newvalue;
  823.         newvalue = value / 10;
  824.         localApm->data[tn + 1] = value - (newvalue * 10);
  825.         value = newvalue;
  826.         newvalue = value / 10;
  827.         localApm->data[tn + 2] = value - (newvalue * 10);
  828.         value = newvalue;
  829.         newvalue = value / 10;
  830.         localApm->data[tn + 3] = value - (newvalue * 10);
  831.     }
  832.     ercode = apm_assign(apm, localApm);
  833.     if (ercode >= APM_OK) {
  834.         ercode = APM_trim(apm, 1, 1);
  835.     }
  836.     return (ercode);
  837. }
  838.  
  839. int
  840. APM_size(apm, len)
  841. APM apm;
  842. int len;
  843. {
  844.     short *temp;
  845.     apm_errno = APM_OK;
  846.  
  847.     if (len < 0) {
  848.         return (APM_set_errno(APM_EPARM));
  849.     }
  850.     if (apm == (APM)NULL) {
  851.         return (APM_set_errno(APM_ENULL));
  852.     }
  853.  
  854.     if (len > apm->alloclen || apm->alloclen < 1) {
  855.         if (len < 8) {
  856.             len = 8;
  857.         }
  858.         if (apm->alloclen < 1) {
  859.             temp = (short *)APM_alloc_mem(NULL, len,
  860.                            sizeof (short));
  861.         }
  862.         else {
  863.             temp = (short *)APM_alloc_mem(apm->data, len,
  864.                            sizeof (short));
  865.         }
  866.         if (temp == (short *)NULL) {
  867.             return (APM_set_errno(APM_ENOMEM));
  868.         }
  869.         apm->data = temp;
  870.         apm->alloclen = len;
  871.     }
  872.  
  873.     return (APM_OK);
  874. }
  875.  
  876. int
  877. APM_parse_string(apm, string, base)
  878. APM apm;
  879. char *string;
  880. short base;
  881. {
  882.     static char *localString = NULL;
  883.     static int localLen = 0;
  884.     int ercode;
  885.     int len;
  886.     int dp;
  887.     int special = 0;
  888.     short sign = 1;
  889.     char *temp;
  890.     short *bp;
  891.     char *tp;
  892.  
  893.     apm_errno = APM_OK;
  894.  
  895.     if (apm == (APM)NULL) {
  896.         return (APM_set_errno(APM_ENULL));
  897.     }
  898.  
  899.     if (string == NULL) {
  900.         return (APM_set_errno(APM_ENULLVAL));
  901.     }
  902.  
  903.     if (base == 0) {
  904.         base = SPECIAL_BASE;
  905.     }
  906.  
  907.     ercode = APM_val_base(base);
  908.     if (ercode < APM_OK) {
  909.         return (ercode);
  910.     }
  911.  
  912.     if (base == SPECIAL_BASE) {
  913.         special = 1;
  914.         base = 10;
  915.     }
  916.  
  917.     len = strlen(string);
  918.     if (localString == NULL || localLen < len + 1) {
  919.         int xlen = len + 1;
  920.         if (xlen < 16) {
  921.             xlen = 16;
  922.         }
  923.         localString = APM_alloc_mem(localLen < 1 ? NULL : localString,
  924.                      xlen, sizeof (char));
  925.         if (localString == NULL) {
  926.             return (APM_set_errno(APM_ENOMEM));
  927.         }
  928.         localLen = xlen;
  929.     }
  930.     APM_copy_bytes(localString, string, len + 1);
  931.  
  932.     temp = APM_trim_string(APM_left_justify(localString, " \t"));
  933.     if (*temp == '-') {
  934.         sign = -1;
  935.         ++temp;
  936.     }
  937.     else if (*temp == '+') {
  938.         sign = 1;
  939.         ++temp;
  940.     }
  941.  
  942.     dp = APM_radix_pos(temp, base);
  943.     if (dp < 0) {
  944.         return (APM_set_errno(APM_EFMT));
  945.     }
  946.  
  947.     len = strlen(temp);
  948.     if (dp > 0) {
  949.         char *sp = &temp[dp];
  950.         do {
  951.             sp[-1] = *sp;
  952.         } while (*sp++ != '\0');
  953.         --len;
  954.         dp = len - (dp - 1);
  955.     }
  956.  
  957.     ercode = APM_size(apm, len);
  958.     if (ercode < APM_OK) {
  959.         return (ercode);
  960.     }
  961.  
  962.     apm->base = base;
  963.     apm->length = len;
  964.     apm->dp = dp;
  965.     apm->sign = SIGNOF(sign);
  966.     for (bp = apm->data, tp = &temp[len]; tp-- > temp; ++bp) {
  967.         *bp = APM_get_digit(*tp, apm->base);
  968.     }
  969.  
  970.     if (special) {
  971.         ercode = APM_norm_to_spec(apm);
  972.     }
  973.  
  974.     if (ercode >= APM_OK) {
  975.         ercode = APM_trim(apm, 1, 1);
  976.     }
  977.  
  978.     return (ercode);
  979. }
  980.  
  981. char *
  982. APM_build_string(string, data, length, dpos)
  983. char *string;
  984. short *data;
  985. int length;
  986. int dpos;
  987. {
  988.     short *bp;
  989.     int n = 0;
  990.  
  991.     for (bp = &(data[length]); bp-- > data; ++n) {
  992.         if (n == dpos) {
  993.             *string++ = '.';
  994.         }
  995.         *string++ = APM_digits[*bp];
  996.     }
  997.     return (string);
  998. }
  999.  
  1000. int
  1001. APM_parse_long(apm, value, base)
  1002. APM apm;
  1003. long value;
  1004. short base;
  1005. {
  1006.     int ercode;
  1007.     int n;
  1008.     long temp;
  1009.  
  1010.     apm_errno = APM_OK;
  1011.  
  1012.     if (apm == (APM)NULL) {
  1013.         return (APM_set_errno(APM_ENULL));
  1014.     }
  1015.  
  1016.     if (base == 0) {
  1017.         base = SPECIAL_BASE;
  1018.     }
  1019.     ercode = APM_val_base(base);
  1020.     if (ercode < APM_OK) {
  1021.         return (ercode);
  1022.     }
  1023.  
  1024.     apm->sign = 1;
  1025.     apm->base = base;
  1026.     apm->dp = 0;
  1027.  
  1028.     if (value < 0) {
  1029.         apm->sign = -1;
  1030.         value = -value;
  1031.     }
  1032.  
  1033.     for (apm->length = 0, temp = value; temp != 0; temp /= base) {
  1034.         ++(apm->length);
  1035.     }
  1036.     if (apm->length == 0) {
  1037.         return (APM_OK);
  1038.     }
  1039.  
  1040.     ercode = APM_size(apm, apm->length);
  1041.     if (ercode < APM_OK) {
  1042.         return (ercode);
  1043.     }
  1044.  
  1045.     for (n = 0; n < apm->length; ++n) {
  1046.         apm->data[n] = value % base;
  1047.         value /= base;
  1048.     }
  1049.  
  1050.     return (APM_OK);
  1051. }
  1052.  
  1053. short
  1054. APM_array_add(result, addend, length, base)
  1055. short *result;
  1056. short *addend;
  1057. int length;
  1058. short base;
  1059. {
  1060.     int n;
  1061.     short tempval;
  1062.     short carry = 0;
  1063.  
  1064.     for (n = 0; n < length; ++n) {
  1065.         tempval = result[n] + carry + addend[n];
  1066.         result[n] = tempval % base;
  1067.         carry = tempval / base;
  1068.     }
  1069.  
  1070.     return (carry);
  1071. }
  1072.  
  1073. short
  1074. APM_array_sub(result, subtrahend, length, base)
  1075. short *result;
  1076. short *subtrahend;
  1077. int length;
  1078. short base;
  1079. {
  1080.     int n;
  1081.     short tempval;
  1082.     short borrow = 0;
  1083.  
  1084.     for (n = 0; n < length; ++n) {
  1085.         tempval = (result[n] + borrow) - subtrahend[n];
  1086.         if (tempval < 0) {
  1087.             result[n] = tempval + base;
  1088.             borrow = -1;
  1089.         }
  1090.         else {
  1091.             result[n] = tempval;
  1092.             borrow = 0;
  1093.         }
  1094.     }
  1095.     return (borrow);
  1096. }
  1097.  
  1098. short
  1099. APM_scalar_mul(result, multiplicand, length, multiplier, base)
  1100. short *result;
  1101. short *multiplicand;
  1102. int length;
  1103. short multiplier;
  1104. short base;
  1105. {
  1106.     int n;
  1107.     long tempval;
  1108.     short carry = 0;
  1109.  
  1110.     for (n = 0; n < length; ++n) {
  1111.         tempval = multiplicand[n];
  1112.         tempval *= multiplier;
  1113.         tempval += carry;
  1114.         result[n] = (short)(tempval % base);
  1115.         carry = (short)(tempval / base);
  1116.     }
  1117.     return (carry);
  1118. }
  1119.  
  1120. int
  1121. APM_scalar_div(result, dividend, length, dp, sign, base, divisor)
  1122. APM result;
  1123. short *dividend;
  1124. int length;
  1125. int dp;
  1126. short sign;
  1127. short base;
  1128. short divisor;
  1129. {
  1130.     static APM apmDividend = (APM)NULL;
  1131.     static APM apmDivisor = (APM)NULL;
  1132.     int ercode;
  1133.  
  1134.     apm_errno = APM_OK;
  1135.  
  1136.     if (result == (APM)NULL || dividend == (short *)NULL) {
  1137.         return (APM_set_errno(APM_ENULL));
  1138.     }
  1139.  
  1140.     if (apmDividend == (APM)NULL) {
  1141.         apmDividend = APM_alloc();
  1142.         if (apmDividend == (APM)NULL) {
  1143.             return (APM_set_errno(APM_ENOMEM));
  1144.         }
  1145.     }
  1146.     if (apmDivisor == (APM)NULL) {
  1147.         apmDivisor = APM_alloc();
  1148.         if (apmDivisor == (APM)NULL) {
  1149.             return (APM_set_errno(APM_ENOMEM));
  1150.         }
  1151.         ercode = APM_size(apmDivisor, 1);
  1152.         if (ercode < APM_OK) {
  1153.             return (ercode);
  1154.         }
  1155.         apmDivisor->length = 1;
  1156.         apmDivisor->dp = 0;
  1157.     }
  1158.  
  1159.     ercode = APM_size(apmDividend, length);
  1160.     if (ercode < APM_OK) {
  1161.         return (ercode);
  1162.     }
  1163.     APM_copy_shorts(apmDividend->data, dividend, length);
  1164.  
  1165.     apmDividend->sign = sign;
  1166.     apmDividend->length = length;
  1167.     apmDividend->dp = dp;
  1168.     apmDividend->base = base;
  1169.  
  1170.     if (divisor < 0) {
  1171.         apmDivisor->data[0] = -divisor;
  1172.         apmDivisor->sign = -1;
  1173.     }
  1174.     else {
  1175.         apmDivisor->data[0] = divisor;
  1176.         apmDivisor->sign = 1;
  1177.     }
  1178.     apmDivisor->base = base;
  1179.  
  1180.     return (apm_divide(result, length, (APM)NULL,
  1181.                apmDividend, apmDivisor));
  1182. }
  1183.  
  1184. int
  1185. APM_copy_bytes(to, from, num)
  1186. register char *to;
  1187. register char *from;
  1188. int num;
  1189. {
  1190.     register int n = num;
  1191.  
  1192.     if (to == NULL || from == NULL || num <= 0) {
  1193.         return (0);
  1194.     }
  1195.  
  1196.     if (to > from) {
  1197.         to += n;
  1198.         from += n;
  1199.         while (n-- > 0) {
  1200.             *(--to) = *(--from);
  1201.         }
  1202.     }
  1203.     else if (to < from) {
  1204.         while (n-- > 0) {
  1205.             *to++ = *from++;
  1206.         }
  1207.     }
  1208.  
  1209.     return (num);
  1210. }
  1211.  
  1212. int
  1213. APM_zero_bytes(to, num)
  1214. register char *to;
  1215. int num;
  1216. {
  1217.     register int n = num;
  1218.  
  1219.     if (to == NULL || num <= 0) {
  1220.         return (0);
  1221.     }
  1222.  
  1223.     while (n-- > 0) {
  1224.         *to++ = 0;
  1225.     }
  1226.  
  1227.     return (num);
  1228. }
  1229.  
  1230. int
  1231. APM_copy_shorts(to, from, num)
  1232. short *to;
  1233. short *from;
  1234. int num;
  1235. {
  1236.     return (APM_copy_bytes((char *)to, (char *)from,
  1237.                 num * sizeof (short)) / sizeof (short));
  1238. }
  1239.  
  1240. int
  1241. APM_zero_shorts(to, num)
  1242. short *to;
  1243. int num;
  1244. {
  1245.     return (APM_zero_bytes((char *)to,
  1246.                 num * sizeof (short)) / sizeof (short));
  1247. }
  1248.  
  1249. char *
  1250. APM_index(s, c)
  1251. register char *s;
  1252. int c;
  1253. {
  1254.     if (s != NULL) {
  1255.         for (; *s != '\0'; ++s) {
  1256.             if (*s == (char)c) {
  1257.                 return (s);
  1258.             }
  1259.         }
  1260.     }
  1261.  
  1262.     return (NULL);
  1263. }
  1264.  
  1265. void
  1266. APM_debug(va_alist)
  1267. va_dcl
  1268. {
  1269.     va_list ap;
  1270.     char *format;
  1271.     FILE *debug_file = apm_debug_file(NULL);
  1272.  
  1273.     if (debug_file == (FILE *)NULL) {
  1274.         return;
  1275.     }
  1276.  
  1277.     (void)apm_debug_file(debug_file);
  1278.  
  1279.     va_start(ap);
  1280.  
  1281.     format = va_arg(ap, char *);
  1282.     if (format == NULL) {
  1283.         return;
  1284.     }
  1285.  
  1286.     vfprintf(debug_file, format, ap);
  1287.     fflush(debug_file);
  1288.  
  1289.     va_end(ap);
  1290. }
  1291.