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

/*********************************************************************\
*
* Macros definitions to make life in the DBCS world easier
*
\*********************************************************************/

/* lowest possible lead in character for DBCS char sets */
#define CH_LOW_DBCS_LEAD	0x80

#define DBCS_PTR_SUB( p1, p2 )	    ((USHORT)(	(ULONG) p1) - \
												(USHORT)((ULONG) p2))

/* Need a byte that can always be used as a trailing byte */
#define VALID_TRAIL     '\1'

/*********************************************************************\
*
* Macros to manipulate DBCS Strings.
*
* when these macros return a character in a USHORT, it is always
* encoded as follows:
*
* The char returned is in the low byte if it is a 1 byte char,
* or both bytes of a DBChar with the lead in byte in the low byte.
* this allows a simple cast of (char) to convert single byte chars,
* and keeps the 2nd byte of a DBchar from looking like a valid SB char.
*
* for example:
*   if returning the single byte char 'A', it would be stored as 0x0041
*   if returning the dbchar with lead in of 0x81 and 2nd byte of 0x40,
*	    it would be stored as 0x4081
*
*
* NOTES:
*   These macros assume that a lead in char for DBCS MUST be >= 128
*   they also assume that a 0 can NEVER be a valid 2nd byte of a DBCS char
*
\*********************************************************************/
/*
 * void GetCharAndBmpPtr( PCHAR far *ppstr, PUSHORT pusChar )
 *
 *	Loads the character pointed to by *ppsz and bumps *ppsz by
 * the correct number of bytes.
 *
 * THIS MACRO ASSUMES THE LEAD IN BYTE OF A DBCS CHAR MUST BE >= 128
 */
#define GetCharAndBmpPtr( ppstr, pusChar ) {	\
	if( *(*ppstr) < CH_LOW_DBCS_LEAD ) {	\
	*pusChar = (USHORT)(*(*ppstr)++);	\
	} else {					\
	FSH_LOADCHAR( ppstr, pusChar ); 	\
	}						\
}

/*
 * void GetCharBmpAndDec( PCHAR far *ppstr, PUSHORT pusCount, PUSHORT pusChar)
 *
 *	Loads the character pointed to by *ppsz and bumps *ppsz by
 * the correct number of bytes, and decrements the count pointed to by pusCount
 * by the same ammount
 *
 * THIS MACRO ASSUMES THE LEAD IN BYTE OF A DBCS CHAR MUST BE >= 128
 * THIS MACRO ASSUMES 0 CAN NEVER BE THE 2nd BYTE OF A DBCS CHAR
 */
#define GetCharBmpAndDec( ppstr, pusCount , pusChar ) { \
	if( *(*ppstr) < CH_LOW_DBCS_LEAD ) {		\
	*pusChar = (USHORT)(*(*ppstr)++);		\
	*pusCount -= 1; 				\
	} else {						\
	FSH_LOADCHAR( ppstr, pusChar );			\
	if( *pusChar > 0xFF ) { 			\
		*pusCount -= 2;				\
	} else {					\
		*pusCount -= 1;				\
	}						\
	}							\
}

/*
 * void GetCharBmpAndInc( PCHAR far *ppstr, PUSHORT pusCount, PUSHORT pusChar )
 *
 *	Loads the character pointed to by *ppsz and bumps *ppsz by
 * the correct number of bytes, and increments the count pointed to by pusCount
 * by the same ammount
 *
 * THIS MACRO ASSUMES THE LEAD IN BYTE OF A DBCS CHAR MUST BE >= 128
 * THIS MACRO ASSUMES 0 CAN NEVER BE THE 2nd BYTE OF A DBCS CHAR
 */
#define GetCharBmpAndInc( ppstr, pusCount, pusChar ) {	\
	if( *(*ppstr) < CH_LOW_DBCS_LEAD ) {		\
	*pusChar = (USHORT)(*(*ppstr)++);		\
	*pusCount += 1; 				\
	} else {						\
	FSH_LOADCHAR( ppstr, pusChar );			\
	if( *pusChar > 0xFF ) { 			\
		*pusCount += 2;				\
	} else {					\
		*pusCount += 1;				\
	}						\
	}							\
}


/*
 * void GetCharBmpIndex( PCHAR pstr, PUSHORT pusIndex, PUSHORT pusChar )
 *
 *	Loads the character pointed to by pstr[*pusIndex] and increments
 * the index pointed to by pusIndex by the the correct number of bytes.
 *
 * Use in loops that normally would go something like:
 *	for( i = 0; i < MAX; i++ ) {
 *	    if( ach[i] == CH_TEST )
 *		break or what ever;
 *	}
 *
 * THIS MACRO ASSUMES THE LEAD IN BYTE OF A DBCS CHAR MUST BE >= 128
 */
#define GetCharBmpIndex( pstr, pusIndex, pusChar ) {			\
	if( (*pusChar = (USHORT)(pstr[*pusIndex])) < CH_LOW_DBCS_LEAD ) {	\
	*pusIndex += 1; 						\
	} else {								\
	/* could be a DBCS char, use Krnl to get it */			\
	PCHAR pch = (PCHAR)&pstr[*pusIndex];				\
									\
	FSH_LOADCHAR( &pch, pusChar );					\
	*pusIndex = DBCS_PTR_SUB( pch, pstr );				\
	}									\
}



/*
 * void PrevIndex( PCHAR pstr, PUSHORT pusIndex )
 *
 * Returns the index of the char before this one,  THIS WILL
 * BE SLOW IN SYSTEMS THAT USE DBCS!
 * and pretty slow on systems that don't too!
 */
#define PrevIndex( pstr, pusIndex ) {		    \
	PCHAR pch = (PCHAR)&pstr[*pusIndex];	    \
	FSH_PREVCHAR( pstr, &pch ); 		    \
	*pusIndex = DBCS_PTR_SUB( pch, pstr );	    \
}

/*
 * void PutCharBmpIndex( PCHAR pstr, PUSHORT pusIndex, USHORT usChar )
 *
 *	Stores the character usChar to pstr[*pusIndex] and bumps *pusIndex by
 * the correct number of bytes.
 *
 * THIS MACRO ASSUMES 0 CAN NEVER BE THE 2nd BYTE OF A DBCS CHAR
 */
#define PutCharBmpIndex( pstr, pusIndex, usChar ) {	\
	if( usChar <= 0xFF ) {				\
	pstr[(*pusIndex)++] = (UCHAR)usChar;		\
	} else {						\
	PCHAR pch = (PCHAR)&pstr[*pusIndex];		\
	FSH_STORECHAR( (USHORT)usChar, &pch );		\
	*pusIndex = DBCS_PTR_SUB( pch, pstr );		\
	}							\
}
