D
dj3vande
I wrote these for a hobby project (I wanted to use them, but needed to
be able to build it on systems that don't have them), and it's probably
worth letting CLC rip them to shreds before I call them done.
They implement, modulo bugs, the behavior of the BSD strlcat and
strlcpy functions. Interestingly, the system I'm actually posting from
(SunOS 5.8) fails one of the tests at the bottom when it uses the
versions in the system library.
They're intended to be in the common subset of C90 and C99. Comments
on correctness and clarity are welcome; comments on style will be
tolerated.
dave
strl.h:
--------
#ifndef H_STRL
#define H_STRL
/*Implementation of BSD strlcat and strlcpy, for systems that don't have them.
Written by Dave Vandervies, December 2007.
Placed in the public domain; attribution is appreciated.
*/
#ifdef __cplusplus
extern "C" { /*make C++ compilers play nicely with the linker*/
#endif
#ifndef HAS_STRLFUNCS
/*strlcpy copies a string from src to dest, creating a string at most
maxlen bytes long (including the '\0' terminator).
Returns the length of the string that would be created without
truncation, excluding the '\0' terminator. (So if the return value
is >= maxlen, the result was truncated.)
*/
size_t my_strlcpy(char *dest,const char *src,size_t maxlen);
/*strlcat appends the contents of src to dest, creating a string at
most maxlen bytes long (including the '\0' terminator).
If src is already longer than maxlen bytes long, its contents
are not changed.
Returns the length of the string that would be created without
truncation, excluding the '\0' terminator, or maxlen+strlen(src)
if no '\0' is found within maxlen bytes of *dest. (So if the
return value is >= maxlen, the result was truncated.)
*/
size_t my_strlcat(char *dest,const char *src,size_t maxlen);
#ifndef CLC_PEDANTIC
#undef strlcpy
#define strlcpy my_strlcpy
#undef strlcat
#define strlcat my_strlcat
#endif /*CLC_PEDANTIC*/
#else /*HAS_STRLFUNCS*/
#include <string.h>
#endif /*HAS_STRLFUNCS*/
#ifdef __cplusplus
} /*close extern "C"*/
#endif
#endif /*H_STRL #include guard*/
--------
strl.c:
--------
#include <assert.h>
#include <string.h>
#include "strl.c"
/*Implementation of BSD strlcat and strlcpy, for systems that don't have them.
Written by Dave Vandervies, December 2007.
Placed in the public domain; attribution is appreciated.
*/
#ifndef HAS_STRLFUNCS
size_t my_strlcpy(char *dest,const char *src,size_t maxlen)
{
size_t len,needed;
#ifdef PARANOID
assert(dest!=NULL);
assert(src!=NULL);
#endif
len=needed=strlen(src)+1;
if(len >= maxlen)
len=maxlen-1;
memcpy(dest,src,len);
dest[len]='\0';
return needed-1;
}
size_t my_strlcat(char *dest,const char *src,size_t maxlen)
{
size_t src_len,dst_len;
size_t len,needed;
#ifdef PARANOID
assert(dest!=NULL);
assert(src!=NULL);
#endif
src_len=strlen(src);
/*Be paranoid about dest being a properly terminated string*/
{
char *end=memchr(dest,'\0',maxlen);
if(!end)
return maxlen+src_len;
dst_len=end-dest;
}
len=needed=dst_len+src_len+1;
if(len >= maxlen)
len=maxlen-1;
memcpy(dest+dst_len,src,len-dst_len);
dest[len]='\0';
return needed-1;
}
#endif /*!HAS_STRLFUNCS*/
#ifdef UNIT_TEST
#include <stdio.h>
/*
dj3vande@goofy:~/clc (0) $ gcc -W -Wall -ansi -pedantic -O -DUNIT_TEST -ostrl strl.c
dj3vande@goofy:~/clc (0) $ ./strl
strlcpy with truncation: Expect `hel'/5: `hel'/5
strlcat with truncation: Expect `help!'/9: `help!'/9
strlcpy without truncation: Expect `help!'/5: `help!'/5
strlcat without truncation: Expect `help!help!'/10: `help!help!'/10
strlcat with maxlen<strlen(dest): Expect `help!help!'/9: `help!help!'/9
dj3vande@goofy:~/clc (0) $
*/
int main(void)
{
char buf1[256],buf2[256];
unsigned long ret;
#ifdef HAS_STRLFUNCS
#define my_strlcpy strlcpy
#define my_strlcat strlcat
printf("Using system library versions\n");
#endif
ret=my_strlcpy(buf1,"hello",4);
printf("strlcpy with truncation: Expect `hel'/5: `%s'/%lu\n",buf1,ret);
ret=my_strlcat(buf1,"p!!!!!",6);
printf("strlcat with truncation: Expect `help!'/9: `%s'/%lu\n",buf1,ret);
ret=my_strlcpy(buf2,buf1,sizeof buf2);
printf("strlcpy without truncation: Expect `help!'/5: `%s'/%lu\n",buf2,ret);
ret=my_strlcat(buf2,buf1,sizeof buf2);
printf("strlcat without truncation: Expect `help!help!'/10: `%s'/%lu\n",buf2,ret);
ret=my_strlcat(buf2,buf1,4);
printf("strlcat with maxlen<strlen(dest): Expect `help!help!'/9: `%s'/%lu\n",buf2,ret);
return 0;
}
#endif /*UNIT_TEST*/
--------
be able to build it on systems that don't have them), and it's probably
worth letting CLC rip them to shreds before I call them done.
They implement, modulo bugs, the behavior of the BSD strlcat and
strlcpy functions. Interestingly, the system I'm actually posting from
(SunOS 5.8) fails one of the tests at the bottom when it uses the
versions in the system library.
They're intended to be in the common subset of C90 and C99. Comments
on correctness and clarity are welcome; comments on style will be
tolerated.
dave
strl.h:
--------
#ifndef H_STRL
#define H_STRL
/*Implementation of BSD strlcat and strlcpy, for systems that don't have them.
Written by Dave Vandervies, December 2007.
Placed in the public domain; attribution is appreciated.
*/
#ifdef __cplusplus
extern "C" { /*make C++ compilers play nicely with the linker*/
#endif
#ifndef HAS_STRLFUNCS
/*strlcpy copies a string from src to dest, creating a string at most
maxlen bytes long (including the '\0' terminator).
Returns the length of the string that would be created without
truncation, excluding the '\0' terminator. (So if the return value
is >= maxlen, the result was truncated.)
*/
size_t my_strlcpy(char *dest,const char *src,size_t maxlen);
/*strlcat appends the contents of src to dest, creating a string at
most maxlen bytes long (including the '\0' terminator).
If src is already longer than maxlen bytes long, its contents
are not changed.
Returns the length of the string that would be created without
truncation, excluding the '\0' terminator, or maxlen+strlen(src)
if no '\0' is found within maxlen bytes of *dest. (So if the
return value is >= maxlen, the result was truncated.)
*/
size_t my_strlcat(char *dest,const char *src,size_t maxlen);
#ifndef CLC_PEDANTIC
#undef strlcpy
#define strlcpy my_strlcpy
#undef strlcat
#define strlcat my_strlcat
#endif /*CLC_PEDANTIC*/
#else /*HAS_STRLFUNCS*/
#include <string.h>
#endif /*HAS_STRLFUNCS*/
#ifdef __cplusplus
} /*close extern "C"*/
#endif
#endif /*H_STRL #include guard*/
--------
strl.c:
--------
#include <assert.h>
#include <string.h>
#include "strl.c"
/*Implementation of BSD strlcat and strlcpy, for systems that don't have them.
Written by Dave Vandervies, December 2007.
Placed in the public domain; attribution is appreciated.
*/
#ifndef HAS_STRLFUNCS
size_t my_strlcpy(char *dest,const char *src,size_t maxlen)
{
size_t len,needed;
#ifdef PARANOID
assert(dest!=NULL);
assert(src!=NULL);
#endif
len=needed=strlen(src)+1;
if(len >= maxlen)
len=maxlen-1;
memcpy(dest,src,len);
dest[len]='\0';
return needed-1;
}
size_t my_strlcat(char *dest,const char *src,size_t maxlen)
{
size_t src_len,dst_len;
size_t len,needed;
#ifdef PARANOID
assert(dest!=NULL);
assert(src!=NULL);
#endif
src_len=strlen(src);
/*Be paranoid about dest being a properly terminated string*/
{
char *end=memchr(dest,'\0',maxlen);
if(!end)
return maxlen+src_len;
dst_len=end-dest;
}
len=needed=dst_len+src_len+1;
if(len >= maxlen)
len=maxlen-1;
memcpy(dest+dst_len,src,len-dst_len);
dest[len]='\0';
return needed-1;
}
#endif /*!HAS_STRLFUNCS*/
#ifdef UNIT_TEST
#include <stdio.h>
/*
dj3vande@goofy:~/clc (0) $ gcc -W -Wall -ansi -pedantic -O -DUNIT_TEST -ostrl strl.c
dj3vande@goofy:~/clc (0) $ ./strl
strlcpy with truncation: Expect `hel'/5: `hel'/5
strlcat with truncation: Expect `help!'/9: `help!'/9
strlcpy without truncation: Expect `help!'/5: `help!'/5
strlcat without truncation: Expect `help!help!'/10: `help!help!'/10
strlcat with maxlen<strlen(dest): Expect `help!help!'/9: `help!help!'/9
dj3vande@goofy:~/clc (0) $
*/
int main(void)
{
char buf1[256],buf2[256];
unsigned long ret;
#ifdef HAS_STRLFUNCS
#define my_strlcpy strlcpy
#define my_strlcat strlcat
printf("Using system library versions\n");
#endif
ret=my_strlcpy(buf1,"hello",4);
printf("strlcpy with truncation: Expect `hel'/5: `%s'/%lu\n",buf1,ret);
ret=my_strlcat(buf1,"p!!!!!",6);
printf("strlcat with truncation: Expect `help!'/9: `%s'/%lu\n",buf1,ret);
ret=my_strlcpy(buf2,buf1,sizeof buf2);
printf("strlcpy without truncation: Expect `help!'/5: `%s'/%lu\n",buf2,ret);
ret=my_strlcat(buf2,buf1,sizeof buf2);
printf("strlcat without truncation: Expect `help!help!'/10: `%s'/%lu\n",buf2,ret);
ret=my_strlcat(buf2,buf1,4);
printf("strlcat with maxlen<strlen(dest): Expect `help!help!'/9: `%s'/%lu\n",buf2,ret);
return 0;
}
#endif /*UNIT_TEST*/
--------