ASCI Strings C/C++ Macros
by Stanislav Sýkora, Extra Byte, Via R.Sanzio 22C, Castano Primo, Italy 20022
in Stan's Library, Ed.S.Sykora, Vol.II. First release March 30, 2007.
Permalink via DOI:  10.3247/SL2Soft07.005
PREVIOUS | NEXT | Code snippets | Software Books and Links Programming Section of Stan' LIBRARY | Stan's HUB

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 DWORD, WORD, BYTE, CHAR and NULL, click here.

The strings considered here are zero-terminated, composed of CHARs and pointed to as CHAR* (or LPSTR).
Some of the macros, however, would work also with strings composed of wide, 16 bit characters (such as Unicode).
This condition will be explicitely mentioned.

CATEGORY MACRO
ALLOCATIONS mNewStr, mNewBlankStr, mKillStr,
TESTS mIsVoidStr, mIsNotVoidStr, mIsEmptyStr,
EXTRACTIONS mFirstChr, mLastChr
OUTPUT mStrYN, mStrTF
HANDLING mSkipToEnd, mSkipChrIfNZ, mSkipToChr, mSkipBeyondChr
mSkipWhiteSpace, mSkipToWhiteSpace, mSkipOverWhiteSpace
mTerminateAtChr, mSkipToChrAndTerminate, mRestoreChrAndSkip

Allocations / disallocations

Code:

#define mNewStr(len) (new CHAR[(len)+1])
#define mNewBlankStr(str,len) {(str)=mNewStr(len);if (str) (str)[0]=0;}
#define mKillStr(str) {if (str) {delete (str); (str)=NULL;}}

Arguments:

len, ex are expressions of any integer type evaluating to a non-negative value.
str is a pointer to a dynamically allocated string.

For return values, see the individual descriptions.


mNewStr(len)
allocates space for a string of len characters, plus the terminating zero.
It returns the pointer to the new string or, in case of failure, a NULL pointer.
Remember that all dynamically allocated strings must be eventually disallocated.
mNewBlankStr(str,len)
is an action macro which allocates space for a string of len characters, sets pointer to it into str
and, upon success, initializes it by inserting a terminator into its first character.
Again, once it is no longer needed, the new string must be disallocated.
mKillStr(str)
deletes the dynamically allocated string str, unless already disallocated.
To flag that it has been deleted, it sets the pointer str to NULL and it avoids deleting NULL strings.
This is an action macro which does not return anything.
 
