Coverage Report

Created: 2026-03-12 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gettext/gettext-tools/libgettextpo/string-desc.h
Line
Count
Source
1
/* String descriptors.
2
   Copyright (C) 2023-2026 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>.  */
16
17
/* Written by Bruno Haible <bruno@clisp.org>, 2023.  */
18
19
#ifndef _STRING_DESC_H
20
#define _STRING_DESC_H 1
21
22
/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE,
23
   _GL_ATTRIBUTE_NODISCARD, _GL_ATTRIBUTE_NONNULL,
24
   _GL_ATTRIBUTE_NONNULL_IF_NONZERO.  */
25
#if !_GL_CONFIG_H_INCLUDED
26
 #error "Please include config.h first."
27
#endif
28
29
/* Get ptrdiff_t.  */
30
#include <stddef.h>
31
32
/* Get FILE.  */
33
#include <stdio.h>
34
35
/* Get abort(), free().  */
36
#include <stdlib.h>
37
38
/* Get idx_t.  */
39
#include "idx.h"
40
41
/* Whether the compiler supports statement-expressions.
42
   Test program:
43
     int f (int x) { return ({ x; x; }); }
44
 */
45
#if defined __GNUC__ /* both C and C++ mode */ \
46
    || defined __clang__ /* both C and C++ mode */ \
47
    || (defined __SUNPRO_C && __SUNPRO_C >= 0x5150) /* C mode */ \
48
    || (defined __SUNPRO_CC && __SUNPRO_CC >= 0x5150) /* C++ mode */
49
# define HAVE_STATEMENT_EXPRESSIONS 1
50
#endif
51
52
/* Whether the compiler supports _Generic.
53
   Test program:
54
     int f (int x) { return _Generic (x, char *: 2, int: 3); }
55
 */
56
#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 9) > 4 && !defined __cplusplus) /* C mode */ \
57
    || (defined __clang__ && __clang_major__ >= 3) /* both C and C++ mode */ \
58
    || (defined __SUNPRO_C && __SUNPRO_C >= 0x5150) /* C mode */ \
59
    || (__STDC_VERSION__ >= 201112L && !defined __GNUC__) /* C mode */
60
# define HAVE__GENERIC 1
61
#endif
62
63
/* Whether the compiler supports typeof.
64
   Test program:
65
     int f (int x) { typeof (x) y = x; return y; }
66
 */
67
#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 1) > 3) /* both C and C++ mode */ \
68
    || (defined __clang__ && __clang_major__ >= 3 /* both C and C++ mode */ \
69
        && !(defined __cplusplus && !defined __GNUC__)) /* except for clang-cl in C++ mode */ \
70
    || (defined __SUNPRO_C && __SUNPRO_C >= 0x5110) /* C mode */ \
71
    || __STDC_VERSION__ >= 202311L /* C mode */
72
# define HAVE_TYPEOF 1
73
#endif
74
75
/* Whether the compiler supports __builtin_choose_expr.
76
   _Generic and __builtin_choose_expr are like conditional expressions,
77
   except that the return types of the branches need not match: They avoid an
78
   "error: type mismatch in conditional expression".
79
   Test program:
80
     int f (int x) { return __builtin_choose_expr (sizeof (x) == 4, 2, 3); }
81
 */
82
#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 1) > 3) /* both C and C++ mode */ \
83
    || (defined __clang__ && __clang_major__ >= 3) /* both C and C++ mode */
84
# define HAVE_BUILTIN_CHOOSE_EXPR 1
85
#endif
86
87
/* Whether the compiler supports __builtin_constant_p and whether that built-in
88
   returns true for string literals.
89
   _Generic has an antiquated treatment of string literals: It treats string
90
   literals like 'char *', not 'const char *'.  To compensate for this, we need
91
   __builtin_constant_p.
92
   Test program:
93
     int i, v[__builtin_constant_p ("x") > __builtin_constant_p (i) ? 1 : -1];
94
 */
95
#if (defined __GNUC__ && __GNUC__ + (__GNUC_MINOR__ >= 1) > 3) /* both C and C++ mode */ \
96
    || (defined __clang__ && __clang_major__ >= 4) /* both C and C++ mode */
