/* int	StringPrintDecimal(buffer, fmt,	arg,)
 *
 * ARGUMENT
 *	char	*fmt, *buffer;
 *	(?)	arg;
 *
 * DESCRIPTION
 *	Prints out arguments, which may	include	DEC structures,
 *   into a string in formatted	form, according
 *   to	the format string fmt.	The function converts the DEC's	to strings
 *   and calls printf.
 *
 * SIDE	EFFECTS
 *	None.
 *
 * RETURNS
 *	The number of characters printed, the return from sprintf.
 *
 * POSSIBLE ERRORS
 *	GM_NULLPOINTER
 *	GM_NULLSTRING
 *	GM_INVALIDID
 *	GM_CNVRW
 *
 * AUTHOR
 *  Jared Levy
 *   Copyright (C) 1987-1990 Greenleaf Software	Inc.  All rights reserved.
 *
 * MODIFICATIONS
 *
 *
 */

#include <stdio.h>
#include <string.h>
#include "gmsystem.h"

static int _StackSize(char, char);

int StringPrintDecimal(char * buffer, char * fmt, ELLIPSES)
{
	char	newfmt[256], lastcode, thiscode;
	int	*inval,	outval[21];
	SHORT	i,j,k,l, inarg,	outarg,	wNumStar, wStack;
	mbool	wfRegChar, wfDecChar, wfOld3Color;
	DEC	*pDec;
#ifdef _LDATA
	long	*pLong;
#endif

	_MacStart(GM_DSPRINTF);

	wfOld3Color = wfGM3Color;

	if (!fmt || !buffer)  {
		if (buffer)
			buffer[0]='\0';
		wfGM3Color = FALSE;
		_MacErr(GM_NULLSTRING);
		wfGM3Color = wfOld3Color;
		_MacRet(0);
	}

	inval =	(int *)	&fmt;
/* int casting guarantees 16 bit word size regardless of model */
	inarg =	sizeof(char *) / sizeof(int);
	outarg = 0;

/* trace through format	string */
	i=0;
	j=0;

	if (wfGM3Color)	 {
		newfmt[j]=cGMCodeNon;
		lastcode=cGMCodeNon;
		j++;
	}

	while (fmt[i]!='\0')  {
		if (fmt[i]!='%')  {
			if (wfGM3Color && (lastcode!=cGMCodeNon))  {
				newfmt[j]=cGMCodeNon;
				lastcode=cGMCodeNon;
				j++;
			}
			newfmt[j]=fmt[i];		/* copy	element	*/
			j++;
			i++;
		}

		else  {
			/* check for specification */
			wfRegChar=FALSE;
			wfDecChar=FALSE;
			wNumStar=0;
			k=i;
			do {
				k++;
				if (fmt[k]=='d'||fmt[k]=='u'||
				    fmt[k]=='o'||fmt[k]=='x'||
				    fmt[k]=='f'||fmt[k]=='e'||
				    fmt[k]=='g'||fmt[k]=='c'||
				    fmt[k]=='X'||fmt[k]=='E'||
				    fmt[k]=='p'||fmt[k]=='G'||
#ifdef LATTICE
				    fmt[k]=='P'||
#else
				    fmt[k]=='i'||fmt[k]=='n'||
#endif
				    fmt[k]=='s')
					    wfRegChar =	TRUE;

				if (fmt[k]==cGMFmt   ||fmt[k]==cGMFmtComma||
				    fmt[k]==cGMFmtSci||fmt[k]==cGMFmtSciE ||
				    fmt[k]==cGMFmtEng||fmt[k]==cGMFmtEngE)
					    wfDecChar =	TRUE;

				if (fmt[k]=='*')
					wNumStar++;

			} while	(fmt[k]!='\0'&&!wfRegChar&&
				!wfDecChar&&fmt[k]!='%');

			if (wfRegChar)	{	/* regular C type */
				/* copy	arguments into output list */
				/* find	size of	argument */
				wStack = _StackSize(fmt[k],fmt[k-1]);
				/* each	* requires an additional argument */
				for (l=0;l<wNumStar+wStack;l++)	 {
					outval[outarg]=inval[inarg];
					outarg++;
					inarg++;
				}

				if (wfGM3Color && (lastcode!=cGMCodeNon))  {
					newfmt[j]=cGMCodeNon;
					lastcode=cGMCodeNon;
					j++;
				}

				/* copy	format string */
				while (i<=k)  {
					newfmt[j]=fmt[i];
					i++;
					j++;
				}
			}  /*  regular C type */

			if (wfDecChar)	{	/* DEC type */
				/* retrieve starred values */
				if (wNumStar > 0)  {
					wGMStar= inval[inarg];
					inarg++;
				}
				if (wNumStar > 1)  {
					wGMStar2= inval[inarg];
					inarg++;
				}

				/* find	DEC pointer */
#ifdef _LDATA
				pLong =	(long *) &inval[inarg];
				pDec = (DEC *) *pLong;
#else
				pDec = (DEC *) inval[inarg];
#endif

				if (wfGM3Color)	 {
					if (!pDec || _MacBad(pDec))
						thiscode = cGMCodeNon;
					else if	(_MacIsDecN(pDec))
						thiscode = cGMCodeNeg;
					else
						thiscode = cGMCodePos;
					if (lastcode!=thiscode)	 {
						newfmt[j]=thiscode;
						lastcode=thiscode;
						j++;
					}
				}

				/* convert to formatted	ascii */
				wfGM3Color = FALSE;
				_ConvDecimalToAsciiFormatted(&newfmt[j],
					pDec, &fmt[i]);
/*
 * Lattice C 6.0 says I	should remove this line	since it is redundant.
 * It looks to me like they are	right.
 *
 *				wfOld3Color = wfGM3Color; */
				i = k+1;
				j = strlen(newfmt);

				/* advance arg list once for small data,
					twice for large	*/
				inarg++;
#ifdef _LDATA
#ifndef M_I386
				inarg++;
#endif
#endif
			}  /* if (wfDecChar) */

			if (!wfRegChar && !wfDecChar)  {  /* neither */
				if (wfGM3Color && (lastcode!=cGMCodeNon))  {
					newfmt[j]=cGMCodeNon;
					lastcode=cGMCodeNon;
					j++;
				}

				newfmt[j]=fmt[i];
				i++;
				j++;
				if (fmt[i]!='\0')  {
					newfmt[j]=fmt[i];
					i++;
					j++;
				}
			}  /* neither */

		} /* fmt[i]=='%' */
	} /* while */

	newfmt[j]='\0';

/* print the output */
	i=sprintf(buffer, newfmt,
		outval[0], outval[1], outval[2], outval[3], outval[4],
		outval[5], outval[6], outval[7], outval[8], outval[9]
		,outval[10], outval[11], outval[12], outval[13], outval[14],
		 outval[15], outval[16], outval[17], outval[18], outval[19]
		);
	_MacRet(i);
}

