hansen (01/21/83)
After writing the portable version of strcatx recently posted on the net by David Yablon (seismo!dmy), and seeing efficient versions also posted, I decided to make my portable version efficient as well. I don't know why I didn't code the routine efficiently in the first place. But it is now highly efficient, AND highly portable, as long as your system has a varargs.h. If it doesn't, it SHOULD be rather simple to whip one up. It has also been de-linted and TESTED, so I know it works. While I was at it, I wrote corresponding versions of strcpy(3), strncat(3), and strncpy(3). Some of you may know the latter two as strcatn(3) and strcpyn(3). The names of these two routines were changed by Bell around the time of PWB Unix so that the names would be library-unique in the first six characters. In keeping with this philosophy, I renamed the strcatx(3) routine to be strxcat(3), and named the other routines strxncat(3), strxcpy(3) and strxncpy(3). I also whipped up a manual page, called xstring(3c) for the routines. This should probably be combined with the existing string(3c) manual page. The routines now also return a pointer to their destination, as do the routines in string(3c). Sincerely, Tony Hansen pegasus!hansen P.S. I've already found a few uses for these routines in some of my own code. Thanks, Dave, for asking for this useful routine and prompting me to write the others. ==> xstring.3c <== .TH XSTRING 3C .SH NAME strxcat, strxncat, strxcpy, strxncpy \- string operations with variable number of arguments .SH SYNOPSIS .nf .PP .B char \(**strxcat (dest, s1, s2, 0) .B char \(**dest, \(**s1, \(**s2, ...; .PP .B char \(**strxncat (dest, n, s1, s2, 0) .B char \(**dest, \(**s1, \(**s2, ...; .B int n; .PP .B char \(**strxcpy (dest, s1, s2, ..., 0) .B char \(**dest, \(**s1, \(**s2, ...; .PP .B char \(**strxncpy (dest, n, s1, s2, ..., 0) .B char \(**dest, \(**s1, \(**s2, ...; .B int n; .SH DESCRIPTION Thes functions operate on null-terminated strings. They do not check for overflow of any receiving string. They are equivalent to the corresponding functions .IR strcat(3c) , .IR strncat(3c) , .IR strcpy(3c) , and .IR strncpy(3c) , except that they allow more than one source string to be named. All routines return a pointer to their destination. .PP .I Strxcat\^ appends a copy of the strings .IR s1 , s2 , and so on, to .IR dest . .I Strxncat\^ copies at most .I n\^ characters. .I Strxcpy\^ copies strings .IR s1 , s2 , and so on, into .IR dest . .I Strxncpy\^ copies exactly .I n\^ characters, truncating or null-padding the source strings; the target may not be null-terminated if the length of the concatenation of .IR s1 , s2 , etc., is .I n\^ or more. .SH BUGS The placement for the .I n\^ variable is different from that in the functions .I strncat(3c) and .IR strncpy(3c) . ==> xstring.c <== #include <varargs.h> /* VARARGS1 */ /* strxcat(dest, s1, s2, ..., 0) */ char *strxcat(dest, va_alist) register char *dest; va_dcl { va_list argptr; register char *src; char *p = dest; while (*dest) dest++; /* go to end of destination */ va_start(argptr); while (src = va_arg(argptr, char *))/* src=s[i] */ while (*src) *dest++ = *src++; /* strcat(dest,s[i]) */ *dest = '\0'; va_end(argptr); return p; } /* VARARGS2 */ /* strxncat(dest, n, s1, s2, ..., 0) */ char *strxncat(dest, n, va_alist) register char *dest; register int n; va_dcl { va_list argptr; register char *src; char *p = dest; while (*dest) dest++; /* go to end of destination */ va_start(argptr); while (src = va_arg(argptr, char *))/* src = s[n] */ while (*src && n--) /* strncat(dest,s[n],n) */ *dest++ = *src++; *dest = '\0'; va_end(argptr); return p; } /* VARARGS1 */ /* strxcpy(dest, s1, s2, ..., 0) */ char *strxcpy(dest, va_alist) register char *dest; va_dcl { va_list argptr; register char *src; char *p = dest; va_start(argptr); /* dest="" */ while (src = va_arg(argptr, char *))/* src=s[i] */ while (*src) /* strcat(dest,s[i]) */ *dest++ = *src++; *dest = '\0'; va_end(argptr); return p; } /* VARARGS2 */ /* strxncpy(dest, n, s1, s2, ..., 0) */ char *strxncpy(dest, n, va_alist) register char *dest; register int n; va_dcl { va_list argptr; register char *src; char *p = dest; va_start(argptr); /* dest="" */ while (src = va_arg(argptr, char *))/* src=s[i] */ while (*src && n--) /* strncat(dest,s[i],n) */ *dest++ = *src++; if (n) *dest = '\0'; va_end(argptr); return p; }