97
# define HAVE_BUILTIN_CONSTANT_P 1
98
#endif
99
100
/* Whether we support rw_string_desc_t as distinct from string_desc_t.  */
101
#if HAVE_STATEMENT_EXPRESSIONS && HAVE__GENERIC && HAVE_TYPEOF \
102
    && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_CONSTANT_P
103
# define HAVE_RW_STRING_DESC 1
104
#endif
105
106
_GL_INLINE_HEADER_BEGIN
107
#ifndef GL_STRING_DESC_INLINE
108
# define GL_STRING_DESC_INLINE _GL_INLINE
109
#endif
110
111
#ifdef __cplusplus
112
extern "C" {
113
#endif
114
115
116
/* Type describing a string that may contain NUL bytes.
117
   It's merely a descriptor of an array of bytes.
118
   It comes in two flavours:
119
     - string_desc_t is read-only,
120
     - rw_string_desc_t is read-write.
121
   When we write
122
     [rw_]string_desc_t
123
   it means either string_desc_t or rw_string_desc_t.  */
124
typedef struct rw_string_desc_t rw_string_desc_t;
125
struct rw_string_desc_t
126
{
127
  /* The fields of this struct should be considered private.  */
128
  idx_t _nbytes;
129
  char *_data;
130
};
131
#if HAVE_RW_STRING_DESC
132
typedef struct string_desc_t string_desc_t;
133
struct string_desc_t
134
{
135
  /* The fields of this struct should be considered private.  */
136
  idx_t _nbytes;
137
  const char *_data;
138
};
139
#else
140
typedef rw_string_desc_t string_desc_t;
141
#endif
142
143
/* String descriptors can be passed and returned by value.
144
145
   String descriptors and NUL-terminated 'const char *'/'char *' C strings
146
   cannot be used interchangeably.  You will get compilation errors if you
147
   attempt to assign a string descriptor to a C string or vice versa.  */
148
149
150
/* ==== Conversions between string descriptors ==== */
151
152
/* Return a read-only view of S.  */
153
#if 0 /* Defined inline below.  */
154
extern string_desc_t sd_readonly (rw_string_desc_t s);
155
#endif
156
157
/* Return a read-only view of S.
158
   Attention: This function is as dangerous as a cast from 'const char *'
159
   to 'char *'!  */
160
#if 0 /* Defined inline below.  */
161
extern rw_string_desc_t sd_readwrite (string_desc_t s);
162
#endif
163
164
165
/* ==== Side-effect-free operations on string descriptors ==== */
166
167
/* Return the length of the string S.  */
168
#if 0 /* Defined inline below.  */
169
extern idx_t sd_length ([rw_]string_desc_t s);
170
#endif
171
172
/* Return the byte at index I of string S.
173
   I must be < length(S).  */
174
#if 0 /* Defined inline below.  */
175
extern char sd_char_at ([rw_]string_desc_t s, idx_t i);
176
#endif
177
178
/* Return a read-only view of the bytes of S.  */
179
#if 0 /* Defined inline below.  */
180
extern const char * sd_data (string_desc_t s);
181
extern       char * sd_data (rw_string_desc_t s);
182
#endif
183
184
/* Return true if S is the empty string.  */
185
#if 0 /* Defined inline below.  */
186
extern bool sd_is_empty ([rw_]string_desc_t s);
187
#endif
188
189
/* Return true if A and B are equal.  */
190
#if 0 /* Defined inline below.  */
191
extern bool sd_equals ([rw_]string_desc_t a, [rw_]string_desc_t b);
192
#endif
193
194
/* Return true if S starts with PREFIX.  */
195
#if 0 /* Defined inline below.  */
196
extern bool sd_startswith ([rw_]string_desc_t s, [rw_]string_desc_t prefix);
197
#endif
198
199
/* Return true if S ends with SUFFIX.  */
200
#if 0 /* Defined inline below.  */
201
extern bool sd_endswith ([rw_]string_desc_t s, [rw_]string_desc_t suffix);
202
#endif
203
204
/* Return > 0, == 0, or < 0 if A > B, A == B, A < B.
205
   This uses a lexicographic ordering, where the bytes are compared as
206
   'unsigned char'.  */
207
#if 0 /* Defined inline below.  */
208
extern int sd_cmp ([rw_]string_desc_t a, [rw_]string_desc_t b);
209
#endif
210
211
/* Return > 0, == 0, or < 0 if A > B, A == B, A < B.
212
   Either A or B must be entirely ASCII.
213
   This uses a lexicographic ordering, where the bytes are compared as
214
   'unsigned char', ignoring case, in the "C" locale.  */
215
#if 0 /* Defined inline below.  */
216
extern int sd_c_casecmp ([rw_]string_desc_t a, [rw_]string_desc_t b);
217
#endif
218
219
/* Return the index of the first occurrence of C in S,
220
   or -1 if there is none.  */
221
#if 0 /* Defined inline below.  */
222
extern ptrdiff_t sd_index ([rw_]string_desc_t s, char c);
223
#endif
224
225
/* Return the index of the last occurrence of C in S,
226
   or -1 if there is none.  */
227
#if 0 /* Defined inline below.  */
228
extern ptrdiff_t sd_last_index ([rw_]string_desc_t s, char c);
229
#endif
230
231
/* Return the index of the first occurrence of NEEDLE in HAYSTACK,
232
   or -1 if there is none.  */
233
#if 0 /* Defined inline below.  */
234
extern ptrdiff_t sd_contains ([rw_]string_desc_t haystack, [rw_]string_desc_t needle);
235
#endif
236
237
/* Return an empty string.  */
238
extern string_desc_t sd_new_empty (void);
239
240
/* Construct and return a string of length N, at the given memory address.  */
241
#if 0 /* Defined inline below.  */
242
extern string_desc_t sd_new_addr (idx_t n, const char *addr)
243
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1);
244
extern rw_string_desc_t sd_new_addr (idx_t n, char *addr)
245
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1);
246
#endif
247
248
/* Return a string that represents the C string S, of length strlen (S).  */
249
extern string_desc_t sd_from_c (const char *s);
250
251
/* Return the substring of S, starting at offset START and ending at offset END.
252
   START must be <= END.
253
   The result is of length END - START.
254
   The result must not be freed (since its storage is part of the storage
255
   of S).  */
