ztring.c: A few important extension for <string.h>
 All Classes Files Functions Variables Enumerator Friends Macros
Functions
ztring.c File Reference

Implementation for <ztring.h> More...

#include "ztring.h"
#include <cassert>
#include "uUnit.h"
#include <stdio.h>
#include <string.h>

Go to the source code of this file.

Functions

char * ztrcpy (size_t size, char *dest, const char *src)
 Copies up to 'size' characters from 'src' to 'dest'. More...
 
char * ztrcat (size_t size, char *dest, const char *src)
 Append characters to a string. More...
 
char * ztrins (size_t size, char *dest, size_t n, const char *insert)
 Inserts string 'insert' into 'dest' at position 'n'. More...
 
char * strdel (char *dest, size_t len)
 Deletes the leading 'len' characters from 'str'. More...
 
char * ztrsub (size_t size, char *dest, const char *src, size_t len)
 Copies the first 'len' characters from 'src' to 'dest'. More...
 
char * strltrim (const char *src, char tr)
 Returns a pointer to the first character in 'str' different from 'tr'. More...
 
char * strrtrim (char *src, char tr)
 Removes from 'str' all trailing characters that are equal to 'tr'. More...
 
char * strtrim (char *src, char tr)
 return strrtrim( strltrim(s,tr),tr ). More...
 
size_t memczap (size_t size, void *mem, int ch)
 Removes every ocurrence of 'ch' from 'mem'. More...
 
int strpfx (const char *str, const char *prefix)
 Returns '1' if 'prefix' is a prefix of 'str'. More...
 
int strsffx (const char *str, const char *suffix)
 Returns '1' if 'suffix' is a suffix of 'str'. More...
 
size_t strrspn (const char *str, char a, char z)
 Get span until character in character range '[a..z]'. More...
 
char * strxacct (char *str)
 Uses strxltn1() to convert all letters in 'str'. More...
 
char * strtokl (char *str, const char *delimiters, size_t *len)
 

Detailed Description

Implementation for <ztring.h>

Author
Adolfo Di Mare adolf.nosp@m.o@di.nosp@m.-mare.nosp@m..com
Date
2014

Definition in file ztring.c.

Function Documentation

char* ztrcpy ( size_t  size,
char *  dest,
const char *  src 
)

Copies up to 'size' characters from 'src' to 'dest'.

This is a 'size' checked versions of 'strcpy()'. The 'dest' memory block will always be a null terminated C string (unless 'size' is zero or 'dest' is NULL).

Stops copying when the end of the source C string is found (which is signaled by a null-character), even if less than 'size' characters have been copied (but 'dest' is not padded with zeros).

A null-character is implicitly appended at the end of 'dest' if the length of the 'src' C string is 'size' or bigger; in this case, only a portion of the leading characters from 'src' get copied into 'dest'.

'dest' and 'src' shall not overlap (see 'memmove()' for a safer alternative when overlapping).

See Also
http://www.drdobbs.com/managed-string-library-for-c/184402023
http://en.wikipedia.org/wiki/C_string_handling
Remarks
An alternative to this function is 'strlcpy()': when the size of 'dest' is not big enough, invoking 'strlcpy()' will return the minimun size that 'dest' should have to fit every character from 'src'.
See Also
http://www.openbsd.org/cgi-bin/man.cgi?query=strlcpy
Remarks
Note the differences between this function and strncpy():
  • strncpy() doesn't always NUL terminate; ztrcpy() does.
  • strncpy() pads the destination string with NULs, which is often unnecessary; ztrcpy() does not.
  • zstrcpy() returns a pointer to the destination 'dest' string; this is the same behaviour of both strcpy() and strncpy().
Parameters
sizeSize of the 'dest' memory block.
destPointer to the destination array where the content is to be copied.
srcC string to be copied.
Returns
'dest' is returned.
{{ /* test::ztrcpy() */
char s10[9+1]; /* No more than 9 chars get copied */
{
ztrcpy( sizeof(s10),s10 , "123456789.abcdefghi.");
assertTrue( eqstr( s10 , "123456789" ) );
}
#define ZS(x) sizeof(x),x /* Shortcut macro */
{
ztrcpy( ZS( s10 ), "123456789.abcdefghi.");
assertTrue( eqstr( s10 , "123456789" ) );
}
#undef ZS /* ZS() could make code more compatible with strcpy() */
}}

