NeoMutt  2025-01-09-117-gace867
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
number.c
Go to the documentation of this file.
1
36#include "config.h"
37#include <limits.h>
38#include <stdbool.h>
39#include <stddef.h>
40#include <stdint.h>
41#include "mutt/lib.h"
42#include "number.h"
43#include "set.h"
44#include "subset.h"
45#include "types.h"
46
47#define TOGGLE_BIT ((SHRT_MAX + 1) << 1)
51static intptr_t native_get(void *var)
52{
53 // take care of endianess and always read intptr_t value
54 intptr_t v = *(intptr_t *) var;
55 return (v & TOGGLE_BIT) ? 0 : (short) v;
56}
57
61static void native_set(void *var, intptr_t val)
62{
63 // cast to unsigned short to clear any pending toggle status bits
64 val = (unsigned short) val;
65 *(intptr_t *) var = val;
66}
67
71static void native_toggle(void *var)
72{
73 *(intptr_t *) var = *(uintptr_t *) var ^ TOGGLE_BIT;
74}
75
79static int number_string_set(void *var, struct ConfigDef *cdef,
80 const char *value, struct Buffer *err)
81{
82 int num = 0;
83 if (value && *value && !mutt_str_atoi_full(value, &num))
84 {
85 buf_printf(err, _("Invalid number: %s"), value);
87 }
88
89 if ((num < SHRT_MIN) || (num > SHRT_MAX))
90 {
91 buf_printf(err, _("Number is too big: %s"), value);
93 }
94
95 if ((num < 0) && (cdef->type & D_INTEGER_NOT_NEGATIVE))
96 {
97 buf_printf(err, _("Option %s may not be negative"), cdef->name);
99 }
100
101 if (var)
102 {
103 if (num == native_get(var))
105
106 if (cdef->validator)
107 {
108 int rc = cdef->validator(cdef, (intptr_t) num, err);
109
110 if (CSR_RESULT(rc) != CSR_SUCCESS)
111 return rc | CSR_INV_VALIDATOR;
112 }
113
114 if (startup_only(cdef, err))
116
117 native_set(var, num);
118 }
119 else
120 {
121 cdef->initial = num;
122 }
123
124 return CSR_SUCCESS;
125}
126
130static int number_string_get(void *var, const struct ConfigDef *cdef, struct Buffer *result)
131{
132 int value;
133
134 if (var)
135 value = native_get(var);
136 else
137 value = (int) cdef->initial;
138
139 buf_printf(result, "%d", value);
140 return CSR_SUCCESS;
141}
142
146static int number_native_set(void *var, const struct ConfigDef *cdef,
147 intptr_t value, struct Buffer *err)
148{
149 if ((value < SHRT_MIN) || (value > SHRT_MAX))
150 {
151 buf_printf(err, _("Invalid number: %ld"), (long) value);
153 }
154
155 if ((value < 0) && (cdef->type & D_INTEGER_NOT_NEGATIVE))
156 {
157 buf_printf(err, _("Option %s may not be negative"), cdef->name);
159 }
160
161 if (value == native_get(var))
163
164 if (cdef->validator)
165 {
166 int rc = cdef->validator(cdef, value, err);
167
168 if (CSR_RESULT(rc) != CSR_SUCCESS)
169 return rc | CSR_INV_VALIDATOR;
170 }
171
172 if (startup_only(cdef, err))
174
175 native_set(var, value);
176 return CSR_SUCCESS;
177}
178
182static intptr_t number_native_get(void *var, const struct ConfigDef *cdef, struct Buffer *err)
183{
184 return native_get(var);
185}
186
190static int number_string_plus_equals(void *var, const struct ConfigDef *cdef,
191 const char *value, struct Buffer *err)
192{
193 int num = 0;
194 if (!mutt_str_atoi_full(value, &num))
195 {
196 buf_printf(err, _("Invalid number: %s"), NONULL(value));
198 }
199
200 int result = number_native_get(var, NULL, NULL) + num;
201 if ((result < SHRT_MIN) || (result > SHRT_MAX))
202 {
203 buf_printf(err, _("Number is too big: %s"), value);
205 }
206
207 if ((result < 0) && (cdef->type & D_INTEGER_NOT_NEGATIVE))
208 {
209 buf_printf(err, _("Option %s may not be negative"), cdef->name);
211 }
212
213 if (cdef->validator)
214 {
215 int rc = cdef->validator(cdef, (intptr_t) result, err);
216
217 if (CSR_RESULT(rc) != CSR_SUCCESS)
218 return rc | CSR_INV_VALIDATOR;
219 }
220
221 if (startup_only(cdef, err))
223
224 native_set(var, result);
225 return CSR_SUCCESS;
226}
227
231static int number_string_minus_equals(void *var, const struct ConfigDef *cdef,
232 const char *value, struct Buffer *err)
233{
234 int num = 0;
235 if (!mutt_str_atoi(value, &num))
236 {
237 buf_printf(err, _("Invalid number: %s"), NONULL(value));
239 }
240
241 int result = native_get(var) - num;
242 if ((result < SHRT_MIN) || (result > SHRT_MAX))
243 {
244 buf_printf(err, _("Number is too big: %s"), value);
246 }
247
248 if ((result < 0) && (cdef->type & D_INTEGER_NOT_NEGATIVE))
249 {
250 buf_printf(err, _("Option %s may not be negative"), cdef->name);
252 }
253
254 if (cdef->validator)
255 {
256 int rc = cdef->validator(cdef, (intptr_t) result, err);
257
258 if (CSR_RESULT(rc) != CSR_SUCCESS)
259 return rc | CSR_INV_VALIDATOR;
260 }
261
262 if (startup_only(cdef, err))
264
265 native_set(var, result);
266 return CSR_SUCCESS;
267}
268
272static bool number_has_been_set(void *var, const struct ConfigDef *cdef)
273{
274 return (cdef->initial != native_get(var));
275}
276
280static int number_reset(void *var, const struct ConfigDef *cdef, struct Buffer *err)
281{
282 if (cdef->initial == native_get(var))
284
285 if (cdef->validator)
286 {
287 int rc = cdef->validator(cdef, cdef->initial, err);
288
289 if (CSR_RESULT(rc) != CSR_SUCCESS)
290 return rc | CSR_INV_VALIDATOR;
291 }
292
293 if (startup_only(cdef, err))
295
296 native_set(var, cdef->initial);
297 return CSR_SUCCESS;
298}
299
307int number_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
308{
309 if (!sub || !he || !he->data)
310 return CSR_ERR_CODE;
311
312 struct HashElem *he_base = cs_get_base(he);
313 if (CONFIG_TYPE(he_base->type) != DT_NUMBER)
314 return CSR_ERR_CODE;
315
316 struct ConfigDef *cdef = he_base->data;
317 native_toggle(&cdef->var);
318
320
321 return CSR_SUCCESS;
322}
323
327const struct ConfigSetType CstNumber = {
328 DT_NUMBER,
329 "number",
338 NULL, // destroy
339};
const char * mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: atoi.c:192
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
struct HashElem * cs_get_base(struct HashElem *he)
Find the root Config Item.
Definition: set.c:160
static bool startup_only(const struct ConfigDef *cdef, struct Buffer *err)
Validator function for D_ON_STARTUP.
Definition: set.h:293
#define CSR_ERR_INVALID
Value hasn't been set.
Definition: set.h:36
#define CSR_INV_TYPE
Value is not valid for the type.
Definition: set.h:45
#define CSR_INV_VALIDATOR
Value was rejected by the validator.
Definition: set.h:46
#define CSR_SUC_NO_CHANGE
The value hasn't changed.
Definition: set.h:42
#define CSR_ERR_CODE
Problem with the code.
Definition: set.h:34
#define CSR_RESULT(x)
Definition: set.h:50
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:33
static bool number_has_been_set(void *var, const struct ConfigDef *cdef)
Is the config value different to its initial value? - Implements ConfigSetType::has_been_set() -.
Definition: number.c:272
static intptr_t number_native_get(void *var, const struct ConfigDef *cdef, struct Buffer *err)
Get an int from a Number config item - Implements ConfigSetType::native_get() -.
Definition: number.c:182
static int number_native_set(void *var, const struct ConfigDef *cdef, intptr_t value, struct Buffer *err)
Set a Number config item by int - Implements ConfigSetType::native_set() -.
Definition: number.c:146
static int number_reset(void *var, const struct ConfigDef *cdef, struct Buffer *err)
Reset a Number to its initial value - Implements ConfigSetType::reset() -.
Definition: number.c:280
static int number_string_get(void *var, const struct ConfigDef *cdef, struct Buffer *result)
Get a Number as a string - Implements ConfigSetType::string_get() -.
Definition: number.c:130
static int number_string_minus_equals(void *var, const struct ConfigDef *cdef, const char *value, struct Buffer *err)
Subtract from a Number by string - Implements ConfigSetType::string_minus_equals() -.
Definition: number.c:231
static int number_string_plus_equals(void *var, const struct ConfigDef *cdef, const char *value, struct Buffer *err)
Add to a Number by string - Implements ConfigSetType::string_plus_equals() -.
Definition: number.c:190
static int number_string_set(void *var, struct ConfigDef *cdef, const char *value, struct Buffer *err)
Set a Number by string - Implements ConfigSetType::string_set() -.
Definition: number.c:79
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
static void native_set(void *var, intptr_t val)
Set an int into a Number config item.
Definition: number.c:61
const struct ConfigSetType CstNumber
Config type representing a number.
Definition: number.c:327
#define TOGGLE_BIT
Definition: number.c:47
static void native_toggle(void *var)
Toggle a Number config item.
Definition: number.c:71
static intptr_t native_get(void *var)
Get an int from a Number config item.
Definition: number.c:51
int number_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Toggle the value of a number (value <-> 0)
Definition: number.c:307
Type representing a number.
Parse the 'set' command.
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:36
Definition: set.h:62
const char * name
User-visible name.
Definition: set.h:63
intptr_t var
Storage for the variable.
Definition: set.h:82
int(* validator)(const struct ConfigDef *cdef, intptr_t value, struct Buffer *err)
Definition: set.h:79
intptr_t initial
Initial value.
Definition: set.h:65
uint32_t type
Variable type, e.g. DT_STRING.
Definition: set.h:64
A set of inherited config items.
Definition: subset.h:46
The item stored in a Hash Table.
Definition: hash.h:44
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition: hash.h:45
void * data
User-supplied data.
Definition: hash.h:47
void cs_subset_notify_observers(const struct ConfigSubset *sub, struct HashElem *he, enum NotifyConfig ev)
Notify all observers of an event.
Definition: subset.c:239
Subset of Config Items.
@ NT_CONFIG_SET
Config item has been set.
Definition: subset.h:61
Constants for all the config types.
#define CONFIG_TYPE(t)
Definition: types.h:49
@ DT_NUMBER
a number
Definition: types.h:38
#define D_INTEGER_NOT_NEGATIVE
Negative numbers are not allowed.
Definition: types.h:100