256
#if 0 /* Defined inline below.  */
257
extern string_desc_t sd_substring (string_desc_t s, idx_t start, idx_t end);
258
extern rw_string_desc_t sd_substring (rw_string_desc_t s, idx_t start, idx_t end);
259
#endif
260
261
/* Output S to the file descriptor FD.
262
   Return 0 if successful.
263
   Upon error, return -1 with errno set.  */
264
#if 0 /* Defined inline below.  */
265
extern int sd_write (int fd, [rw_]string_desc_t s);
266
#endif
267
268
/* Output S to the FILE stream FP.
269
   Return 0 if successful.
270
   Upon error, return -1.  */
271
#if 0 /* Defined inline below.  */
272
extern int sd_fwrite (FILE *fp, [rw_]string_desc_t s);
273
#endif
274
275
276
/* ==== Memory-allocating operations on string descriptors ==== */
277
278
/* Construct a string of length N, with uninitialized contents.
279
   Return 0 if successful.
280
   Upon error, return -1 with errno set.  */
281
_GL_ATTRIBUTE_NODISCARD
282
extern int sd_new (rw_string_desc_t *resultp, idx_t n);
283
284
/* Construct a string of length N, filled with C.
285
   Return 0 if successful.
286
   Upon error, return -1 with errno set.  */
287
_GL_ATTRIBUTE_NODISCARD
288
extern int sd_new_filled (rw_string_desc_t *resultp, idx_t n, char c);
289
290
/* Construct a copy of string S.
291
   Return 0 if successful.
292
   Upon error, return -1 with errno set.  */