/* finds number	of 16-bit words	on stack representing data element */
static int	_StackSize(cType, cPrec)
char	cType;
char cPrec;
{
	int	w,x;

	switch (cType)	{
		case 'c':  {
			w = sizeof(char);
			break;
		}

#ifndef	LATTICE
	case 'i':
#endif
		case 'd': case 'o': case 'u': case 'x':	case 'X': {
			if (cPrec=='l')
				w = sizeof(long);
			else
				w = sizeof(int);
			break;
		}

		case 'f': case 'e': case 'g': case 'E':	case 'G':  {
			if (cPrec=='l')
				w = sizeof(double);
				/* usual arithmetic conversion */
			else
#ifdef _MSC
			if (cPrec=='L')
				w = sizeof(long	/*double*/);
			else
#endif
				w = sizeof(double);
			break;
		}

#ifdef LATTICE
		case 'P':
#else
		case 'n':
#endif
		case 's': case 'p': {
#ifndef	LATTICE
#ifndef	M_I386
#ifndef WIN32
#ifndef __GNUC__
			if (cPrec=='F')
				w = sizeof(char	far *);
			else if	(cPrec=='N')
				w = sizeof(char	near *);
			else
#endif
#endif
#endif
#endif
				w = sizeof(char	*);
			break;
		}
	} /* switch */

	x = sizeof(int);
	return((w+x-1)/x);	/* rounds up to	an integer */
}