1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 #include <libpspp/alloc.h>
29 #include <libpspp/message.h>
30 #include <libpspp/pool.h>
36 /* Reverses the order of NBYTES bytes at address P, thus converting
37 between little- and big-endian byte orders. */
39 buf_reverse (char *p, size_t nbytes)
41 char *h = p, *t = &h[nbytes - 1];
53 /* Finds the last NEEDLE of length NEEDLE_LEN in a HAYSTACK of length
54 HAYSTACK_LEN. Returns a pointer to the needle found. */
56 buf_find_reverse (const char *haystack, size_t haystack_len,
57 const char *needle, size_t needle_len)
60 for (i = haystack_len - needle_len; i >= 0; i--)
61 if (!memcmp (needle, &haystack[i], needle_len))
62 return (char *) &haystack[i];
66 /* Compares the SIZE bytes in A to those in B, disregarding case,
67 and returns a strcmp()-type result. */
69 buf_compare_case (const char *a_, const char *b_, size_t size)
71 const unsigned char *a = (unsigned char *) a_;
72 const unsigned char *b = (unsigned char *) b_;
76 unsigned char ac = toupper (*a++);
77 unsigned char bc = toupper (*b++);
80 return ac > bc ? 1 : -1;
86 /* Compares A of length A_LEN to B of length B_LEN. The shorter
87 string is considered to be padded with spaces to the length of
90 buf_compare_rpad (const char *a, size_t a_len, const char *b, size_t b_len)
95 min_len = a_len < b_len ? a_len : b_len;
96 result = memcmp (a, b, min_len);
105 for (idx = min_len; idx < b_len; idx++)
107 return ' ' > b[idx] ? 1 : -1;
111 for (idx = min_len; idx < a_len; idx++)
113 return a[idx] > ' ' ? 1 : -1;
119 /* Compares strin A to string B. The shorter string is
120 considered to be padded with spaces to the length of the
123 str_compare_rpad (const char *a, const char *b)
125 return buf_compare_rpad (a, strlen (a), b, strlen (b));
128 /* Copies string SRC to buffer DST, of size DST_SIZE bytes.
129 DST is truncated to DST_SIZE bytes or padded on the right with
132 buf_copy_str_rpad (char *dst, size_t dst_size, const char *src)
134 size_t src_len = strlen (src);
135 if (src_len >= dst_size)
136 memcpy (dst, src, dst_size);
139 memcpy (dst, src, src_len);
140 memset (&dst[src_len], ' ', dst_size - src_len);
144 /* Copies string SRC to buffer DST, of size DST_SIZE bytes.
145 DST is truncated to DST_SIZE bytes or padded on the left with
148 buf_copy_str_lpad (char *dst, size_t dst_size, const char *src)
150 size_t src_len = strlen (src);
151 if (src_len >= dst_size)
152 memcpy (dst, src, dst_size);
155 size_t pad_cnt = dst_size - src_len;
156 memset (&dst[0], ' ', pad_cnt);
157 memcpy (dst + pad_cnt, src, src_len);
161 /* Copies buffer SRC, of SRC_SIZE bytes, to DST, of DST_SIZE bytes.
162 DST is truncated to DST_SIZE bytes or padded on the left with
165 buf_copy_lpad (char *dst, size_t dst_size,
166 const char *src, size_t src_size)
168 if (src_size >= dst_size)
169 memmove (dst, src, dst_size);
172 memset (dst, ' ', dst_size - src_size);
173 memmove (&dst[dst_size - src_size], src, src_size);
177 /* Copies buffer SRC, of SRC_SIZE bytes, to DST, of DST_SIZE bytes.
178 DST is truncated to DST_SIZE bytes or padded on the right with
181 buf_copy_rpad (char *dst, size_t dst_size,
182 const char *src, size_t src_size)
184 if (src_size >= dst_size)
185 memmove (dst, src, dst_size);
188 memmove (dst, src, src_size);
189 memset (&dst[src_size], ' ', dst_size - src_size);
193 /* Copies string SRC to string DST, which is in a buffer DST_SIZE
195 Truncates DST to DST_SIZE - 1 characters or right-pads with
196 spaces to DST_SIZE - 1 characters if necessary. */
198 str_copy_rpad (char *dst, size_t dst_size, const char *src)
200 size_t src_len = strlen (src);
201 if (src_len < dst_size - 1)
203 memcpy (dst, src, src_len);
204 memset (&dst[src_len], ' ', dst_size - 1 - src_len);
207 memcpy (dst, src, dst_size - 1);
208 dst[dst_size - 1] = 0;
211 /* Copies SRC to DST, which is in a buffer DST_SIZE bytes long.
212 Truncates DST to DST_SIZE - 1 characters, if necessary. */
214 str_copy_trunc (char *dst, size_t dst_size, const char *src)
216 size_t src_len = strlen (src);
217 assert (dst_size > 0);
218 if (src_len + 1 < dst_size)
219 memcpy (dst, src, src_len + 1);
222 memcpy (dst, src, dst_size - 1);
223 dst[dst_size - 1] = '\0';
227 /* Copies buffer SRC, of SRC_LEN bytes,
228 to DST, which is in a buffer DST_SIZE bytes long.
229 Truncates DST to DST_SIZE - 1 characters, if necessary. */
231 str_copy_buf_trunc (char *dst, size_t dst_size,
232 const char *src, size_t src_size)
235 assert (dst_size > 0);
237 dst_len = src_size < dst_size ? src_size : dst_size - 1;
238 memcpy (dst, src, dst_len);
242 /* Converts each character in S to uppercase. */
244 str_uppercase (char *s)
246 for (; *s != '\0'; s++)
247 *s = toupper ((unsigned char) *s);
250 /* Converts each character in S to lowercase. */
252 str_lowercase (char *s)
254 for (; *s != '\0'; s++)
255 *s = tolower ((unsigned char) *s);
258 /* Formats FORMAT into DST, as with sprintf(), and returns the
259 address of the terminating null written to DST. */
261 spprintf (char *dst, const char *format, ...)
266 va_start (args, format);
267 count = vsprintf (dst, format, args);
273 /* Sets the SIZE bytes starting at BLOCK to C,
274 and returns the byte following BLOCK. */
276 mempset (void *block, int c, size_t size)
278 memset (block, c, size);
279 return (char *) block + size;
284 /* Returns an empty substring. */
294 /* Returns a substring whose contents are the given C-style
297 ss_cstr (const char *cstr)
299 return ss_buffer (cstr, strlen (cstr));
302 /* Returns a substring whose contents are the CNT characters in
305 ss_buffer (const char *buffer, size_t cnt)
308 ss.string = (char *) buffer;
313 /* Returns a substring whose contents are the CNT characters
314 starting at the (0-based) position START in SS. */
316 ss_substr (struct substring ss, size_t start, size_t cnt)
318 if (start < ss.length)
319 return ss_buffer (ss.string + start, MIN (cnt, ss.length - start));
321 return ss_buffer (ss.string + ss.length, 0);
324 /* Returns a substring whose contents are the first CNT
327 ss_head (struct substring ss, size_t cnt)
329 return ss_buffer (ss.string, MIN (cnt, ss.length));
332 /* Returns a substring whose contents are the last CNT characters
335 ss_tail (struct substring ss, size_t cnt)
338 return ss_buffer (ss.string + (ss.length - cnt), cnt);
343 /* Makes a malloc()'d copy of the contents of OLD
344 and stores it in NEW. */
346 ss_alloc_substring (struct substring *new, struct substring old)
348 new->string = xmalloc (old.length);
349 new->length = old.length;
350 memcpy (new->string, old.string, old.length);
353 /* Allocates room for a CNT-character string in NEW. */
355 ss_alloc_uninit (struct substring *new, size_t cnt)
357 new->string = xmalloc (cnt);
361 /* Makes a pool_alloc_unaligned()'d copy of the contents of OLD
362 in POOL, and stores it in NEW. */
364 ss_alloc_substring_pool (struct substring *new, struct substring old,
367 new->string = pool_alloc_unaligned (pool, old.length);
368 new->length = old.length;
369 memcpy (new->string, old.string, old.length);
372 /* Allocates room for a CNT-character string in NEW in POOL. */
374 ss_alloc_uninit_pool (struct substring *new, size_t cnt, struct pool *pool)
376 new->string = pool_alloc_unaligned (pool, cnt);
380 /* Frees the string that SS points to. */
382 ss_dealloc (struct substring *ss)
387 /* Truncates SS to at most CNT characters in length. */
389 ss_truncate (struct substring *ss, size_t cnt)
391 if (ss->length > cnt)
395 /* Removes trailing characters in TRIM_SET from SS.
396 Returns number of characters removed. */
398 ss_rtrim (struct substring *ss, struct substring trim_set)
401 while (cnt < ss->length
402 && ss_find_char (trim_set,
403 ss->string[ss->length - cnt - 1]) != SIZE_MAX)
409 /* Removes leading characters in TRIM_SET from SS.
410 Returns number of characters removed. */
412 ss_ltrim (struct substring *ss, struct substring trim_set)
414 size_t cnt = ss_span (*ss, trim_set);
415 ss_advance (ss, cnt);
419 /* Trims leading and trailing characters in TRIM_SET from SS. */
421 ss_trim (struct substring *ss, struct substring trim_set)
423 ss_ltrim (ss, trim_set);
424 ss_rtrim (ss, trim_set);
427 /* If the last character in SS is C, removes it and returns true.
428 Otherwise, returns false without changing the string. */
430 ss_chomp (struct substring *ss, char c)
432 if (ss_last (*ss) == c)
441 /* Divides SS into tokens separated by any of the DELIMITERS.
442 Each call replaces TOKEN by the next token in SS, or by an
443 empty string if no tokens remain. Returns true if a token was
444 obtained, false otherwise.
446 Before the first call, initialize *SAVE_IDX to 0. Do not
447 modify *SAVE_IDX between calls.
449 SS divides into exactly one more tokens than it contains
450 delimiters. That is, a delimiter at the start or end of SS or
451 a pair of adjacent delimiters yields an empty token, and the
452 empty string contains a single token. */
454 ss_separate (struct substring ss, struct substring delimiters,
455 size_t *save_idx, struct substring *token)
457 if (*save_idx <= ss_length (ss))
459 struct substring tmp = ss_substr (ss, *save_idx, SIZE_MAX);
460 size_t length = ss_cspan (tmp, delimiters);
461 *token = ss_head (tmp, length);
462 *save_idx += length + 1;
467 *token = ss_empty ();
472 /* Divides SS into tokens separated by any of the DELIMITERS,
473 merging adjacent delimiters so that the empty string is never
474 produced as a token. Each call replaces TOKEN by the next
475 token in SS, or by an empty string if no tokens remain.
476 Returns true if a token was obtained, false otherwise.
478 Before the first call, initialize *SAVE_IDX to 0. Do not
479 modify *SAVE_IDX between calls. */
481 ss_tokenize (struct substring ss, struct substring delimiters,
482 size_t *save_idx, struct substring *token)
484 ss_advance (&ss, *save_idx);
485 *save_idx += ss_ltrim (&ss, delimiters);
486 *save_idx += ss_get_chars (&ss, ss_cspan (ss, delimiters), token);
487 return ss_length (*token) > 0;
490 /* Removes the first CNT characters from SS. */
492 ss_advance (struct substring *ss, size_t cnt)
494 if (cnt > ss->length)
500 /* If the first character in SS is C, removes it and returns true.
501 Otherwise, returns false without changing the string. */
503 ss_match_char (struct substring *ss, char c)
505 if (ss_first (*ss) == c)
515 /* Removes the first character from SS and returns it.
516 If SS is empty, returns EOF without modifying SS. */
518 ss_get_char (struct substring *ss)
520 int c = ss_first (*ss);
529 /* Stores the prefix of SS up to the first DELIMITER in OUT (if
530 any). Trims those same characters from SS. DELIMITER is
531 removed from SS but not made part of OUT. Returns true if
532 DELIMITER was found (and removed), false otherwise. */
534 ss_get_until (struct substring *ss, char delimiter, struct substring *out)
536 ss_get_chars (ss, ss_cspan (*ss, ss_buffer (&delimiter, 1)), out);
537 return ss_match_char (ss, delimiter);
540 /* Stores the first CNT characters in SS in OUT (or fewer, if SS
541 is shorter than CNT characters). Trims the same characters
542 from the beginning of SS. Returns CNT. */
544 ss_get_chars (struct substring *ss, size_t cnt, struct substring *out)
546 *out = ss_head (*ss, cnt);
547 ss_advance (ss, cnt);
551 /* Parses and removes an optionally signed decimal integer from
552 the beginning of SS. Returns 0 if an error occurred,
553 otherwise the number of characters removed from SS. Stores
554 the integer's value into *VALUE. */
556 ss_get_long (struct substring *ss, long *value)
561 length = ss_span (*ss, ss_cstr ("+-"));
562 length += ss_span (ss_substr (*ss, length, SIZE_MAX), ss_cstr (CC_DIGITS));
563 if (length > 0 && length < sizeof tmp)
567 memcpy (tmp, ss_data (*ss), length);
570 *value = strtol (tmp, &tail, 10);
571 if (tail - tmp == length)
573 ss_advance (ss, length);
581 /* Returns true if SS is empty (contains no characters),
584 ss_is_empty (struct substring ss)
586 return ss.length == 0;
589 /* Returns the number of characters in SS. */
591 ss_length (struct substring ss)
596 /* Returns a pointer to the characters in SS. */
598 ss_data (struct substring ss)
603 /* Returns a pointer just past the last character in SS. */
605 ss_end (struct substring ss)
607 return ss.string + ss.length;
610 /* Returns the character in position IDX in SS, as a value in the
611 range of unsigned char. Returns EOF if IDX is out of the
612 range of indexes for SS. */
614 ss_at (struct substring ss, size_t idx)
616 return idx < ss.length ? (unsigned char) ss.string[idx] : EOF;
619 /* Returns the first character in SS as a value in the range of
620 unsigned char. Returns EOF if SS is the empty string. */
622 ss_first (struct substring ss)
624 return ss_at (ss, 0);
627 /* Returns the last character in SS as a value in the range of
628 unsigned char. Returns EOF if SS is the empty string. */
630 ss_last (struct substring ss)
632 return ss.length > 0 ? (unsigned char) ss.string[ss.length - 1] : EOF;
635 /* Returns the number of contiguous characters at the beginning
636 of SS that are in SKIP_SET. */
638 ss_span (struct substring ss, struct substring skip_set)
641 for (i = 0; i < ss.length; i++)
642 if (ss_find_char (skip_set, ss.string[i]) == SIZE_MAX)
647 /* Returns the number of contiguous characters at the beginning
648 of SS that are not in SKIP_SET. */
650 ss_cspan (struct substring ss, struct substring stop_set)
653 for (i = 0; i < ss.length; i++)
654 if (ss_find_char (stop_set, ss.string[i]) != SIZE_MAX)
659 /* Returns the offset in SS of the first instance of C,
660 or SIZE_MAX if C does not occur in SS. */
662 ss_find_char (struct substring ss, char c)
664 const char *p = memchr (ss.string, c, ss.length);
665 return p != NULL ? p - ss.string : SIZE_MAX;
668 /* Compares A and B and returns a strcmp()-type comparison
671 ss_compare (struct substring a, struct substring b)
673 int retval = memcmp (a.string, b.string, MIN (a.length, b.length));
675 retval = a.length < b.length ? -1 : a.length > b.length;
679 /* Compares A and B case-insensitively and returns a
680 strcmp()-type comparison result. */
682 ss_compare_case (struct substring a, struct substring b)
684 int retval = memcasecmp (a.string, b.string, MIN (a.length, b.length));
686 retval = a.length < b.length ? -1 : a.length > b.length;
690 /* Compares A and B and returns true if their contents are
691 identical, false otherwise. */
693 ss_equals (struct substring a, struct substring b)
695 return a.length == b.length && !memcmp (a.string, b.string, a.length);
698 /* Compares A and B and returns true if their contents are
699 identical except possibly for case differences, false
702 ss_equals_case (struct substring a, struct substring b)
704 return a.length == b.length && !memcasecmp (a.string, b.string, a.length);
707 /* Returns the position in SS that the character at P occupies.
708 P must point within SS or one past its end. */
710 ss_pointer_to_position (struct substring ss, const char *p)
712 size_t pos = p - ss.string;
713 assert (pos <= ss.length);
717 /* Allocates and returns a null-terminated string that contains
720 ss_xstrdup (struct substring ss)
722 char *s = xmalloc (ss.length + 1);
723 memcpy (s, ss.string, ss.length);
728 /* Initializes ST as an empty string. */
730 ds_init_empty (struct string *st)
732 st->ss = ss_empty ();
736 /* Initializes ST with initial contents S. */
738 ds_init_string (struct string *st, const struct string *s)
740 ds_init_substring (st, ds_ss (s));
743 /* Initializes ST with initial contents SS. */
745 ds_init_substring (struct string *st, struct substring ss)
747 st->capacity = MAX (8, ss.length * 2);
748 st->ss.string = xmalloc (st->capacity + 1);
749 memcpy (st->ss.string, ss.string, ss.length);
750 st->ss.length = ss.length;
753 /* Initializes ST with initial contents S. */
755 ds_init_cstr (struct string *st, const char *s)
757 ds_init_substring (st, ss_cstr (s));
762 ds_destroy (struct string *st)
766 ss_dealloc (&st->ss);
767 st->ss.string = NULL;
773 /* Swaps the contents of strings A and B. */
775 ds_swap (struct string *a, struct string *b)
777 struct string tmp = *a;
782 /* Helper function for ds_register_pool. */
784 free_string (void *st_)
786 struct string *st = st_;
790 /* Arranges for ST to be destroyed automatically as part of
793 ds_register_pool (struct string *st, struct pool *pool)
795 pool_register (pool, free_string, st);
798 /* Cancels the arrangement for ST to be destroyed automatically
801 ds_unregister_pool (struct string *st, struct pool *pool)
803 pool_unregister (pool, st);
806 /* Copies SRC into DST.
807 DST and SRC may be the same string. */
809 ds_assign_string (struct string *dst, const struct string *src)
811 ds_assign_substring (dst, ds_ss (src));
814 /* Replaces DST by SS.
815 SS may be a substring of DST. */
817 ds_assign_substring (struct string *dst, struct substring ss)
819 dst->ss.length = ss.length;
820 ds_extend (dst, ss.length);
821 memmove (dst->ss.string, ss.string, ss.length);
824 /* Replaces DST by null-terminated string SRC. SRC may overlap
827 ds_assign_cstr (struct string *dst, const char *src)
829 ds_assign_substring (dst, ss_cstr (src));
832 /* Truncates ST to zero length. */
834 ds_clear (struct string *st)
839 /* Returns a substring that contains ST. */
841 ds_ss (const struct string *st)
846 /* Returns a substring that contains CNT characters from ST
847 starting at position START.
849 If START is greater than or equal to the length of ST, then
850 the substring will be the empty string. If START + CNT
851 exceeds the length of ST, then the substring will only be
852 ds_length(ST) - START characters long. */
854 ds_substr (const struct string *st, size_t start, size_t cnt)
856 return ss_substr (ds_ss (st), start, cnt);
859 /* Returns a substring that contains the first CNT characters in
860 ST. If CNT exceeds the length of ST, then the substring will
861 contain all of ST. */
863 ds_head (const struct string *st, size_t cnt)
865 return ss_head (ds_ss (st), cnt);
868 /* Returns a substring that contains the last CNT characters in
869 ST. If CNT exceeds the length of ST, then the substring will
870 contain all of ST. */
872 ds_tail (const struct string *st, size_t cnt)
874 return ss_tail (ds_ss (st), cnt);
877 /* Ensures that ST can hold at least MIN_CAPACITY characters plus a null
880 ds_extend (struct string *st, size_t min_capacity)
882 if (min_capacity > st->capacity)
885 if (st->capacity < min_capacity)
886 st->capacity = 2 * min_capacity;
888 st->ss.string = xrealloc (st->ss.string, st->capacity + 1);
892 /* Shrink ST to the minimum capacity need to contain its content. */
894 ds_shrink (struct string *st)
896 if (st->capacity != st->ss.length)
898 st->capacity = st->ss.length;
899 st->ss.string = xrealloc (st->ss.string, st->capacity + 1);
903 /* Truncates ST to at most LENGTH characters long. */
905 ds_truncate (struct string *st, size_t length)
907 ss_truncate (&st->ss, length);
910 /* Removes trailing characters in TRIM_SET from ST.
911 Returns number of characters removed. */
913 ds_rtrim (struct string *st, struct substring trim_set)
915 return ss_rtrim (&st->ss, trim_set);
918 /* Removes leading characters in TRIM_SET from ST.
919 Returns number of characters removed. */
921 ds_ltrim (struct string *st, struct substring trim_set)
923 size_t cnt = ds_span (st, trim_set);
925 ds_assign_substring (st, ds_substr (st, cnt, SIZE_MAX));
929 /* Trims leading and trailing characters in TRIM_SET from ST.
930 Returns number of charactesr removed. */
932 ds_trim (struct string *st, struct substring trim_set)
934 size_t cnt = ds_rtrim (st, trim_set);
935 return cnt + ds_ltrim (st, trim_set);
938 /* If the last character in ST is C, removes it and returns true.
939 Otherwise, returns false without modifying ST. */
941 ds_chomp (struct string *st, char c)
943 return ss_chomp (&st->ss, c);
946 /* Divides ST into tokens separated by any of the DELIMITERS.
947 Each call replaces TOKEN by the next token in ST, or by an
948 empty string if no tokens remain. Returns true if a token was
949 obtained, false otherwise.
951 Before the first call, initialize *SAVE_IDX to 0. Do not
952 modify *SAVE_IDX between calls.
954 ST divides into exactly one more tokens than it contains
955 delimiters. That is, a delimiter at the start or end of ST or
956 a pair of adjacent delimiters yields an empty token, and the
957 empty string contains a single token. */
959 ds_separate (const struct string *st, struct substring delimiters,
960 size_t *save_idx, struct substring *token)
962 return ss_separate (ds_ss (st), delimiters, save_idx, token);
965 /* Divides ST into tokens separated by any of the DELIMITERS,
966 merging adjacent delimiters so that the empty string is never
967 produced as a token. Each call replaces TOKEN by the next
968 token in ST, or by an empty string if no tokens remain.
969 Returns true if a token was obtained, false otherwise.
971 Before the first call, initialize *SAVE_IDX to 0. Do not
972 modify *SAVE_IDX between calls. */
974 ds_tokenize (const struct string *st, struct substring delimiters,
975 size_t *save_idx, struct substring *token)
977 return ss_tokenize (ds_ss (st), delimiters, save_idx, token);
980 /* Pad ST on the right with copies of PAD until ST is at least
981 LENGTH characters in size. If ST is initially LENGTH
982 characters or longer, this is a no-op. */
984 ds_rpad (struct string *st, size_t length, char pad)
986 if (length > st->ss.length)
987 ds_put_char_multiple (st, pad, length - st->ss.length);
990 /* Sets the length of ST to exactly NEW_LENGTH,
991 either by truncating characters from the end,
992 or by padding on the right with PAD. */
994 ds_set_length (struct string *st, size_t new_length, char pad)
996 if (st->ss.length < new_length)
997 ds_rpad (st, new_length, pad);
999 st->ss.length = new_length;
1002 /* Returns true if ST is empty, false otherwise. */
1004 ds_is_empty (const struct string *st)
1006 return ss_is_empty (st->ss);
1009 /* Returns the length of ST. */
1011 ds_length (const struct string *st)
1013 return ss_length (ds_ss (st));
1016 /* Returns the string data inside ST. */
1018 ds_data (const struct string *st)
1020 return ss_data (ds_ss (st));
1023 /* Returns a pointer to the null terminator ST.
1024 This might not be an actual null character unless ds_c_str() has
1025 been called since the last modification to ST. */
1027 ds_end (const struct string *st)
1029 return ss_end (ds_ss (st));
1032 /* Returns the character in position IDX in ST, as a value in the
1033 range of unsigned char. Returns EOF if IDX is out of the
1034 range of indexes for ST. */
1036 ds_at (const struct string *st, size_t idx)
1038 return ss_at (ds_ss (st), idx);
1041 /* Returns the first character in ST as a value in the range of
1042 unsigned char. Returns EOF if ST is the empty string. */
1044 ds_first (const struct string *st)
1046 return ss_first (ds_ss (st));
1049 /* Returns the last character in ST as a value in the range of
1050 unsigned char. Returns EOF if ST is the empty string. */
1052 ds_last (const struct string *st)
1054 return ss_last (ds_ss (st));
1057 /* Returns the number of consecutive characters at the beginning
1058 of ST that are in SKIP_SET. */
1060 ds_span (const struct string *st, struct substring skip_set)
1062 return ss_span (ds_ss (st), skip_set);
1065 /* Returns the number of consecutive characters at the beginning
1066 of ST that are not in STOP_SET. */
1068 ds_cspan (const struct string *st, struct substring stop_set)
1070 return ss_cspan (ds_ss (st), stop_set);
1073 /* Returns the position of the first occurrence of character C in
1074 ST at or after position OFS, or SIZE_MAX if there is no such
1077 ds_find_char (const struct string *st, char c)
1079 return ss_find_char (ds_ss (st), c);
1082 /* Compares A and B and returns a strcmp()-type comparison
1085 ds_compare (const struct string *a, const struct string *b)
1087 return ss_compare (ds_ss (a), ds_ss (b));
1090 /* Returns the position in ST that the character at P occupies.
1091 P must point within ST or one past its end. */
1093 ds_pointer_to_position (const struct string *st, const char *p)
1095 return ss_pointer_to_position (ds_ss (st), p);
1098 /* Allocates and returns a null-terminated string that contains
1101 ds_xstrdup (const struct string *st)
1103 return ss_xstrdup (ds_ss (st));
1106 /* Returns the allocation size of ST. */
1108 ds_capacity (const struct string *st)
1110 return st->capacity;
1113 /* Returns the value of ST as a null-terminated string. */
1115 ds_cstr (const struct string *st_)
1117 struct string *st = (struct string *) st_;
1118 if (st->ss.string == NULL)
1120 st->ss.string[st->ss.length] = '\0';
1121 return st->ss.string;
1124 /* Appends to ST a newline-terminated line read from STREAM.
1125 Newline is the last character of ST on return, unless an I/O error
1126 or end of file is encountered after reading some characters.
1127 Returns true if a line is successfully read, false if no characters at
1128 all were read before an I/O error or end of file was
1131 ds_read_line (struct string *st, FILE *stream)
1141 ds_put_char (st, c);
1151 /* Removes a comment introduced by `#' from ST,
1152 ignoring occurrences inside quoted strings. */
1154 remove_comment (struct string *st)
1159 for (cp = ds_data (st); cp < ds_end (st); cp++)
1164 else if (*cp == '\\')
1167 else if (*cp == '\'' || *cp == '"')
1169 else if (*cp == '#')
1171 ds_truncate (st, cp - ds_cstr (st));
1176 /* Reads a line from STREAM into ST, then preprocesses as follows:
1178 - Splices lines terminated with `\'.
1180 - Deletes comments introduced by `#' outside of single or double
1183 - Deletes trailing white space.
1185 Returns true if a line was successfully read, false on
1186 failure. If LINE_NUMBER is non-null, then *LINE_NUMBER is
1187 incremented by the number of lines read. */
1189 ds_read_config_line (struct string *st, int *line_number, FILE *stream)
1194 if (!ds_read_line (st, stream))
1197 ds_rtrim (st, ss_cstr (CC_SPACES));
1199 while (ds_chomp (st, '\\'));
1201 remove_comment (st);
1205 /* Attempts to read SIZE * CNT bytes from STREAM and append them
1207 Returns number of bytes actually read. */
1209 ds_read_stream (struct string *st, size_t size, size_t cnt, FILE *stream)
1213 size_t try_bytes = xtimes (cnt, size);
1214 if (size_in_bounds_p (xsum (ds_length (st), try_bytes)))
1216 char *buffer = ds_put_uninit (st, try_bytes);
1217 size_t got_bytes = fread (buffer, size, cnt, stream);
1218 ds_truncate (st, ds_length (st) - (try_bytes - got_bytes));
1225 /* Concatenates S onto ST. */
1227 ds_put_cstr (struct string *st, const char *s)
1230 ds_put_substring (st, ss_cstr (s));
1233 /* Concatenates SS to ST. */
1235 ds_put_substring (struct string *st, struct substring ss)
1237 memcpy (ds_put_uninit (st, ss_length (ss)), ss_data (ss), ss_length (ss));
1240 /* Returns ds_end(ST) and THEN increases the length by INCR. */
1242 ds_put_uninit (struct string *st, size_t incr)
1245 ds_extend (st, ds_length (st) + incr);
1247 st->ss.length += incr;
1251 /* Formats FORMAT as a printf string and appends the result to ST. */
1253 ds_put_format (struct string *st, const char *format, ...)
1257 va_start (args, format);
1258 ds_put_vformat (st, format, args);
1262 /* Formats FORMAT as a printf string and appends the result to ST. */
1264 ds_put_vformat (struct string *st, const char *format, va_list args_)
1269 va_copy (args, args_);
1270 avail = st->ss.string != NULL ? st->capacity - st->ss.length + 1 : 0;
1271 needed = vsnprintf (st->ss.string + st->ss.length, avail, format, args);
1274 if (needed >= avail)
1276 va_copy (args, args_);
1277 vsprintf (ds_put_uninit (st, needed), format, args);
1282 /* Some old libc's returned -1 when the destination string
1284 while (needed == -1)
1286 ds_extend (st, (st->capacity + 1) * 2);
1287 avail = st->capacity - st->ss.length + 1;
1289 va_copy (args, args_);
1290 needed = vsnprintf (ds_end (st), avail, format, args);
1293 st->ss.length += needed;
1297 /* Appends character CH to ST. */
1299 ds_put_char (struct string *st, int ch)
1301 ds_put_uninit (st, 1)[0] = ch;
1304 /* Appends CNT copies of character CH to ST. */
1306 ds_put_char_multiple (struct string *st, int ch, size_t cnt)
1308 memset (ds_put_uninit (st, cnt), ch, cnt);