Coverage Report

Created: 2026-01-25 07:18

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