SELKIELogger  1.0.0
LoggerConfig.c
1 /*
2  * Copyright (C) 2023 Swansea University
3  *
4  * This file is part of the SELKIELogger suite of tools.
5  *
6  * SELKIELogger is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation, either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * SELKIELogger is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this SELKIELogger product.
18  * If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include "LoggerConfig.h"
22 
36 int config_handler(void *user, const char *section, const char *name, const char *value) {
37  ini_config *c = (ini_config *)user;
38 
39  // For each new key/value:
40  // - Find section
41  // - If not found, create section (realloc as required)
42  // - Append new kv item (realloc as required)
43  int sectFound = -1;
44  for (int i = 0; i < c->numsects; ++i) {
45  if (c->sects[i].name && (strcmp(c->sects[i].name, section) == 0)) {
46  sectFound = i;
47  break;
48  }
49  }
50 
51  config_section *cs = NULL;
52  if (sectFound < 0) {
53  if (c->numsects < (ssize_t) c->sectsize) {
54  cs = &(c->sects[c->numsects++]);
55  cs->name = strdup(section);
56  } else {
57  c->sectsize += 5;
58  config_section *a =
59  realloc(c->sects, c->sectsize * sizeof(config_section));
60  if (a == NULL) {
61  perror("config_handler");
62  return 0;
63  }
64  c->sects = a;
65  memset(&(c->sects[c->numsects]), 0, sizeof(config_section) * 5);
66  cs = &(c->sects[c->numsects++]);
67  cs->name = strdup(section);
68  }
69  } else {
70  cs = &(c->sects[sectFound]);
71  }
72 
73  config_kv *k = NULL;
74  if (cs->numopts < (ssize_t) cs->optsize) {
75  k = &(cs->opts[cs->numopts++]);
76  } else {
77  cs->optsize += 5;
78  config_kv *a = NULL;
79  if (cs->opts) {
80  a = realloc(cs->opts, cs->optsize * sizeof(config_kv));
81  } else {
82  a = calloc(cs->optsize, sizeof(config_kv));
83  }
84 
85  if (a == NULL) {
86  perror("config_handler");
87  return 0;
88  }
89  cs->opts = a;
90  memset(&(cs->opts[cs->numopts]), 0, sizeof(config_kv) * 5);
91  k = &(cs->opts[cs->numopts++]);
92  }
93  k->key = config_qstrdup(name);
94  k->value = config_qstrdup(value);
95 
96  return 1;
97 }
98 
109  if (c == NULL) { return false; }
110  c->sectsize = 10;
111  c->sects = calloc(c->sectsize, sizeof(config_section));
112  if (c->sects == NULL) {
113  c->sectsize = 0;
114  c->numsects = 0;
115  perror("new_config");
116  return false;
117  }
118 
119  c->numsects = 1;
120  c->sects[0].name = strdup("");
121  c->sects[0].numopts = 0;
122  c->sects[0].optsize = 10;
123  c->sects[0].opts = calloc(c->sects[0].optsize, sizeof(config_kv));
124  if (c->sects[0].opts == NULL) {
125  c->sects[0].optsize = 0;
126  c->sects[0].numopts = 0;
127  c->numsects = 0;
128  c->sectsize = 0;
129  free(c->sects);
130  perror("new_config");
131  return false;
132  }
133 
134  return true;
135 }
136 
143  if (c == NULL) { return; }
144 
145  for (int i = 0; i < c->numsects; ++i) {
146  config_section *cs = &(c->sects[i]);
147  for (int j = 0; j < cs->numopts; ++j) {
148  free(cs->opts[j].key);
149  free(cs->opts[j].value);
150  }
151  free(cs->opts);
152  free(cs->name);
153  }
154  free(c->sects);
155 }
156 
164  if (c == NULL) { return; }
165 
166  for (int i = 0; i < c->numsects; ++i) {
167  config_section *cs = &(c->sects[i]);
168  if (strcmp("", cs->name) != 0) { fprintf(stdout, "[%s]\n", cs->name); }
169  for (int j = 0; j < cs->numopts; ++j) {
170  fprintf(stdout, "%s = %s\n", cs->opts[j].key, cs->opts[j].value);
171  }
172  fprintf(stdout, "\n");
173  }
174 }
175 
186 config_section *config_get_section(const ini_config *in, const char *sn) {
187  for (int i = 0; i < in->numsects; i++) {
188  config_section *cs = &(in->sects[i]);
189  if (strcasecmp(sn, cs->name) == 0) { return cs; }
190  }
191  return NULL;
192 }
193 
204 config_kv *config_get_key(const config_section *cs, const char *kn) {
205  for (int i = 0; i < cs->numopts; i++) {
206  config_kv *k = &(cs->opts[i]);
207  if (strcasecmp(kn, k->key) == 0) { return k; }
208  }
209  return NULL;
210 }
211 
222 config_kv *config_get_option(const ini_config *in, const char *sn, const char *kn) {
223  config_section *cs = config_get_section(in, sn);
224  if (cs == NULL) { return NULL; }
225  return config_get_key(cs, kn);
226 }
227 
240 int config_parse_bool(const char *b) {
241  if (b == NULL || (strcmp(b, "") == 0)) { return -1; }
242 
243  switch (b[0]) {
244  case 'Y':
245  case 'y':
246  case 'T':
247  case 't':
248  case '1':
249  return 1;
250  case 'N':
251  case 'n':
252  case 'F':
253  case 'f':
254  case '0':
255  return 0;
256  }
257  return -1;
258 }
259 
271 char *config_qstrdup(const char *c) {
272  size_t sl = strlen(c);
273  if (((c[0] == '"') && (c[sl - 1] == '"')) || ((c[0] == '\'') && (c[sl - 1] == '\''))) {
274  // Length minus the two quote chars
275  return strndup(&(c[1]), sl - 2);
276  }
277 
278  // No matched quotes? Dup what we were given
279  return strdup(c);
280 }
bool new_config(ini_config *c)
Initialise a new ini_config instance.
Definition: LoggerConfig.c:108
void destroy_config(ini_config *c)
Destroy ini_config instance.
Definition: LoggerConfig.c:142
void print_config(ini_config *c)
Print ini_config instance to stdout.
Definition: LoggerConfig.c:163
int config_parse_bool(const char *b)
Parse string to boolean.
Definition: LoggerConfig.c:240
char * config_qstrdup(const char *c)
Duplicate string, stripping optional leading/trailing quote marks.
Definition: LoggerConfig.c:271
config_kv * config_get_option(const ini_config *in, const char *sn, const char *kn)
Find configuration option by section and key names.
Definition: LoggerConfig.c:222
int config_handler(void *user, const char *section, const char *name, const char *value)
Populate ini_config instance with values from file.
Definition: LoggerConfig.c:36
config_section * config_get_section(const ini_config *in, const char *sn)
Find configuration section by name.
Definition: LoggerConfig.c:186
config_kv * config_get_key(const config_section *cs, const char *kn)
Find configugration key within specific section, by name.
Definition: LoggerConfig.c:204
Represent a key=value pair.
Definition: LoggerConfig.h:42
char * value
Configuration item value.
Definition: LoggerConfig.h:44
char * key
Configuration item key.
Definition: LoggerConfig.h:43
Configuration file section.
Definition: LoggerConfig.h:54
int numopts
Number of *opts in use.
Definition: LoggerConfig.h:57
config_kv * opts
Key=value pairs belonging to this section.
Definition: LoggerConfig.h:58
char * name
Section [tag].
Definition: LoggerConfig.h:55
size_t optsize
Allocated size of *opts.
Definition: LoggerConfig.h:56
Representation of a parsed .ini file.
Definition: LoggerConfig.h:72
config_section * sects
Array of sections.
Definition: LoggerConfig.h:75
int numsects
Number of sections defined.
Definition: LoggerConfig.h:74
size_t sectsize
Allocated size of *sects.
Definition: LoggerConfig.h:73