/src/neomutt/config/string.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * @file |
3 | | * Type representing a string |
4 | | * |
5 | | * @authors |
6 | | * Copyright (C) 2017-2018 Richard Russon <rich@flatcap.org> |
7 | | * |
8 | | * @copyright |
9 | | * This program is free software: you can redistribute it and/or modify it under |
10 | | * the terms of the GNU General Public License as published by the Free Software |
11 | | * Foundation, either version 2 of the License, or (at your option) any later |
12 | | * version. |
13 | | * |
14 | | * This program is distributed in the hope that it will be useful, but WITHOUT |
15 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
16 | | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
17 | | * details. |
18 | | * |
19 | | * You should have received a copy of the GNU General Public License along with |
20 | | * this program. If not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | /** |
24 | | * @page config_string Type: String |
25 | | * |
26 | | * Config type representing a string. |
27 | | * |
28 | | * - Backed by `char *` |
29 | | * - Empty string is stored as `NULL` |
30 | | * - Validator is passed `char *`, which may be `NULL` |
31 | | * - Data is freed when `ConfigSet` is freed |
32 | | * - Implementation: #CstString |
33 | | */ |
34 | | |
35 | | #include "config.h" |
36 | | #include <stddef.h> |
37 | | #include <stdint.h> |
38 | | #include "mutt/lib.h" |
39 | | #include "set.h" |
40 | | #include "types.h" |
41 | | |
42 | | /** |
43 | | * string_destroy - Destroy a String - Implements ConfigSetType::destroy() - @ingroup cfg_type_destroy |
44 | | */ |
45 | | static void string_destroy(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef) |
46 | 1.63M | { |
47 | 1.63M | const char **str = (const char **) var; |
48 | 1.63M | if (!*str) |
49 | 1.14M | return; |
50 | | |
51 | 489k | FREE(var); |
52 | 489k | } |
53 | | |
54 | | /** |
55 | | * string_string_set - Set a String by string - Implements ConfigSetType::string_set() - @ingroup cfg_type_string_set |
56 | | */ |
57 | | static int string_string_set(const struct ConfigSet *cs, void *var, struct ConfigDef *cdef, |
58 | | const char *value, struct Buffer *err) |
59 | 0 | { |
60 | | /* Store empty strings as NULL */ |
61 | 0 | if (value && (value[0] == '\0')) |
62 | 0 | value = NULL; |
63 | |
|
64 | 0 | if (!value && (cdef->type & DT_NOT_EMPTY)) |
65 | 0 | { |
66 | 0 | buf_printf(err, _("Option %s may not be empty"), cdef->name); |
67 | 0 | return CSR_ERR_INVALID | CSR_INV_VALIDATOR; |
68 | 0 | } |
69 | | |
70 | 0 | int rc = CSR_SUCCESS; |
71 | |
|
72 | 0 | if (var) |
73 | 0 | { |
74 | 0 | if (mutt_str_equal(value, (*(char **) var))) |
75 | 0 | return CSR_SUCCESS | CSR_SUC_NO_CHANGE; |
76 | | |
77 | 0 | if (cdef->validator) |
78 | 0 | { |
79 | 0 | rc = cdef->validator(cs, cdef, (intptr_t) value, err); |
80 | |
|
81 | 0 | if (CSR_RESULT(rc) != CSR_SUCCESS) |
82 | 0 | return rc | CSR_INV_VALIDATOR; |
83 | 0 | } |
84 | | |
85 | 0 | string_destroy(cs, var, cdef); |
86 | |
|
87 | 0 | const char *str = mutt_str_dup(value); |
88 | 0 | if (!str) |
89 | 0 | rc |= CSR_SUC_EMPTY; |
90 | |
|
91 | 0 | *(const char **) var = str; |
92 | 0 | } |
93 | 0 | else |
94 | 0 | { |
95 | 0 | if (cdef->type & DT_INITIAL_SET) |
96 | 0 | FREE(&cdef->initial); |
97 | |
|
98 | 0 | cdef->type |= DT_INITIAL_SET; |
99 | 0 | cdef->initial = (intptr_t) mutt_str_dup(value); |
100 | 0 | } |
101 | | |
102 | 0 | return rc; |
103 | 0 | } |
104 | | |
105 | | /** |
106 | | * string_string_get - Get a String as a string - Implements ConfigSetType::string_get() - @ingroup cfg_type_string_get |
107 | | */ |
108 | | static int string_string_get(const struct ConfigSet *cs, void *var, |
109 | | const struct ConfigDef *cdef, struct Buffer *result) |
110 | 0 | { |
111 | 0 | const char *str = NULL; |
112 | |
|
113 | 0 | if (var) |
114 | 0 | str = *(const char **) var; |
115 | 0 | else |
116 | 0 | str = (char *) cdef->initial; |
117 | |
|
118 | 0 | if (!str) |
119 | 0 | return CSR_SUCCESS | CSR_SUC_EMPTY; /* empty string */ |
120 | | |
121 | 0 | buf_addstr(result, str); |
122 | 0 | return CSR_SUCCESS; |
123 | 0 | } |
124 | | |
125 | | /** |
126 | | * string_native_set - Set a String config item by string - Implements ConfigSetType::native_set() - @ingroup cfg_type_native_set |
127 | | */ |
128 | | static int string_native_set(const struct ConfigSet *cs, void *var, |
129 | | const struct ConfigDef *cdef, intptr_t value, |
130 | | struct Buffer *err) |
131 | 0 | { |
132 | 0 | const char *str = (const char *) value; |
133 | | |
134 | | /* Store empty strings as NULL */ |
135 | 0 | if (str && (str[0] == '\0')) |
136 | 0 | value = 0; |
137 | |
|
138 | 0 | if ((value == 0) && (cdef->type & DT_NOT_EMPTY)) |
139 | 0 | { |
140 | 0 | buf_printf(err, _("Option %s may not be empty"), cdef->name); |
141 | 0 | return CSR_ERR_INVALID | CSR_INV_VALIDATOR; |
142 | 0 | } |
143 | | |
144 | 0 | if (mutt_str_equal((const char *) value, (*(char **) var))) |
145 | 0 | return CSR_SUCCESS | CSR_SUC_NO_CHANGE; |
146 | | |
147 | 0 | int rc; |
148 | |
|
149 | 0 | if (cdef->validator) |
150 | 0 | { |
151 | 0 | rc = cdef->validator(cs, cdef, value, err); |
152 | |
|
153 | 0 | if (CSR_RESULT(rc) != CSR_SUCCESS) |
154 | 0 | return rc | CSR_INV_VALIDATOR; |
155 | 0 | } |
156 | | |
157 | 0 | string_destroy(cs, var, cdef); |
158 | |
|
159 | 0 | str = mutt_str_dup(str); |
160 | 0 | rc = CSR_SUCCESS; |
161 | 0 | if (!str) |
162 | 0 | rc |= CSR_SUC_EMPTY; |
163 | |
|
164 | 0 | *(const char **) var = str; |
165 | 0 | return rc; |
166 | 0 | } |
167 | | |
168 | | /** |
169 | | * string_native_get - Get a string from a String config item - Implements ConfigSetType::native_get() - @ingroup cfg_type_native_get |
170 | | */ |
171 | | static intptr_t string_native_get(const struct ConfigSet *cs, void *var, |
172 | | const struct ConfigDef *cdef, struct Buffer *err) |
173 | 1 | { |
174 | 1 | const char *str = *(const char **) var; |
175 | | |
176 | 1 | return (intptr_t) str; |
177 | 1 | } |
178 | | |
179 | | /** |
180 | | * string_string_plus_equals - Concat String to a string - Implements ConfigSetType::string_plus_equals() - @ingroup cfg_type_string_plus_equals |
181 | | */ |
182 | | static int string_string_plus_equals(const struct ConfigSet *cs, void *var, |
183 | | const struct ConfigDef *cdef, |
184 | | const char *value, struct Buffer *err) |
185 | 0 | { |
186 | | /* Skip if the value is missing or empty string*/ |
187 | 0 | if (!value || (value[0] == '\0')) |
188 | 0 | return CSR_SUCCESS | CSR_SUC_NO_CHANGE; |
189 | | |
190 | 0 | int rc = CSR_SUCCESS; |
191 | |
|
192 | 0 | char *str = NULL; |
193 | 0 | const char **var_str = (const char **) var; |
194 | |
|
195 | 0 | if (*var_str) |
196 | 0 | mutt_str_asprintf(&str, "%s%s", *var_str, value); |
197 | 0 | else |
198 | 0 | str = mutt_str_dup(value); |
199 | |
|
200 | 0 | if (cdef->validator) |
201 | 0 | { |
202 | 0 | rc = cdef->validator(cs, cdef, (intptr_t) str, err); |
203 | |
|
204 | 0 | if (CSR_RESULT(rc) != CSR_SUCCESS) |
205 | 0 | { |
206 | 0 | FREE(&str); |
207 | 0 | return rc | CSR_INV_VALIDATOR; |
208 | 0 | } |
209 | 0 | } |
210 | | |
211 | 0 | string_destroy(cs, var, cdef); |
212 | 0 | *var_str = str; |
213 | |
|
214 | 0 | return rc; |
215 | 0 | } |
216 | | |
217 | | /** |
218 | | * string_reset - Reset a String to its initial value - Implements ConfigSetType::reset() - @ingroup cfg_type_reset |
219 | | */ |
220 | | static int string_reset(const struct ConfigSet *cs, void *var, |
221 | | const struct ConfigDef *cdef, struct Buffer *err) |
222 | 1.14M | { |
223 | 1.14M | int rc = CSR_SUCCESS; |
224 | | |
225 | 1.14M | const char *str = mutt_str_dup((const char *) cdef->initial); |
226 | 1.14M | if (!str) |
227 | 650k | rc |= CSR_SUC_EMPTY; |
228 | | |
229 | 1.14M | if (mutt_str_equal(str, (*(char **) var))) |
230 | 650k | { |
231 | 650k | FREE(&str); |
232 | 650k | return rc | CSR_SUC_NO_CHANGE; |
233 | 650k | } |
234 | | |
235 | 489k | if (cdef->validator) |
236 | 18.8k | { |
237 | 18.8k | rc = cdef->validator(cs, cdef, cdef->initial, err); |
238 | | |
239 | 18.8k | if (CSR_RESULT(rc) != CSR_SUCCESS) |
240 | 0 | { |
241 | 0 | FREE(&str); |
242 | 0 | return rc | CSR_INV_VALIDATOR; |
243 | 0 | } |
244 | 18.8k | } |
245 | | |
246 | 489k | string_destroy(cs, var, cdef); |
247 | | |
248 | 489k | if (!str) |
249 | 0 | rc |= CSR_SUC_EMPTY; |
250 | | |
251 | 489k | *(const char **) var = str; |
252 | 489k | return rc; |
253 | 489k | } |
254 | | |
255 | | /** |
256 | | * CstString - Config type representing a string |
257 | | */ |
258 | | const struct ConfigSetType CstString = { |
259 | | DT_STRING, |
260 | | "string", |
261 | | string_string_set, |
262 | | string_string_get, |
263 | | string_native_set, |
264 | | string_native_get, |
265 | | string_string_plus_equals, |
266 | | NULL, // string_minus_equals |
267 | | string_reset, |
268 | | string_destroy, |
269 | | }; |