Rev 5191 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5191 | serge | 1 | /* Concatenate variable number of strings. |
6324 | serge | 2 | Copyright (C) 1991, 1994, 2001, 2011, 2013 Free Software Foundation, Inc. |
5191 | serge | 3 | Written by Fred Fish @ Cygnus Support |
4 | |||
5 | This file is part of the libiberty library. |
||
6 | Libiberty is free software; you can redistribute it and/or |
||
7 | modify it under the terms of the GNU Library General Public |
||
8 | License as published by the Free Software Foundation; either |
||
9 | version 2 of the License, or (at your option) any later version. |
||
10 | |||
11 | Libiberty is distributed in the hope that it will be useful, |
||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
14 | Library General Public License for more details. |
||
15 | |||
16 | You should have received a copy of the GNU Library General Public |
||
17 | License along with libiberty; see the file COPYING.LIB. If |
||
18 | not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
||
19 | Boston, MA 02110-1301, USA. */ |
||
20 | |||
21 | |||
22 | /* |
||
23 | |||
24 | @deftypefn Extension char* concat (const char *@var{s1}, const char *@var{s2}, @ |
||
25 | @dots{}, @code{NULL}) |
||
26 | |||
27 | Concatenate zero or more of strings and return the result in freshly |
||
6324 | serge | 28 | @code{xmalloc}ed memory. The argument list is terminated by the first |
29 | @code{NULL} pointer encountered. Pointers to empty strings are ignored. |
||
5191 | serge | 30 | |
31 | @end deftypefn |
||
32 | |||
33 | */ |
||
34 | |||
35 | |||
36 | #ifdef HAVE_CONFIG_H |
||
37 | #include "config.h" |
||
38 | #endif |
||
39 | #include "ansidecl.h" |
||
40 | #include "libiberty.h" |
||
41 | #include |
||
42 | |||
43 | #include |
||
44 | |||
45 | # if HAVE_STRING_H |
||
46 | # include |
||
47 | # else |
||
48 | # if HAVE_STRINGS_H |
||
49 | # include |
||
50 | # endif |
||
51 | # endif |
||
52 | |||
53 | #if HAVE_STDLIB_H |
||
54 | #include |
||
55 | #endif |
||
56 | |||
57 | static inline unsigned long vconcat_length (const char *, va_list); |
||
58 | static inline unsigned long |
||
59 | vconcat_length (const char *first, va_list args) |
||
60 | { |
||
61 | unsigned long length = 0; |
||
62 | const char *arg; |
||
63 | |||
64 | for (arg = first; arg ; arg = va_arg (args, const char *)) |
||
65 | length += strlen (arg); |
||
66 | |||
67 | return length; |
||
68 | } |
||
69 | |||
70 | static inline char * |
||
71 | vconcat_copy (char *dst, const char *first, va_list args) |
||
72 | { |
||
73 | char *end = dst; |
||
74 | const char *arg; |
||
75 | |||
76 | for (arg = first; arg ; arg = va_arg (args, const char *)) |
||
77 | { |
||
78 | unsigned long length = strlen (arg); |
||
79 | memcpy (end, arg, length); |
||
80 | end += length; |
||
81 | } |
||
82 | *end = '\000'; |
||
83 | |||
84 | return dst; |
||
85 | } |
||
86 | |||
87 | /* @undocumented concat_length */ |
||
88 | |||
89 | unsigned long |
||
90 | concat_length (const char *first, ...) |
||
91 | { |
||
92 | unsigned long length; |
||
6324 | serge | 93 | va_list args; |
5191 | serge | 94 | |
6324 | serge | 95 | va_start (args, first); |
5191 | serge | 96 | length = vconcat_length (first, args); |
6324 | serge | 97 | va_end (args); |
5191 | serge | 98 | |
99 | return length; |
||
100 | } |
||
101 | |||
102 | /* @undocumented concat_copy */ |
||
103 | |||
104 | char * |
||
105 | concat_copy (char *dst, const char *first, ...) |
||
106 | { |
||
107 | char *save_dst; |
||
6324 | serge | 108 | va_list args; |
5191 | serge | 109 | |
6324 | serge | 110 | va_start (args, first); |
5191 | serge | 111 | vconcat_copy (dst, first, args); |
112 | save_dst = dst; /* With K&R C, dst goes out of scope here. */ |
||
6324 | serge | 113 | va_end (args); |
5191 | serge | 114 | |
115 | return save_dst; |
||
116 | } |
||
117 | |||
118 | #ifdef __cplusplus |
||
119 | extern "C" { |
||
120 | #endif /* __cplusplus */ |
||
121 | char *libiberty_concat_ptr; |
||
122 | #ifdef __cplusplus |
||
123 | } |
||
124 | #endif /* __cplusplus */ |
||
125 | |||
126 | /* @undocumented concat_copy2 */ |
||
127 | |||
128 | char * |
||
129 | concat_copy2 (const char *first, ...) |
||
130 | { |
||
6324 | serge | 131 | va_list args; |
132 | va_start (args, first); |
||
5191 | serge | 133 | vconcat_copy (libiberty_concat_ptr, first, args); |
6324 | serge | 134 | va_end (args); |
5191 | serge | 135 | |
136 | return libiberty_concat_ptr; |
||
137 | } |
||
138 | |||
139 | char * |
||
140 | concat (const char *first, ...) |
||
141 | { |
||
142 | char *newstr; |
||
6324 | serge | 143 | va_list args; |
5191 | serge | 144 | |
145 | /* First compute the size of the result and get sufficient memory. */ |
||
6324 | serge | 146 | va_start (args, first); |
5191 | serge | 147 | newstr = XNEWVEC (char, vconcat_length (first, args) + 1); |
6324 | serge | 148 | va_end (args); |
5191 | serge | 149 | |
150 | /* Now copy the individual pieces to the result string. */ |
||
6324 | serge | 151 | va_start (args, first); |
5191 | serge | 152 | vconcat_copy (newstr, first, args); |
6324 | serge | 153 | va_end (args); |
5191 | serge | 154 | |
155 | return newstr; |
||
156 | } |
||
157 | |||
158 | /* |
||
159 | |||
160 | @deftypefn Extension char* reconcat (char *@var{optr}, const char *@var{s1}, @ |
||
161 | @dots{}, @code{NULL}) |
||
162 | |||
163 | Same as @code{concat}, except that if @var{optr} is not @code{NULL} it |
||
164 | is freed after the string is created. This is intended to be useful |
||
165 | when you're extending an existing string or building up a string in a |
||
166 | loop: |
||
167 | |||
168 | @example |
||
169 | str = reconcat (str, "pre-", str, NULL); |
||
170 | @end example |
||
171 | |||
172 | @end deftypefn |
||
173 | |||
174 | */ |
||
175 | |||
176 | char * |
||
177 | reconcat (char *optr, const char *first, ...) |
||
178 | { |
||
179 | char *newstr; |
||
6324 | serge | 180 | va_list args; |
5191 | serge | 181 | |
182 | /* First compute the size of the result and get sufficient memory. */ |
||
6324 | serge | 183 | va_start (args, first); |
5191 | serge | 184 | newstr = XNEWVEC (char, vconcat_length (first, args) + 1); |
6324 | serge | 185 | va_end (args); |
5191 | serge | 186 | |
187 | /* Now copy the individual pieces to the result string. */ |
||
6324 | serge | 188 | va_start (args, first); |
5191 | serge | 189 | vconcat_copy (newstr, first, args); |
190 | if (optr) /* Done before VA_CLOSE so optr stays in scope for K&R C. */ |
||
191 | free (optr); |
||
6324 | serge | 192 | va_end (args); |
5191 | serge | 193 | |
194 | return newstr; |
||
195 | } |
||
196 | |||
197 | #ifdef MAIN |
||
198 | #define NULLP (char *)0 |
||
199 | |||
200 | /* Simple little test driver. */ |
||
201 | |||
202 | #include |
||
203 | |||
204 | int |
||
205 | main (void) |
||
206 | { |
||
207 | printf ("\"\" = \"%s\"\n", concat (NULLP)); |
||
208 | printf ("\"a\" = \"%s\"\n", concat ("a", NULLP)); |
||
209 | printf ("\"ab\" = \"%s\"\n", concat ("a", "b", NULLP)); |
||
210 | printf ("\"abc\" = \"%s\"\n", concat ("a", "b", "c", NULLP)); |
||
211 | printf ("\"abcd\" = \"%s\"\n", concat ("ab", "cd", NULLP)); |
||
212 | printf ("\"abcde\" = \"%s\"\n", concat ("ab", "c", "de", NULLP)); |
||
213 | printf ("\"abcdef\" = \"%s\"\n", concat ("", "a", "", "bcd", "ef", NULLP)); |
||
214 | return 0; |
||
215 | } |
||
216 | |||
217 | #endif |