DTS Application Library  0.2.3
Application library containing referenced objects and interfaces to common libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
config.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 2012 Gregory Nietsky <gregory@distrotetch.co.za>
3  http://www.distrotech.co.za
4 
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include "include/dtsapp.h"
30 
34  const char *name;
37 };
38 
40 struct config_file {
42  const char *filename;
44  const char *filepath;
46  struct bucket_list *cat;
47 };
48 
49 static struct bucket_list *configfiles = NULL;
50 
51 static int32_t hash_files(const void *data, int key) {
52  int ret;
53  const struct config_file *file = data;
54  const char *hashkey = (key) ? data : file->filename;
55 
56  ret = jenhash(hashkey, strlen(hashkey), 0);
57 
58  return(ret);
59 }
60 
61 static int32_t hash_cats(const void *data, int key) {
62  int ret;
63  const struct config_category *cat = data;
64  const char *hashkey = (key) ? data : cat->name;
65 
66  ret = jenhash(hashkey, strlen(hashkey), 0);
67 
68  return(ret);
69 }
70 
71 static void initconfigfiles(void) {
72  if (!configfiles) {
73  configfiles = create_bucketlist(4, hash_files);
74  }
75 }
76 
78 extern void unrefconfigfiles(void) {
79  if (configfiles) {
80  objunref(configfiles);
81  }
82 }
83 
84 static void free_config_entry(void *data) {
85  struct config_entry *entry = data;
86 
87  if (entry->item) {
88  free((void *)entry->item);
89  }
90  if (entry->value) {
91  free((void *)entry->value);
92  }
93 }
94 
95 static void add_conf_entry(struct config_category *category, const char *item, const char *value) {
96  struct config_entry *newentry;
97 
98  if (!category || !category->entries || !(newentry = objalloc(sizeof(*newentry), free_config_entry))) {
99  return;
100  }
101 
102  ALLOC_CONST(newentry->item, item);
103  ALLOC_CONST(newentry->value, value);
104 
105  addtobucket(category->entries, newentry);
106  objunref(newentry);
107 }
108 
109 static void free_config_category(void *data) {
110  struct config_category *cat = data;
111 
112  if (cat->name) {
113  free((void *)cat->name);
114  }
115  if (cat->entries) {
116  objunref(cat->entries);
117  }
118 }
119 
120 static struct config_category *create_conf_category(const char *name) {
121  struct config_category *newcat;
122 
123  if (!(newcat = objalloc(sizeof(*newcat), free_config_category))) {
124  return (NULL);
125  }
126 
127  ALLOC_CONST(newcat->name, name);
128  newcat->entries = create_bucketlist(5, hash_cats);
129 
130  return (newcat);
131 }
132 
133 static void free_config_file(void *data) {
134  struct config_file *file = data;
135 
136  if (file->filename) {
137  free((void *)file->filename);
138  }
139  if (file->filepath) {
140  free((void *)file->filepath);
141  }
142  if (file->cat) {
143  objunref(file->cat);
144  }
145 }
146 
147 static struct config_file *create_conf_file(const char *filename, const char *filepath) {
148  struct config_file *newfile;
149 
150  if (!(newfile = objalloc(sizeof(*newfile), free_config_file))) {
151  return (NULL);
152  }
153 
154  ALLOC_CONST(newfile->filename, filename);
155  ALLOC_CONST(newfile->filepath, filepath);
156  newfile->cat = create_bucketlist(4, hash_files);
157 
158  return (newfile);
159 }
160 
161 static char *filterconf(const char *str, int minlen) {
162  char *tmp, *token;
163 
164  /*trim leading and trailing white space*/
165  tmp = trim(str);
166 
167  /*remove everything after the last # ignore if # is first*/
168  if ((token = strrchr(tmp, '#'))) {
169  if (token == tmp) {
170  return NULL;
171  }
172  token[0] = '\0';
173  }
174 
175  /*first char is #*/
176  if ((token = strchr(tmp, '#')) && (token == tmp)) {
177  return NULL;
178  }
179 
180  /*remove ; as first char*/
181  if ((token = strchr(tmp, ';')) && (token == tmp)) {
182  return NULL;
183  }
184 
185  /*too short*/
186  if (strlen(tmp) < minlen) {
187  return NULL;
188  }
189 
190  return (tmp);
191 }
192 
197 extern int process_config(const char *configname, const char *configfile) {
198  struct config_file *file;
199  struct config_category *category = NULL;
200  FILE *config;
201  char line[256];
202  char item[128];
203  char value[128];
204  char *tmp = (char *)&line;
205  char *token;
206 
207  if (!configfiles) {
208  initconfigfiles();
209  }
210 
211  file = create_conf_file(configname, configfile);
212  addtobucket(configfiles, file);
213 
214  if (!(config = fopen(file->filepath, "r"))) {
215  return (-1);
216  }
217 
218  while(fgets(line, sizeof(line) - 1, config)) {
219  if (!(tmp = filterconf(line, 3))) {
220  continue;
221  }
222 
223  /*this is a new category*/
224  if ((token = strchr(tmp, '[')) && (token == tmp)) {
225  tmp++;
226  token = strrchr(tmp, ']');
227  token[0] = '\0';
228  tmp = trim(tmp);
229  if (!strlenzero(tmp)) {
230  if (category) {
231  objunref(category);
232  }
233  category = create_conf_category(tmp);
234  addtobucket(file->cat, category);
235  }
236  continue;
237  }
238 
239  if (sscanf(tmp, "%[^=] %*[=] %[^\n]", (char *)&item, (char *)&value) != 2) {
240  continue;
241  }
242 
243  if (!category) {
244  category = create_conf_category("default");
245  addtobucket(file->cat, category);
246  }
247 
248  add_conf_entry(category, trim(item), trim(value));
249  }
250  fclose(config);
251  if (category) {
252  objunref(category);
253  }
254  if (file) {
255  objunref(file);
256  }
257  return (0);
258 }
259 
263 extern struct bucket_list *get_config_file(const char *configname) {
264  struct config_file *file;
265 
266  if ((file = bucket_list_find_key(configfiles, configname))) {
267  if (file->cat) {
268  if (!objref(file->cat)) {
269  objunref(file);
270  return (NULL);
271  }
272  objunref(file);
273  return (file->cat);
274  }
275  objunref(file);
276  }
277  return (NULL);
278 }
279 
286 extern struct bucket_list *get_config_category(const char *configname, const char *category) {
287  struct bucket_list *file;
288  struct config_category *cat;
289 
290  file = get_config_file(configname);
291  if (category) {
292  cat = bucket_list_find_key(file, category);
293  } else {
294  cat = bucket_list_find_key(file, "default");
295  }
296 
297  objunref(file);
298  if (cat) {
299  if (!objref(cat->entries)) {
300  objunref(cat);
301  return (NULL);
302  }
303  objunref(cat);
304  return (cat->entries);
305  } else {
306  return (NULL);
307  }
308 }
309 
317 extern struct bucket_list *get_category_next(struct bucket_loop *cloop, char *name, int len) {
318  struct config_category *category;
319 
320  if (cloop && (category = next_bucket_loop(cloop))) {
321  if (category->entries) {
322  if (!objref(category->entries)) {
323  objunref(category);
324  return (NULL);
325  }
326  if (!strlenzero(name)) {
327  strncpy(name, category->name, len);
328  }
329  objunref(category);
330  return (category->entries);
331  } else {
332  objunref(category);
333  }
334  }
335  return (NULL);
336 }
337 
341 extern struct bucket_loop *get_category_loop(const char *configname) {
342  struct bucket_loop *cloop;
343  struct bucket_list *file;
344 
345  file = get_config_file(configname);
346  cloop = init_bucket_loop(file);
347  objunref(file);
348  return (cloop);
349 }
350 
351 static void entry_callback(void *data, void *entry_cb) {
352  struct config_entry *entry = data;
353  config_entrycb *cb_entry = entry_cb, callback;
354 
355  callback = *cb_entry;
356 
357  callback(entry->item, entry->value);
358 }
359 
365 extern void config_entry_callback(struct bucket_list *entries, config_entrycb entry_cb) {
366  bucketlist_callback(entries, entry_callback, &entry_cb);
367 }
368 
369 static void category_callback(void *data, void *category_cb) {
370  struct config_category *category = data;
371  config_catcb *cb_catptr = category_cb, cb_cat;
372 
373  cb_cat = *cb_catptr;
374 
375  cb_cat(category->entries, category->name);
376 }
377 
383 extern void config_cat_callback(struct bucket_list *categories, config_catcb cat_cb) {
384  bucketlist_callback(categories, category_callback, &cat_cb);
385 }
386 
387 static void file_callback(void *data, void *file_cb) {
388  struct config_file *file = data;
389  config_filecb *cb_fileptr = file_cb, cb_file;
390 
391  cb_file = *cb_fileptr;
392 
393  cb_file(file->cat, file->filename, file->filepath);
394 }
395 
400 extern void config_file_callback(config_filecb file_cb) {
401  bucketlist_callback(configfiles, file_callback, &file_cb);
402 }
403 
408 extern struct config_entry *get_config_entry(struct bucket_list *categories, const char *item) {
409  struct config_entry *entry;
410 
411  entry = bucket_list_find_key(categories, item);
412 
413  return (entry);
414 }
415 
Bucket iterator.
Definition: refobj.c:97
int strlenzero(const char *str)
Check if a string is zero length.
Definition: util.c:341
struct bucket_list * cat
Categories.
Definition: config.c:46
const char * item
Definition: dtsapp.h:157
void * create_bucketlist(int bitmask, blisthash hash_function)
Definition: refobj.c:356
int objref(void *data)
Reference a object.
Definition: refobj.c:153
void config_entry_callback(struct bucket_list *entries, config_entrycb entry_cb)
Callback Wraper that iterates through all items calling a callback for each item. ...
Definition: config.c:365
void config_file_callback(config_filecb file_cb)
Callback wrapper to iterate over all configfiles calling a callback on each file. ...
Definition: config.c:400
const char * value
Definition: dtsapp.h:159
const char * name
Category name.
Definition: config.c:34
void * objalloc(int size, objdestroy)
Allocate a referenced lockable object.
Definition: refobj.c:129
struct config_entry * get_config_entry(struct bucket_list *categories, const char *item)
Find the entry in a config file.
Definition: config.c:408
Configuration category entry.
Definition: dtsapp.h:155
void unrefconfigfiles(void)
Empty out and unreference config files.
Definition: config.c:78
void * next_bucket_loop(struct bucket_loop *bloop)
Return a reference to the next item in the list this could be the first item.
Definition: refobj.c:662
Config file.
Definition: config.c:40
DTS Application library API Include file.
char * trim(const char *str)
Trim whitesapce from the beggining and end of a string.
Definition: util.c:393
void(* config_filecb)(struct bucket_list *, const char *, const char *)
Calback used when processing config files.
Definition: dtsapp.h:285
struct bucket_list * entries
Entries in category.
Definition: config.c:36
const char * filepath
File path.
Definition: config.c:44
struct bucket_loop * get_category_loop(const char *configname)
Return a bucket loop to allow iterating over categories.
Definition: config.c:341
struct bucket_list * get_config_file(const char *configname)
Returns the catergories bucket for a config file.
Definition: config.c:263
struct bucket_list * get_category_next(struct bucket_loop *cloop, char *name, int len)
Iterate through categories returning the entries bucket.
Definition: config.c:317
void bucketlist_callback(struct bucket_list *blist, blist_cb callback, void *data2)
Run a callback function on all items in the list.
Definition: refobj.c:613
#define jenhash(key, length, initval)
Define jenhash as hashlittle on big endian it should be hashbig.
Definition: dtsapp.h:914
void(* config_entrycb)(const char *, const char *)
Callback used when processing a entry.
Definition: dtsapp.h:297
const char * filename
Filename.
Definition: config.c:42
void(* config_catcb)(struct bucket_list *, const char *)
Calback used when processing a category.
Definition: dtsapp.h:291
Configuration file category.
Definition: config.c:32
#define ALLOC_CONST(const_var, val)
Macro to assign values to char const.
Definition: dtsapp.h:959
void config_cat_callback(struct bucket_list *categories, config_catcb cat_cb)
Callback wrapper that iterates through categories calling a callback on each category.
Definition: config.c:383
int addtobucket(struct bucket_list *blist, void *data)
Add a reference to the bucketlist.
Definition: refobj.c:428
void * bucket_list_find_key(struct bucket_list *list, const void *key)
Find and return a reference to a item matching supplied key.
Definition: refobj.c:572
int objunref(void *data)
Drop reference held.
Definition: refobj.c:184
struct bucket_list * get_config_category(const char *configname, const char *category)
Return a single category.
Definition: config.c:286
int process_config(const char *configname, const char *configfile)
Process a configfile into buckets.
Definition: config.c:197
struct bucket_loop * init_bucket_loop(struct bucket_list *blist)
Create a bucket list iterator to safely iterate the list.
Definition: refobj.c:640
Bucket list, hold hashed objects in buckets.
Definition: refobj.c:75