/*static char *SCCSID = "@(#)string.c	6.2 91/01/14";*/
#define SCCSID "@(#)string.c	6.2 91/01/14"
/*
 *	IBM/Microsoft Confidential
 *
 *	Copyright (c) IBM Corporation 1987, 1989
 *	Copyright (c) Microsoft Corporation 1987, 1989
 *
 *	All Rights Reserved
 *
 */

/*
 *  STRING.C
 *
 *    DESCRIPTION
 *    
 *      The functions here perform operations on strings.
 *      
 *
 *    FUNCTIONS DEFINED
 *
 *      CopyNullTerm ()     -   Copy string from source to dest and append
 *                                  NULL.
 *      AppendNull ()       -   Append a NULL to a string.
 *      VersionToNumber ()  -   Convert number from ASCII string
 *                                  to number.
 *      CopyVersionToNumber ()  -   Convert number from ASCII string
 *                                  to number, copying to dest as well.
 *
 *      DecimalToASCII      -   Converts an unsigned short to an ASCII
 *                              string.
 *
 *
 *  REVISION HISTORY (in reverse chronological order)
 *  -----------------------------------------------------------------------
 *  4/4/90      Brian Andrew    Added function DecimalToASCII.
 *
 *  12/21/89    Brian Andrew    Corrected CopyVersiontoNumber to return
 *                              NO_VERSION if there are too many bytes
 *                              in the version extension.
 *
 *  12/14/89    Brian Andrew    Added function CopyVersionToNumber, this 
 *                              an enhanced version of VersionToNumber
 * 
 *  8/25/89     Brian Andrew    Added functions which analyze a filename:
 *                                  strslice, isterminator, canon_file,
 *                                  VersionToNumber.
 *  8/24/89     Brian Andrew    Added notes on ForwardDir
 *  8/21/89     Brian Andrew    Added ForwardDir
 *  8/4/89      Brian Andrew    Initial Blank Template
 *
 *
 *  TO DO
 *  -------------------------------------------------------------------------
 */


#define INCL_DOSERRORS
#define INCL_NOPMAPI

#include <os2.h>
#include <fsd.h>

#include "cdfs.h"
#include "sem.h"
#include "path.h"
#include "vol.h"
#include "file.h"
#include "buffer.h"
#include "mem.h"
#include "heap.h"
#include "message.h"

#ifdef STATS_H
#include "stats.h"
#endif

#include "fsdata.h"
#include "pr_strng.h"
#include "stdlib.h"
#include "memory.h"

#ifdef DEBUG
#include "pr_debug.h"
#endif


/*
 ***    CopyNullTerm ()     Copy the string from the source to the
 *                  destination.  The boolean flag indicates whether
 *                  to swap the single byte '\0' with the string "." (self)
 *                  or the single byte '\1' with ".." (parent).
 */

VOID CopyNullTerm (pcDest, pcSrc, cbLen, fConvert)
PCHAR       pcDest;
PCHAR       pcSrc;
USHORT      cbLen;
BOOL        fConvert;
{
	/* Check flag whether to convert '\0' or '\1' bytes */
	if (fConvert)
	{
		if (*pcSrc == '\0')
		{
			pcSrc = szSelf;
			cbLen = 1;
		}

		else if (*pcSrc == '\1')
		{
			pcSrc = szParent;
			cbLen = 2;
		}

	}

	CopyWithNull (pcDest, pcSrc, cbLen);

} /* end CopyNullTerm */


/*
 ***    AppendNull ()       Put a NULL byte at the end of a string
 *
 *              The length of the string should allow for a character
 *              to be put after the first 'cbMaxLen' characters in
 *              the string or replacing the first blank character.
 */

 VOID AppendNull (szString, cbMaxLen)
 PCHAR      szString;       /* String to Null terminate         */
 USHORT     cbMaxLen;       /* Last position to consider        */
 {
	/* Look for the first blank character in the string */
	while (cbMaxLen--)
	{
		if (*szString == ' ')
			break;

		szString++;

	} /* end while */

	*szString = '\0';

 } /* end AppendNull */


/*
 *  VersionToNumber ()          Convert an ASCII number string to a USHORT
 *
 */

SHORT VersionToNumber (pcSrc, cbBytes)
PCHAR       pcSrc;
USHORT      cbBytes;
{
	SHORT   usRet;

	/* check if the version exists */
	if (!cbBytes)
	{
		usRet = NO_VERSION;
	}

	else
	{
		usRet = 0;

		while (cbBytes--)
		{
			usRet = (usRet * 10 + ((SHORT) (*(pcSrc++) - '0')));

		} /* end while */

	}

	return usRet;

} /* end VersionToNumber */

/*
 *  CopyVersionToNumber ()  - Convert an ASCII number string to a USHORT
 *                          - Copy string as well
 */

