Mstdlib-1.24.0
m_settings.h
1/* The MIT License (MIT)
2 *
3 * Copyright (c) 2015 Monetra Technologies, LLC.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#ifndef __M_SETTINGS_H__
25#define __M_SETTINGS_H__
26
27/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
28
29#include <mstdlib/base/m_defs.h>
30#include <mstdlib/base/m_types.h>
31#include <mstdlib/base/m_hash_dict.h>
32#include <mstdlib/base/m_list_str.h>
33
34/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
35
36__BEGIN_DECLS
37
38/*! \addtogroup m_settings Settings
39 * \ingroup m_formats
40 *
41 * Platform independent settings storage and retrieval.
42 *
43 * Settings a are a series of string based key, value pairs. The settings themselves
44 * are stored/represented by a M_hash_dict_t. The M_settings_t object handles storing
45 * and retrieving the M_hash_dict_t data.
46 *
47 * Multi-Value M_hash_dict_t's are not currently supported.
48 *
49 * M_settings_t only handles the storage aspect of settings. It handles determining
50 * the OS specific location and format for settings. Though the location and format
51 * can be overridden.
52 *
53 * Settings can be stored in groups by using the '/' character to separate groups,
54 * sub groups, and keys.
55 * E.g.: group1/group2/key=value
56 *
57 * Limitation of using the Registry for Windows users:
58 * - Key names (includes the full path) cannot exceed 255 characters.
59 * - Values cannot exceed 16,383 characters.
60 * - It's recommended not to use the registry to store values exceeding 2,048 characters.
61 * Instead a file (such as INI) should be used.
62 * - Only 512 sub groups (full path) are supported.
63 * - Only 32 sub groups can be created at one given time using M_settings. Meaning you shouldn't
64 * use more than approximately 29 sub groups.
65 *
66 * Example:
67 *
68 * \code{.c}
69 * M_settings_t *s;
70 * M_hash_dict_t *h;
71 *
72 * s = M_settings_create("org", "app", M_SETTINGS_SCOPE_USER, M_SETTINGS_TYPE_NATIVE, M_SETTINGS_READER_NONE);
73 * if (!M_settings_read(s, &h)) {
74 * h = M_settings_create_dict(s);
75 * }
76 *
77 * M_hash_dict_insert(h, "key", "val");
78 * M_settings_write(s, h);
79 *
80 * M_hash_dict_destroy(h);
81 * M_settings_destroy(s);
82 * \endcode
83 *
84 * @{
85 */
86
87struct M_settings;
88typedef struct M_settings M_settings_t;
89
90
91/*! The visibility of the settings. */
92typedef enum {
93 M_SETTINGS_SCOPE_USER = 0, /*!< The settings are local to the current user.
94 - Windows:
95 - HKEY_CURRENT_USER -- When type is registry.
96 - "$HOME\Application Data\" -- Any other type.
97 - Apple's OS X
98 - $HOME/Library/Preferences/
99 - Other OS (Unix/Linux):
100 - $HOME/.config/ */
101 M_SETTINGS_SCOPE_SYSTEM /*!< The settings are global or system level.
102 - Windows:
103 - HKEY_LOCAL_MACHINE -- When type is registry.
104 - Directory where the running process is located -- Any other type.
105 - Apple's OS X
106 - /Library/Preferences/
107 - Other OS (Unix/Linux):
108 - /etc/ */
110
111
112/*! The format the settings should be stored on disk in.
113 *
114 * NATIVE is the recommended format as m_settings abstracts the underlying format
115 * for the given OS.
116 *
117 * That said it is possible to select a specific format. For example
118 * always using a portable format such as INI or JSON means that settings can shared
119 * between OS's. However, sharing settings between OS's is dependant on the data itself
120 * being cross platform as well.
121 * */
122typedef enum {
123 M_SETTINGS_TYPE_NATIVE = 0, /*!< The OS preferred format.
124 - Windows:
125 - Registry.
126 - Apple's OS X
127 - JSON
128 - Other OS (Unix/Linux):
129 - INI */
130 M_SETTINGS_TYPE_INI, /*!< INI file. */
131 /*!< JSON file. */
133#ifdef _WIN32
134 ,
135 M_SETTINGS_TYPE_REGISTRY /*!< The Windows Registry. This is only valid and available on Windows. */
136#endif
138
139
140/*! Access permissions for a settings. */
141typedef enum {
142 M_SETTINGS_ACCESS_NONE = 0, /*!< Cannot read or write. */
143 M_SETTINGS_ACCESS_EXISTS = 1 << 0, /*!< File exists. */
144 M_SETTINGS_ACCESS_READ = 1 << 1, /*!< Can read. */
145 M_SETTINGS_ACCESS_WRITE = 1 << 2 /*!< Can write. */
147
148
149/*! Flags to control the behavior of the settings reader. */
150typedef enum {
151 M_SETTINGS_READER_NONE = 0, /*!< Normal operation. */
152 M_SETTINGS_READER_CASECMP = 1 << 0 /*!< Key compare is case insensitive. The dictionary returned by read
153 will be created with case insensitive key compare. */
155
156
157/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
158
159/*! Create a settings object.
160 *
161 * \param[in] organization Organization information to store the settings under. This is recommended
162 * for organizational purposes. It is recommended (for widest compatibility)
163 * to use a domain name.
164 * Optional and can be NULL if application is specified. If application is
165 * not specified this will be used as the name stored on disk.
166 * \param[in] application The application name.
167 * Optional and can be NULL if organization is specified.
168 * \param[in] scope The visibility of the configuration. User vs system level.
169 * \param[in] type The underlying data type the settings should be stored using.
170 * \param[in] flags M_settings_reader_flags_t flags controlling the reader behavior.
171 *
172 * \return Settings object on success. NULL on error.
173 */
174M_API M_settings_t *M_settings_create(const char *organization, const char *application, M_settings_scope_t scope, M_settings_type_t type, M_uint32 flags);
175
176
177/*! Create a settings object at a specific location.
178 *
179 * Instead of using the default system paths and constructing the filename from the given information
180 * a use the specified filename (including path).
181 *
182 * \param[in] filename The filename the settings file should be created using.
183 * If the type is REGISTRY then this will be under HKEY_CURRENT_USER.
184 * \param[in] type The underlying data type the settings should be stored using.
185 * \param[in] flags M_settings_reader_flags_t flags controlling the reader behavior.
186 *
187 * \return Settings object on success. NULL on error.
188 */
189M_API M_settings_t *M_settings_create_file(const char *filename, M_settings_type_t type, M_uint32 flags);
190
191
192/*! Destroy a settings object.
193 *
194 * \param[in] settings The settings object.
195 */
196M_API void M_settings_destroy(M_settings_t *settings);
197
198
199/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
200
201/*! Check what types of operations can be performed for the settings.
202 *
203 * \param[in] settings The settings object.
204 *
205 * \return The access permissions.
206 */
208
209
210/*! Get the filename (and path) for the settings.
211 *
212 * \param[in] settings The settings.
213 *
214 * \return The associated filename. If the type is registry the filename is
215 * the location under either HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE.
216 * The HKEY itself will not be returned. The scope needs to be used
217 * to determine which HKEY would be used.
218 */
219M_API const char *M_settings_filename(const M_settings_t *settings);
220
221
222/*! Get the scope for the settings.
223 *
224 * \param[in] settings The settings
225 *
226 * \return The scope.
227 */
229
230
231/*! Get the type for the settings.
232 *
233 * \param[in] settings The settings.
234 *
235 * \return The underlying type the settings will be stored on disk using. This
236 * is the actual underlying type. If the settings object was created with
237 * NATIVE type this will not return NATIVE but the type that is considered
238 * 'native' for the OS.
239 */
241
242
243/*! Create an empty dictionary for storing settings.
244 *
245 * In cases where there is a parse errot this can be used to create
246 * and emptry dictionary to overwrite and store new settings.
247 *
248 * \param[in] settings The settings
249 *
250 * \return An empty dict for storing settings.
251 */
253
254
255/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
256
257/*! Read stored settings.
258 *
259 * M_settings_access should be used to determing if the parse error
260 * was due to a permissions error. If access shows the file exists
261 * and does not show it can be read from then it is a permission error.
262 *
263 * \param[in] settings The settings.
264 * \param[out] dict A dict with the settings.
265 *
266 * \return M_TRUE on successful read or if the "file" does not exist. M_FALSE on parse error.
267 *
268 * \see M_settings_access
269 */
270M_API M_bool M_settings_read(const M_settings_t *settings, M_hash_dict_t **dict);
271
272
273/*! Write settings to disk.
274 *
275 * This will overwrite any existing settings at the location represented by the settings object.
276 *
277 * \param[in] settings The settings.
278 * \param[in] dict The dict of key, value pairs that hold the setting data.
279 *
280 * \return M_TRUE on success, otherwise M_FALSE.
281 */
282M_API M_bool M_settings_write(const M_settings_t *settings, M_hash_dict_t *dict);
283
284
285/*! Clear settings in memory and on disk.
286 *
287 * This will clear all existing settings at the location represented by the settings object.
288 *
289 * \param[in] settings The settings.
290 * \param[out] dict The dict of key, value pairs that hold the setting data.
291 *
292 * \return M_TRUE on success, otherwise M_FALSE.
293 */
294M_API M_bool M_settings_clear(const M_settings_t *settings, M_hash_dict_t **dict);
295
296/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
297
298/*! Combine a group and key into a full key.
299 *
300 * \param[in] group The group.
301 * \param[in] key The key.
302 *
303 * \return The full key.
304 */
305M_API char *M_settings_full_key(const char *group, const char *key);
306
307
308/*! Split a full key into group and key parts.
309 *
310 * \param[in] s Full key;
311 * \param[out] group The group part.
312 * \param[out] key The key part.
313 */
314M_API void M_settings_split_key(const char *s, char **group, char **key);
315
316
317/*! Set a settings value.
318 *
319 * This is a convince function that handles combining the group and key. Otherwise it
320 * is no different than adding the value to the dict directly.
321 *
322 * \param[in,out] dict The dict to store the value in.
323 * \param[in] group The group. Optional, can be NULL if not storing into a group.
324 * \param[in] key The key to store under.
325 * \param[in] value The value to store.
326 */
327M_API void M_settings_set_value(M_hash_dict_t *dict, const char *group, const char *key, const char *value);
328
329
330/*! Get a settings value.
331 *
332 * This is a convince function that handles combining the group and key. Otherwise it
333 * is no different than accessing the dict directly.
334 *
335 * \param[in] dict The dict to read from.
336 * \param[in] group The group. Optional, can be NULL if not storing into a group.
337 * \param[in] key The key to store under.
338 *
339 * \return The value or NULL if the key under group does not exist.
340 */
341M_API const char *M_settings_value(M_hash_dict_t *dict, const char *group, const char *key);
342
343
344/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
345
346/*! Get a list of sub groups under a given group.
347 *
348 * This only returns direct sub group.
349 * E.g. Full key is "g1/g2/g3/k1"
350 * - Searching NULL -> "g1"
351 * - Searching "g1" -> "g2"
352 * - Searching "g1/g2" -> "g2"
353 * - Searching "g2 -> Nothing because there is no top level g2 group.
354 *
355 * \param[in] dict The dict to read from.
356 * \param[in] group The group to filer using. Optional, can be NULL to list all top level groups.
357 *
358 * \return A list of sub groups.
359 */
360M_API M_list_str_t *M_settings_groups(M_hash_dict_t *dict, const char *group);
361
362
363/*! Get a list of keys under a given group.
364 *
365 * This only returns keys under the given group.
366 * E.g. Full key is "g1/g2/g3/k1"
367 * - Searching "g1/g2/g3" -> "k1"
368 * - Searching "g1" -> Nothing because there are no keys directly under this group.
369 * - Searching "g1/g2" -> Nothing because there are no keys directly under this group.
370 *
371 * \param[in] dict The dict to read from.
372 * \param[in] group The group to filer using. Optional, can be NULL to list all top level groups.
373 *
374 * \return A list of keys.
375 */
376M_API M_list_str_t *M_settings_group_keys(M_hash_dict_t *dict, const char *group);
377
378/*! @} */
379
380__END_DECLS
381
382#endif /* __M_SETTINGS_H__ */
struct M_hash_dict M_hash_dict_t
Definition: m_hash_dict.h:52
struct M_list_str M_list_str_t
Definition: m_list_str.h:80
M_settings_reader_flags_t
Definition: m_settings.h:150
M_bool M_settings_write(const M_settings_t *settings, M_hash_dict_t *dict)
M_settings_t * M_settings_create_file(const char *filename, M_settings_type_t type, M_uint32 flags)
M_list_str_t * M_settings_groups(M_hash_dict_t *dict, const char *group)
M_list_str_t * M_settings_group_keys(M_hash_dict_t *dict, const char *group)
M_settings_t * M_settings_create(const char *organization, const char *application, M_settings_scope_t scope, M_settings_type_t type, M_uint32 flags)
const char * M_settings_filename(const M_settings_t *settings)
const char * M_settings_value(M_hash_dict_t *dict, const char *group, const char *key)
M_settings_type_t
Definition: m_settings.h:122
char * M_settings_full_key(const char *group, const char *key)
M_settings_type_t M_settings_type(const M_settings_t *settings)
M_bool M_settings_clear(const M_settings_t *settings, M_hash_dict_t **dict)
M_settings_scope_t M_settings_scope(const M_settings_t *settings)
void M_settings_split_key(const char *s, char **group, char **key)
struct M_settings M_settings_t
Definition: m_settings.h:88
M_settings_scope_t
Definition: m_settings.h:92
void M_settings_destroy(M_settings_t *settings)
void M_settings_set_value(M_hash_dict_t *dict, const char *group, const char *key, const char *value)
M_bool M_settings_read(const M_settings_t *settings, M_hash_dict_t **dict)
M_settings_access_t M_settings_access(const M_settings_t *settings)
M_hash_dict_t * M_settings_create_dict(const M_settings_t *settings)
M_settings_access_t
Definition: m_settings.h:141
@ M_SETTINGS_READER_NONE
Definition: m_settings.h:151
@ M_SETTINGS_READER_CASECMP
Definition: m_settings.h:152
@ M_SETTINGS_TYPE_INI
Definition: m_settings.h:130
@ M_SETTINGS_TYPE_NATIVE
Definition: m_settings.h:123
@ M_SETTINGS_TYPE_JSON
Definition: m_settings.h:132
@ M_SETTINGS_SCOPE_USER
Definition: m_settings.h:93
@ M_SETTINGS_SCOPE_SYSTEM
Definition: m_settings.h:101
@ M_SETTINGS_ACCESS_READ
Definition: m_settings.h:144
@ M_SETTINGS_ACCESS_NONE
Definition: m_settings.h:142
@ M_SETTINGS_ACCESS_EXISTS
Definition: m_settings.h:143
@ M_SETTINGS_ACCESS_WRITE
Definition: m_settings.h:145