exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / string-desc.c
blob17856d95549db288592a3a954ca0d055ba70da78
1 /* String descriptors.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation, either version 3 of the
7 License, or (at your option) any later version.
9 This file is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2023. */
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
23 #define GL_STRING_DESC_INLINE _GL_EXTERN_INLINE
25 /* Specification and inline definitions. */
26 #include "string-desc.h"
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include "ialloc.h"
33 #include "full-write.h"
36 /* ==== Side-effect-free operations on string descriptors ==== */
38 /* Return true if A and B are equal. */
39 bool
40 string_desc_equals (string_desc_t a, string_desc_t b)
42 return (a._nbytes == b._nbytes
43 && (a._nbytes == 0 || memcmp (a._data, b._data, a._nbytes) == 0));
46 bool
47 string_desc_startswith (string_desc_t s, string_desc_t prefix)
49 return (s._nbytes >= prefix._nbytes
50 && (prefix._nbytes == 0
51 || memcmp (s._data, prefix._data, prefix._nbytes) == 0));
54 bool
55 string_desc_endswith (string_desc_t s, string_desc_t suffix)
57 return (s._nbytes >= suffix._nbytes
58 && (suffix._nbytes == 0
59 || memcmp (s._data + (s._nbytes - suffix._nbytes), suffix._data,
60 suffix._nbytes) == 0));
63 int
64 string_desc_cmp (string_desc_t a, string_desc_t b)
66 if (a._nbytes > b._nbytes)
68 if (b._nbytes == 0)
69 return 1;
70 return (memcmp (a._data, b._data, b._nbytes) < 0 ? -1 : 1);
72 else if (a._nbytes < b._nbytes)
74 if (a._nbytes == 0)
75 return -1;
76 return (memcmp (a._data, b._data, a._nbytes) > 0 ? 1 : -1);
78 else /* a._nbytes == b._nbytes */
80 if (a._nbytes == 0)
81 return 0;
82 return memcmp (a._data, b._data, a._nbytes);
86 ptrdiff_t
87 string_desc_index (string_desc_t s, char c)
89 if (s._nbytes > 0)
91 void *found = memchr (s._data, (unsigned char) c, s._nbytes);
92 if (found != NULL)
93 return (char *) found - s._data;
95 return -1;
98 ptrdiff_t
99 string_desc_last_index (string_desc_t s, char c)
101 if (s._nbytes > 0)
103 void *found = memrchr (s._data, (unsigned char) c, s._nbytes);
104 if (found != NULL)
105 return (char *) found - s._data;
107 return -1;
110 string_desc_t
111 string_desc_new_empty (void)
113 string_desc_t result;
115 result._nbytes = 0;
116 result._data = NULL;
118 return result;
122 string_desc_t
123 string_desc_from_c (const char *s)
125 string_desc_t result;
127 result._nbytes = strlen (s);
128 result._data = (char *) s;
130 return result;
133 string_desc_t
134 string_desc_substring (string_desc_t s, idx_t start, idx_t end)
136 string_desc_t result;
138 if (!(start >= 0 && start <= end))
139 /* Invalid arguments. */
140 abort ();
142 result._nbytes = end - start;
143 result._data = s._data + start;
145 return result;
149 string_desc_write (int fd, string_desc_t s)
151 if (s._nbytes > 0)
152 if (full_write (fd, s._data, s._nbytes) != s._nbytes)
153 /* errno is set here. */
154 return -1;
155 return 0;
159 string_desc_fwrite (FILE *fp, string_desc_t s)
161 if (s._nbytes > 0)
162 if (fwrite (s._data, 1, s._nbytes, fp) != s._nbytes)
163 return -1;
164 return 0;
168 /* ==== Memory-allocating operations on string descriptors ==== */
171 string_desc_new (string_desc_t *resultp, idx_t n)
173 string_desc_t result;
175 if (!(n >= 0))
176 /* Invalid argument. */
177 abort ();
179 result._nbytes = n;
180 if (n == 0)
181 result._data = NULL;
182 else
184 result._data = (char *) imalloc (n);
185 if (result._data == NULL)
186 /* errno is set here. */
187 return -1;
190 *resultp = result;
191 return 0;
194 string_desc_t
195 string_desc_new_addr (idx_t n, char *addr)
197 string_desc_t result;
199 result._nbytes = n;
200 if (n == 0)
201 result._data = NULL;
202 else
203 result._data = addr;
205 return result;
209 string_desc_new_filled (string_desc_t *resultp, idx_t n, char c)
211 string_desc_t result;
213 result._nbytes = n;
214 if (n == 0)
215 result._data = NULL;
216 else
218 result._data = (char *) imalloc (n);
219 if (result._data == NULL)
220 /* errno is set here. */
221 return -1;
222 memset (result._data, (unsigned char) c, n);
225 *resultp = result;
226 return 0;
230 string_desc_copy (string_desc_t *resultp, string_desc_t s)
232 string_desc_t result;
233 idx_t n = s._nbytes;
235 result._nbytes = n;
236 if (n == 0)
237 result._data = NULL;
238 else
240 result._data = (char *) imalloc (n);
241 if (result._data == NULL)
242 /* errno is set here. */
243 return -1;
244 memcpy (result._data, s._data, n);
247 *resultp = result;
248 return 0;
252 string_desc_concat (string_desc_t *resultp, idx_t n, string_desc_t string1, ...)
254 if (n <= 0)
255 /* Invalid argument. */
256 abort ();
258 idx_t total = 0;
259 total += string1._nbytes;
260 if (n > 1)
262 va_list other_strings;
263 idx_t i;
265 va_start (other_strings, string1);
266 for (i = n - 1; i > 0; i--)
268 string_desc_t arg = va_arg (other_strings, string_desc_t);
269 total += arg._nbytes;
271 va_end (other_strings);
274 char *combined = (char *) imalloc (total);
275 if (combined == NULL)
276 /* errno is set here. */
277 return -1;
278 idx_t pos = 0;
279 memcpy (combined, string1._data, string1._nbytes);
280 pos += string1._nbytes;
281 if (n > 1)
283 va_list other_strings;
284 idx_t i;
286 va_start (other_strings, string1);
287 for (i = n - 1; i > 0; i--)
289 string_desc_t arg = va_arg (other_strings, string_desc_t);
290 if (arg._nbytes > 0)
291 memcpy (combined + pos, arg._data, arg._nbytes);
292 pos += arg._nbytes;
294 va_end (other_strings);
297 string_desc_t result;
298 result._nbytes = total;
299 result._data = combined;
301 *resultp = result;
302 return 0;
305 char *
306 string_desc_c (string_desc_t s)
308 idx_t n = s._nbytes;
309 char *result = (char *) imalloc (n + 1);
310 if (result == NULL)
311 /* errno is set here. */
312 return NULL;
313 if (n > 0)
314 memcpy (result, s._data, n);
315 result[n] = '\0';
317 return result;
321 /* ==== Operations with side effects on string descriptors ==== */
323 void
324 string_desc_set_char_at (string_desc_t s, idx_t i, char c)
326 if (!(i >= 0 && i < s._nbytes))
327 /* Invalid argument. */
328 abort ();
329 s._data[i] = c;
332 void
333 string_desc_fill (string_desc_t s, idx_t start, idx_t end, char c)
335 if (!(start >= 0 && start <= end))
336 /* Invalid arguments. */
337 abort ();
339 if (start < end)
340 memset (s._data + start, (unsigned char) c, end - start);
343 void
344 string_desc_overwrite (string_desc_t s, idx_t start, string_desc_t t)
346 if (!(start >= 0 && start + t._nbytes <= s._nbytes))
347 /* Invalid arguments. */
348 abort ();
350 if (t._nbytes > 0)
351 memcpy (s._data + start, t._data, t._nbytes);
354 void
355 string_desc_free (string_desc_t s)
357 free (s._data);