#include "internal.h"
#include <sys/types.h>

/*
 * Function:
 *      _xtoa
 *
 * Description:
 *      This procedure is a helper function to convert a long (or unsigned)
 *      long to ascii. The operation is done with the aid of partial divide
 *      operations from "Mathametical Algorithms for Computers".
 *
 * Entry:
 *      val      - Value to be converted
 *      pszOut   - Pointer to the output character string
 *      radix    - Radix for the output. This may be any value from 2 through
 *                 36. It is not checked.
 *      sign     - Is the input signed / unsigned. If the value is signed
 *                 and it is negative decimal then a leading negative sign
 *                 is emitted.
 *
 * Returns:
 *      pszOut.
 */

char *_xtoa (const long int val, char *pszOut, int radix, int sign)
    {
    union
	{
	u_long v;	/* Long value					*/
	struct
	    {
	    u_short l;  /* lower half of long int			*/
	    u_short h;  /* upper half of long int			*/
	    } x1;
	} x, v;		/* Nice way to divide a long int into shorts	*/

    char *pszRev;	/* Temp used in the buffer flip			*/
    char  chTemp;	/* Temp used in the buffer flip			*/
    int   nDigit;	/* Current digit value				*/
    char *pszAns = pszOut; /* Result of this function is the buffer	*/
/*
 *	Change the radix to a legal value
 */
    if (radix < 2 || radix > 36)
	{
	radix = 10;
	}
/*
 *	Emit the sign of the value if the value is negative decimal and
 *      invert the sign of the value.
 */
    v.v = (u_long) val;

    if (sign)
        {
	if (radix == 10)
	    {
	    if (((long) v.v) < 0L)
	        {
		v.v = (u_long) -((long) v.v);
		*pszOut++ = '-';
	        }
	    }
        }
/*
 *	divide the entry by the corresponding radix
 */
    pszRev	= pszOut;	/* Save start of the reversed buffer	  */
    *pszOut++	= '\0';		/* Mark the "end" of the buffer with nul  */
/*
 *	Divide the high and low words by the radix factor
 */
    do
	{
	x.v		= v.v;
	v.x1.h		= (u_short) ((u_long) x.x1.h) / ((u_long) radix);
	x.x1.h		= (u_short) ((u_long) x.x1.h) % ((u_long) radix);

	nDigit		= (int) (x.v % (u_long) radix);
	v.x1.l		= (u_short) (x.v / (u_long) radix);
/*
 *	Generate the digit value
 */
	if (nDigit < 10)
	    {
	    *pszOut++ = (char) (nDigit + '0');
	    }
	else
	    {
	    *pszOut++ = (char) (nDigit + ('A' - 10));
	    }
	}
    while (v.v != 0L);
/*
 *	Reverse the digits which are in the buffer
 */
    while ((unsigned long) pszOut > (unsigned long) pszRev)
	{
	--pszOut;
	chTemp     = *pszOut;
	*pszOut    = *pszRev;
	*pszRev++  = chTemp;
	}
/*
 *	Return a pointer to the buffer.
 */
    return (pszAns);
    }
