1 /* string-util.c - Extra or enhanced routines for null terminated strings.
3 * Copyright (c) 2012 Jani Nikula
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU 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, see https://www.gnu.org/licenses/ .
18 * Author: Jani Nikula <jani@nikula.org>
22 #include "string-util.h"
30 strtok_len (char *s, const char *delim, size_t *len)
32 /* skip initial delims */
33 s += strspn (s, delim);
36 *len = strcspn (s, delim);
38 return *len ? s : NULL;
42 strsplit_len (const char *s, char delim, size_t *len)
44 bool escaping = false;
45 size_t count = 0, last_nonspace = 0;
47 /* Skip initial unescaped delimiters and whitespace */
48 while (*s && (*s == delim || isspace (*s)))
51 while (s[count] && (escaping || s[count] != delim)) {
52 if (! isspace (s[count]))
53 last_nonspace = count;
54 escaping = (s[count] == '\\');
61 *len = last_nonspace + 1;
66 strtok_len_c (const char *s, const char *delim, size_t *len)
68 /* strtok_len is already const-safe, but we can't express both
69 * versions in the C type system. */
70 return strtok_len ((char *) s, delim, len);
74 sanitize_string (const void *ctx, const char *str)
81 out = talloc_strdup (ctx, str);
85 for (loop = out; *loop; loop++) {
86 if (*loop == '\t' || *loop == '\n')
88 else if ((unsigned char) (*loop) < 32)
96 is_unquoted_terminator (unsigned char c)
98 return c == 0 || c <= ' ' || c == ')';
102 make_boolean_term (void *ctx, const char *prefix, const char *term,
103 char **buf, size_t *len)
108 int need_quoting = 0;
110 /* Do we need quoting? To be paranoid, we quote anything
111 * containing a quote or '(', even though these only matter at the
112 * beginning, and anything containing non-ASCII text. */
115 for (in = term; *in && ! need_quoting; in++)
116 if (is_unquoted_terminator (*in) || *in == '"' || *in == '('
117 || (unsigned char) *in > 127)
121 for (in = term; *in; in++)
122 needed += (*in == '"') ? 2 : 1;
124 needed = strlen (term) + 1;
126 /* Reserve space for the prefix */
128 needed += strlen (prefix) + 1;
130 if ((*buf == NULL) || (needed > *len)) {
132 *buf = talloc_realloc (ctx, *buf, char, *len);
142 /* Copy in the prefix */
144 strcpy (out, prefix);
145 out += strlen (prefix);
149 if (! need_quoting) {
154 /* Quote term by enclosing it in double quotes and doubling any
155 * internal double quotes. */
170 skip_space (const char *str)
172 while (*str && isspace ((unsigned char) *str))
178 parse_boolean_term (void *ctx, const char *str,
179 char **prefix_out, char **term_out)
183 *prefix_out = *term_out = NULL;
186 str = skip_space (str);
187 const char *pos = strchr (str, ':');
189 if (! pos || pos == str)
191 *prefix_out = talloc_strndup (ctx, str, pos - str);
198 /* Implement de-quoting compatible with make_boolean_term. */
200 char *out = talloc_array (ctx, char, strlen (pos));
207 /* Skip the opening quote, find the closing quote, and
208 * un-double doubled internal quotes. */
209 for (++pos; *pos; ) {
213 /* Found the closing quote. */
215 pos = skip_space (pos);
221 /* Did the term terminate without a closing quote or is there
222 * trailing text after the closing quote? */
223 if (! closed || *pos)
227 const char *start = pos;
228 /* Check for text after the boolean term. */
229 while (! is_unquoted_terminator (*pos))
231 if (*skip_space (pos)) {
235 /* No trailing text; dup the string so the caller can free
237 *term_out = talloc_strndup (ctx, start, pos - start);
246 talloc_free (*prefix_out);
247 talloc_free (*term_out);
253 strcmp_null (const char *s1, const char *s2)
256 return strcmp (s1, s2);
257 else if (! s1 && ! s2)
260 return 1; /* s1 (non-NULL) is greater than s2 (NULL) */
262 return -1; /* s1 (NULL) is less than s2 (non-NULL) */
266 strcase_equal (const void *a, const void *b)
268 return strcasecmp (a, b) == 0;
272 strcase_hash (const void *ptr)
276 /* This is the djb2 hash. */
277 unsigned int hash = 5381;
280 hash = ((hash << 5) + hash) + tolower (*s);
288 strip_trailing (char *str, char ch)
292 for (i = strlen (str) - 1; i >= 0; i--) {