Message-ID: <3EBD1E56.351FFBC@yahoo.com> Date: Sat, 10 May 2003 11:44:22 -0400 From: CBFalconer Organization: Ched Research X-Mailer: Mozilla 4.75 [en] (Win98; U) X-Accept-Language: en MIME-Version: 1.0 To: djgpp-workers Subject: strlcpy and strlcat Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit 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: /* ------- 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 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 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. USE worldnet address!