Coverage Report

Created: 2023-06-07 06:15

/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
};