This document is a part of a collection of macros. For introductory remarks, see the first part (General Purpose Macros).
For a review of macro-syntax rules and related tips and tricks, see Writing Macros.
For the typedefs CHAR and BYTE, click here.
ASCI characters tests
Code:
#define mIsLetter(ch) \
(!((((BYTE)(ch))<((BYTE)'A'))||((ch)>'z')||(((ch)>'Z')&&(((BYTE)(ch))<((BYTE)'a')))))
#define mIsCapLetter(ch) (((ch)>='A')&&(((BYTE)(ch))<=((BYTE)'Z')))
#define mIsSmallLetter(ch) (((ch)>='a')&&(((BYTE)(ch))<=((BYTE)'z')))
#define mIsWhitespace(ch) (((BYTE)(ch))<=((BYTE)0x20))
#define mIsDecDigit(ch) (((ch)>='0')&&(((BYTE)(ch))<=((BYTE)'9')))
#define mIsHexDigit(ch) (isDecDigit(ch)|| \
!((((BYTE)(ch))<((BYTE)'A'))||((ch)>'f')||((((BYTE)(ch))<((BYTE)'a'))&&((ch)>'F'))))
#define mIsDigit(ch,hexok) (isDecDigit(ch)|| (hexok)? \
!((((BYTE)(ch))<((BYTE)'A'))||((ch)>'f')||((((BYTE)(ch))<((BYTE)'a'))&&((ch)>'F'))):0)
#define mIsOctDigit(ch) (((ch)>='0')&&(((BYTE)(ch))<=((BYTE)'7')))
#define mIsBinDigit(ch) (((ch)=='0')||((ch)=='1'))
#define mIsChrOneOf2(ch,c1,c2) ((((ch)==c1)||((ch)==c2))
#define mIsChrOneOf3(ch,c1,c2,c3) (mIsChrOneOf2(ch,c1,c2)||((ch)==c3))
#define mIsChrOneOf4(ch,c1,c2,c3,c4) (mIsChrOneOf3(ch,c1,c2,c3)||((ch)==c4))
#define mIsChrOneOf5(ch,c1,c2,c3,c4,c5) (mIsChrOneOf4(ch,c1,c2,c3,c4)||((ch)==c5))
#define mIsChrOneOf6(ch,c1,c2,c3,c4,c5,c6) (mIsChrOneOf5(ch,c1,c2,c3,c4,c5)||((ch)==c6))
Arguments:
ch, c1, c2, ... are values or expressions of the type char, CHAR or BYTE
(or one which the compiler can automatically cast to one of these types).
hexok is a flag of any type which can be either zero or nonzero.
The return value is a Boolean type which can be tested for true (0) or false (1).
These macros work also with wide, 16-bit characters (char_w) such as those of Unicode,
provided one limits their use and meaning to the ASCI-compatible subset (bits 7-15 equal to 0).
Notice the casting to (BYTE) of both sides of comparisons of the types < and ≤
This is necessary to force the compiler to do unsigned comparisons rather than a signed one (char is usually configured as signed short, and CHAR is defined in that way). Without the casting, bit 7 could play a havok; for example, the relation (ch)<'A' would be true for any character with bit 7 set. In situations where bit 7 is used as parity bit (e.g., communications of some types) or as a control bit (old Wordstar texts), you should first strip it off. In situation where it is meaningful (extended character sets), instead, the implementations presented here work correctly as they are.
ASCI character conversions
Code:
#define mNoBit7(ch) ((ch)&0x7f)
#define mUCaseChr(ch) (isSmallLetter(ch)?((char)((ch)-32)):(ch))
#define mLCaseChr(ch) (isCapLetter(ch)?((char)((ch)+32)):(ch))
#define mChr2Digit(ch) ((ch)-'0')
#define mChr2HexDigit(ch) \
((((BYTE)(ch))<((BYTE)'A'))?mChr2Digit(ch):mUCaseChr(ch)-('A'-10) )
#define mDigit2Chr(k) ((char)((k)+'0'))
#define mHexDigit2Chr(k) ((char)(((k)<10)?(k)+'0':(k)+('A'-10)))
#define mHexDigit2chr(k) ((char)(((k)<10)?(k)+'0':(k)+('a'-10)))
#define mLastBit2Chr(k) ((k)&1?'1':'0')
Arguments:
ch is a value or expression of the type char, CHAR or BYTE
(or one which the compiler can automatically cast to one of these types).
k is an integer-type value (or a type which the compiler can automatically cast to an integer).
The return value depends upon the particular macro.
These macros work also with wide, 16-bit characters (char_w) such as those of Unicode,
provided one limits their use and meaning to the ASCI-compatible subset (bits 7-15 equal to 0).