[comp.sources.misc] v04i117: Arbitrary Precision Math Library -- 4 of 5

ljz@fxgrp.UUCP (Lloyd Zusman) (10/07/88)

Posting-number: Volume 4, Issue 117
Submitted-by: "Lloyd Zusman" <ljz@fxgrp.UUCP>
Archive-name: apml/Part4

Enclosed you will find the Arbitrary Precision Math Library (4 of 5)

Please post this to the comp.sources.misc newsgroup.

I finally got this into good enough shape to send out to the net. To use,
just unshar the 5 pieces, read the README file, possibly alter the makefiles
to conform to your system's conventions, and then type 'make test'.

Good luck!

--
  Lloyd Zusman                  Internet:  ljz@fx.com
  Master Byte Software                  or ljz%fx.com@ames.arc.nasa.gov
  Los Gatos, California                 or fxgrp!ljz@ames.arc.nasa.gov
  "We take things well in hand."    uucp:  ...!ames!fxgrp!ljz
  [ our Internet connection is down: use uucp or mail to the entry above it ]

#--------------------------Cut Here--------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before the "#! /bin/sh" line,
# then unpack it by saving it in a file and typing "sh file."
#
# Wrapped by Lloyd Zusman (ljz) at fxgrp on Wed Oct  5 12:41:51 1988
#
# unpacks with default permissions
#
# Contents : muldiv.c utils.c
#
if `test ! -s muldiv.c`
then
echo "x - muldiv.c"
sed 's/^X//' > muldiv.c << '@\END_OF_FILE_muldiv.c'
X/******************************************************************************
X
X	Arbitrary Precision Math Library General Public License
X		    (Written October 5, 1988)
X
X Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
X Gatos, California.  Everyone is permitted to copy and distribute
X verbatim copies of this license, but changing it is not allowed.
X You can also use this wording to make the terms for other programs.
X
X The wording of this license is based on that of the
X "GNU EMACS GENERAL PUBLIC LICENSE" by Richard Stallman,
X Copyright (C) 1985, 1987, 1988, version of February 11, 1988,
X but since some of the text has been changed, please be sure to
X READ THIS CAREFULLY!
X
X  This general public license is intended to give everyone the right
Xto share the Arbitrary Precision Math Library (hereinafter referred to
Xas the "APM Library").  To make sure that you get the rights we want
Xyou to have, I need to make restrictions that forbid anyone to deny
Xyou these rights or to ask you to surrender the rights.
X
X  Specifically, we want to make sure that you have the right to give
Xaway copies of the APM Library, that you receive source code or else
Xcan get it if you want it, that you can change the APM Library or use
Xpieces of it in new programs, and that you know you can do these
Xthings.
X
X  To make sure that everyone has such rights, we have to forbid you to
Xdeprive anyone else of these rights.  For example, if you distribute
Xcopies of the APM Library, you must give the recipients all the
Xrights that you have.  You must make sure that they, too, receive or
Xcan get the source code.  And you must tell them their rights.
X
X  Also, for our own protection, we must make certain that everyone
Xfinds out that there is no warranty for the APM Library.  If the APM
XLibrary is modified by someone else and passed on, we want its
Xrecipients to know that what they have is not what we distributed, so
Xthat any problems introduced by others will not reflect on our
Xreputation.
X
X  Therefore we (Lloyd Zusman and Master Byte Software) make the
Xfollowing terms which say what you must do to be allowed to
Xdistribute or change the APM Library.
X
X			COPYING POLICIES
X
X1. You may copy and distribute verbatim copies of the APM Library
Xsource code as you receive it, in any medium, provided that you
Xconspicuously and appropriately publish on each copy a valid copyright
Xnotice "Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
XGatos, California" (or with whatever year is appropriate); keep intact
Xthe notices on all files that refer to this License Agreement and to
Xthe absence of any warranty; and give any other recipients of the the
XAPM Library program a copy of this License Agreement along with the
Xprogram.  You may charge a distribution fee for the physical act of
Xtransferring a copy.
X
X  2. You may modify your copy or copies of the APM Library source code or
Xany portion of it, and copy and distribute such modifications under
Xthe terms of Paragraph 1 above, provided that you also do the following:
X
X    a) cause the modified files to carry prominent notices stating
X    that you changed the files and the date of any change; and
X
X    b) cause the whole of any work that you distribute or publish, that in
X    whole or in part contains or is a derivative of the APM Library or any
X    part thereof, to be licensed to all third parties on terms identical
X    to those contained in this License Agreement (except that you may
X    choose to grant more extensive warranty protection to some or all
X    third parties, at your option).
X
X    c) You may charge a distribution fee for the physical act of
X    transferring a copy, and you may at your option offer warranty
X    protection in exchange for a fee.
X
X    d) You may not charge a license fee for the whole of any work that
X    you distribute or publish, that in whole or in part contains or is
X    a derivative of the APM library or any part thereof, without the
X    express written permission of Lloyd Zusman and Master Byte Software;
X    whether this permission is granted for free or in return for goods
X    services, royalties, or other compensation will be determined
X    solely by Lloyd Zusman and Master Byte Software.
X
XMere aggregation of another unrelated program with this program (or its
Xderivative) on a volume of a storage or distribution medium does not bring
Xthe other program under the scope of these terms.
X
X  3. You may copy and distribute the APM Library (or a portion or
Xderivative of it, under Paragraph 2) in object code or executable form
Xunder all the terms of Paragraphs 1 and 2 above provided that you also
Xdo one of the following:
X
X    a) accompany it with the complete corresponding machine-readable
X    source code, which must be distributed under the terms of
X    Paragraphs 1 and 2 above; or,
X
X    b) accompany it with a written offer, valid for at least three
X    years, to give any third party free (except for a nominal
X    shipping charge) a complete machine-readable copy of the
X    corresponding source code, to be distributed under the terms of
X    Paragraphs 1 and 2 above; or,
X
X    c) accompany it with the information you received as to where the
X    corresponding source code may be obtained.  (This alternative is
X    allowed only for noncommercial distribution and only if you
X    received the program in object code or executable form alone.)
X
XFor an executable file, complete source code means all the source code
Xfor all modules it contains; but, as a special exception, it need not
Xinclude source code for modules which are standard libraries that
Xaccompany the operating system on which the executable file runs.
X
X  4. You may not copy, sublicense, distribute or transfer the APM
XLibrary except as expressly provided under this License Agreement.
XAny attempt otherwise to copy, sublicense, distribute or transfer the
XAPM Library is void and your rights to use the APM Library under this
XLicense agreement shall be automatically terminated.  However, parties
Xwho have received computer software programs from you with this
XLicense Agreement will not have their licenses terminated so long as
Xsuch parties remain in full compliance.
X
X  5. If you wish to incorporate parts of the APM Library into other
Xprograms whose distribution conditions are different, write to Lloyd
XZusman at Master Byte Software.  We have not yet worked out a simple
Xrule that can be stated here, but we will often permit this.  We will
Xbe guided by the goals of (1) preserving the free status of all
Xderivatives of our free software; of (2) promoting the sharing and
Xreuse of software; and of (3) not allowing anyone to profit from the
Xuse of our software without us also having the opportunity to share
Xin these profits.
X
XYour comments and suggestions about our licensing policies and our
Xsoftware are welcome!  Please contact Lloyd Zusman, Master Byte
XSoftware, 127 Wilder Ave., Los Gatos, California 95030, or call
X(408) 395-5693.
X
X			   NO WARRANTY
X
X  BECAUSE THE APM LIBRARY IS LICENSED FREE OF CHARGE, WE PROVIDE
XABSOLUTELY NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE
XLAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING, MASTER BYTE SOFTWARE,
XLLOYD ZUSMAN AND/OR OTHER PARTIES PROVIDE THE APM LIBRARY "AS IS"
XWITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
XBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
XFITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
XAND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE THE APM
XLIBRARY PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
XSERVICING, REPAIR OR CORRECTION.
X
X  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL MASTER BYTE
XSOFTWARE, LLOYD ZUSMAN, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND
XREDISTRIBUTE THE APM LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
XDAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL,
XINCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
XINABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
XBEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
XFAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
XMASTER BYTE SOFTWARE) THE PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF
XTHE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
X
X******************************************************************************/
X
X
X/*
X * Multiplication and division routines for the APM library.
X *
X * $Log:	muldiv.c,v $
X * Revision 1.0  88/10/05  12:38:15  ljz
X * Initial release.
X * 
X */
X#ifndef lint
Xstatic char rcsid[] = "$Header: muldiv.c,v 1.0 88/10/05 12:38:15 ljz Exp $";
X#endif /* ! lint */
X
X#include <stdio.h>
X#include "apm.h"
X#include "apmlocal.h"
X
Xint
Xapm_multiply(result, num1, num2)
XAPM result;
XAPM num1;
XAPM num2;
X{
X	int length1;
X	int length2;
X	int len;
X	int dp;
X	int n1;
X	int n2;
X	int sum;
X	short sign;
X	short base;
X	short carry;
X	long tempval;
X
X	apm_errno = APM_OK;
X
X	ERR_RETURN(APM_val_format(result));
X	ERR_RETURN(apm_validate(num1));
X	ERR_RETURN(apm_validate(num2));
X
X	if (num1->base != num2->base) {
X		return (APM_error(APM_EBASE));
X	}
X
X	if (result == num1 || result == num2) {
X		return (APM_error(APM_EOVERLAP));
X	}
X
X	base = num1->base;
X
X	sign = SIGNOF(num1->sign) * SIGNOF(num2->sign);
X
X	ERR_RETURN(APM_trim(num1, 1, 1));
X	ERR_RETURN(APM_trim(num2, 1, 1));
X
X	length1 = num1->length;
X	length2 = num2->length;
X	
X	len = length1 + length2;
X	dp = num1->dp + num2->dp;
X
X	ERR_RETURN(APM_size(result, len));
X
X	APM_zero_shorts(result->data, len);
X
X	for (n1 = 0; n1 < length1; ++n1) {
X		carry = 0;
X		sum = n1;
X		for (n2 = 0; n2 < length2; ++n2, ++sum) {
X			tempval = num1->data[n1];
X			tempval *= num2->data[n2];
X			tempval += result->data[sum] + carry;
X			result->data[sum] =
X			    (short)(tempval % base);
X			carry =
X			    (short)(tempval / base);
X		}
X		result->data[sum] = carry;
X	}
X
X	result->length = len;
X	result->dp = dp;
X	result->base = base;
X	result->sign = sign;
X
X	return (APM_error(APM_trim(result, 1, 1)));
X}
X
X/*
X * For division, I use the algorithm described in Knuth, "The Art of
X * Computer Programming, Volume 2, Seminumerical Algorithms", second
X * edition, pp. 255-260.
X */
Xint
Xapm_divide(result, frac_precision, remainder, num1, num2)
XAPM result;
Xint frac_precision;
XAPM remainder;
XAPM num1;
XAPM num2;
X{
X	static APM temp = (APM)NULL;
X	static short *dividend = (short *)NULL;
X	static int dividendLength = 0;
X	static short *divisor = (short *)NULL;
X	static short *xdivisor = (short *)NULL;
X	static int divisorLength = 0;
X
X	int i;
X	int j;
X	int n;
X	int uJ;
X	int vJ;
X	int M;
X	int N;
X	int MplusN;
X	int Nplus1;
X	int MplusNplus1;
X	int length1;
X	int length2;
X	int offset;
X	int left;
X	int frac;
X	short divN1;
X	short divN2;
X	short sign;
X	short base;
X	short scaleFactor;
X	short borrow;
X	short qHat;
X	long temp1;
X	long temp2;
X	long temp3;
X
X	apm_errno = APM_OK;
X
X	if (frac_precision <= 0) {
X		return (APM_set_errno(APM_EPARM));
X	}
X
X	ERR_RETURN(APM_val_format(result));
X	if (remainder != NULL) {
X		ERR_RETURN(APM_val_format(remainder));
X	}
X	ERR_RETURN(apm_validate(num1));
X	ERR_RETURN(apm_validate(num2));
X
X	if (result == remainder || result == num1 || result == num2) {
X		return (APM_error(APM_EOVERLAP));
X	}
X	if (remainder == num1 || remainder == num2) {
X		return (APM_error(APM_EOVERLAP));
X	}
X
X	base = num1->base;
X
X	ERR_RETURN(APM_trim(num2, 1, 1));
X	if (num2->length <= 0) {
X		/*
X		 * Division by zero.
X		 */
X		result->length = 0;
X		result->dp = 0;
X		result->base = base;
X		if (remainder != (APM)NULL) {
X			remainder->length = 0;
X			remainder->dp = 0;
X			remainder->base = base;
X		}
X		return (APM_error(APM_WDIVBYZERO));
X	}
X
X	ERR_RETURN(APM_trim(num1, 1, 1));
X	if (num1->length <= 0) {
X		/*
X		 * Dividend is zero, so result is zero.
X		 */
X		result->length = 0;
X		result->dp = 0;
X		result->base = base;
X		if (remainder != (APM)NULL) {
X			remainder->length = 0;
X			remainder->dp = 0;
X			remainder->base = base;
X		}
X		return (APM_OK);
X	}
X
X	sign = num1->sign * num2->sign;
X
X	length1 = num1->length;
X	length2 = num2->length;
X	for (offset = length2; offset > 0; --offset) {
X		if (num2->data[offset - 1] != 0) {
X			break;
X		}
X	}
X
X	offset = length2 - offset;
X
X	frac = frac_precision;
X	if (base == SPECIAL_BASE) {
X		frac = (frac + (SPECIAL_SCALE - 1)) / SPECIAL_SCALE;
X	}
X
X	
X	left = (length1 - num1->dp) - (length2 - num1->dp);
X	if (left < 0) {
X		left = 0;
X	}
X
X	M = frac + left + 1;
X	if (M < length1) {
X		M = length1;
X	}
X
X	N = (length2 - offset) + 1;
X	Nplus1 = N + 1;
X	MplusN = M + N;
X	MplusNplus1 = MplusN + 1;
X
X	if (temp == (APM)NULL) {
X		temp = APM_alloc();
X		if (temp == (APM)NULL) {
X			return (APM_error(APM_ENOMEM));
X		}
X	}
X
X	ERR_RETURN(APM_size(temp, M + 1));
X
X	if (MplusNplus1 > dividendLength) {
X		int xlen = MplusNplus1;
X		if (xlen < 8) {
X			xlen = 8;
X		}
X		if (dividendLength < 1) {
X			dividend = (short *)APM_alloc_mem(NULL, xlen,
X					    sizeof (short));
X		}
X		else {
X			dividend = (short *)APM_alloc_mem(dividend, xlen,
X					    sizeof (short));
X		}
X		if (dividend == (short *)NULL) {
X			return (APM_error(APM_ENOMEM));
X		}
X		dividendLength = xlen;
X	}
X
X	if (Nplus1 > divisorLength) {
X		int xlen = Nplus1;
X		if (xlen < 8) {
X			xlen = 8;
X		}
X		if (divisorLength < 1) {
X			divisor = (short *)APM_alloc_mem(NULL, xlen,
X						      sizeof (short));
X		}
X		else {
X			divisor = (short *)APM_alloc_mem(divisor, xlen,
X						      sizeof (short));
X		}
X		if (divisor == (short *)NULL) {
X			return (APM_error(APM_ENOMEM));
X		}
X		if (divisorLength < 1) {
X			xdivisor = (short *)APM_alloc_mem(NULL, xlen,
X						       sizeof (short));
X		}
X		else {
X			xdivisor = (short *)APM_alloc_mem(xdivisor, xlen,
X						       sizeof (short));
X		}
X		if (xdivisor == (short *)NULL) {
X			return (APM_error(APM_ENOMEM));
X		}
X		divisorLength = xlen;
X	}
X
X	i = MplusN - length1;
X
X	APM_zero_shorts(dividend, i);
X	APM_copy_shorts(&dividend[i], num1->data, length1);
X
X	divisor[0] = 0;
X	APM_copy_shorts(&divisor[1], num2->data, length2 - offset);
X
X	/*
X	 * Knuth: step D1.
X	 */
X	scaleFactor = base / (divisor[N - 1] + 1);
X	if (scaleFactor <= 1) {
X		dividend[MplusN] = 0;
X	}
X	else {
X		dividend[MplusN] = APM_scalar_mul(dividend, dividend,
X						       MplusN,
X						       scaleFactor, base);
X		APM_scalar_mul(divisor, divisor, N, scaleFactor, base);
X	}
X
X	divN1 = divisor[N - 1];
X	divN2 = divisor[N - 2];
X
X	/*
X	 * Knuth: steps D2 and D7.
X	 */
X	for (j = 0, vJ = M, uJ = MplusN; j <= M; ++j, --vJ, --uJ) {
X		/*
X		 * Knuth: step D3.
X		 */
X		temp1 = dividend[uJ];
X		temp1 *= base;
X		temp1 += dividend[uJ - 1];
X
X		if (dividend[uJ] == divN1) {
X			qHat = base - 1;
X		}
X		else {
X			temp2 = temp1 / divN1;
X			qHat = (short)temp2;
X		}
X
X		for (;;) {
X			temp2 = divN2;
X			temp2 *= qHat;
X
X			temp3 = divN1;
X			temp3 *= qHat;
X			temp3 = temp1 - temp3;
X			temp3 *= base;
X			temp3 += dividend[uJ - 2];
X
X			if (temp2 > temp3) {
X				--qHat;
X			}
X			else {
X				break;
X			}
X		}
X
X		/*
X		 * Knuth: step D4.
X		 */
X		xdivisor[N] = APM_scalar_mul(xdivisor, divisor, N, qHat,
X						  base);
X		borrow = APM_array_sub(&(dividend[vJ]), xdivisor,
X			       Nplus1, base);
X
X		/*
X		 * Knuth: step D5.
X		 */
X		if (borrow == 0) {
X			temp->data[vJ] = qHat;
X		}
X		else {
X			/*
X			 * Knuth: step D6.
X			 */
X			temp->data[vJ] = qHat - 1;
X			divisor[N] = 0;
X			APM_array_add(&(dividend[vJ]), divisor, Nplus1, base);
X		}
X	}
X
X	/*
X	 * Knuth: step D8.
X	 */
X	temp->length = M + 1;
X	temp->dp = (M - offset) -
X	    ((length1 - num1->dp) - (length2 - num2->dp));
X	temp->base = base;
X	temp->sign = sign;
X
X	ERR_RETURN(apm_round(result, temp, frac_precision));
X	ERR_RETURN(APM_trim(result, 1, 1));
X
X	if (remainder != (APM)NULL) {
X		ERR_RETURN(APM_size(temp, length2));
X		if (scaleFactor > 1) {
X			ERR_RETURN(APM_scalar_div(temp, &dividend[1],
X						     length2,
X						     num2->dp,
X						     num2->sign,
X						     base, scaleFactor));
X		}
X		else {
X			temp->length = length2;
X			temp->dp = num2->dp;
X			temp->sign = num2->sign;
X			temp->base = base;
X			APM_copy_shorts(temp->data, &dividend[1], length2);
X		}
X		ERR_RETURN(apm_round(remainder, temp, frac_precision));
X		ERR_RETURN(APM_trim(remainder, 1, 1));
X	}
X
X	return (APM_OK);
X}
@\END_OF_FILE_muldiv.c
else
  echo "shar: Will not over write muldiv.c"
