1 /*
2  * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /** @file
18  * Config file parser.
19  */
20 #ifndef _USUAL_CFPARSER_H_
21 #define _USUAL_CFPARSER_H_
22 
23 #include <usual/base.h>
24 
25 /**
26  * @name Simple line-by-line parser
27  * @{
28  */
29 
30 /** Callback signarure for @ref parse_ini_file() */
31 typedef bool (*cf_handler_f)(void *arg, bool is_sect, const char *key, const char *val);
32 
33 /**
34  * Simple parser, launches callback for each line
35  */
36 bool parse_ini_file(const char *fn, cf_handler_f user_handler, void *arg) _MUSTCHECK;
37 
38 /* @} */
39 
40 /**
41  * @name Complex parser with variable setting.
42  * @{
43  */
44 
45 /** @name Per-key flags
46  * @{
47  */
48 
49 /** The pointer is absolute */
50 #define CF_VAL_ABS 0
51 
52 /** The pointer is relative to base */
53 #define CF_VAL_REL (1<<1)
54 
55 /** Value must not be changed on reload */
56 #define CF_NO_RELOAD (1<<2)
57 
58 /** Value can only be read */
59 #define CF_READONLY (1<<3)
60 
61 /** @} */
62 
63 /**
64  * Helper structure for passing key info to CfOps
65  */
66 struct CfValue {
67 	void *value_p;
68 	const void *extra;
69 	const char *key_name;
70 	char *buf;
71 	int buflen;
72 };
73 
74 /**
75  * Callbacks for setting and getting a variable value.
76  *
77  * Getter requires temp buf, returns string pointer, which
78  * may or may not point to temp buf.  Getter is optional.
79  */
80 struct CfOps {
81 	bool (*setter)(struct CfValue *cv, const char *value);
82 	const char *(*getter)(struct CfValue *cv);
83 	const void *op_extra;
84 };
85 
86 /**
87  * Parameter description
88  */
89 struct CfKey {
90 	/** Parameter name */
91 	const char *key_name;
92 	/** Type-specific functions, called with absolute pointer */
93 	struct CfOps op;
94 	/** Flags: CF_VAL_ABS, CF_VAL_REL */
95 	int flags;
96 	/** Absolute or relative offset */
97 	uintptr_t key_ofs;
98 	/** Default value as string */
99 	const char *def_value;
100 };
101 
102 /**
103  * Section description
104  */
105 struct CfSect {
106 	/** Section name */
107 	const char *sect_name;
108 
109 	/** Key list */
110 	const struct CfKey *key_list;
111 
112 	/** Get base pointer to dynamic sections (optional) */
113 	void *(*base_lookup)(void *top_base, const char *sect_name);
114 
115 	/** Set dynamic keys (optional) */
116 	bool (*set_key)(void *base, const char *key, const char *val);
117 
118 	/** Get dynamic keys (optional) */
119 	const char *(*get_key)(void *base, const char *key, char *buf, int buflen);
120 
121 	/** New section callback (optional) */
122 	bool (*section_start)(void *top_base, const char *sect_name);
123 };
124 
125 /**
126  * Top-level config information
127  */
128 struct CfContext {
129 	/** Section list */
130 	const struct CfSect *sect_list;
131 	/** Top-level base pointer, needed for relative addressing */
132 	void *base;
133 	/** If set, then CF_NO_RELOAD keys cannot be changed anymore */
134 	bool loaded;
135 };
136 
137 /**
138  * @name Type-specific helpers
139  * @{
140  */
141 
142 /** Setter for string */
143 bool cf_set_str(struct CfValue *cv, const char *value);
144 /** Setter for filename */
145 bool cf_set_filename(struct CfValue *cv, const char *value);
146 /** Setter for int */
147 bool cf_set_int(struct CfValue *cv, const char *value);
148 /** Setter for unsigned int */
149 bool cf_set_uint(struct CfValue *cv, const char *value);
150 /** Setter for time-usec */
151 bool cf_set_time_usec(struct CfValue *cv, const char *value);
152 /** Setter for time-double */
153 bool cf_set_time_double(struct CfValue *cv, const char *value);
154 /** Setter for lookup */
155 bool cf_set_lookup(struct CfValue *cv, const char *value);
156 
157 /** Getter for string */
158 const char *cf_get_str(struct CfValue *cv);
159 /** Getter for int */
160 const char *cf_get_int(struct CfValue *cv);
161 /** Getter for unsigned int */
162 const char *cf_get_uint(struct CfValue *cv);
163 /** Getter for time-usec */
164 const char *cf_get_time_usec(struct CfValue *cv);
165 /** Getter for time-double */
166 const char *cf_get_time_double(struct CfValue *cv);
167 /** Getter for int lookup */
168 const char *cf_get_lookup(struct CfValue *cv);
169 
170 /** @} */
171 
172 /**
173  * @name Shortcut CfOps for well-known types
174  * @{
175  */
176 
177 /** Ops for string */
178 #define CF_STR	{ cf_set_str, cf_get_str }
179 /** Ops for filename */
180 #define CF_FILE	{ cf_set_filename, cf_get_str }
181 /** Ops for integer */
182 #define CF_INT	{ cf_set_int, cf_get_int }
183 /** Ops for unsigned integer */
184 #define CF_UINT { cf_set_uint, cf_get_uint }
185 /** Ops for boolean */
186 #define CF_BOOL	{ cf_set_int, cf_get_int }
187 /** Ops for time as usec */
188 #define CF_TIME_USEC	{ cf_set_time_usec, cf_get_time_usec }
189 /** Ops for time as double */
190 #define CF_TIME_DOUBLE	{ cf_set_time_double, cf_get_time_double }
191 /** Ops for lookup, takes table as argument */
192 #define CF_LOOKUP(t)	{ cf_set_lookup, cf_get_lookup, t }
193 
194 /** @} */
195 
196 /**
197  * Lookup entry for CF_LOOKUP table.
198  */
199 struct CfLookup {
200 	const char *name;
201 	int value;
202 };
203 
204 /**
205  * Helper to describe CfKey with absolute addressing
206  */
207 #define CF_ABS(name, ops, var, flags, def) \
208 	{ name, ops, flags | CF_VAL_ABS, (uintptr_t)&(var), def }
209 
210 /**
211  * Helper to describe CfKey with relative addressing.
212  *
213  * Before using it defined CF_REL_BASE to base struct.
214  *
215  * The var should be field in that struct.
216  *
217  * @code
218  * struct Foo {
219  * 	char *foo_name;
220  * };
221  * #define CF_REL_BASE struct Foo
222  * ...
223  * CF_REL("name", CF_STR, foo_name, 0, NULL)
224  * ...
225  * #undef CF_REL_BASE
226  * @endcode
227  */
228 #define CF_REL(name, ops, var, flags, def) \
229 	{ name, ops, flags | CF_VAL_REL, offsetof(CF_REL_BASE, var), def }
230 
231 /**
232  * Load config from file.
233  */
234 bool cf_load_file(const struct CfContext *cf, const char *fn) _MUSTCHECK;
235 
236 /**
237  * Get single value.
238  */
239 const char *cf_get(const struct CfContext *cf, const char *sect, const char *var, char *buf, int buflen);
240 
241 /**
242  * Set single value.
243  */
244 bool cf_set(const struct CfContext *cf, const char *sect, const char *var, const char *val);
245 
246 /* @} */
247 
248 #endif
249