[net.sources] strcatx revisited

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;
}