SHORT CopyVersionToNumber (pcDst, pcSrc, cbBytes, pusVerLen)
PCHAR       pcDst;
PCHAR       pcSrc;
USHORT      cbBytes;
PUSHORT     pusVerLen;
{
	SHORT   usRet;
	USHORT  fLegalVersion;
	USHORT  usIndex;

	/* Set the length of the version to 0 */
	*pusVerLen = 0;

	/* check if the version exists */
	if (!cbBytes)
	{
		usRet = NO_VERSION;
	}

	else
	{
		/* Step over the first position */
		*(pcDst++) = '\0';
		
		/* Initialize the various values */
		usRet = 0;
		fLegalVersion = TRUE;
		usIndex = min (MAX_DIGITS, cbBytes);
		cbBytes -= usIndex;

		/* Walk through the number of legal digits */
		while (usIndex--)
		{
			/* Copy the next byte over and increment the length */
			*(pcDst++) = *pcSrc;
			(*pusVerLen)++;

			/* If the version is still legal, check the next digit */
			if (fLegalVersion)
			{
				/* Check if this is a legal digit */
				if ((*pcSrc >= '0') && (*pcSrc <= '9'))
				{
					usRet = (usRet * 10 + ((USHORT) (*pcSrc - '0')));

				}

				/* Else clear the LegalVersion flag */
				else
				{
					fLegalVersion = FALSE;
					usRet = NO_VERSION;
				}
			}

			/* Move along the source string */
			pcSrc++;
			
		} /* End while move version digits */

		/* Check that the resulting version is legal */
		if (!(usRet && (usRet <= MAX_VERSION)))
		{
			usRet = NO_VERSION;
		}

		/* Now work through the rest of the digits */
		if (cbBytes)
		{
			usRet = NO_VERSION;
		}

		while (cbBytes--)
		{
			/* Copy the next byte over and increment the length */
			*(pcDst++) = *(pcSrc++);
			(*pusVerLen)++;

		}

	} /* End else at least one digit after ';' */

	return usRet;

} /* end CopyVersionToNumber */


/*
 *  CopyNumberToString ()   - Convert an unsigned integer to a null
 *                          - terminated string.
 */

VOID CopyNumberToString (pcString, usNum)
PCHAR       pcString;
USHORT      usNum;
{
	UCHAR       cTemp;
	UCHAR   FAR *pcStrEnd;

	/* Check for usNum == 0 */
	if (!usNum)
	{
		*pcString++ = '0';
		*pcString = '\0';
	}


	/* Else walk through the string */
	else
	{
		pcStrEnd = pcString;

		/* Walk through the number, stripping the digits */
		while (usNum)
		{
			*pcStrEnd++ = (UCHAR) ('0' + (usNum % 10));
			usNum = usNum / 10;
		}

		/* Null terminate the string */
		*pcStrEnd-- = '\0';

		/* Number stored in reverse, reverse the digits */
		while (pcStrEnd > pcString)
		{
			cTemp = *pcStrEnd;
			*pcStrEnd-- = *pcString;
			*pcString++ = cTemp;
		}

	}
}

/***    DecimalToASCII ()   --  Convert a USHORT to an ASCII string.
 *      
 *  DESCRIPTION
 *
 *      This function takes a USHORT and converts it to an ASCII value.
 *      It will optionally append a NULL to the string and always returns
 *      the length of the string (without the NULL).
 *      
 *      
 *  ENTRY   (Arguements passed to function)
 *      
 *      pcDest      --  Location to store the created string.
 *      ulSource    --  Number to convert.
 *      fAppendNull --  Flag indicating whether to NULL terminate.
 *      
 *
 *  GLOBAL  (Global variables accessed by this function)
 *      
 *     NONE
 *
 *
 *  GOTO    (Jump targets)
 *      
 *      NONE
 *
 *
 *  RETURN  (Value returned by this function)
 *      
 *      Length of created string.
 *
 *
 *  EXIT    (Changes to variables seen outside this function)
 *      
 *      ASCII string stored in pcDst.
 *
 *      
 *  LOCAL   (Variables declared within this function)    
 *      
 *      pcCurrent   --  Local pointer into buffer.
 *      usRet       --  Length of return string.
 *      ucTemp      --  Temporary location for a character.
 */

USHORT  DecimalToASCII (pcDest, ulSource, fAppendNull)
PCHAR   pcDest;
ULONG   ulSource;
BOOL    fAppendNull;
{
	/* Local Variables */
	PCHAR       pcCurrent;
	USHORT      usRet;
	UCHAR       ucTemp;

	/* Set pcCurrent to start of the buffer */
	pcCurrent = pcDest;

	/*
	 *  do loop :
	 *
	 *      The ASCII result is copied in reverse order into the string
	 *      by pulling off digit by digit.
	 *
	 *      At the end, 'pcDst' points to the first character and
	 *      'pcCurrent' points past the last character.
	 */
	do
	{
		*(pcCurrent++) = (UCHAR) (ulSource % 10 + '0');

	} while (ulSource /= 10);

	/* Check for NULL termination */
	if (fAppendNull)
	{
		*pcCurrent = '\0';
	}

	/* Remember the length of the list */
	usRet = (pcCurrent--) - pcDest;

	/* Reverse the list by copy one character into a temp location */
	while (pcCurrent > pcDest)
	{
		ucTemp = *pcCurrent;
		*(pcCurrent--) = *pcDest;
		*(pcDest++) = ucTemp;
	}

	/* Return the length */
	return usRet;
}