293
#if 0 /* Defined inline below.  */
294
_GL_ATTRIBUTE_NODISCARD
295
extern int sd_copy (rw_string_desc_t *resultp, [rw_]string_desc_t s);
296
#endif
297
298
/* Construct the concatenation of N strings.  N must be > 0.
299
   Return 0 if successful.
300
   Upon error, return -1 with errno set.  */
301
_GL_ATTRIBUTE_NODISCARD
302
extern int sd_concat (rw_string_desc_t *resultp, idx_t n, /* [rw_]string_desc_t string1, */ ...);
303
304
/* Construct a copy of string S, as a NUL-terminated C string.
305
   Return it is successful.
306
   Upon error, return NULL with errno set.  */
307
#if 0 /* Defined inline below.  */
308
extern char * sd_c ([rw_]string_desc_t s) _GL_ATTRIBUTE_DEALLOC_FREE;
309
#endif
310
311
312
/* ==== Operations with side effects on string descriptors ==== */
313
314
/* Overwrite the byte at index I of string S with C.
315
   I must be < length(S).  */
316
extern void sd_set_char_at (rw_string_desc_t s, idx_t i, char c);
317
318
/* Fill part of S, starting at offset START and ending at offset END,
319
   with copies of C.
320
   START must be <= END.  */
321
extern void sd_fill (rw_string_desc_t s, idx_t start, idx_t end, char c);
322
323
/* Overwrite part of S with T, starting at offset START.
324
   START + length(T) must be <= length (S).  */
325
#if 0 /* Defined inline below.  */
326
extern void sd_overwrite (rw_string_desc_t s, idx_t start, [rw_]string_desc_t t);
327
#endif
328
329
/* Free S.  */
330
extern void sd_free (rw_string_desc_t s);
331
332
333
/* ==== Inline function definitions ==== */
334
335
#if HAVE_RW_STRING_DESC
336
GL_STRING_DESC_INLINE string_desc_t
337
sd_readonly (rw_string_desc_t s)
338
0
{
339
0
  string_desc_t result;
340
0
  result._nbytes = s._nbytes;
341
0
  result._data = s._data;
342
0
  return result;
343
0
}
344
#else
345
# define sd_readonly(s) (s)
346
#endif
347
348
#if HAVE_RW_STRING_DESC
349
GL_STRING_DESC_INLINE rw_string_desc_t
350
sd_readwrite (string_desc_t s)
351
0
{
352
0
  rw_string_desc_t result;
353
0
  result._nbytes = s._nbytes;
354
0
  result._data = (char *) s._data;
355
0
  return result;
356
0
}
357
#else
358
# define sd_readwrite(s) (s)
359
#endif
360
361
#if HAVE_RW_STRING_DESC
362
# define sd_length(s) \
363
0
   _Generic (s, \
364
0
             string_desc_t    : (s)._nbytes, \
365
0
             rw_string_desc_t : (s)._nbytes)
366
#else
367
GL_STRING_DESC_INLINE idx_t
368
sd_length (string_desc_t s)
369
{
370
  return s._nbytes;
371
}
372
#endif
373
374
#if HAVE_RW_STRING_DESC
375
# define sd_char_at(s, i) \
376
0
   ({typeof (s) _s_ = (s); \
377
0
     _sd_char_at (_s_._nbytes, _s_._data, i); \
378
0
   })
379
GL_STRING_DESC_INLINE char
380
_sd_char_at (idx_t s_nbytes, const char *s_data, idx_t i)
381
  _GL_ATTRIBUTE_NONNULL ((2));
382
GL_STRING_DESC_INLINE char
383
_sd_char_at (idx_t s_nbytes, const char *s_data, idx_t i)
384
0
{
385
0
  if (!(i >= 0 && i < s_nbytes))
386
    /* Invalid argument.  */
387
0
    abort ();
388
0
  return s_data[i];
389
0
}
390
#else
391
GL_STRING_DESC_INLINE char
392
sd_char_at (string_desc_t s, idx_t i)
393
{
394
  if (!(i >= 0 && i < s._nbytes))
395
    /* Invalid argument.  */
396
    abort ();
397
  return s._data[i];
398
}
399
#endif
400
401
#if HAVE_RW_STRING_DESC
402
# define sd_data(s) \
403
   _Generic (s, \
404
             string_desc_t    : (s)._data, \
405
             rw_string_desc_t : (s)._data)