Consequently, nothing bad happens when it is called more than once for the same string.
This is a trick I use for all allocations/disallocations (pity that most compilers don't do it automatically).
Example of usage:

LPSTR mystring = mNewStr(32);   /* Allocate a string of 32 characters (net) */
if (mystring) { /* Upon success, do something with it */ }
mKillStr(mystring);   /* When finished and not NULL, delete it */

Elementary tests

Code:

#define mIsVoidStr(str) ((!(str))||(*(str)==0))
#define mIsNotVoidStr(str) ((str)&&(*(str)!=0))
#define mIsEmptyStr(str) (*(str)==0)

Arguments:

str is a pointer to string of the type char*, or equivalent.

The return value is a boolean type which can be tested for true (0) or false (1).

These macros work also with strings containing wide characters.


mIsVoidStr(str)
tests whether the string is either NULL or blank (i.e., contains no characters).
Passing NULL string instead of a blank one is often used to flag a special calling condition
or as a default argument value and the possibility needs to be taken into account.
mIsNotVoidStr(str)
tests whether the string contains at least one character. Equivalent to !mIsVoidString(str).
mIsEmptyStr(str)
tests whether the string is blank (i.e., contains no characters).
In this case, the pointer str may not be NULL.

Elementary extractions

Code:

#define mFirstChr(str) (mIsVoidStr(str)?0:(str)[0])
#define mLastChr(str) (mIsVoidStr(str)?0:(str)[StrLength(str)-1])

Arguments:

str is a pointer to string of the type char*, or equivalent.

The return value is a character. The macros work with ASCI characters, as well as with wide, 16-bit characters (char_w) such as those of Unicode.


mFirstChr(str)
returns the first character of the string, or 0 when it is NULL or empty.
mLastChr(str)
returns the last valid character of the string, or 0 when it is NULL or empty.
This macro relies on the function StrLength(str) which returns the length of the string.
Every strings-handling program should contain an implementation of such a function.
this is our preferred implementation:

DWORD StrLength(str) {CHAR* ptr=str; while (*ptr) ptr++; return (ptr-str);}

Special output strings

Code:

#define mStrYN(ex) ((ex) ? "Yes" : "Not")
#define mStrTF(ex) ((ex) ? "True" : "False")

Arguments:

ex is any expression that can be interpreted as (or converted to a boolean type) and tested for true or false.

The return value is a pointer to a constant ASCI string.
These and similar macros can be also implemented by means of the mChoice... macros.
For example, mStrYN(ex) is equivalent to mChoiceTF(ex,"Yes","Not").


mStrYN(ex)
returns either "Yes" or "Not", depending upon the actual value of the argument.
mStrTF(ex)
returns either "True" or "False", depending upon the actual value of the argument.

Strings handling

Code:

#define mSkipToEnd(str) {while(*(str))(str)++;}
#define mSkipChrIfNZ(str) {if(*(str))(str)++;}
#define mSkipToChr(str,ch) {while((*(str))&&(*(str)!=(ch)))(str)++;}
#define mSkipBeyondChr(str,ch) {mSkipToChr(str,ch);mSkipChrIfNZ(str);}

#define mSkipWhiteSpace(str) {while((*(str))&& mIsWhitespace(*(str)))(str)++;}
#define mSkipToWhiteSpace(str) {while((*(str))&& !mIsWhitespace(*(str)))(str)++;}
#define mSkipOverWhiteSpace(str) {mSkipToWhiteSpace(str);mSkipWhiteSpace(str);}

#define mTerminateAtChr(str,ch) {mSkipToChr(str,ch);*(str)=0;}
#define mSkipToChrAndTerminate(str,ch,auxch) {mSkipToChr(str,ch);auxch=*(str);*(str)=0;}
#define mRestoreChrAndSkip(str,auxch) {*(str)=auxch;if(auxch)(str)++;}

Arguments:

str is an l-value of the type char*, or equivalent.
ch is a value or expressions of the type char, CHAR or BYTE, or equivalent.
auxch is an l-value of the type char, CHAR or BYTE, or equivalent.

These are action macros which have no return value.
As elementary parsers, they are useful in many string-interpretation situations.


mSkipToEnd(str)
increments the string pointer until it points to a string-terminating zero character.
mSkipChrIfNZ(str)
increments (advances) the string pointer by 1, unless it points to a zero character (string terminator).
mSkipToChr(str,ch)
increments the string pointer until it points to a character whose value either matches ch or is zero.
mSkipBeyondChr(str,ch)
Like mSkipToChr, increments the string pointer until it points to a character whose value either matches ch or is zero.
In the first case, increments it by one to point just beyond the character.
mSkipWhiteSpace(str)
In case str points to a non-printing (white) character, increments it until
it either hits a printing non-white character or the terminating zero.
mSkipToWhiteSpace(str)
In case str points to a printing (non-white) character, increments it until
it either hits a non-printing white character or the terminating zero. Opposite of mSkipWhiteSpace(str).
mSkipOverWhiteSpace(str)
Concatenates mSkipToWhiteSpace(str) with mSkipWhiteSpace(str).
mTerminateAtChr(str,ch)
skips to next character equal to ch and replaces it by zero.
If the string does not contain ch, stops at the terminating zero with nothing done.
mSkipToChrAndTerminate(str,ch,auxch)
is like mTerminateAtChr but saves in auxch either the cgaracter ch (if found) or zero (if not found).
Used during parsing to set a temporary terminator (see mRestoreChrAndSkip for the opposite action)
mRestoreChrAndSkip(str,auxch)
replaces the currently pointed character with auxch and, when this is not zero, increments the string pointer by 1.
Usually used as an 'undo' for mSkipToChrAndTerminate.
TOP | PREVIOUS | NEXT | Code snippets | Software Books and Links Programming Section of Stan' LIBRARY | Stan's HUB
Copyright ©2007 Stanislav Sýkora    DOI: 10.3247/SL2Soft07.005 Designed by Stan Sýkora