See Also
test_ztrcpy()
{{ /* test::BeUNsafe::SZ() */
#ifdef USE_ZTR
#define ZS(x) sizeof(x),x /* Shortcut macro */
#else
#define ZS(x) x
/* convert ztrcpy(ZS(dest),src) -> strcpy(dest,src) */
#define ztrcpy( dest, src) strcpy(dest,src)
/* convert ztrcat(ZS(dest),src) -> strcat(dest,src) */
#define ztrcat( dest, src) strcat(dest,src)
#endif
}}

See Also
test_BeUNsafe::SZ()

Definition at line 57 of file ztring.c.

char* ztrcat ( size_t  size,
char *  dest,
const char *  src 
)

Append characters to a string.

This is a 'size' checked versions of 'strcat()'. The 'dest' memory block will always be a null terminated C string (unless 'size' is zero or 'dest' is NULL in which case no characters would be appended).

If appending all characters from 'src' would result in a string with 'size' or more characters, a null-character is implicitly appended to 'dest' to ensure that its length is less than 'size'; in this case, only a portion of the leading characters from 'src' would be appended.

See Also
http://www.openbsd.org/cgi-bin/man.cgi?query=strlcat
http://en.wikipedia.org/wiki/C_string_handling
Parameters
sizeSize of the 'dest' memory block.
destPointer to the destination array of 'size' characters.
srcC string to be appended.
Returns
'dest' is returned.
{{ /* test::ztrcat() */
char s10[9+1]; s10[0] = 0;
ztrcat( sizeof(s10),s10 , "123456789.abcdefghi.");
assertTrue( eqstr( s10 , "123456789" ) );
{
s10[3] = '.'; s10[3+1] = 0;
assertTrue( eqstr( s10 , "123." ) );
ztrcat( sizeof(s10),s10 , "123456789.abcdefghi.");
assertTrue( eqstr( s10 , "123.12345" ) );
}
#define ZS(x) sizeof(x),x /* Shortcut macro */
{
s10[3] = '.'; s10[3+1] = 0;
assertTrue( eqstr( s10 , "123." ) );
ztrcat( ZS(s10), "123456789.abcdefghi.");
assertTrue( eqstr( s10 , "123.12345" ) );
}
#undef ZS /* ZS() could make code more compatible with strcat() */
}}

See Also
test_ztrcat()
{{ /* test::BeUNsafe::SZ() */
#ifdef USE_ZTR
#define ZS(x) sizeof(x),x /* Shortcut macro */
#else
#define ZS(x) x
/* convert ztrcpy(ZS(dest),src) -> strcpy(dest,src) */
#define ztrcpy( dest, src) strcpy(dest,src)
/* convert ztrcat(ZS(dest),src) -> strcat(dest,src) */
#define ztrcat( dest, src) strcat(dest,src)
#endif
}}

See Also
test_BeUNsafe::SZ()

Definition at line 95 of file ztring.c.

char* ztrins ( size_t  size,
char *  dest,
size_t  n,
const char *  insert 
)

Inserts string 'insert' into 'dest' at position 'n'.

If inserting all characters from 'dest' would result in a string with 'size' or more characters, a null-character is implicitly appended to 'dest' to ensure that its length is less than 'size'; in this case, only a portion of the leading characters from 'insert' would be inserted into 'dest'. The 'dest' memory block will always be a null terminated C string.

Any of the following conditions leaves the value in 'dest' unchanged:

  • (insert[0]==0) -> 'insert' is the null string
  • (size == 0)
  • (dest == NULL)

Any of the following conditions will null terminate 'dest':

  • (n >= size)
  • (n > strlen(dest)) -> index out of bounce
  • (insert[0]==0) -> Insert empty string
  • (size==1)
