www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/05/10/11:40:56

Message-ID: <3EBD1E56.351FFBC@yahoo.com>
Date: Sat, 10 May 2003 11:44:22 -0400
From: CBFalconer <cbfalconer AT yahoo DOT com>
Organization: Ched Research
X-Mailer: Mozilla 4.75 [en] (Win98; U)
X-Accept-Language: en
MIME-Version: 1.0
To: djgpp-workers <djgpp-workers AT delorie DOT com>
Subject: strlcpy and strlcat
Reply-To: djgpp-workers AT delorie DOT com

I don't know if these are planned for inclusion in 2.04 - I
recommend they be.  At any rate, following is my implementation of
them, with a built in regression test by using -dTESTING.  The
strlcpy code is a bit tricky and minimized. 

They are also available as a package at:

   <http://cbfalconer.home.att.net/download/>

/* ------- file strlcpy.h ------- */
#ifndef strlcpy_h_
#define strlcpy_h_

#ifdef __cplusplus
   extern "C" {
#endif

/* Implementation of strlcpy and strlcat
   See http://www.courtesan.com/todd/papers/strlcpy.html

   These routines are explicitly designed to move no
   data and simply return the projected size of the
   final strings when called with sz == 0.

   In addition they treat src == NULL as an empty string

   strlcat expects that the sz parameter is greater than
   the size of the dst string.  If not, the treatment is
   exactly the same as if a sz value of 0 was used.

   NOTE: these routines are deliberately designed to
   not require any assistance from the standard
   libraries.  This makes them more useful in any
   embedded systems that must minimize the load size.

   Public domain, by C.B. Falconer
   bug reports to mailto:cbfalconer AT worldnet DOT att DOT net
*/

#include <stddef.h>

size_t strlcpy(char *dst, const char *src, size_t sz);
size_t strlcat(char *dst, const char *src, size_t sz);

#ifdef __cplusplus
   }
#endif

#endif
/* ------- End file strlcpy.h ------- */

/* ------- file strlcpy.c ------- */
/* Implementation of strlcpy and strlcat
   See http://www.courtesan.com/todd/papers/strlcpy.html

   These routines are explicitly designed to move no
   data and simply return the projected size of the
   final strings when called with sz == 0.

   In addition they treat src == NULL as an empty string

   strlcat expects that the sz parameter is greater than
   the size of the dst string.  If not, the treatment is
   exactly the same as if a sz value of 0 was used.
*/

#include "strlcpy.h"

/* NOTE: these routines are deliberately designed to
   not require any assistance from the standard
   libraries.  This makes them more useful in any
   embedded systems that must minimize the load size.

   Public domain, by C.B. Falconer
   bug reports to mailto:cbfalconer AT worldnet DOT att DOT net
*/

/* ---------------------- */

size_t strlcpy(char *dst, const char *src, size_t sz)
{
   const char *start = src;

   if (src && sz--) {
      while ((*dst++ = *src))
         if (sz--) src++;
         else {
            *(--dst) = '\0';
            break;
         }
   }
   if (src) {
      while (*src++) continue;
      return src - start - 1;
   }
   else if (sz) *dst = '\0';
   return 0;
} /* strlcpy */

/* ---------------------- */

size_t strlcat(char *dst, const char *src, size_t sz)
{
   char  *start = dst;

   while (*dst++)    /* assumes sz >= strlen(dst) */
      if (sz) sz--;    /* i.e. well formed string */
   dst--;
   return dst - start + strlcpy(dst, src, sz);
} /* strlcat */

/* ---------------------- */

#ifdef TESTING
#include <stdio.h>

typedef size_t (*op)(char *, const char *, size_t);
#define FLD 16

/* ---------------------- */

static void putleftinfld(const char *str, int field, int quote)
{
   int                used;
   static const char *nullstr = "(NULL)";

   if (!str) str = nullstr;
   if (quote) used = printf("\"%s\"", str);
   else       used = printf("%s", str);
   while (used++ < field) putchar(' ');
} /* putleftinfld */

/* ---------------------- */

static void dotest(op fn, char *s1, char *s2, size_t sz)
{
   unsigned long lgh;

   putleftinfld(s1, FLD, 1); putleftinfld(s2, FLD, 1);
   if      (fn == strlcat) printf(" cat ");
   else if (fn == strlcpy) printf(" cpy ");
   else                        printf(" ??? ");
   lgh = fn(s1, s2, sz);
   printf("%3lu %3lu \"%s\"\n", (unsigned long)sz, lgh, s1);
} /* dotest */

/* ---------------------- */

int main(void)
{
   char         *str1     = "string1";
   char          str2[10] = "";
   char          str3[5]  = "";
   char          str4[]   = "";

   puts("Testing lgh = stringop(dest, source, sz)\n");
   putleftinfld(" dest", FLD, 0);
   putleftinfld(" source", FLD, 0);
   puts(" opn  sz lgh  result");
   putleftinfld(" ====", FLD, 0);
   putleftinfld(" ======", FLD, 0);
   puts(" ===  == ===  ======");

   dotest(strlcpy, str2, str1, sizeof str2);
   dotest(strlcpy, str3, str1, sizeof str3);
   dotest(strlcpy, str4, str1, sizeof str4);
   dotest(strlcat, str2, str1, sizeof str2);
   dotest(strlcpy, str2, "x ", sizeof str2);
   dotest(strlcat, str2, str1, sizeof str2);
   dotest(strlcpy, str2, "x ", sizeof str2);
   dotest(strlcat, str2, str1, 0);
   dotest(strlcpy, str2, str1, 0);
   dotest(strlcat, str2, "longer string", 0);
   dotest(strlcpy, str2, NULL, sizeof str2);
   dotest(strlcpy, str2, "x ", sizeof str2);
   dotest(strlcat, str2, NULL, sizeof str2);

   return 0;
} /* main */
#endif
/* ------- End file strlcpy.c ------- */

And the regression test results:

Testing lgh = stringop(dest, source, sz)

 dest            source          opn  sz lgh  result
 ====            ======          ===  == ===  ======
""              "string1"        cpy  10   7 "string1"
""              "string1"        cpy   5   7 "stri"
""              "string1"        cpy   1   7 ""
"string1"       "string1"        cat  10  14 "string1st"
"string1st"     "x "             cpy  10   2 "x "
"x "            "string1"        cat  10   9 "x string1"
"x string1"     "x "             cpy  10   2 "x "
"x "            "string1"        cat   0   9 "x "
"x "            "string1"        cpy   0   7 "x "
"x "            "longer string"  cat   0  15 "x "
"x "            "(NULL)"         cpy  10   0 ""
""              "x "             cpy  10   2 "x "
"x "            "(NULL)"         cat  10   2 "x "


-- 
Chuck F (cbfalconer AT yahoo DOT com) (cbfalconer AT worldnet DOT att DOT net)
   Available for consulting/temporary embedded and systems.
   <http://cbfalconer.home.att.net>  USE worldnet address!

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019