/src/binutils-gdb/libiberty/concat.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Concatenate variable number of strings. |
2 | | Copyright (C) 1991-2025 Free Software Foundation, Inc. |
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 |
28 | | @code{xmalloc}ed memory. The argument list is terminated by the first |
29 | | @code{NULL} pointer encountered. Pointers to empty strings are ignored. |
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 <sys/types.h> /* size_t */ |
42 | | |
43 | | #include <stdarg.h> |
44 | | |
45 | | # if HAVE_STRING_H |
46 | | # include <string.h> |
47 | | # else |
48 | | # if HAVE_STRINGS_H |
49 | | # include <strings.h> |
50 | | # endif |
51 | | # endif |
52 | | |
53 | | #if HAVE_STDLIB_H |
54 | | #include <stdlib.h> |
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 | 1.50k | { |
61 | 1.50k | unsigned long length = 0; |
62 | 1.50k | const char *arg; |
63 | | |
64 | 5.92k | for (arg = first; arg ; arg = va_arg (args, const char *)) |
65 | 4.42k | length += strlen (arg); |
66 | | |
67 | 1.50k | return length; |
68 | 1.50k | } |
69 | | |
70 | | static inline char * |
71 | | vconcat_copy (char *dst, const char *first, va_list args) |
72 | 1.50k | { |
73 | 1.50k | char *end = dst; |
74 | 1.50k | const char *arg; |
75 | | |
76 | 5.92k | for (arg = first; arg ; arg = va_arg (args, const char *)) |
77 | 4.42k | { |
78 | 4.42k | unsigned long length = strlen (arg); |
79 | 4.42k | memcpy (end, arg, length); |
80 | 4.42k | end += length; |
81 | 4.42k | } |
82 | 1.50k | *end = '\000'; |
83 | | |
84 | 1.50k | return dst; |
85 | 1.50k | } |
86 | | |
87 | | /* @undocumented concat_length */ |
88 | | |
89 | | unsigned long |
90 | | concat_length (const char *first, ...) |
91 | 0 | { |
92 | 0 | unsigned long length; |
93 | 0 | va_list args; |
94 | |
|
95 | 0 | va_start (args, first); |
96 | 0 | length = vconcat_length (first, args); |
97 | 0 | va_end (args); |
98 | |
|
99 | 0 | return length; |
100 | 0 | } |
101 | | |
102 | | /* @undocumented concat_copy */ |
103 | | |
104 | | char * |
105 | | concat_copy (char *dst, const char *first, ...) |
106 | 0 | { |
107 | 0 | char *save_dst; |
108 | 0 | va_list args; |
109 | |
|
110 | 0 | va_start (args, first); |
111 | 0 | vconcat_copy (dst, first, args); |
112 | 0 | save_dst = dst; /* With K&R C, dst goes out of scope here. */ |
113 | 0 | va_end (args); |
114 | |
|
115 | 0 | return save_dst; |
116 | 0 | } |
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 | 0 | { |
131 | 0 | va_list args; |
132 | 0 | va_start (args, first); |
133 | 0 | vconcat_copy (libiberty_concat_ptr, first, args); |
134 | 0 | va_end (args); |
135 | |
|
136 | 0 | return libiberty_concat_ptr; |
137 | 0 | } |
138 | | |
139 | | char * |
140 | | concat (const char *first, ...) |
141 | 1.50k | { |
142 | 1.50k | char *newstr; |
143 | 1.50k | va_list args; |
144 | | |
145 | | /* First compute the size of the result and get sufficient memory. */ |
146 | 1.50k | va_start (args, first); |
147 | 1.50k | newstr = XNEWVEC (char, vconcat_length (first, args) + 1); |
148 | 1.50k | va_end (args); |
149 | | |
150 | | /* Now copy the individual pieces to the result string. */ |
151 | 1.50k | va_start (args, first); |
152 | 1.50k | vconcat_copy (newstr, first, args); |
153 | 1.50k | va_end (args); |
154 | | |
155 | 1.50k | return newstr; |
156 | 1.50k | } |
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 | 0 | { |
179 | 0 | char *newstr; |
180 | 0 | va_list args; |
181 | | |
182 | | /* First compute the size of the result and get sufficient memory. */ |
183 | 0 | va_start (args, first); |
184 | 0 | newstr = XNEWVEC (char, vconcat_length (first, args) + 1); |
185 | 0 | va_end (args); |
186 | | |
187 | | /* Now copy the individual pieces to the result string. */ |
188 | 0 | va_start (args, first); |
189 | 0 | vconcat_copy (newstr, first, args); |
190 | 0 | if (optr) /* Done before VA_CLOSE so optr stays in scope for K&R C. */ |
191 | 0 | free (optr); |
192 | 0 | va_end (args); |
193 | |
|
194 | 0 | return newstr; |
195 | 0 | } |
196 | | |
197 | | #ifdef MAIN |
198 | | #define NULLP (char *)0 |
199 | | |
200 | | /* Simple little test driver. */ |
201 | | |
202 | | #include <stdio.h> |
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 |