[net.sources] strxcat.c and xstring revisited

hansen@pegasus.UUCP (05/24/84)

A year ago, I posted the following functions to the net. They are a set
of functions that are similar to strcat and strcpy, except that they accept
a variable number of string arguments.

The reason that I am reposting them is that, recently, I found out that my
use of <varargs.h> may not have been completely portable! It seems that
there may be certain architectures or implementations of C that do not allow
one to declare a varargs program as:

	#include <varargs.h>
	foo (format, va_alist)
	char *format;
	va_dcl
	{

Instead, one must declare them as:

	#include <varargs.h>
	foo (va_alist)
	va_dcl
	{

and then pick ALL of the arguments off of the stack, as in:

	    va_list argptr;
	    char *format;
	    va_start(argptr);
	    format = va_arg(argptr, char *);

Note that I have NOT actually SEEN any computer with this problem, but it
seems to me that I've heard of certain implementations where pointers and
integers are actually placed on different stacks rather than intermixed on
the same stack.

The documentation for varargs in 4.xBSD and System V Release 2 have an
example similar to the second one above. However, I have seen many programs
that implemented an error() function with the first couple of arguments
defined, as I did in my first set of xstring functions. The sample
implementation of error() to be found on the vprintf(3S) manual page in Sys
Vr2 does NOT declare any additional arguments, but picks them off.

Anyways, I thought you should all get the latest version of xstring.3 with
its new and improved portability.

If anyone knows more about the purposed problems, please keep the discussion
only to net.unix-wizards and not to net.sources.

				Sincerely,
				Tony Hansen
				pegasus!hansen

---------------- cut here ----------------
echo x - xstring.3c
sed 's/^X//' > xstring.3c << '~FUNKY STUFF~'
X.TH XSTRING 3C
X.SH NAME
Xstrxcat, strxncat, strxcpy, strxncpy \- string operations with variable number of arguments
X.SH SYNOPSIS
X.nf
X.P
X.B "char \(**strxcat (dest, s1, s2, ..., (char \(**) 0)"
X.B "char \(**dest, \(**s1, \(**s2, ...;"
X.P
X.B "char \(**strxncat (dest, n, s1, s2, ..., (char \(**) 0)"
X.B "char \(**dest, \(**s1, \(**s2, ...;"
X.B "int n;"
X.P
X.B "char \(**strxcpy (dest, s1, s2, ..., (char \(**) 0)"
X.B "char \(**dest, \(**s1, \(**s2, ...;"
X.P
X.B "char \(**strxncpy (dest, n, s1, s2, ..., (char \(**) 0)"
X.B "char \(**dest, \(**s1, \(**s2, ...;"
X.B "int n;"
X.SH DESCRIPTION
XThese functions operate on null-terminated strings.
XThey are equivalent to the corresponding functions
X.IR strcat (3c),
X.IR strncat (3c),
X.IR strcpy (3c),
Xand
X.IR strncpy (3c),
Xexcept that they allow more than one source string to be named.
XAll routines return a pointer to their destination.
XThey do not check for overflow of any receiving string.
X.P
X.I Strxcat\^
Xappends a copy of the strings
X.IR s1 ,
X.IR s2 ,
Xand so on, to
X.IR dest .
X.I Strxncat\^
Xcopies at most
X.I n\^
Xcharacters.
XThe resulting string will always be null-terminated.
X.P
X.I Strxcpy\^
Xcopies the strings
X.IR s1 ,
X.IR s2 ,
Xand so on, into
X.IR dest .
X.I Strxncpy\^
Xcopies at most
X.I n\^
Xcharacters.
XThe resulting string will not be null-terminated if
X.I n\^
Xor more characters were in the source strings.
X.SH CAVEATS
XThe placement for the
X.I n\^
Xvariable is different from the placement in the functions
X.IR strncat (3c) 
Xand
X.IR strncpy (3c).
~FUNKY STUFF~
echo x - makefile
sed 's/^X//' > makefile << '~FUNKY STUFF~'
XSRC= strxcat.c strxcpy.c strxncat.c strxncpy.c
XOBJ= $(SRC:.c=.o)
XLIB= xstring.a
X
X$(LIB): $(OBJ)
X	ar rv $(LIB) $?
X
Xxstrtest: xstrtest.c $(LIB)
X	cc $@.c $(LIB) -o $@
~FUNKY STUFF~
echo x - str*.c.3c
sed 's/^X//' > str*.c.3c << '~FUNKY STUFF~'
~FUNKY STUFF~

hansen@pegasus.UUCP (Tony L. Hansen) (05/25/84)

Sorry about that, the .c files weren't in the previous shar that I posted.
You'll find it all below.

				Sincerely,
				Tony Hansen
				pegasus!hansen

---------------- cut here ----------------
echo x - xstring.3c
sed 's/^X//' > xstring.3c << '~FUNKY STUFF~'
X.TH XSTRING 3C
X.SH NAME
Xstrxcat, strxncat, strxcpy, strxncpy \- string operations with variable number of arguments
X.SH SYNOPSIS
X.nf
X.P
X.B "char \(**strxcat (dest, s1, s2, ..., (char \(**) 0)"
X.B "char \(**dest, \(**s1, \(**s2, ...;"
X.P
X.B "char \(**strxncat (dest, n, s1, s2, ..., (char \(**) 0)"
X.B "char \(**dest, \(**s1, \(**s2, ...;"
X.B "int n;"
X.P
X.B "char \(**strxcpy (dest, s1, s2, ..., (char \(**) 0)"
X.B "char \(**dest, \(**s1, \(**s2, ...;"
X.P
X.B "char \(**strxncpy (dest, n, s1, s2, ..., (char \(**) 0)"
X.B "char \(**dest, \(**s1, \(**s2, ...;"
X.B "int n;"
X.SH DESCRIPTION
XThese functions operate on null-terminated strings.
XThey are equivalent to the corresponding functions
X.IR strcat (3c),
X.IR strncat (3c),
X.IR strcpy (3c),
Xand
X.IR strncpy (3c),
Xexcept that they allow more than one source string to be named.
XAll routines return a pointer to their destination.
XThey do not check for overflow of any receiving string.
X.P
X.I Strxcat\^
Xappends a copy of the strings
X.IR s1 ,
X.IR s2 ,
Xand so on, to
X.IR dest .
X.I Strxncat\^
Xcopies at most
X.I n\^
Xcharacters.
XThe resulting string will always be null-terminated.
X.P
X.I Strxcpy\^
Xcopies the strings
X.IR s1 ,
X.IR s2 ,
Xand so on, into
X.IR dest .
X.I Strxncpy\^
Xcopies at most
X.I n\^
Xcharacters.
XThe resulting string will not be null-terminated if
X.I n\^
Xor more characters were in the source strings.
X.SH CAVEATS
XThe placement for the
X.I n\^
Xvariable is different from the placement in the functions
X.IR strncat (3c) 
Xand
X.IR strncpy (3c).
~FUNKY STUFF~
echo x - makefile
sed 's/^X//' > makefile << '~FUNKY STUFF~'
XSRC= strxcat.c strxcpy.c strxncat.c strxncpy.c
XOBJ= $(SRC:.c=.o)
XLIB= xstring.a
X
X$(LIB): $(OBJ)
X	ar rv $(LIB) $?
X
Xxstrtest: xstrtest.c $(LIB)
X	cc $@.c $(LIB) -o $@
~FUNKY STUFF~
echo x - strxcat.c
sed 's/^X//' > strxcat.c << '~FUNKY STUFF~'
X#include <varargs.h>
X
X/* VARARGS */
X/* strxcat(dest, s1, s2, ..., (char *) 0) */
Xchar *strxcat (va_alist)
Xva_dcl
X{
X    va_list argptr;
X    register char *dest, *src, *retptr;
X
X    va_start(argptr);
X    retptr = dest = va_arg(argptr, char *);
X
X    /* go to the end of the destination */
X    while (*dest != '\0')
X	dest++;
X
X    /* src = arg[i] */
X    while ((src = va_arg(argptr, char *)) != (char *)0)
X	/* strcat(dest,arg[i]) */
X	while (*src != '\0')
X	    *dest++ = *src++;
X
X    *dest = '\0';
X    va_end(argptr);
X    return retptr;
X}
~FUNKY STUFF~
echo x - strxcpy.c
sed 's/^X//' > strxcpy.c << '~FUNKY STUFF~'
X#include <varargs.h>
X
X/* VARARGS */
X/* strxcpy(dest, s1, s2, ..., (char *) 0) */
Xchar *strxcpy(va_alist)
Xva_dcl
X{
X    va_list argptr;
X    register char *dest, *src, *retptr;
X
X    va_start(argptr);
X    retptr = dest = va_arg(argptr, char *);	    /* dest="" */
X
X    /* src = arg[i] */
X    while ((src = va_arg(argptr, char *)) != (char *) 0)
X	/* strcat(dest,s[i]) */
X	while (*src != '\0')
X	    *dest++ = *src++;
X
X    *dest = '\0';
X    va_end(argptr);
X    return retptr;
X}
~FUNKY STUFF~
echo x - strxncat.c
sed 's/^X//' > strxncat.c << '~FUNKY STUFF~'
X#include <varargs.h>
X
X/* VARARGS */
X/* strxncat(dest, n, s1, s2, ..., (char *) 0) */
Xchar *strxncat(va_alist)
Xva_dcl
X{
X    va_list argptr;
X    register char *dest, *src, *retptr;
X    register int n;
X
X    va_start(argptr);
X    retptr = dest = va_arg(argptr, char *);
X    n = va_arg(argptr, int);
X
X    /* go to the end of the destination */
X    while (*dest)
X	dest++;
X
X    /* src = arg[i] */
X    while ((src = va_arg(argptr, char *)) != (char *)0)
X	/* strncat(dest,arg[i],n) */
X	while ((*src != '\0') && n--)
X	    *dest++ = *src++;
X
X    *dest = '\0';
X    va_end(argptr);
X    return retptr;
X}
~FUNKY STUFF~
echo x - strxncpy.c
sed 's/^X//' > strxncpy.c << '~FUNKY STUFF~'
X#include <varargs.h>
X
X/* VARARGS */
X/* strxncpy(dest, n, s1, s2, ..., (char *) 0) */
Xchar *strxncpy(va_alist)
Xva_dcl
X{
X    va_list argptr;
X    register char *dest, *src, *retptr;
X    register int n;
X
X    va_start(argptr);
X    retptr = dest = va_arg(argptr, char *);		/* dest="" */
X    n = va_arg(argptr, int);
X
X    /* src = arg[i] */
X    while ((src = va_arg(argptr, char *)) != (char *)0)
X	/* strncat(dest,arg[i],n) */
X	while ((*src != '\0') && n--)
X	    *dest++ = *src++;
X
X    if (n > 0)
X	*dest = '\0';
X    va_end(argptr);
X    return retptr;
X}
~FUNKY STUFF~