/* Concatenate variable number of strings.
- Copyright (C) 1991, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1991-2021 Free Software Foundation, Inc.
Written by Fred Fish @ Cygnus Support
This file is part of the libiberty library.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA. */
/*
-NAME
+@deftypefn Extension char* concat (const char *@var{s1}, const char *@var{s2}, @
+ @dots{}, @code{NULL})
- concat -- concatenate a variable number of strings
+Concatenate zero or more of strings and return the result in freshly
+@code{xmalloc}ed memory. The argument list is terminated by the first
+@code{NULL} pointer encountered. Pointers to empty strings are ignored.
-SYNOPSIS
+@end deftypefn
- #include <varargs.h>
+*/
- char *concat (s1, s2, s3, ..., NULL)
-DESCRIPTION
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "ansidecl.h"
+#include "libiberty.h"
+#include <sys/types.h> /* size_t */
- Concatenate a variable number of strings and return the result
- in freshly malloc'd memory.
+#include <stdarg.h>
- Returns NULL if insufficient memory is available. The argument
- list is terminated by the first NULL pointer encountered. Pointers
- to empty strings are ignored.
+# if HAVE_STRING_H
+# include <string.h>
+# else
+# if HAVE_STRINGS_H
+# include <strings.h>
+# endif
+# endif
-NOTES
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
- This function uses xmalloc() which is expected to be a front end
- function to malloc() that deals with low memory situations. In
- typical use, if malloc() returns NULL then xmalloc() diverts to an
- error handler routine which never returns, and thus xmalloc will
- never return a NULL pointer. If the client application wishes to
- deal with low memory situations itself, it should supply an xmalloc
- that just directly invokes malloc and blindly returns whatever
- malloc returns.
-*/
+static inline unsigned long vconcat_length (const char *, va_list);
+static inline unsigned long
+vconcat_length (const char *first, va_list args)
+{
+ unsigned long length = 0;
+ const char *arg;
+ for (arg = first; arg ; arg = va_arg (args, const char *))
+ length += strlen (arg);
-#include "ansidecl.h"
-#include "libiberty.h"
+ return length;
+}
-#ifdef ANSI_PROTOTYPES
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
+static inline char *
+vconcat_copy (char *dst, const char *first, va_list args)
+{
+ char *end = dst;
+ const char *arg;
-#ifdef __STDC__
-#include <stddef.h>
-extern size_t strlen (const char *s);
-#else
-extern int strlen ();
-#endif
+ for (arg = first; arg ; arg = va_arg (args, const char *))
+ {
+ unsigned long length = strlen (arg);
+ memcpy (end, arg, length);
+ end += length;
+ }
+ *end = '\000';
-#define NULLP (char *)0
+ return dst;
+}
+
+/* @undocumented concat_length */
+
+unsigned long
+concat_length (const char *first, ...)
+{
+ unsigned long length;
+ va_list args;
+
+ va_start (args, first);
+ length = vconcat_length (first, args);
+ va_end (args);
+
+ return length;
+}
+
+/* @undocumented concat_copy */
-/* VARARGS */
-#ifdef ANSI_PROTOTYPES
-char *
-concat (const char *first, ...)
-#else
char *
-concat (va_alist)
- va_dcl
-#endif
+concat_copy (char *dst, const char *first, ...)
{
- register int length;
- register char *newstr;
- register char *end;
- register const char *arg;
+ char *save_dst;
va_list args;
-#ifndef ANSI_PROTOTYPES
- const char *first;
-#endif
- /* First compute the size of the result and get sufficient memory. */
+ va_start (args, first);
+ vconcat_copy (dst, first, args);
+ save_dst = dst; /* With K&R C, dst goes out of scope here. */
+ va_end (args);
+
+ return save_dst;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+char *libiberty_concat_ptr;
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
-#ifdef ANSI_PROTOTYPES
+/* @undocumented concat_copy2 */
+
+char *
+concat_copy2 (const char *first, ...)
+{
+ va_list args;
va_start (args, first);
-#else
- va_start (args);
- first = va_arg (args, const char *);
-#endif
+ vconcat_copy (libiberty_concat_ptr, first, args);
+ va_end (args);
- if (first == NULLP)
- length = 0;
- else
- {
- length = strlen (first);
- while ((arg = va_arg (args, const char *)) != NULLP)
- {
- length += strlen (arg);
- }
- }
- newstr = (char *) xmalloc (length + 1);
+ return libiberty_concat_ptr;
+}
+
+char *
+concat (const char *first, ...)
+{
+ char *newstr;
+ va_list args;
+
+ /* First compute the size of the result and get sufficient memory. */
+ va_start (args, first);
+ newstr = XNEWVEC (char, vconcat_length (first, args) + 1);
va_end (args);
/* Now copy the individual pieces to the result string. */
+ va_start (args, first);
+ vconcat_copy (newstr, first, args);
+ va_end (args);
- if (newstr != NULLP)
- {
-#ifdef ANSI_PROTOTYPES
- va_start (args, first);
-#else
- va_start (args);
- first = va_arg (args, const char *);
-#endif
- end = newstr;
- if (first != NULLP)
- {
- arg = first;
- while (*arg)
- {
- *end++ = *arg++;
- }
- while ((arg = va_arg (args, const char *)) != NULLP)
- {
- while (*arg)
- {
- *end++ = *arg++;
- }
- }
- }
- *end = '\000';
- va_end (args);
- }
+ return newstr;
+}
- return (newstr);
+/*
+
+@deftypefn Extension char* reconcat (char *@var{optr}, const char *@var{s1}, @
+ @dots{}, @code{NULL})
+
+Same as @code{concat}, except that if @var{optr} is not @code{NULL} it
+is freed after the string is created. This is intended to be useful
+when you're extending an existing string or building up a string in a
+loop:
+
+@example
+ str = reconcat (str, "pre-", str, NULL);
+@end example
+
+@end deftypefn
+
+*/
+
+char *
+reconcat (char *optr, const char *first, ...)
+{
+ char *newstr;
+ va_list args;
+
+ /* First compute the size of the result and get sufficient memory. */
+ va_start (args, first);
+ newstr = XNEWVEC (char, vconcat_length (first, args) + 1);
+ va_end (args);
+
+ /* Now copy the individual pieces to the result string. */
+ va_start (args, first);
+ vconcat_copy (newstr, first, args);
+ if (optr) /* Done before VA_CLOSE so optr stays in scope for K&R C. */
+ free (optr);
+ va_end (args);
+
+ return newstr;
}
#ifdef MAIN
+#define NULLP (char *)0
/* Simple little test driver. */
#include <stdio.h>
int
-main ()
+main (void)
{
printf ("\"\" = \"%s\"\n", concat (NULLP));
printf ("\"a\" = \"%s\"\n", concat ("a", NULLP));