1169695Skan/* Concatenate variable number of strings.
2169695Skan   Copyright (C) 1991, 1994, 2001 Free Software Foundation, Inc.
3169695Skan   Written by Fred Fish @ Cygnus Support
4169695Skan
5169695SkanThis file is part of the libiberty library.
6169695SkanLibiberty is free software; you can redistribute it and/or
7169695Skanmodify it under the terms of the GNU Library General Public
8169695SkanLicense as published by the Free Software Foundation; either
9169695Skanversion 2 of the License, or (at your option) any later version.
10169695Skan
11169695SkanLibiberty is distributed in the hope that it will be useful,
12169695Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of
13169695SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14169695SkanLibrary General Public License for more details.
15169695Skan
16169695SkanYou should have received a copy of the GNU Library General Public
17169695SkanLicense along with libiberty; see the file COPYING.LIB.  If
18169695Skannot, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19169695SkanBoston, MA 02110-1301, USA.  */
20169695Skan
21169695Skan
22169695Skan/*
23169695Skan
24169695Skan@deftypefn Extension char* concat (const char *@var{s1}, const char *@var{s2}, @dots{}, @code{NULL})
25169695Skan
26169695SkanConcatenate zero or more of strings and return the result in freshly
27169695Skan@code{xmalloc}ed memory.  Returns @code{NULL} if insufficient memory is
28169695Skanavailable.  The argument list is terminated by the first @code{NULL}
29169695Skanpointer encountered.  Pointers to empty strings are ignored.
30169695Skan
31169695Skan@end deftypefn
32169695Skan
33169695SkanNOTES
34169695Skan
35169695Skan	This function uses xmalloc() which is expected to be a front end
36169695Skan	function to malloc() that deals with low memory situations.  In
37169695Skan	typical use, if malloc() returns NULL then xmalloc() diverts to an
38169695Skan	error handler routine which never returns, and thus xmalloc will
39169695Skan	never return a NULL pointer.  If the client application wishes to
40169695Skan	deal with low memory situations itself, it should supply an xmalloc
41169695Skan	that just directly invokes malloc and blindly returns whatever
42169695Skan	malloc returns.
43169695Skan
44169695Skan*/
45169695Skan
46169695Skan
47169695Skan#ifdef HAVE_CONFIG_H
48169695Skan#include "config.h"
49169695Skan#endif
50169695Skan#include "ansidecl.h"
51169695Skan#include "libiberty.h"
52169695Skan#include <sys/types.h>		/* size_t */
53169695Skan
54169695Skan#include <stdarg.h>
55169695Skan
56169695Skan# if HAVE_STRING_H
57169695Skan#  include <string.h>
58169695Skan# else
59169695Skan#  if HAVE_STRINGS_H
60169695Skan#   include <strings.h>
61169695Skan#  endif
62169695Skan# endif
63169695Skan
64169695Skan#if HAVE_STDLIB_H
65169695Skan#include <stdlib.h>
66169695Skan#endif
67169695Skan
68169695Skanstatic inline unsigned long vconcat_length (const char *, va_list);
69169695Skanstatic inline unsigned long
70169695Skanvconcat_length (const char *first, va_list args)
71169695Skan{
72169695Skan  unsigned long length = 0;
73169695Skan  const char *arg;
74169695Skan
75169695Skan  for (arg = first; arg ; arg = va_arg (args, const char *))
76169695Skan    length += strlen (arg);
77169695Skan
78169695Skan  return length;
79169695Skan}
80169695Skan
81169695Skanstatic inline char *
82169695Skanvconcat_copy (char *dst, const char *first, va_list args)
83169695Skan{
84169695Skan  char *end = dst;
85169695Skan  const char *arg;
86169695Skan
87169695Skan  for (arg = first; arg ; arg = va_arg (args, const char *))
88169695Skan    {
89169695Skan      unsigned long length = strlen (arg);
90169695Skan      memcpy (end, arg, length);
91169695Skan      end += length;
92169695Skan    }
93169695Skan  *end = '\000';
94169695Skan
95169695Skan  return dst;
96169695Skan}
97169695Skan
98169695Skan/* @undocumented concat_length */
99169695Skan
100169695Skanunsigned long
101169695Skanconcat_length (const char *first, ...)
102169695Skan{
103169695Skan  unsigned long length;
104169695Skan
105169695Skan  VA_OPEN (args, first);
106169695Skan  VA_FIXEDARG (args, const char *, first);
107169695Skan  length = vconcat_length (first, args);
108169695Skan  VA_CLOSE (args);
109169695Skan
110169695Skan  return length;
111169695Skan}
112169695Skan
113169695Skan/* @undocumented concat_copy */
114169695Skan
115169695Skanchar *
116169695Skanconcat_copy (char *dst, const char *first, ...)
117169695Skan{
118169695Skan  char *save_dst;
119169695Skan
120169695Skan  VA_OPEN (args, first);
121169695Skan  VA_FIXEDARG (args, char *, dst);
122169695Skan  VA_FIXEDARG (args, const char *, first);
123169695Skan  vconcat_copy (dst, first, args);
124169695Skan  save_dst = dst; /* With K&R C, dst goes out of scope here.  */
125169695Skan  VA_CLOSE (args);
126169695Skan
127169695Skan  return save_dst;
128169695Skan}
129169695Skan
130169695Skan#ifdef __cplusplus
131169695Skanextern "C" {
132169695Skan#endif /* __cplusplus */
133169695Skanchar *libiberty_concat_ptr;
134169695Skan#ifdef __cplusplus
135169695Skan}
136169695Skan#endif /* __cplusplus */
137169695Skan
138169695Skan/* @undocumented concat_copy2 */
139169695Skan
140169695Skanchar *
141169695Skanconcat_copy2 (const char *first, ...)
142169695Skan{
143169695Skan  VA_OPEN (args, first);
144169695Skan  VA_FIXEDARG (args, const char *, first);
145169695Skan  vconcat_copy (libiberty_concat_ptr, first, args);
146169695Skan  VA_CLOSE (args);
147169695Skan
148169695Skan  return libiberty_concat_ptr;
149169695Skan}
150169695Skan
151169695Skanchar *
152169695Skanconcat (const char *first, ...)
153169695Skan{
154169695Skan  char *newstr;
155169695Skan
156169695Skan  /* First compute the size of the result and get sufficient memory.  */
157169695Skan  VA_OPEN (args, first);
158169695Skan  VA_FIXEDARG (args, const char *, first);
159169695Skan  newstr = XNEWVEC (char, vconcat_length (first, args) + 1);
160169695Skan  VA_CLOSE (args);
161169695Skan
162169695Skan  /* Now copy the individual pieces to the result string. */
163169695Skan  VA_OPEN (args, first);
164169695Skan  VA_FIXEDARG (args, const char *, first);
165169695Skan  vconcat_copy (newstr, first, args);
166169695Skan  VA_CLOSE (args);
167169695Skan
168169695Skan  return newstr;
169169695Skan}
170169695Skan
171169695Skan/*
172169695Skan
173169695Skan@deftypefn Extension char* reconcat (char *@var{optr}, const char *@var{s1}, @dots{}, @code{NULL})
174169695Skan
175169695SkanSame as @code{concat}, except that if @var{optr} is not @code{NULL} it
176169695Skanis freed after the string is created.  This is intended to be useful
177169695Skanwhen you're extending an existing string or building up a string in a
178169695Skanloop:
179169695Skan
180169695Skan@example
181169695Skan  str = reconcat (str, "pre-", str, NULL);
182169695Skan@end example
183169695Skan
184169695Skan@end deftypefn
185169695Skan
186169695Skan*/
187169695Skan
188169695Skanchar *
189169695Skanreconcat (char *optr, const char *first, ...)
190169695Skan{
191169695Skan  char *newstr;
192169695Skan
193169695Skan  /* First compute the size of the result and get sufficient memory.  */
194169695Skan  VA_OPEN (args, first);
195169695Skan  VA_FIXEDARG (args, char *, optr);
196169695Skan  VA_FIXEDARG (args, const char *, first);
197169695Skan  newstr = XNEWVEC (char, vconcat_length (first, args) + 1);
198169695Skan  VA_CLOSE (args);
199169695Skan
200169695Skan  /* Now copy the individual pieces to the result string. */
201169695Skan  VA_OPEN (args, first);
202169695Skan  VA_FIXEDARG (args, char *, optr);
203169695Skan  VA_FIXEDARG (args, const char *, first);
204169695Skan  vconcat_copy (newstr, first, args);
205169695Skan  if (optr) /* Done before VA_CLOSE so optr stays in scope for K&R C.  */
206169695Skan    free (optr);
207169695Skan  VA_CLOSE (args);
208169695Skan
209169695Skan  return newstr;
210169695Skan}
211169695Skan
212169695Skan#ifdef MAIN
213169695Skan#define NULLP (char *)0
214169695Skan
215169695Skan/* Simple little test driver. */
216169695Skan
217169695Skan#include <stdio.h>
218169695Skan
219169695Skanint
220169695Skanmain (void)
221169695Skan{
222169695Skan  printf ("\"\" = \"%s\"\n", concat (NULLP));
223169695Skan  printf ("\"a\" = \"%s\"\n", concat ("a", NULLP));
224169695Skan  printf ("\"ab\" = \"%s\"\n", concat ("a", "b", NULLP));
225169695Skan  printf ("\"abc\" = \"%s\"\n", concat ("a", "b", "c", NULLP));
226169695Skan  printf ("\"abcd\" = \"%s\"\n", concat ("ab", "cd", NULLP));
227169695Skan  printf ("\"abcde\" = \"%s\"\n", concat ("ab", "c", "de", NULLP));
228169695Skan  printf ("\"abcdef\" = \"%s\"\n", concat ("", "a", "", "bcd", "ef", NULLP));
229169695Skan  return 0;
230169695Skan}
231169695Skan
232169695Skan#endif
233