Parameters
sizeSize of the 'dest' memory block.
destPointer to the destination array of 'size' characters.
insertC string to be inserted.
nPosition in 'dest' where the string will be inserted.
Returns
'dest' is returned.
{{ /* test::ztrins() */
char s30[30]; /* 123456789.123456789.1 -> 21 chars */
ztrcpy( sizeof(s30),s30, "====!-----+.........+" );
{ { ztrins( sizeof(s30),s30, 4, "_2_4_"); } } /* [4] <-> s30+(4) */
/* /!\ */
assertTrue( eqstr(s30, "====_2_4_!-----+.........+") );
assertTrue( 26 == strlen("====_2_4_!-----+.........+") );
{ { { assertTrue( 21+strlen("_2_4_") == strlen(s30) ); } } }
{ /* replace JIM with ROMEO */
char *p; char poem[] = "JIM, JIM, JIM ... Where are you?";
while ( 0!=(p=strstr(poem,"JIM")) ) {
strdel( p, strlen("JIM") );
ztrins( sizeof(poem),poem, p-poem, "ROMEO" );
}
assertTrue( eqstr(poem,"ROMEO, ROMEO, ROMEO ... Where ar") );
assertTrue( strlen("JIM")<strlen("ROMEO") ); /* -> truncation */
assertTrue( strlen("ROMEO, ROMEO, ROMEO ... Where ar") ==
strlen("JIM, JIM, JIM ... Where are you?") );
}
ztrcpy( sizeof(s30),s30, "====!-----+.........+" ); /* -> 21 chars */
{ { ztrins( sizeof(s30),s30, 00, "________18________"); } } /* [0] */
assertTrue( eqstr(s30, "________18________====!-----+") );
assertTrue( strlen(s30) == sizeof(s30)-1 ); /* max size */
ztrcpy( sizeof(s30),s30, "0123456789" );
{ { ztrins( /*size->*/1,s30, 0, "" ); } }
assertTrue( eqstr(s30, "") ); /* (size==1) ==> (s30[0]==0) */
assertTrue( eqstr(s30+1 , "123456789" ) );
}}

See Also
test_ztrins()

Definition at line 144 of file ztring.c.

char* strdel ( char *  dest,
size_t  len 
)

Deletes the leading 'len' characters from 'str'.

When 'dest' has less than 'len' characters, it becomes the null string. Any of the following conditions leaves the value in 'dest' unchanged:

  • (dest[0]==0) ==> 'dest' is the null string
  • (len == 0)
  • (dest == NULL)
Parameters
destPointer to the destination array of characters.
lenNumber of characters to remove from 'dest'.
Returns
'dest' is returned.
{{ /* test::strdel() */
char s10[9+1]; char *p; assertTrue( sizeof(s10)>9 );
{ /* remove 5 leading chars from string 's10' */
ztrcpy( sizeof(s10),s10, "123456789.123456789.abcde" );
assertTrue( eqstr(s10, "123456789") );
{ { strdel( s10, 5 ); } }
assertTrue( strlen(s10)==4 && eqstr( s10, "6789" ) );
}
{ /* find leading '.' and remove up to it */
ztrcpy( sizeof(s10),s10, "1234.abcd.1234.abcd" );
if ( NULL!=(p=strchr(s10,'.')) ) { { strdel( s10 , 1+(p-s10) ); } }
assertTrue( eqstr( s10, "abcd" ) ); assertTrue( 4==(p-s10) );
/* (p-s10) -> length of prefix before '.' */
/* 1+(p-s10) -> remove also the '.' */
}
{ /* remove in the middel of 's10' */
ztrcpy( sizeof(s10),s10, "0123..678" );
{ { strdel( s10+4 , 2 ); } } /* s10+4 points inside 's10' */
assertTrue( eqstr( s10, "0123678" ) );
}
}}

See Also
test_strdel()

Definition at line 200 of file ztring.c.

char* ztrsub ( size_t  size,
char *  dest,
const char *  src,
size_t  len 
)

Copies the first 'len' characters from 'src' to 'dest'.

The string in 'dest' is zero terminated. No more than 'size' characters in 'dest' get overwritten.