406
#else
407
GL_STRING_DESC_INLINE const char *
408
sd_data (string_desc_t s)
409
{
410
  return s._data;
411
}
412
#endif
413
414
#if HAVE_RW_STRING_DESC
415
# define sd_is_empty(s) \
416
   _Generic (s, \
417
             string_desc_t    : (s)._nbytes == 0, \
418
             rw_string_desc_t : (s)._nbytes == 0)
419
#else
420
GL_STRING_DESC_INLINE bool
421
sd_is_empty (string_desc_t s)
422
{
423
  return s._nbytes == 0;
424
}
425
#endif
426
427
extern bool _sd_equals (idx_t a_nbytes, const char *a_data,
428
                        idx_t b_nbytes, const char *b_data)
429
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1)
430
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (4, 3);
431
#if HAVE_RW_STRING_DESC
432
# define sd_equals(a, b) \
433
   ({typeof (a) _a_ = (a); \
434
     typeof (b) _b_ = (b); \
435
     _sd_equals (_a_._nbytes, _a_._data, _b_._nbytes, _b_._data); \
436
   })
437
#else
438
GL_STRING_DESC_INLINE bool
439
sd_equals (string_desc_t a, string_desc_t b)
440
{
441
  return _sd_equals (a._nbytes, a._data, b._nbytes, b._data);
442
}
443
#endif
444
445
extern bool _sd_startswith (idx_t s_nbytes, const char *s_data,
446
                            idx_t prefix_nbytes, const char *prefix_data)
447
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1)
448
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (4, 3);
449
#if HAVE_RW_STRING_DESC
450
# define sd_startswith(s, prefix) \
451
   ({typeof (s) _s_ = (s); \
452
     typeof (prefix) _prefix_ = (prefix); \
453
     _sd_startswith (_s_._nbytes, _s_._data, _prefix_._nbytes, _prefix_._data); \
454
   })
455
#else
456
GL_STRING_DESC_INLINE bool
457
sd_startswith (string_desc_t s, string_desc_t prefix)
458
{
459
  return _sd_startswith (s._nbytes, s._data, prefix._nbytes, prefix._data);
460
}
461
#endif
462
463
extern bool _sd_endswith (idx_t s_nbytes, const char *s_data,
464
                          idx_t suffix_nbytes, const char *suffix_data)
465
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1)
466
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (4, 3);
467
#if HAVE_RW_STRING_DESC
468
# define sd_endswith(s, suffix) \
469
   ({typeof (s) _s_ = (s); \
470
     typeof (suffix) _suffix_ = (suffix); \
471
     _sd_endswith (_s_._nbytes, _s_._data, _suffix_._nbytes, _suffix_._data); \
472
   })
473
#else
474
GL_STRING_DESC_INLINE bool
475
sd_endswith (string_desc_t s, string_desc_t suffix)
476
{
477
  return _sd_endswith (s._nbytes, s._data, suffix._nbytes, suffix._data);
478
}
479
#endif
480
481
extern int _sd_cmp (idx_t a_nbytes, const char *a_data,
482
                    idx_t b_nbytes, const char *b_data)
483
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1)
484
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (4, 3);
485
#if HAVE_RW_STRING_DESC
486
# define sd_cmp(a, b) \
487
   ({typeof (a) _a_ = (a); \
488
     typeof (b) _b_ = (b); \
489
     _sd_cmp (_a_._nbytes, _a_._data, _b_._nbytes, _b_._data); \
490
   })
491
#else
492
GL_STRING_DESC_INLINE int
493
sd_cmp (string_desc_t a, string_desc_t b)
494
{
495
  return _sd_cmp (a._nbytes, a._data, b._nbytes, b._data);
496
}
497
#endif
498
499
extern int _sd_c_casecmp (idx_t a_nbytes, const char *a_data,
500
                          idx_t b_nbytes, const char *b_data)
