1 /**
2  * @file
3  * A collection of config items
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 #ifndef MUTT_CONFIG_SET_H
24 #define MUTT_CONFIG_SET_H
25 
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 
30 struct Buffer;
31 struct ConfigSet;
32 struct HashElem;
33 
34 /* Config Set Results */
35 #define CSR_SUCCESS       0 ///< Action completed successfully
36 #define CSR_ERR_CODE      1 ///< Problem with the code
37 #define CSR_ERR_UNKNOWN   2 ///< Unrecognised config item
38 #define CSR_ERR_INVALID   3 ///< Value hasn't been set
39 
40 /* Flags for CSR_SUCCESS */
41 #define CSR_SUC_INHERITED (1 << 4) ///< Value is inherited
42 #define CSR_SUC_EMPTY     (1 << 5) ///< Value is empty/unset
43 #define CSR_SUC_WARNING   (1 << 6) ///< Notify the user of a warning
44 #define CSR_SUC_NO_CHANGE (1 << 7) ///< The value hasn't changed
45 
46 /* Flags for CSR_INVALID */
47 #define CSR_INV_TYPE      (1 << 4) ///< Value is not valid for the type
48 #define CSR_INV_VALIDATOR (1 << 5) ///< Value was rejected by the validator
49 #define CSV_INV_NOT_IMPL  (1 << 6) ///< Operation not permitted for the type
50 
51 #define CSR_RESULT_MASK 0x0F
52 #define CSR_RESULT(x) ((x) & CSR_RESULT_MASK)
53 
54 #define IP (intptr_t)
55 
56 /**
57  * @defgroup cfg_def_api Config Definition API
58  *
59  * Config item definition
60  *
61  * Every config variable that NeoMutt supports is backed by a ConfigDef.
62  */
63 struct ConfigDef
64 {
65   const char   *name;      ///< User-visible name
66   uint32_t      type;      ///< Variable type, e.g. #DT_STRING
67   intptr_t      initial;   ///< Initial value
68   intptr_t      data;      ///< Extra variable data
69 
70   /**
71    * @defgroup cfg_def_validator validator()
72    * @ingroup cfg_def_api
73    *
74    * validator - Validate a config variable
75    * @param cs    Config items
76    * @param cdef  Config definition
77    * @param value Native value
78    * @param err   Message for the user
79    * @retval #CSR_SUCCESS     Success
80    * @retval #CSR_ERR_INVALID Failure
81    */
82   int (*validator)(const struct ConfigSet *cs, const struct ConfigDef *cdef, intptr_t value, struct Buffer *err);
83 
84   const char *docs; ///< One-liner description
85   intptr_t    var;  ///< Storage for the variable
86 };
87 
88 /**
89  * @defgroup cfg_type_api Config Type API
90  *
91  * Type definition for a config item
92  *
93  * Each config item has a type which is defined by a set of callback functions.
94  */
95 struct ConfigSetType
96 {
97   int type;                  ///< Data type, e.g. #DT_STRING
98   const char *name;          ///< Name of the type, e.g. "String"
99 
100   /**
101    * @defgroup cfg_type_string_set string_set()
102    * @ingroup cfg_type_api
103    *
104    * string_set - Set a config item by string
105    * @param cs    Config items
106    * @param var   Variable to set (may be NULL)
107    * @param cdef  Variable definition
108    * @param value Value to set (may be NULL)
109    * @param err   Buffer for error messages (may be NULL)
110    * @retval num Result, e.g. #CSR_SUCCESS
111    *
112    * If var is NULL, then the config item's initial value will be set.
113    *
114    * **Contract**
115    * - @a cs   is not NULL
116    * - @a cdef is not NULL
117    */
118   int (*string_set)(const struct ConfigSet *cs, void *var, struct ConfigDef *cdef, const char *value, struct Buffer *err);
119 
120   /**
121    * @defgroup cfg_type_string_get string_get()
122    * @ingroup cfg_type_api
123    *
124    * string_get - Get a config item as a string
125    * @param cs     Config items
126    * @param var    Variable to get (may be NULL)
127    * @param cdef   Variable definition
128    * @param result Buffer for results or error messages
129    * @retval num Result, e.g. #CSR_SUCCESS
130    *
131    * If var is NULL, then the config item's initial value will be returned.
132    *
133    * **Contract**
134    * - @a cs     is not NULL
135    * - @a cdef   is not NULL
136    * - @a result is not NULL
137    */
138   int (*string_get)(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, struct Buffer *result);
139 
140   /**
141    * @defgroup cfg_type_native_set native_set()
142    * @ingroup cfg_type_api
143    *
144    * native_set - Set a config item by string
145    * @param cs    Config items
146    * @param var   Variable to set
147    * @param cdef  Variable definition
148    * @param value Native pointer/value to set
149    * @param err   Buffer for error messages (may be NULL)
150    * @retval num Result, e.g. #CSR_SUCCESS
151    *
152    * **Contract**
153    * - @a cs   is not NULL
154    * - @a var  is not NULL
155    * - @a cdef is not NULL
156    */
157   int (*native_set)(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, intptr_t value, struct Buffer *err);
158 
159   /**
160    * @defgroup cfg_type_native_get native_get()
161    * @ingroup cfg_type_api
162    *
163    * native_get - Get a string from a config item
164    * @param cs   Config items
165    * @param var  Variable to get
166    * @param cdef Variable definition
167    * @param err  Buffer for error messages (may be NULL)
168    * @retval intptr_t Config item string
169    * @retval INT_MIN  Error
170    *
171    * **Contract**
172    * - @a cs   is not NULL
173    * - @a var  is not NULL
174    * - @a cdef is not NULL
175    */
176   intptr_t (*native_get)(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, struct Buffer *err);
177 
178   /**
179    * @defgroup cfg_type_string_plus_equals string_plus_equals()
180    * @ingroup cfg_type_api
181    *
182    * string_plus_equals - Add to a config item by string
183    * @param cs    Config items
184    * @param var   Variable to set
185    * @param cdef  Variable definition
186    * @param value Value to set
187    * @param err   Buffer for error messages (may be NULL)
188    * @retval num Result, e.g. #CSR_SUCCESS
189    *
190    * **Contract**
191    * - @a cs   is not NULL
192    * - @a var  is not NULL
193    * - @a cdef is not NULL
194    */
195   int (*string_plus_equals)(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, const char *value, struct Buffer *err);
196 
197   /**
198    * @defgroup cfg_type_string_minus_equals string_minus_equals()
199    * @ingroup cfg_type_api
200    *
201    * string_minus_equals - Remove from a config item as a string
202    * @param cs    Config items
203    * @param var   Variable to set
204    * @param cdef  Variable definition
205    * @param value Value to set
206    * @param err   Buffer for error messages (may be NULL)
207    * @retval num Result, e.g. #CSR_SUCCESS
208    *
209    * **Contract**
210    * - @a cs   is not NULL
211    * - @a var  is not NULL
212    * - @a cdef is not NULL
213    */
214   int (*string_minus_equals)(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, const char *value, struct Buffer *err);
215 
216   /**
217    * @defgroup cfg_type_reset reset()
218    * @ingroup cfg_type_api
219    *
220    * reset - Reset a config item to its initial value
221    * @param cs   Config items
222    * @param var  Variable to reset
223    * @param cdef Variable definition
224    * @param err  Buffer for error messages (may be NULL)
225    * @retval num Result, e.g. #CSR_SUCCESS
226    *
227    * **Contract**
228    * - @a cs   is not NULL
229    * - @a var  is not NULL
230    * - @a cdef is not NULL
231    */
232   int (*reset)(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef, struct Buffer *err);
233 
234   /**
235    * @defgroup cfg_type_destroy destroy()
236    * @ingroup cfg_type_api
237    *
238    * destroy - Destroy a config item
239    * @param cs   Config items
240    * @param var  Variable to destroy
241    * @param cdef Variable definition
242    *
243    * **Contract**
244    * - @a cs   is not NULL
245    * - @a var  is not NULL
246    * - @a cdef is not NULL
247    */
248   void (*destroy)(const struct ConfigSet *cs, void *var, const struct ConfigDef *cdef);
249 };
250 
251 /**
252  * struct ConfigSet - Container for lots of config items
253  *
254  * The config items are stored in a HashTable so that their names can be looked
255  * up efficiently.  Each config item is represented by a HashElem.  Once
256  * created, this HashElem is static and may be used for the lifetime of the
257  * ConfigSet.
258  */
259 struct ConfigSet
260 {
261   struct HashTable *hash;         ///< HashTable storing the config items
262   struct ConfigSetType types[18]; ///< All the defined config types
263 };
264 
265 struct ConfigSet *cs_new(size_t size);
266 void              cs_free(struct ConfigSet **ptr);
267 
268 struct HashElem *           cs_get_base    (struct HashElem *he);
269 struct HashElem *           cs_get_elem    (const struct ConfigSet *cs, const char *name);
270 const struct ConfigSetType *cs_get_type_def(const struct ConfigSet *cs, unsigned int type);
271 
272 bool             cs_register_type     (struct ConfigSet *cs, const struct ConfigSetType *cst);
273 bool             cs_register_variables(const struct ConfigSet *cs, struct ConfigDef vars[], uint32_t flags);
274 struct HashElem *cs_inherit_variable  (const struct ConfigSet *cs, struct HashElem *parent, const char *name);
275 void             cs_uninherit_variable(const struct ConfigSet *cs, const char *name);
276 
277 int      cs_he_initial_get         (const struct ConfigSet *cs, struct HashElem *he,                    struct Buffer *result);
278 int      cs_he_initial_set         (const struct ConfigSet *cs, struct HashElem *he, const char *value, struct Buffer *err);
279 intptr_t cs_he_native_get          (const struct ConfigSet *cs, struct HashElem *he,                    struct Buffer *err);
280 int      cs_he_native_set          (const struct ConfigSet *cs, struct HashElem *he, intptr_t value,    struct Buffer *err);
281 int      cs_he_reset               (const struct ConfigSet *cs, struct HashElem *he,                    struct Buffer *err);
282 int      cs_he_string_get          (const struct ConfigSet *cs, struct HashElem *he,                    struct Buffer *result);
283 int      cs_he_string_minus_equals (const struct ConfigSet *cs, struct HashElem *he, const char *value, struct Buffer *err);
284 int      cs_he_string_plus_equals  (const struct ConfigSet *cs, struct HashElem *he, const char *value, struct Buffer *err);
285 int      cs_he_string_set          (const struct ConfigSet *cs, struct HashElem *he, const char *value, struct Buffer *err);
286 
287 int      cs_str_initial_get        (const struct ConfigSet *cs, const char *name,                       struct Buffer *result);
288 int      cs_str_initial_set        (const struct ConfigSet *cs, const char *name,    const char *value, struct Buffer *err);
289 intptr_t cs_str_native_get         (const struct ConfigSet *cs, const char *name,                       struct Buffer *err);
290 int      cs_str_native_set         (const struct ConfigSet *cs, const char *name,    intptr_t value,    struct Buffer *err);
291 int      cs_str_reset              (const struct ConfigSet *cs, const char *name,                       struct Buffer *err);
292 int      cs_str_string_get         (const struct ConfigSet *cs, const char *name,                       struct Buffer *result);
293 int      cs_str_string_minus_equals(const struct ConfigSet *cs, const char *name,    const char *value, struct Buffer *err);
294 int      cs_str_string_plus_equals (const struct ConfigSet *cs, const char *name,    const char *value, struct Buffer *err);
295 int      cs_str_string_set         (const struct ConfigSet *cs, const char *name,    const char *value, struct Buffer *err);
296 
297 #endif /* MUTT_CONFIG_SET_H */
298