Parameters
sizeSize of the 'dest' memory block.
destC substring to be produced.
srcSource string.
lenmaximum length of substring to be produced.
{{ /* test::ztrsub() .123456789 */
char str[] = ".123456789.abcdefghi.";
char sub[22];
assertTrue( strlen(str) == 21 && sizeof(sub)==22 );
{ /* first 5 chars from 'str' */
ztrsub( sizeof(sub),sub , str,5 );
assertTrue( eqstr( sub , ".1234" ) );
}
{ /* all chars from 'str' [similar to ztrcpy()] */
ztrsub( sizeof(sub),sub , str,UINT_MAX );
assertTrue( eqstr( sub , str ) );
}
{ /* a substring taken from the middle of 'str' */
ztrsub( sizeof(sub),sub , str+10,7 );
assertTrue( eqstr( sub , ".abcdef" ) );
assertTrue( eqstr( str+10 , ".abcdefghi." ) );
assertTrue( 7 == strlen( ".abcdef" ) );
}
{ /* 0 length substring produces the empty string */
ztrsub( sizeof(sub),sub , str,000 );
assertTrue( eqstr( sub , "" ) );
}
}}

See Also
test_ztrsub()

Definition at line 222 of file ztring.c.

char* strltrim ( const char *  src,
char  tr 
)

Returns a pointer to the first character in 'str' different from 'tr'.

Does not change 'str' but returns a pointer inside it.

Parameters
srcSource string.
trCharacter to trim from left of 'src'.
{{ /* test::strltrim() */
char s[] = " la mona es una loca ";
assertTrue( eqstr( "la mona es una loca " , strltrim( s, ' ' ) ) );
{
char t[] = "XXXla mona es una loca ";
assertTrue( eqstr( "la mona es una loca " , strltrim( t, 'X' ) ) );
assertTrue( eqstr( "XXXla mona es una loca " , t ) ); /* no change */
}
}}

See Also
test_strltrim()

Definition at line 244 of file ztring.c.

char* strrtrim ( char *  src,
char  tr 
)

Removes from 'str' all trailing characters that are equal to 'tr'.

Changes string 'str' and returns a pointer to it. All trailing characters equal to 'tr' are removed inserting one char(0).

Parameters
srcSource string.
trCharacter to trim from right of 'src'.
{{ /* test::strrtrim() */
char s[] = " la mona es una loca ";
assertTrue( eqstr( " la mona es una loca" , strrtrim( s, ' ' ) ) );
{
char t[] = " la mona es una loca XXX";
assertTrue( eqstr( " la mona es una loca " , strrtrim( t, 'X' ) ) );
assertFalse( eqstr( "XXXla mona es una loca ", t ) );
}
}}

See Also
test_strrtrim()

Definition at line 260 of file ztring.c.

char* strtrim ( char *  src,
char  tr 
)

return strrtrim( strltrim(s,tr),tr ).

Returns a pointer to the first character in 's' different from 'tr' but also removes from 's' all trailing characters equal to 'tr'.

Definition at line 288 of file ztring.c.

size_t memczap ( size_t  size,
void *  mem,
int  ch 
)

Removes every ocurrence of 'ch' from 'mem'.

Mnemonic: memczap <==> memory-zap-char.

Scans the memory buffer 'mem' for every occurrence of character 'ch' and removes it, for up to 'size' characters.

  • Stops after 'size' characters have been scanned.
  • Returns the number of non deleted characters that remain in 'mem'.
Returns
the size that the block should have after the characters are removed.
Parameters
sizeSize of memory block 'mem'.
memMemory block of characters.
chCharacter to trim from right of 'src'.
{{ /* test::memczap() */
char m30[30]; size_t n;
strcpy( m30, "-!--!--!-" ); assertTrue( strlen(m30)==9 );
{ /* 12345678 */
n = memczap(strlen(m30),m30, '-' ); /* ZAP '-' */
assertTrue( n==3 && 3==(9-6) );
assertTrue( 0==memcmp(m30, "!!!", strlen("!!!") ) );
assertTrue( 0!=strcmp(m30, "!!!" ) );
/* ==> */ m30[n] = 0; /* <== */
assertTrue( 0==strcmp(m30, "!!!" ) );
}
strcpy( m30, "(*:**-*)" ); assertTrue( strlen(m30)==8 );
{ /* 12345678 */
n = memczap(strlen(m30),m30, '*'); /* ZAP '*' */
assertTrue( n==4 && 4==(8-4) );
assertTrue( 0==memcmp(m30, "(:-)", strlen("(:-)") ) );
assertTrue( 0==memcmp(m30, "(:-)*-*)", strlen(m30) ) );
}
strcpy( m30, "*:**-*" ); assertTrue( strlen(m30)==6 );
{ /* 123456 */
n = memczap(strlen(m30),m30, '*'); /* ZAP '*' */
assertTrue( n==2 && 2==(6-4) );
assertTrue( 0==memcmp(m30, ":-", strlen(":-") ) );
}
}}