501
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1)
502
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (4, 3);
503
#if HAVE_RW_STRING_DESC
504
# define sd_c_casecmp(a, b) \
505
   ({typeof (a) _a_ = (a); \
506
     typeof (b) _b_ = (b); \
507
     _sd_c_casecmp (_a_._nbytes, _a_._data, _b_._nbytes, _b_._data); \
508
   })
509
#else
510
GL_STRING_DESC_INLINE int
511
sd_c_casecmp (string_desc_t a, string_desc_t b)
512
{
513
  return _sd_c_casecmp (a._nbytes, a._data, b._nbytes, b._data);
514
}
515
#endif
516
517
extern ptrdiff_t _sd_index (idx_t s_nbytes, const char *s_data, char c)
518
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1);
519
#if HAVE_RW_STRING_DESC
520
# define sd_index(s, c) \
521
   ({typeof (s) _s_ = (s); \
522
     _sd_index (_s_._nbytes, _s_._data, c); \
523
   })
524
#else
525
GL_STRING_DESC_INLINE ptrdiff_t
526
sd_index (string_desc_t s, char c)
527
{
528
  return _sd_index (s._nbytes, s._data, c);
529
}
530
#endif
531
532
extern ptrdiff_t _sd_last_index (idx_t s_nbytes, const char *s_data, char c)
533
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1);
534
#if HAVE_RW_STRING_DESC
535
# define sd_last_index(s, c) \
536
   ({typeof (s) _s_ = (s); \
537
     _sd_last_index (_s_._nbytes, _s_._data, c); \
538
   })
539
#else
540
GL_STRING_DESC_INLINE ptrdiff_t
541
sd_last_index (string_desc_t s, char c)
542
{
543
  return _sd_last_index (s._nbytes, s._data, c);
544
}
545
#endif
546
547
extern ptrdiff_t _sd_contains (idx_t haystack_nbytes, const char *haystack_data,
548
                               idx_t needle_nbytes, const char *needle_data)
549
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1)
550
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (4, 3);
551
#if HAVE_RW_STRING_DESC
552
# define sd_contains(haystack, needle) \
553
   ({typeof (haystack) _haystack_ = (haystack); \
554
     typeof (needle) _needle_ = (needle); \
555
     _sd_contains (_haystack_._nbytes, _haystack_._data, \
556
                   _needle_._nbytes, _needle_._data); \
557
   })
558
#else
559
GL_STRING_DESC_INLINE ptrdiff_t
560
sd_contains (string_desc_t haystack, string_desc_t needle)
561
{
562
  return _sd_contains (haystack._nbytes, haystack._data,
563
                       needle._nbytes, needle._data);
564
}
565
#endif
566
567
extern string_desc_t _sd_new_addr (idx_t n, const char *addr)
568
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1);
569
extern rw_string_desc_t _rwsd_new_addr (idx_t n, /*!*/const/*!*/ char *addr)
570
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1);
571
#if HAVE_RW_STRING_DESC
572
# define sd_new_addr(n, addr) \
573
   _Generic (addr, \
574
             const char * : _sd_new_addr (n, addr), \
575
             char * : /* Treat string literals like 'const char *'.  */ \
576
                      __builtin_choose_expr (__builtin_constant_p (addr), \
577
                                             _sd_new_addr (n, addr), \
578
                                             _rwsd_new_addr (n, addr)))
579
#else
580
# define sd_new_addr(n, addr) \
581
   _rwsd_new_addr (n, addr)
582
#endif
583
584
#if HAVE_RW_STRING_DESC
585
# define sd_substring(s, start, end) \
586
   ({typeof (s) _s_ = (s); \
587
     idx_t _start_ = (start); \
588
     idx_t _end_ = (end); \
589
     if (!(_start_ >= 0 && _start_ <= _end_ && _end_ <= _s_._nbytes)) \
590
       /* Invalid arguments.  */ \
591
       abort (); \
592
     typeof (s) _result_; \
593
     _result_._nbytes = _end_ - _start_; \
594
     _result_._data = _s_._data + _start_; \
595
     _result_; \
596
   })
