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