]> git.notmuchmail.org Git - notmuch/blob - util/string-util.c
util: Factor out boolean term quoting routine
[notmuch] / util / string-util.c
1 /* string-util.c -  Extra or enhanced routines for null terminated strings.
2  *
3  * Copyright (c) 2012 Jani Nikula
4  *
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.
9  *
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.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see http://www.gnu.org/licenses/ .
17  *
18  * Author: Jani Nikula <jani@nikula.org>
19  */
20
21
22 #include "string-util.h"
23 #include "talloc.h"
24
25 #include <errno.h>
26
27 char *
28 strtok_len (char *s, const char *delim, size_t *len)
29 {
30     /* skip initial delims */
31     s += strspn (s, delim);
32
33     /* length of token */
34     *len = strcspn (s, delim);
35
36     return *len ? s : NULL;
37 }
38
39 static int
40 is_unquoted_terminator (unsigned char c)
41 {
42     return c == 0 || c <= ' ' || c == ')';
43 }
44
45 int
46 make_boolean_term (void *ctx, const char *prefix, const char *term,
47                    char **buf, size_t *len)
48 {
49     const char *in;
50     char *out;
51     size_t needed = 3;
52     int need_quoting = 0;
53
54     /* Do we need quoting?  To be paranoid, we quote anything
55      * containing a quote, even though it only matters at the
56      * beginning, and anything containing non-ASCII text. */
57     for (in = term; *in && !need_quoting; in++)
58         if (is_unquoted_terminator (*in) || *in == '"'
59             || (unsigned char)*in > 127)
60             need_quoting = 1;
61
62     if (need_quoting)
63         for (in = term; *in; in++)
64             needed += (*in == '"') ? 2 : 1;
65     else
66         needed = strlen (term) + 1;
67
68     /* Reserve space for the prefix */
69     if (prefix)
70         needed += strlen (prefix) + 1;
71
72     if ((*buf == NULL) || (needed > *len)) {
73         *len = 2 * needed;
74         *buf = talloc_realloc (ctx, *buf, char, *len);
75     }
76
77     if (! *buf) {
78         errno = ENOMEM;
79         return -1;
80     }
81
82     out = *buf;
83
84     /* Copy in the prefix */
85     if (prefix) {
86         strcpy (out, prefix);
87         out += strlen (prefix);
88         *out++ = ':';
89     }
90
91     if (! need_quoting) {
92         strcpy (out, term);
93         return 0;
94     }
95
96     /* Quote term by enclosing it in double quotes and doubling any
97      * internal double quotes. */
98     *out++ = '"';
99     in = term;
100     while (*in) {
101         if (*in == '"')
102             *out++ = '"';
103         *out++ = *in++;
104     }
105     *out++ = '"';
106     *out = '\0';
107
108     return 0;
109 }