NeoMutt  2024-11-14-34-g5aaf0d
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 <stddef.h>
39#include <stdint.h>
40#include "mutt/lib.h"
41#include "number.h"
42#include "set.h"
43#include "subset.h"
44#include "types.h"
45
46#define TOGGLE_BIT ((SHRT_MAX + 1) << 1)
50static intptr_t native_get(void *var)
51{
52 return (*(intptr_t *) var & TOGGLE_BIT) ? 0 : *(short *) var;
53}
54
58static void native_set(void *var, intptr_t val)
59{
60 *(intptr_t *) var = 0; // clear any pending toggle status
61 *(short *) var = val;
62}
63
67static void native_toggle(void *var)
68{
69 *(intptr_t *) var = *(uintptr_t *) var ^ TOGGLE_BIT;
70}
71
75static int number_string_set(const struct ConfigSet *cs, void *var, struct ConfigDef *cdef,
76 const char *value, struct Buffer *err)
77{
78 int num = 0;
79 if (value && *value && !mutt_str_atoi_full(value, &num))
80 {
81 buf_printf(err, _("Invalid number: %s"), value);
83 }
84
85 if ((num < SHRT_MIN) || (num > SHRT_MAX))
86 {
87 buf_printf(err, _("Number is too big: %s"), value);
89 }
90
91 if ((num < 0) && (cdef->type & D_INTEGER_NOT_NEGATIVE))
92 {
93 buf_printf(err, _("Option %s may not be negative"), cdef->name);
95 }
96
97 if (var)
98 {
99 if (num == native_get(var))
101
102 if (cdef->validator)
103 {
104 int rc = cdef->validator(cs, cdef, (intptr_t) num, err);
105
106 if (CSR_RESULT(rc) != CSR_SUCCESS)
107 return rc | CSR_INV_VALIDATOR;
108 }
109
110 if (startup_only(cdef, err))
112
113 native_set(var, num);
114 }
115 else
116 {
117 cdef->initial = num;
118 }
119
120 return CSR_SUCCESS;
121}
122
126static int number_string_get(const struct ConfigSet *cs, void *var,
127 const struct ConfigDef *cdef, struct Buffer *result)
128{
129 int value;
130
131 if (var)
132 value = native_get(var);
133 else
134 value = (int) cdef->initial;
135
136 buf_printf(result, "%d", value);
137 return CSR_SUCCESS;
138}
139
143static int number_native_set(const struct ConfigSet *cs, void *var,
144 const struct ConfigDef *cdef, intptr_t value,
145 struct Buffer *err)
146{
147 if ((value < SHRT_MIN) || (value > SHRT_MAX))
148 {
149 buf_printf(err, _("Invalid number: %ld"), (long) value);
151 }
152
153 if ((value < 0) && (cdef->type & D_INTEGER_NOT_NEGATIVE))
154 {
155 buf_printf(err, _("Option %s may not be negative"), cdef->name);
157 }
158
159 if (value == native_get(var))
161
162 if (cdef->validator)
163 {
164 int rc = cdef->validator(cs, cdef, value, err);
165
166 if (CSR_RESULT(rc) != CSR_SUCCESS)
167 return rc | CSR_INV_VALIDATOR;
168 }
169
170 if (startup_only(cdef, err))
172
173 native_set(var, value);
174 return CSR_SUCCESS;
175}
176
180static intptr_t number_native_get(const struct ConfigSet *cs, void *var,
181 const struct ConfigDef *cdef, struct Buffer *err)
182{
183 return native_get(var);
184}
185
189static int number_string_plus_equals(const struct ConfigSet *cs, void *var,
190 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(NULL, 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(cs, 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(const struct ConfigSet *cs, void *var,
232 const struct ConfigDef *cdef,
233 const char *value, struct Buffer *err)
234{
235 int num = 0;
236 if (!mutt_str_atoi(value, &num))
237 {
238 buf_printf(err, _("Invalid number: %s"), NONULL(value));
240 }
241
242 int result = native_get(var) - num;
243 if ((result < SHRT_MIN) || (result > SHRT_MAX))
244 {
245 buf_printf(err, _("Number is too big: %s"), value);
247 }
248
249 if ((result < 0) && (cdef->type & D_INTEGER_NOT_NEGATIVE))
250 {
251 buf_printf(err, _("Option %s may not be negative"), cdef->name);
253 }
254
255 if (cdef->validator)
256 {
257 int rc = cdef->validator(cs, cdef, (intptr_t) result, err);
258
259 if (CSR_RESULT(rc) != CSR_SUCCESS)
260 return rc | CSR_INV_VALIDATOR;
261 }
262
263 if (startup_only(cdef, err))
265
266 native_set(var, result);
267 return CSR_SUCCESS;
268}
269
273static int number_reset(const struct ConfigSet *cs, void *var,
274 const struct ConfigDef *cdef, struct Buffer *err)
275{
276 if (cdef->initial == native_get(var))
278
279 if (cdef->validator)
280 {
281 int rc = cdef->validator(cs, cdef, cdef->initial, err);
282
283 if (CSR_RESULT(rc) != CSR_SUCCESS)
284 return rc | CSR_INV_VALIDATOR;
285 }
286
287 if (startup_only(cdef, err))
289
290 native_set(var, cdef->initial);
291 return CSR_SUCCESS;
292}
293
301int number_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
302{
303 if (!sub || !he || !he->data)
304 return CSR_ERR_CODE;
305
306 struct HashElem *he_base = cs_get_base(he);
307 if (DTYPE(he_base->type) != DT_NUMBER)
308 return CSR_ERR_CODE;
309
310 struct ConfigDef *cdef = he_base->data;
311 native_toggle(&cdef->var);
312
314
315 return CSR_SUCCESS;
316}
317
321const struct ConfigSetType CstNumber = {
322 DT_NUMBER,
323 "number",
331 NULL, // destroy
332};
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:296
#define CSR_ERR_INVALID
Value hasn't been set.
Definition: set.h:38
#define CSR_INV_TYPE
Value is not valid for the type.
Definition: set.h:47
#define CSR_INV_VALIDATOR
Value was rejected by the validator.
Definition: set.h:48
#define CSR_SUC_NO_CHANGE
The value hasn't changed.
Definition: set.h:44
#define CSR_ERR_CODE
Problem with the code.
Definition: set.h:36
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
static intptr_t number_native_get(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, struct Buffer *err)
Get an int from a Number config item - Implements ConfigSetType::native_get() -.
Definition: number.c:180
static int number_native_set(const struct ConfigSet *cs, 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:143
static int number_reset(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, struct Buffer *err)
Reset a Number to its initial value - Implements ConfigSetType::reset() -.
Definition: number.c:273
static int number_string_get(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, struct Buffer *result)
Get a Number as a string - Implements ConfigSetType::string_get() -.
Definition: number.c:126
static int number_string_minus_equals(const struct ConfigSet *cs, 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(const struct ConfigSet *cs, 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:189
static int number_string_set(const struct ConfigSet *cs, void *var, struct ConfigDef *cdef, const char *value, struct Buffer *err)
Set a Number by string - Implements ConfigSetType::string_set() -.
Definition: number.c:75
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:58
const struct ConfigSetType CstNumber
Config type representing a number.
Definition: number.c:321
#define TOGGLE_BIT
Definition: number.c:46
static void native_toggle(void *var)
Toggle a Number config item.
Definition: number.c:67
static intptr_t native_get(void *var)
Get an int from a Number config item.
Definition: number.c:50
int number_he_toggle(struct ConfigSubset *sub, struct HashElem *he, struct Buffer *err)
Toggle the value of a number (value <-> 0)
Definition: number.c:301
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:64
const char * name
User-visible name.
Definition: set.h:65
intptr_t var
Storage for the variable.
Definition: set.h:85
int(* validator)(const struct ConfigSet *cs, const struct ConfigDef *cdef, intptr_t value, struct Buffer *err)
Definition: set.h:82
intptr_t initial
Initial value.
Definition: set.h:67
uint32_t type
Variable type, e.g. DT_STRING.
Definition: set.h:66
Container for lots of config items.
Definition: set.h:252
A set of inherited config items.
Definition: subset.h:47
The item stored in a Hash Table.
Definition: hash.h:43
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition: hash.h:44
void * data
User-supplied data.
Definition: hash.h:46
void cs_subset_notify_observers(const struct ConfigSubset *sub, struct HashElem *he, enum NotifyConfig ev)
Notify all observers of an event.
Definition: subset.c:237
Subset of Config Items.
@ NT_CONFIG_SET
Config item has been set.
Definition: subset.h:62
Constants for all the config types.
#define DTYPE(t)
Definition: types.h:50
@ DT_NUMBER
a number
Definition: types.h:39
#define D_INTEGER_NOT_NEGATIVE
Negative numbers are not allowed.
Definition: types.h:101