fi
if `test ! -s utils.c`
then
echo "x - utils.c"
sed 's/^X//' > utils.c << '@\END_OF_FILE_utils.c'
X/******************************************************************************
X
X	Arbitrary Precision Math Library General Public License
X		    (Written October 5, 1988)
X
X Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
X Gatos, California.  Everyone is permitted to copy and distribute
X verbatim copies of this license, but changing it is not allowed.
X You can also use this wording to make the terms for other programs.
X
X The wording of this license is based on that of the
X "GNU EMACS GENERAL PUBLIC LICENSE" by Richard Stallman,
X Copyright (C) 1985, 1987, 1988, version of February 11, 1988,
X but since some of the text has been changed, please be sure to
X READ THIS CAREFULLY!
X
X  This general public license is intended to give everyone the right
Xto share the Arbitrary Precision Math Library (hereinafter referred to
Xas the "APM Library").  To make sure that you get the rights we want
Xyou to have, I need to make restrictions that forbid anyone to deny
Xyou these rights or to ask you to surrender the rights.
X
X  Specifically, we want to make sure that you have the right to give
Xaway copies of the APM Library, that you receive source code or else
Xcan get it if you want it, that you can change the APM Library or use
Xpieces of it in new programs, and that you know you can do these
Xthings.
X
X  To make sure that everyone has such rights, we have to forbid you to
Xdeprive anyone else of these rights.  For example, if you distribute
Xcopies of the APM Library, you must give the recipients all the
Xrights that you have.  You must make sure that they, too, receive or
Xcan get the source code.  And you must tell them their rights.
X
X  Also, for our own protection, we must make certain that everyone
Xfinds out that there is no warranty for the APM Library.  If the APM
XLibrary is modified by someone else and passed on, we want its
Xrecipients to know that what they have is not what we distributed, so
Xthat any problems introduced by others will not reflect on our
Xreputation.
X
X  Therefore we (Lloyd Zusman and Master Byte Software) make the
Xfollowing terms which say what you must do to be allowed to
Xdistribute or change the APM Library.
X
X			COPYING POLICIES
X
X1. You may copy and distribute verbatim copies of the APM Library
Xsource code as you receive it, in any medium, provided that you
Xconspicuously and appropriately publish on each copy a valid copyright
Xnotice "Copyright (C) 1988 Lloyd Zusman, Master Byte Software, Los
XGatos, California" (or with whatever year is appropriate); keep intact
Xthe notices on all files that refer to this License Agreement and to
Xthe absence of any warranty; and give any other recipients of the the
XAPM Library program a copy of this License Agreement along with the
Xprogram.  You may charge a distribution fee for the physical act of
Xtransferring a copy.
X
X  2. You may modify your copy or copies of the APM Library source code or
Xany portion of it, and copy and distribute such modifications under
Xthe terms of Paragraph 1 above, provided that you also do the following:
X
X    a) cause the modified files to carry prominent notices stating
X    that you changed the files and the date of any change; and
X
X    b) cause the whole of any work that you distribute or publish, that in
X    whole or in part contains or is a derivative of the APM Library or any
X    part thereof, to be licensed to all third parties on terms identical
X    to those contained in this License Agreement (except that you may
X    choose to grant more extensive warranty protection to some or all
X    third parties, at your option).
X
X    c) You may charge a distribution fee for the physical act of
X    transferring a copy, and you may at your option offer warranty
X    protection in exchange for a fee.
X
X    d) You may not charge a license fee for the whole of any work that
X    you distribute or publish, that in whole or in part contains or is
X    a derivative of the APM library or any part thereof, without the
X    express written permission of Lloyd Zusman and Master Byte Software;
X    whether this permission is granted for free or in return for goods
X    services, royalties, or other compensation will be determined
X    solely by Lloyd Zusman and Master Byte Software.
X
XMere aggregation of another unrelated program with this program (or its
Xderivative) on a volume of a storage or distribution medium does not bring
Xthe other program under the scope of these terms.
X
X  3. You may copy and distribute the APM Library (or a portion or
Xderivative of it, under Paragraph 2) in object code or executable form
Xunder all the terms of Paragraphs 1 and 2 above provided that you also
Xdo one of the following:
X
X    a) accompany it with the complete corresponding machine-readable
X    source code, which must be distributed under the terms of
X    Paragraphs 1 and 2 above; or,
X
X    b) accompany it with a written offer, valid for at least three
X    years, to give any third party free (except for a nominal
X    shipping charge) a complete machine-readable copy of the
X    corresponding source code, to be distributed under the terms of
X    Paragraphs 1 and 2 above; or,
X
X    c) accompany it with the information you received as to where the
X    corresponding source code may be obtained.  (This alternative is
X    allowed only for noncommercial distribution and only if you
X    received the program in object code or executable form alone.)
X
XFor an executable file, complete source code means all the source code
Xfor all modules it contains; but, as a special exception, it need not
Xinclude source code for modules which are standard libraries that
Xaccompany the operating system on which the executable file runs.
X
X  4. You may not copy, sublicense, distribute or transfer the APM
XLibrary except as expressly provided under this License Agreement.
XAny attempt otherwise to copy, sublicense, distribute or transfer the
XAPM Library is void and your rights to use the APM Library under this
XLicense agreement shall be automatically terminated.  However, parties
Xwho have received computer software programs from you with this
XLicense Agreement will not have their licenses terminated so long as
Xsuch parties remain in full compliance.
X
X  5. If you wish to incorporate parts of the APM Library into other
Xprograms whose distribution conditions are different, write to Lloyd
XZusman at Master Byte Software.  We have not yet worked out a simple
Xrule that can be stated here, but we will often permit this.  We will
Xbe guided by the goals of (1) preserving the free status of all
Xderivatives of our free software; of (2) promoting the sharing and
Xreuse of software; and of (3) not allowing anyone to profit from the
Xuse of our software without us also having the opportunity to share
Xin these profits.
X
XYour comments and suggestions about our licensing policies and our
Xsoftware are welcome!  Please contact Lloyd Zusman, Master Byte
XSoftware, 127 Wilder Ave., Los Gatos, California 95030, or call
X(408) 395-5693.
X
X			   NO WARRANTY
X
X  BECAUSE THE APM LIBRARY IS LICENSED FREE OF CHARGE, WE PROVIDE
XABSOLUTELY NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE
XLAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING, MASTER BYTE SOFTWARE,
XLLOYD ZUSMAN AND/OR OTHER PARTIES PROVIDE THE APM LIBRARY "AS IS"
XWITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
XBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
XFITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
XAND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE THE APM
XLIBRARY PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
XSERVICING, REPAIR OR CORRECTION.
X
X  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL MASTER BYTE
XSOFTWARE, LLOYD ZUSMAN, AND/OR ANY OTHER PARTY WHO MAY MODIFY AND
XREDISTRIBUTE THE APM LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
XDAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL,
XINCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
XINABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
XBEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A
XFAILURE OF THE PROGRAM TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY
XMASTER BYTE SOFTWARE) THE PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF
XTHE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.
X
X******************************************************************************/
X
X
X/*
X * Low level utilities for the APM library.  The user never should call
X * any of these directly.
X *
X * $Log:	utils.c,v $
X * Revision 1.0  88/10/05  12:38:16  ljz
X * Initial release.
X * 
X */
X#ifndef lint
Xstatic char rcsid[] = "$Header: utils.c,v 1.0 88/10/05 12:38:16 ljz Exp $";
X#endif /* ! lint */
X
X#include <stdio.h>
X#include <varargs.h>
X#include "apm.h"
X#include "apmlocal.h"
X
Xint apm_errno = APM_OK;
Xint (*APM_error_func)() = (int (*)())NULL;
Xint APM_line = 0;
Xchar *APM_file = "";
Xchar *APM_func_name = "";
X
Xstatic char APM_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
X
X#define MAX_BASE	((sizeof (APM_digits) / sizeof (APM_digits[0])) - 1)
X
Xchar *
XAPM_error_message(code)
Xint code;
X{
X	static char localMessage[80];
X	char *message;
X
X	switch (code) {
X	case APM_ENOMEM:
X		message = "memory allocation failed";
X		break;
X	case APM_WNULL:
X		message = "null argument";
X		break;
X	case APM_WDIVBYZERO:
X		message = "division by zero";
X		break;
X	case APM_WTRUNC:
X		message = "result truncated";
X		break;
X	case APM_WNOALLOC:
X		message = "attempt to free unallocated APM value";
X		break;
X	case APM_EPARM:
X		message = "invalid function parameter";
X		break;
X	case APM_ENULL:
X		message = "null APM value";
X		break;
X	case APM_EBADVAL:
X		message = "bad APM value";
X		break;
X	case APM_ENULLVAL:
X		message = "null value";
X		break;
X	case APM_EFMT:
X		message = "invalid string format";
X		break;
X	case APM_EBASE:
X		message = "invalid base";
X		break;
X	case APM_ESIZE:
X		message = "destination size is too small";
X		break;
X	case APM_EOVERLAP:
X		message = "result overlaps one or more operands";
X		break;
X	default:
X		sprintf(localMessage, "unknown error code: %d", code);
X		message = localMessage;
X		break;
X	}
X
X	return (message);
X}
X
Xint
XAPM_set_errno(code)
Xint code;
X{
X	apm_errno = code;
X	return (code);
X}
X
Xint
XAPM_error(code)
Xint code;
X{
X	code = APM_set_errno(code);
X
X	if (code != APM_OK && APM_error_func != (int (*)())NULL) {
X		code = (*APM_error_func)(code,
X					 APM_error_message(code),
X					 APM_file, APM_line,
X					 APM_func_name);
X	}
X	return (code);
X}
X
Xchar *
XAPM_trim_string(string)
Xchar *string;
X{
X	char *orig = string;
X	char *sp = string;
X
X	if (string != NULL) {
X		for (; *string != '\0'; ++string) {
X			if (*string != ' ' && *string != '\t') {
X				sp = string + 1;
X			}
X		}
X		*sp = '\0';
X	}
X
X	return (orig);
X}
X
Xchar *
XAPM_left_justify(string, ignore)
Xchar *string;
Xchar *ignore;
X{
X	if (string != NULL && ignore != NULL) {
X		for (; *string != '\0'; ++string) {
X			if (APM_index(ignore, *string) == NULL) {
X				break;
X			}
X		}
X	}
X
X	return (string);
X}
X
Xint
XAPM_val_format(apm)
XAPM apm;
X{
X	apm_errno = APM_OK;
X
X	if (apm == (APM)NULL) {
X		return (APM_set_errno(APM_ENULL));
X	}
X	if (apm->magic != APM_MAGIC) {
X		return (APM_set_errno(APM_EBADVAL));
X	}
X	return (APM_OK);
X}
X
Xint
XAPM_val_base(base)
Xshort base;
X{
X	apm_errno = APM_OK;
X
X	if (base == SPECIAL_BASE) {
X		return (APM_OK);
X	}
X
X	if (base < 2 || base > MAX_BASE) {
X		return (APM_set_errno(APM_EBASE));
X	}
X
X	return (APM_OK);
X}
X
Xshort
XAPM_get_digit(ch, base)
Xchar ch;
Xshort base;
X{
X	int ercode;
X	short idx;
X
X	ercode = APM_val_base(base);
X	if (ercode < APM_OK) {
X		return (APM_set_errno(ercode));
X	}
X
X	if (base == SPECIAL_BASE) {
X		base = 10;
X	}
X
X	for (idx = 0; idx < base; ++idx) {
X		if (ch == APM_digits[idx]) {
X			return (idx);
X		}
X	}
X
X	return (APM_set_errno(APM_EBASE));
X}
X
Xint
XAPM_radix_pos(string, base)
Xchar *string;
Xshort base;
X{
X	int dp = -1;
X	int nodigits = 1;
X	int pos = 0;
X	int ercode;
X
X	if (string == NULL) {
X		return (APM_set_errno(APM_ENULLVAL));
X	}
X	ercode = APM_val_base(base);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X
X	for (; string[pos] != '\0'; ++pos) {
X		if (string[pos] == '.') {
X			if (dp >= 0) {
X				return (APM_set_errno(APM_EFMT));
X			}
X			else {
X				dp = pos;
X			}
X		}
X		else if (APM_get_digit(string[pos], base) < 0) {
X			return (APM_set_errno(APM_EFMT));
X		}
X		else {
X			nodigits = 0;
X		}
X	}
X
X	if (nodigits) {
X		return (APM_set_errno(APM_EFMT));
X	}
X
X	return (dp + 1);
X}
X
Xint
XAPM_shift(num, scaleFactor)
XAPM num;
Xint scaleFactor;
X{
X	int ercode;
X
X	apm_errno = APM_OK;
X
X	if (scaleFactor == 0) {
X		return (APM_OK);
X	}
X	if (num->base != 0 && num->base != SPECIAL_BASE) {
X		num->dp -= scaleFactor;
X	}
X	else {
X		/*
X		 * The following code assumes that
X		 * (-X) % Y == -(X % Y).
X		 */
X		int factor = scaleFactor / SPECIAL_SCALE;
X		int n = scaleFactor % SPECIAL_SCALE;
X
X		if (scaleFactor < 0) {
X			--factor;
X			n += SPECIAL_SCALE;
X		}
X		num->dp -= factor;
X		if (n > 0) {
X			int multiplier = 1;
X			while (n-- > 0) {
X				multiplier *= 10;
X			}
X			n = (num->length)++;
X			ercode = APM_size(num, num->length);
X			if (ercode < APM_OK) {
X				return (ercode);
X			}
X			num->data[n] = APM_scalar_mul(num->data,
X							   num->data, n,
X							   multiplier,
X							   num->base);
X		}
X	}
X	return (APM_trim(num, 1, 1));
X}
X
Xint
XAPM_trimlead(apm)
XAPM apm;
X{
X	int n;
X	int ercode;
X
X	apm_errno = APM_OK;
X
X	if (apm == (APM)NULL) {
X		return (APM_set_errno(APM_ENULL));
X	}
X
X	if (apm->data == NULL) {
X		apm->length = 0;
X		return (APM_OK);
X	}
X
X	ercode = APM_normalize(apm);
X	if (ercode < APM_OK) {
X		return (APM_set_errno(ercode));
X	}
X
X	for (n = apm->length; n > 0; --n) {
X		if (apm->data[n - 1] != 0) {
X			break;
X		}
X	}
X
X	if (n < apm->length) {
X		apm->length = n;
X	}
X
X	return (APM_OK);
X}
X
Xint
XAPM_trimtrail(apm)
XAPM apm;
X{
X	int n;
X	int ercode;
X
X	apm_errno = APM_OK;
X
X	if (apm == (APM)NULL) {
X		return (APM_set_errno(APM_ENULL));
X	}
X
X	if (apm->data == NULL) {
X		apm->length = 0;
X		apm->dp = 0;
X		return (APM_OK);
X	}
X
X	ercode = APM_normalize(apm);
X	if (ercode < APM_OK) {
X		return (APM_set_errno(ercode));
X	}
X
X	for (n = 0; n < apm->dp; ++n) {
X		if (apm->data[n] != 0) {
X			break;
X		}
X	}
X
X	if (n == 0) {	/* no trailing zeros */
X		return (APM_OK);
X	}
X
X	/*
X	 * Shift down by 'n', subtracting this from apm->length and
X	 * apm->dp.
X	 */
X	apm->length -= n;
X	apm->dp -= n;
X	APM_copy_shorts(apm->data, &(apm->data[n]), apm->length);
X	APM_zero_shorts(&(apm->data[apm->length]), n);
X
X	return (APM_OK);
X}
X
Xint
XAPM_trim(apm, lead, trail)
XAPM apm;
Xint lead;
Xint trail;
X{
X	int ercode = APM_OK;
X
X	apm_errno = APM_OK;
X
X	if (apm == (APM)NULL) {
X		return (APM_set_errno(APM_ENULL));
X	}
X
X	if (ercode >= APM_OK && lead) {
X		ercode = APM_trimlead(apm);
X	}
X
X	if (ercode >= APM_OK && trail) {
X		ercode = APM_trimtrail(apm);
X	}
X
X	if (ercode >= APM_OK) {
X		ercode = APM_normalize(apm);
X	}
X
X	return (APM_set_errno(ercode));
X}
X
Xint
XAPM_normalize(value)
XAPM value;
X{
X	static short *localData = (short *)NULL;
X	static int localLen = 0;
X	int len;
X	int dp;
X	int offset;
X	int ercode;
X
X	apm_errno = APM_OK;
X
X	ercode = APM_val_format(value);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X	ercode = APM_val_base(value->base);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X
X	if (value->dp >= 0 && value->length >= value->dp) {
X		return (APM_OK);
X	}
X
X	len = value->length;
X	if (value->length < value->dp) {
X		len = value->dp;
X		dp = value->dp;
X		offset = 0;
X	}
X	else if (value->dp < 0) {
X		len = value->length - value->dp;
X		dp = 0;
X		offset = -(value->dp);
X	}
X	else {
X		len = value->length;
X		dp = value->dp;
X		offset = 0;
X	}
X
X	if (len > localLen) {
X		int xlen = len;
X		if (xlen < 8) {
X			xlen = 8;
X		}
X		localData = (short *)APM_alloc_mem(localLen < 1 ?
X						NULL : localData,
X						xlen, sizeof (short));
X		if (localData == (short *)NULL) {
X			return (APM_set_errno(APM_ENOMEM));
X		}
X		localLen = xlen;
X	}
X
X	APM_zero_shorts(localData, len);
X	APM_copy_shorts(localData + offset, value->data, value->length);
X
X	ercode = APM_size(value, len);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X
X	APM_copy_shorts(value->data, localData, len);
X
X	value->length = len;
X	value->dp = dp;
X
X	return (APM_OK);
X}
X
Xint
XAPM_setdp(result, value, dp)
XAPM result;
XAPM value;
Xint dp;
X{
X	int oldlen;
X	int newlen;
X	int voffset;
X	int roffset;
X	int ercode;
X
X	apm_errno = APM_OK;
X
X	ercode = APM_val_format(value);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X	ercode = APM_val_base(value->base);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X	if (result == value) {
X		return (APM_set_errno(APM_EOVERLAP));
X	}
X
X	ercode = APM_normalize(value);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X
X	if (dp < 0) {
X		dp = value->dp;
X	}
X
X	oldlen = newlen = value->length;
X
X	if (dp <= value->dp) {
X		voffset = value->dp - dp;
X		roffset = 0;
X		oldlen -= voffset;
X	}
X	else {
X		voffset = 0;
X		roffset = dp - value->dp;
X		newlen += roffset;
X	}
X
X	ercode = APM_size(result, newlen);
X	if (ercode < APM_OK) {
X		return(ercode);
X	}
X
X	APM_zero_shorts(result->data, newlen);
X	APM_copy_shorts(result->data + roffset, value->data + voffset, oldlen);
X
X	result->sign = SIGNOF(value->sign);
X	result->base = value->base;
X	result->length = newlen;
X	result->dp = dp;
X	return (APM_OK);
X}
X
Xint
XAPM_norm_to_spec(apm)
XAPM apm;
X{
X	static APM localApm = (APM)NULL;
X	int length;
X	int locallen;
X	int localdp;
X	int ercode;
X	int n;
X	short sign;
X
X	apm_errno = APM_OK;
X
X	if (apm == (APM)NULL) {
X		return (APM_set_errno(APM_ENULL));
X	}
X
X	if (apm->base != 10) {
X		return (APM_set_errno(APM_EFMT));
X	}
X
X	length = apm->length;
X	sign = SIGNOF(apm->sign);
X	locallen = length;
X	localdp = ((apm->dp + (SPECIAL_SCALE - 1)) / SPECIAL_SCALE)
X	         * SPECIAL_SCALE;
X	locallen += (localdp - apm->dp);
X	locallen = ((locallen + (SPECIAL_SCALE - 1)) / SPECIAL_SCALE)
X	          * SPECIAL_SCALE;
X
X	if (localApm == (APM)NULL) {
X		localApm = APM_alloc();
X		if (localApm == (APM)NULL) {
X			return (APM_set_errno(APM_ENOMEM));
X		}
X	}
X	ercode = APM_size(localApm, locallen / SPECIAL_SCALE);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X
X	for (n = 0; n < locallen; n += SPECIAL_SCALE) {
X		int value = 0;
X		int tn = n + (apm->dp - localdp);
X		if (tn >= 0 && tn < length) {
X			value += apm->data[tn];
X		}
X		++tn;
X		if (tn >= 0 && tn < length) {
X			value += apm->data[tn] * 10;
X		}
X		++tn;
X		if (tn >= 0 && tn < length) {
X			value += apm->data[tn] * 100;
X		}
X		++tn;
X		if (tn >= 0 && tn < length) {
X			value += apm->data[tn] * 1000;
X		}
X		localApm->data[n / SPECIAL_SCALE] = value;
X	}
X	localApm->length = locallen / SPECIAL_SCALE;
X	localApm->dp = localdp / SPECIAL_SCALE;
X	localApm->sign = sign;
X	localApm->base = SPECIAL_BASE;
X
X	ercode = apm_assign(apm, localApm);
X
X	return (ercode);
X}
X
Xint
XAPM_spec_to_norm(apm)
XAPM apm;
X{
X	static APM localApm = (APM)NULL;
X	int length;
X	int locallen;
X	int n;
X	int ercode;
X	short sign;
X
X	apm_errno = APM_OK;
X
X	if (apm == (APM)NULL) {
X		return (APM_set_errno(APM_ENULL));
X	}
X
X	if (apm->base != SPECIAL_BASE) {
X		return (APM_set_errno(APM_EFMT));
X	}
X
X	ercode = APM_trim(apm, 1, 1);
X	if (ercode < APM_OK) {
X		return (APM_set_errno(APM_EFMT));
X	}
X
X	length = apm->length;
X	sign = SIGNOF(apm->sign);
X	if (localApm == (APM)NULL) {
X		localApm = APM_alloc();
X		if (localApm == (APM)NULL) {
X			return (APM_set_errno(APM_ENOMEM));
X		}
X	}
X	locallen = length * SPECIAL_SCALE;
X	ercode = APM_size(localApm, locallen);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X	localApm->length = locallen;
X	localApm->sign = sign;
X	localApm->dp = apm->dp * SPECIAL_SCALE;
X	localApm->base = 10;
X
X	for (n = 0; n < length; ++n) {
X		int tn = n * SPECIAL_SCALE;
X		int value = apm->data[n];
X		int newvalue = value / 10;
X		localApm->data[tn] = value - (newvalue * 10);
X		value = newvalue;
X		newvalue = value / 10;
X		localApm->data[tn + 1] = value - (newvalue * 10);
X		value = newvalue;
X		newvalue = value / 10;
X		localApm->data[tn + 2] = value - (newvalue * 10);
X		value = newvalue;
X		newvalue = value / 10;
X		localApm->data[tn + 3] = value - (newvalue * 10);
X	}
X	ercode = apm_assign(apm, localApm);
X	if (ercode >= APM_OK) {
X		ercode = APM_trim(apm, 1, 1);
X	}
X	return (ercode);
X}
X
Xint
XAPM_size(apm, len)
XAPM apm;
Xint len;
X{
X	short *temp;
X	apm_errno = APM_OK;
X
X	if (len < 0) {
X		return (APM_set_errno(APM_EPARM));
X	}
X	if (apm == (APM)NULL) {
X		return (APM_set_errno(APM_ENULL));
X	}
X
X	if (len > apm->alloclen || apm->alloclen < 1) {
X		if (len < 8) {
X			len = 8;
X		}
X		if (apm->alloclen < 1) {
X			temp = (short *)APM_alloc_mem(NULL, len,
X						   sizeof (short));
X		}
X		else {
X			temp = (short *)APM_alloc_mem(apm->data, len,
X						   sizeof (short));
X		}
X		if (temp == (short *)NULL) {
X			return (APM_set_errno(APM_ENOMEM));
X		}
X		apm->data = temp;
X		apm->alloclen = len;
X	}
X
X	return (APM_OK);
X}
X
Xint
XAPM_parse_string(apm, string, base)
XAPM apm;
Xchar *string;
Xshort base;
X{
X	static char *localString = NULL;
X	static int localLen = 0;
X	int ercode;
X	int len;
X	int dp;
X	int special = 0;
X	short sign = 1;
X	char *temp;
X	short *bp;
X	char *tp;
X
X	apm_errno = APM_OK;
X
X	if (apm == (APM)NULL) {
X		return (APM_set_errno(APM_ENULL));
X	}
X
X	if (string == NULL) {
X		return (APM_set_errno(APM_ENULLVAL));
X	}
X
X	if (base == 0) {
X		base = SPECIAL_BASE;
X	}
X
X	ercode = APM_val_base(base);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X
X	if (base == SPECIAL_BASE) {
X		special = 1;
X		base = 10;
X	}
X
X	len = strlen(string);
X	if (localString == NULL || localLen < len + 1) {
X		int xlen = len + 1;
X		if (xlen < 16) {
X			xlen = 16;
X		}
X		localString = APM_alloc_mem(localLen < 1 ? NULL : localString,
X					 xlen, sizeof (char));
X		if (localString == NULL) {
X			return (APM_set_errno(APM_ENOMEM));
X		}
X		localLen = xlen;
X	}
X	APM_copy_bytes(localString, string, len + 1);
X
X	temp = APM_trim_string(APM_left_justify(localString, " \t"));
X	if (*temp == '-') {
X		sign = -1;
X		++temp;
X	}
X	else if (*temp == '+') {
X		sign = 1;
X		++temp;
X	}
X
X	dp = APM_radix_pos(temp, base);
X	if (dp < 0) {
X		return (APM_set_errno(APM_EFMT));
X	}
X
X	len = strlen(temp);
X	if (dp > 0) {
X		char *sp = &temp[dp];
X		do {
X			sp[-1] = *sp;
X		} while (*sp++ != '\0');
X		--len;
X		dp = len - (dp - 1);
X	}
X
X	ercode = APM_size(apm, len);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X
X	apm->base = base;
X	apm->length = len;
X	apm->dp = dp;
X	apm->sign = SIGNOF(sign);
X	for (bp = apm->data, tp = &temp[len]; tp-- > temp; ++bp) {
X		*bp = APM_get_digit(*tp, apm->base);
X	}
X
X	if (special) {
X		ercode = APM_norm_to_spec(apm);
X	}
X
X	if (ercode >= APM_OK) {
X		ercode = APM_trim(apm, 1, 1);
X	}
X
X	return (ercode);
X}
X
Xchar *
XAPM_build_string(string, data, length, dpos)
Xchar *string;
Xshort *data;
Xint length;
Xint dpos;
X{
X	short *bp;
X	int n = 0;
X
X	for (bp = &(data[length]); bp-- > data; ++n) {
X		if (n == dpos) {
X			*string++ = '.';
X		}
X		*string++ = APM_digits[*bp];
X	}
X	return (string);
X}
X
Xint
XAPM_parse_long(apm, value, base)
XAPM apm;
Xlong value;
Xshort base;
X{
X	int ercode;
X	int n;
X	long temp;
X
X	apm_errno = APM_OK;
X
X	if (apm == (APM)NULL) {
X		return (APM_set_errno(APM_ENULL));
X	}
X
X	if (base == 0) {
X		base = SPECIAL_BASE;
X	}
X	ercode = APM_val_base(base);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X
X	apm->sign = 1;
X	apm->base = base;
X	apm->dp = 0;
X
X	if (value < 0) {
X		apm->sign = -1;
X		value = -value;
X	}
X
X	for (apm->length = 0, temp = value; temp != 0; temp /= base) {
X		++(apm->length);
X	}
X	if (apm->length == 0) {
X		return (APM_OK);
X	}
X
X	ercode = APM_size(apm, apm->length);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X
X	for (n = 0; n < apm->length; ++n) {
X		apm->data[n] = value % base;
X		value /= base;
X	}
X
X	return (APM_OK);
X}
X
Xshort
XAPM_array_add(result, addend, length, base)
Xshort *result;
Xshort *addend;
Xint length;
Xshort base;
X{
X	int n;
X	short tempval;
X	short carry = 0;
X
X	for (n = 0; n < length; ++n) {
X		tempval = result[n] + carry + addend[n];
X		result[n] = tempval % base;
X		carry = tempval / base;
X	}
X
X	return (carry);
X}
X
Xshort
XAPM_array_sub(result, subtrahend, length, base)
Xshort *result;
Xshort *subtrahend;
Xint length;
Xshort base;
X{
X	int n;
X	short tempval;
X	short borrow = 0;
X
X	for (n = 0; n < length; ++n) {
X		tempval = (result[n] + borrow) - subtrahend[n];
X		if (tempval < 0) {
X			result[n] = tempval + base;
X			borrow = -1;
X		}
X		else {
X			result[n] = tempval;
X			borrow = 0;
X		}
X	}
X	return (borrow);
X}
X
Xshort
XAPM_scalar_mul(result, multiplicand, length, multiplier, base)
Xshort *result;
Xshort *multiplicand;
Xint length;
Xshort multiplier;
Xshort base;
X{
X	int n;
X	long tempval;
X	short carry = 0;
X
X	for (n = 0; n < length; ++n) {
X		tempval = multiplicand[n];
X		tempval *= multiplier;
X		tempval += carry;
X		result[n] = (short)(tempval % base);
X		carry = (short)(tempval / base);
X	}
X	return (carry);
X}
X
Xint
XAPM_scalar_div(result, dividend, length, dp, sign, base, divisor)
XAPM result;
Xshort *dividend;
Xint length;
Xint dp;
Xshort sign;
Xshort base;
Xshort divisor;
X{
X	static APM apmDividend = (APM)NULL;
X	static APM apmDivisor = (APM)NULL;
X	int ercode;
X
X	apm_errno = APM_OK;
X
X	if (result == (APM)NULL || dividend == (short *)NULL) {
X		return (APM_set_errno(APM_ENULL));
X	}
X
X	if (apmDividend == (APM)NULL) {
X		apmDividend = APM_alloc();
X		if (apmDividend == (APM)NULL) {
X			return (APM_set_errno(APM_ENOMEM));
X		}
X	}
X	if (apmDivisor == (APM)NULL) {
X		apmDivisor = APM_alloc();
X		if (apmDivisor == (APM)NULL) {
X			return (APM_set_errno(APM_ENOMEM));
X		}
X		ercode = APM_size(apmDivisor, 1);
X		if (ercode < APM_OK) {
X			return (ercode);
X		}
X		apmDivisor->length = 1;
X		apmDivisor->dp = 0;
X	}
X
X	ercode = APM_size(apmDividend, length);
X	if (ercode < APM_OK) {
X		return (ercode);
X	}
X	APM_copy_shorts(apmDividend->data, dividend, length);
X
X	apmDividend->sign = sign;
X	apmDividend->length = length;
X	apmDividend->dp = dp;
X	apmDividend->base = base;
X
X	if (divisor < 0) {
X		apmDivisor->data[0] = -divisor;
X		apmDivisor->sign = -1;
X	}
X	else {
X		apmDivisor->data[0] = divisor;
X		apmDivisor->sign = 1;
X	}
X	apmDivisor->base = base;
X
X	return (apm_divide(result, length, (APM)NULL,
X			   apmDividend, apmDivisor));
X}
X
Xint
XAPM_copy_bytes(to, from, num)
Xregister char *to;
Xregister char *from;
Xint num;
X{
X	register int n = num;
X
X	if (to == NULL || from == NULL || num <= 0) {
X		return (0);
X	}
X
X	if (to > from) {
X		to += n;
X		from += n;
X		while (n-- > 0) {
X			*(--to) = *(--from);
X		}
X	}
X	else if (to < from) {
X		while (n-- > 0) {
X			*to++ = *from++;
X		}
X	}
X
X	return (num);
X}
X
Xint
XAPM_zero_bytes(to, num)
Xregister char *to;
Xint num;
X{
X	register int n = num;
X
X	if (to == NULL || num <= 0) {
X		return (0);
X	}
X
X	while (n-- > 0) {
X		*to++ = 0;
X	}
X
X	return (num);
X}
X
Xint
XAPM_copy_shorts(to, from, num)
Xshort *to;
Xshort *from;
Xint num;
X{
X	return (APM_copy_bytes((char *)to, (char *)from,
X			    num * sizeof (short)) / sizeof (short));
X}
X
Xint
XAPM_zero_shorts(to, num)
Xshort *to;
Xint num;
X{
X	return (APM_zero_bytes((char *)to,
X			    num * sizeof (short)) / sizeof (short));
X}
X
Xchar *
XAPM_index(s, c)
Xregister char *s;
Xint c;
X{
X	if (s != NULL) {
X		for (; *s != '\0'; ++s) {
X			if (*s == (char)c) {
X				return (s);
X			}
X		}
X	}
X
X	return (NULL);
X}
X
Xvoid
XAPM_debug(va_alist)
Xva_dcl
X{
X	va_list ap;
X	char *format;
X	FILE *debug_file = apm_debug_file(NULL);
X
X	if (debug_file == (FILE *)NULL) {
X		return;
X	}
X
X	(void)apm_debug_file(debug_file);
X
X	va_start(ap);
X
X	format = va_arg(ap, char *);
X	if (format == NULL) {
X		return;
X	}
X
X	vfprintf(debug_file, format, ap);
X	fflush(debug_file);
X
X	va_end(ap);
X}
@\END_OF_FILE_utils.c
else
  echo "shar: Will not over write utils.c"
fi
echo "Finished archive 4 of 5"
# to concatenate archives, remove anything after this line
exit 0