See Also
test_memczap()

Definition at line 306 of file ztring.c.

int strpfx ( const char *  str,
const char *  prefix 
)

Returns '1' if 'prefix' is a prefix of 'str'.

Otherwise, returns '0'.

Parameters
strC string to be scanned.
prefixC string containing the sequence of characters to match.
{{ /* test::strpfx() */
assertTrue( strpfx( "123456789.123456789.", "12345678" ) );
assertTrue( strpfx( "123456789.123456789.", "" ) );
assertFalse( strpfx( "12345678" , "123456789.123456789." ) );
}}

See Also
test_strpfx()

Definition at line 380 of file ztring.c.

int strsffx ( const char *  str,
const char *  suffix 
)

Returns '1' if 'suffix' is a suffix of 'str'.

Otherwise, returns '0'.

Parameters
strC string to be scanned.
suffixC string containing the sequence of characters to match.
{{ /* test::strsffx() */
assertTrue( strsffx( "123456789.123456789.", "6789." ) );
assertTrue( strsffx( "123456789.123456789.", "" ) );
assertFalse( strsffx( "6789.", "123456789.123456789." ) );
}}

See Also
test_strsffx()

Definition at line 393 of file ztring.c.

size_t strrspn ( const char *  str,
char  a,
char  z 
)

Get span until character in character range '[a..z]'.

Scans 'str' for the first occurrence of any of the characters that are part of character range begining in 'a' and ending in 'z', returning the number of characters of 'str' read before this first occurrence. The search includes the terminating null-characters. Therefore, the function will return the length of 'str' if none of the characters in range '[a..z]' are found in 'str'.

Parameters
strC string to be scanned.
aFirst character in character range.
zLast character in character range.
Returns
The length of the initial portion of 'str' containing only characters in range.

See Also
test_strrspn()

Definition at line 421 of file ztring.c.

char* strxacct ( char *  str)

Uses strxltn1() to convert all letters in 'str'.

This has the effect of removing accents in many of those letters; for example, 'á' is translated as 'a' and 'ÿ' as 'y'. The translated characters are the upper 8 bit characters in the Latin 1 alphabet, also know as Windows-1252 and ISO/IEC 8859-1.

See Also
http://en.wikipedia.org/wiki/ISO/IEC_8859-1
http://en.wikipedia.org/wiki/Windows-1252

This is the translation table used:

ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
AAAAAAECEEEEIIIIDNOOOOOx0UUUUYPsaaaaaaeceeeeiiiidnooooo/0uuuuypy
{{ /* test::strxacct() */
char Atilde[] = "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ";
char Asimple[] = "AAAAAAECEEEEIIIIDNOOOOOx0UUUUYPsaaaaaaeceeeeiiiidnooooo/0uuuuypy";
char Astr[ sizeof(Atilde) ];
strcpy( Astr, Atilde );
assertTrue( 0==strcmp( Asimple, strxacct(Astr) ) );
}}

See Also
test_strxacct()
{{ /* test::strxltn1() */
char Atilde[] = "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ";
char Asimple[] = "AAAAAAECEEEEIIIIDNOOOOOx0UUUUYPsaaaaaaeceeeeiiiidnooooo/0uuuuypy";
assertTrue( 'A' == strxltn1('Á') ); assertTrue( 'N' == strxltn1('Ñ') );
assertTrue( 'Y' == strxltn1('Ý') ); assertTrue( 'D' == strxltn1('Ð') );
assertTrue( 's' == strxltn1('ß') ); assertTrue( 'P' == strxltn1('Þ') );
assertTrue( 'x' == strxltn1('×') ); assertTrue( '/' == strxltn1('÷') );
assertTrue( '0' == strxltn1('Ø') ); assertTrue( 'd' == strxltn1('ð') );
assertTrue( Atilde != Asimple );
}}

See Also
test_strxltn1()

Definition at line 445 of file ztring.c.

char* strtokl ( char *  str,
const char *  delimiters,
size_t *  len 
)