Coverage Report

Created: 2025-04-22 06:17

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