/* nstrl.c - optimized strlcpy/strlcat implementation * Time-stamp: <2004-03-15 njk> * * (C) 2003-2004 Nicholas J. Kain * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #ifndef HAVE_STRLCPY #define HAVE_STRLCPY 1 /* strlcat and strlcpy are optimized for strings of intermediate length * (greater than 8 bytes, but less than 512 bytes */ /* for very small and very large strings, it is suggested to instead use * *_s and *_l */ /* Note that strl* are inherently slower than a memcpy(). It's far more * efficient to just keep track of your string lengths externally and just * memcpy() data around, since it's then easy to use the rep movsl * instruction (or even faster mmx-based primitives on modern processors). * * When I bother to write a simple string library, nul-termination is going * to be the first thing to die... */ #ifdef USE_X86_ASM unsigned int strlcpy(char *dest, char *src, unsigned int size) { unsigned int ret = size, sizeo; char *desto, *srco; asm ( "cld \n\t" "repnz movsb \n\t" "dec %2 \n\t" "movb $0, (%2) \n\t" : "=c"(sizeo), "=S"(srco), "=D"(desto) : "0"(size), "1"(src), "2"(dest) ); return ret - sizeo; } unsigned int strlcat(char *dest, char *src, unsigned int size) { unsigned int ret = size, sizeo; char *desto, *srco; asm ( "xor %%eax, %%eax \n\t" "cld \n\t" "repne scasb \n\t" "dec %2 \n\t" "cld \n\t" "repnz movsb \n\t" "dec %2 \n\t" "movb $0, (%2) \n\t" : "=c"(sizeo), "=S"(srco), "=D"(desto) : "0"(size), "1"(src), "2"(dest) : "%eax"); return ret - sizeo; } /* TODO: write mmx-optimized strlcpy_l and strlcat_l */ #else size_t strlcpy(char *dest, char *src, size_t size) { register unsigned int i; for (i=0; size > 0 && src[i] != '\0'; ++i, size--) dest[i] = src[i]; dest[i] = '\0'; return i; } size_t strlcat(char *dest, char *src, size_t size) { register unsigned int i, j; for(i=0; size > 0 && dest[i] != '\0'; size--, i++); for(j=0; size > 0 && src[i] != '\0'; size--, i++, j++) dest[i] = src[j]; dest[i] = '\0'; return i; } size_t strlcpy_l(char *dest, char *src, size_t size) { return strlcpy(dest, src, size); } size_t strlcat_l(char *dest, char *src, size_t size) { return strlcat(dest, src, size); } #endif /* USE_X86_ASM */ #endif /* HAVE_STRLCPY */