597
#else
598
GL_STRING_DESC_INLINE string_desc_t
599
sd_substring (string_desc_t s, idx_t start, idx_t end)
600
{
601
  if (!(start >= 0 && start <= end && end <= s._nbytes))
602
    /* Invalid arguments.  */
603
    abort ();
604
  string_desc_t result;
605
  result._nbytes = end - start;
606
  result._data = s._data + start;
607
  return result;
608
}
609
#endif
610
611
extern int _sd_write (int fd, idx_t s_nbytes, const char *s_data)
612
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (3, 2);
613
#if HAVE_RW_STRING_DESC
614
# define sd_write(fd, s) \
615
   ({int _fd_ = (fd); \
616
     typeof (s) _s_ = (s); \
617
     _sd_write (_fd_, _s_._nbytes, _s_._data); \
618
   })
619
#else
620
GL_STRING_DESC_INLINE int
621
sd_write (int fd, string_desc_t s)
622
{
623
  return _sd_write (fd, s._nbytes, s._data);
624
}
625
#endif
626
627
extern int _sd_fwrite (FILE *fp, idx_t s_nbytes, const char *s_data)
628
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (3, 2);
629
#if HAVE_RW_STRING_DESC
630
# define sd_fwrite(fp, s) \
631
   ({FILE *_fp_ = (fp); \
632
     typeof (s) _s_ = (s); \
633
     _sd_fwrite (_fp_, _s_._nbytes, _s_._data); \
634
   })
635
#else
636
GL_STRING_DESC_INLINE int
637
sd_fwrite (FILE *fp, string_desc_t s)
638
{
639
  return _sd_fwrite (fp, s._nbytes, s._data);
640
}
641
#endif
642
643
extern int _sd_copy (rw_string_desc_t *resultp,
644
                     idx_t s_nbytes, const char *s_data)
645
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (3, 2);
646
#if HAVE_RW_STRING_DESC
647
# define sd_copy(resultp, s) \
648
   ({rw_string_desc_t *_resultp_ = (resultp); \
649
     typeof (s) _s_ = (s); \
650
     _sd_copy (_resultp_, _s_._nbytes, _s_._data); \
651
   })
652
#else
653
_GL_ATTRIBUTE_NODISCARD GL_STRING_DESC_INLINE int
654
sd_copy (rw_string_desc_t *resultp, string_desc_t s)
655
{
656
  return _sd_copy (resultp, s._nbytes, s._data);
657
}
658
#endif
659
660
extern char *_sd_c (idx_t s_nbytes, const char *s_data)
661
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 1);
662
#if HAVE_RW_STRING_DESC
663
# define sd_c(s) \
664
   ({typeof (s) _s_ = (s); \
665
     _sd_c (_s_._nbytes, _s_._data); \
666
   })
667
#else
668
GL_STRING_DESC_INLINE char *
669
sd_c (string_desc_t s)
670
{
671
  return _sd_c (s._nbytes, s._data);
672
}
673
#endif
674
675
extern void _sd_overwrite (rw_string_desc_t s, idx_t start,
676
                           idx_t t_nbytes, const char *t_data)
677
  _GL_ATTRIBUTE_NONNULL_IF_NONZERO (4, 3);
678
#if HAVE_RW_STRING_DESC
679
# define sd_overwrite(s, start, t) \
680
   ({rw_string_desc_t _s_ = (s); \
681
     idx_t _start_ = (start); \
682
     typeof (t) _t_ = (t); \
683
     _sd_overwrite (_s_, _start_, _t_._nbytes, _t_._data); \
684
   })
685
#else
686
GL_STRING_DESC_INLINE void
687
sd_overwrite (rw_string_desc_t s, idx_t start, string_desc_t t)
688
{
689
  _sd_overwrite (s, start, t._nbytes, t._data);
690
}
691
#endif
692
693
694
#ifdef __cplusplus
695
}
696
#endif
697
698
_GL_INLINE_HEADER_END
699
700
701
#endif /* _STRING_DESC_H */