diff --git a/ChangeLog.txt b/ChangeLog.txt index f7e6da9..05a374d 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,17 +1,17 @@ # Canfigger ChangeLog -2024-02-26 +2024-02-29 - - remove canfigger_attr + * release v0.3.0 -2024-02-25 +Changes since 2024-02-21 * canfigger_free() replaced with canfigger_free_current_key_node_advance() * canfigger_free_attr() removed * use 'canfigger_free_current_attr_str_advance()' instead of 'list->attr_node = list->attr_node->next' - * canfigger_attr points to the current attribute, or NULL if there is none * In meson.build, rename dep_canfigger->canfigger_dep + * lines starting with '[' are ignored 2024-02-21 diff --git a/README.md b/README.md index aa6f678..0fbfbd4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![actions-c-badge]][actions-c-url] [![cirrus-badge]][cirrus-url] -# canfigger v0.3.0999 +# canfigger v0.3.0 Canfigger is a lightweight C language library designed to parse configuration files. It provides functionality to read them and represent their contents as @@ -61,6 +61,18 @@ An example program will be built when you run `ninja`. It will read different config file, give `example` the name of a config file as an argument. +## Using canfigger in your project + +If canfigger is not available for your operating system or distribution, you +can copy the required sources (and the LICENSE file) into your project and add +them to your build system. The line `include ` from the top of the +.c file will need to be removed, as it is normally generated during the Meson +setup and only contains version information. + +Alternatively, if your project uses Meson, you can add a [wrap +file](https://mesonbuild.com/Wrap-dependency-system-manual.html#wrap-dependency-system-manual) +for canfigger in your 'subprojects' directory. + ## Projects using canfigger diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index fa08335..1ae1eed 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -1,3 +1,14 @@ Release Notes for v0.3.0 -will be added here before the upcoming release. +This version introduces breaking changes. Please see example.c in the source +root directory for usage. + +Notable changes: + + * Use dynamic memory allocation for keys, values, and attributes. + * canfigger_free() replaced with canfigger_free_current_key_node_advance() + * canfigger_free_attr() removed + * use 'canfigger_free_current_attr_str_advance()' instead of + 'list->attr_node = list->attr_node->next' + * In meson.build, rename dep_canfigger->canfigger_dep + * lines starting with '[' are ignored diff --git a/docs/annotated.html b/docs/annotated.html index 531182b..fa58d0a 100644 --- a/docs/annotated.html +++ b/docs/annotated.html @@ -23,7 +23,7 @@ -
canfigger v0.3.0 +
canfigger v0.3.x
Lightweight config file parser library
diff --git a/docs/canfigger_8c_source.html b/docs/canfigger_8c_source.html new file mode 100644 index 0000000..1d444c7 --- /dev/null +++ b/docs/canfigger_8c_source.html @@ -0,0 +1,542 @@ + + + + + + + +canfigger: canfigger.c Source File + + + + + + + + + + + +
+
+ + + + + + +
+
canfigger v0.3.x +
+
Lightweight config file parser library
+
+
+ + + + + + + + +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
canfigger.c
+
+
+
1/*
+
2This file is part of canfigger<https://github.com/andy5995/canfigger>
+
3
+
4Copyright (C) 2021-2024 Andy Alt (arch_stanton5995@proton.me)
+
5
+
6This program is free software: you can redistribute it and/or modify
+
7it under the terms of the GNU General Public License as published by
+
8the Free Software Foundation, either version 3 of the License, or
+
9any later version.
+
10
+
11This program is distributed in the hope that it will be useful,
+
12but WITHOUT ANY WARRANTY; without even the implied warranty of
+
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+
14GNU General Public License for more details.
+
15
+
16You should have received a copy of the GNU General Public License
+
17along with this program. If not, see <http://www.gnu.org/licenses/>.
+
18*/
+
19
+
20#include <ctype.h> // isspace()
+
21#include <errno.h>
+
22#include <stdbool.h>
+
23#include <stdio.h>
+
24#include <stdlib.h> // free(), malloc()
+
25#include <string.h>
+
26#include <stdarg.h> // valist (variable argument function)
+
27
+
28// This is only required for version info and can be removed
+
29// if you're copying the canfigger source files to use as
+
30// an embedded library with your own project (i.e., not building
+
31// canfigger with the build system it's shipped with).
+
32#include "config.h"
+
33
+
34#include "canfigger.h"
+
35
+
36#define strdup_wrap(...) strdup_wrap_real(__VA_ARGS__, (size_t)0)
+
37
+
38static char *grab_str_segment(char *a, char **dest, const int c);
+
39static void free_list(struct Canfigger **node);
+
40
+
42struct line
+
43{
+
44 size_t len;
+
45 char *start;
+
46 char *end;
+
47};
+
51static char *
+
52strdup_wrap_real(const char *argv, ...)
+
53{
+
54 va_list args;
+
55 char *src = (char *) argv;
+
56 va_start(args, argv);
+
57 size_t n = va_arg(args, size_t); // Try to get the second argument
+
58
+
59 char *retval = NULL;
+
60 if (n == 0) // If n is 0, it means there was no second argument
+
61 retval = strdup(src);
+
62 else
+
63 retval = strndup(src, n);
+
64
+
65 va_end(args);
+
66 if (retval)
+
67 return retval;
+
68
+
69 perror("Failed to duplicate string:");
+
70 return NULL;
+
71}
+
72
+
73
+
74void
+
+
75canfigger_free_current_attr_str_advance(struct attributes *attributes,
+
76 char **attr)
+
77{
+
78 if (!attributes)
+
79 {
+
80 *attr = NULL;
+
81 return;
+
82 }
+
83
+
84 if (attributes->current && attributes->iter_ptr)
+
85 free(attributes->current);
+
86
+
87 if (!attributes->iter_ptr)
+
88 {
+
89 free(attributes->current);
+
90 attributes->current = NULL;
+
91 *attr = NULL;
+
92 return;
+
93 }
+
94
+
95 attributes->iter_ptr = grab_str_segment(attributes->iter_ptr,
+
96 &attributes->current, '\n');
+
97
+
98 if (*attributes->current)
+
99 {
+
100 *attr = attributes->current;
+
101 return;
+
102 }
+
103
+
104 // If we're here, that means strdup() failed to allocate memory in grab_str_segment()
+
105 // If an expected attribute isn't returned, the caller may want to terminate
+
106 // the remainder of the loop that's iterating through the entire linked list
+
107 // and exit the program.
+
108 *attr = NULL;
+
109 return;
+
110}
+
+
111
+
112
+
113void
+
+
114canfigger_free_current_key_node_advance(struct Canfigger **node)
+
115{
+
116 if (*node)
+
117 {
+
118 if ((*node)->attributes)
+
119 {
+
120 if ((*node)->attributes->current)
+
121 {
+
122 free((*node)->attributes->current);
+
123 (*node)->attributes->current = NULL;
+
124 }
+
125
+
126 if ((*node)->attributes->str)
+
127 {
+
128 free((*node)->attributes->str);
+
129 (*node)->attributes->str = NULL;
+
130 }
+
131
+
132 free((*node)->attributes);
+
133 (*node)->attributes = NULL;
+
134 }
+
135
+
136 if ((*node)->value)
+
137 {
+
138 free((*node)->value);
+
139 (*node)->value = NULL;
+
140 }
+
141
+
142 free((*node)->key);
+
143 (*node)->key = NULL;
+
144
+
145 struct Canfigger *temp_node = (*node)->next;
+
146 free(*node);
+
147 *node = temp_node;
+
148 }
+
149
+
150 return;
+
151}
+
+
152
+
153
+
154static void
+
155free_list(struct Canfigger **node)
+
156{
+
157 if (*node)
+
158 {
+
159 while (*node)
+ +
161 }
+
162
+
163 return;
+
164}
+
165
+
166
+
167/*
+
168 * returns a pointer to the first character after lc
+
169 * If lc appears more than once, the pointer
+
170 * will move past that as well.
+
171 *
+
172 * Ex1: "__Hello World": the pointer will be set to the 'H'.
+
173 * Ex2: "_H_ello World": Again, the pointer will be set to the 'H'.
+
174 */
+
175static char *
+
176erase_lead_char(const int lc, char *haystack)
+
177{
+
178 char *ptr = haystack;
+
179 if (*ptr != lc)
+
180 return ptr;
+
181
+
182 while (*ptr == lc)
+
183 ptr++;
+
184
+
185 return ptr;
+
186}
+
187
+
188
+
189static void
+
190truncate_whitespace(char *str)
+
191{
+
192 if (!str)
+
193 return;
+
194
+
195 char *pos_0 = str;
+
196 /* Advance pointer until NULL terminator is found
+
197 * Don't try to use strchr() because you'll get a different
+
198 * result if the pointer is already at '\0'. */
+
199 while (*str != '\0')
+
200 str++;
+
201
+
202 /* set pointer to segment preceding NULL terminator */
+
203 if (str != pos_0)
+
204 str--;
+
205 else
+
206 return;
+
207
+
208 while (isspace(*str))
+
209 {
+
210 *str = '\0';
+
211 if (str != pos_0)
+
212 str--;
+
213 else
+
214 break;
+
215 }
+
216
+
217 return;
+
218}
+
219
+
220
+
221static char *
+
222grab_str_segment(char *a, char **dest, const int c)
+
223{
+
224 a = erase_lead_char(' ', a);
+
225
+
226 char *b = strchr(a, c);
+
227 if (!b)
+
228 {
+
229 *dest = strdup_wrap(a);
+
230 return b; // NULL
+
231 }
+
232
+
233 size_t len = b - a;
+
234 *dest = strdup_wrap(a, len);
+
235 if (!*dest)
+
236 return NULL;
+
237
+
238 truncate_whitespace(*dest);
+
239 return b + 1;
+
240}
+
241
+
242static void *
+
243malloc_wrap(size_t size)
+
244{
+
245 void *retval = malloc(size);
+
246 if (retval)
+
247 return retval;
+
248
+
249 perror("Failed to allocate memory: ");
+
250
+
251 return NULL;
+
252}
+
253
+
254static void
+
255add_key_node(struct Canfigger **root, struct Canfigger **cur_node)
+
256{
+
257 struct Canfigger *tmp_node = malloc_wrap(sizeof(struct Canfigger));
+
258 if (!tmp_node)
+
259 return;
+
260
+
261 if (*root)
+
262 (*cur_node)->next = tmp_node;
+
263 else
+
264 *root = tmp_node;
+
265
+
266 *cur_node = tmp_node;
+
267
+
268 return;
+
269}
+
270
+
271
+
272static char *
+
273read_entire_file(const char *filename)
+
274{
+
275 FILE *fp = fopen(filename, "r");
+
276 if (!fp)
+
277 {
+
278 fprintf(stderr, "Failed to open %s:%s\n", filename, strerror(errno));
+
279 return NULL;
+
280 }
+
281
+
282 fseek(fp, 0, SEEK_END);
+
283 long file_size = ftell(fp);
+
284 fseek(fp, 0, SEEK_SET);
+
285
+
286 char *buffer = malloc_wrap(file_size + 1);
+
287 if (!buffer)
+
288 {
+
289 fclose(fp);
+
290 return NULL;
+
291 }
+
292
+
293 fread(buffer, 1, file_size, fp);
+
294 buffer[file_size] = '\0';
+
295
+
296 int r = ferror(fp);
+
297 clearerr(fp);
+
298 fclose(fp);
+
299
+
300 if (r == 0)
+
301 return buffer;
+
302
+
303 fprintf(stderr, "Error reading %s(%d)\n", filename, r);
+
304 return NULL;
+
305}
+
306
+
307
+
308static void
+
309free_incomplete_node(struct Canfigger **node)
+
310{
+
311 if (*node)
+
312 {
+
313 if ((*node)->key)
+
314 free((*node)->key);
+
315
+
316 if ((*node)->value)
+
317 free((*node)->value);
+
318
+
319 if ((*node)->attributes)
+
320 if ((*node)->attributes->str)
+
321 free((*node)->attributes->str);
+
322 }
+
323 free(*node);
+
324
+
325 return;
+
326}
+
327
+
328
+
329struct Canfigger *
+
+
330canfigger_parse_file(const char *file, const int delimiter)
+
331{
+
332 struct Canfigger *root = NULL, *cur_node = NULL;
+
333
+
334 char *buffer = read_entire_file(file);
+
335 if (buffer == NULL)
+
336 return NULL;
+
337
+
338 char file_contents[strlen(buffer) + 1];
+
339 memcpy(file_contents, buffer, sizeof file_contents);
+
340 free(buffer);
+
341
+
342 struct line line;
+
343 line.start = file_contents;
+
344 line.end = strchr(line.start, '\n');
+
345
+
346 bool node_complete;
+
347
+
348 while (line.end)
+
349 {
+
350 line.len = line.end - line.start;
+
351 char tmp_line[line.len + 1];
+
352 memcpy(tmp_line, line.start, line.len);
+
353 tmp_line[line.len] = '\0';
+
354
+
355 // Used in the next loop
+
356 if (line.end)
+
357 {
+
358 line.start = line.end + 1;
+
359 line.end = strchr(line.start, '\n');
+
360 }
+
361
+
362 char *line_ptr = tmp_line;
+
363 truncate_whitespace(line_ptr);
+
364
+
365 while (isspace(*line_ptr))
+
366 line_ptr = erase_lead_char(*line_ptr, line_ptr);
+
367
+
368 if (*line_ptr == '\0' || *line_ptr == '#' || *line_ptr == '[')
+
369 continue;
+
370
+
371 node_complete = false;
+
372 add_key_node(&root, &cur_node);
+
373 if (!cur_node)
+
374 break;
+
375
+
376 // Get key
+
377 cur_node->key = NULL;
+
378 line_ptr = grab_str_segment(line_ptr, &cur_node->key, '=');
+
379 if (!cur_node->key)
+
380 {
+
381 free_incomplete_node(&cur_node);
+
382 break;
+
383 }
+
384
+
385 // Get value
+
386 cur_node->value = NULL;
+
387
+
388 if (line_ptr)
+
389 {
+
390 line_ptr = grab_str_segment(line_ptr, &cur_node->value, delimiter);
+
391 if (!cur_node->value)
+
392 {
+
393 free_incomplete_node(&cur_node);
+
394 break;
+
395 }
+
396 }
+
397
+
398 // Handle attributes
+
399 if (line_ptr)
+
400 {
+
401 cur_node->attributes = malloc_wrap(sizeof(struct attributes));
+
402 if (!cur_node->attributes)
+
403 {
+
404 free_incomplete_node(&cur_node);
+
405 break;
+
406 }
+
407
+
408 struct attributes *attr_ptr = cur_node->attributes;
+
409 attr_ptr->current = NULL;
+
410
+
411 attr_ptr->str = strdup_wrap(line_ptr);
+
412 if (!attr_ptr->str)
+
413 {
+
414 free_incomplete_node(&cur_node);
+
415 break;
+
416 }
+
417
+
418 attr_ptr->iter_ptr = attr_ptr->str;
+
419
+
420 // Change the delimiter, which will be used later
+
421 // in canfigger_free_current_attr_str_advance()
+
422 char *delimiter_ptr = strchr(attr_ptr->iter_ptr, delimiter);
+
423 while (delimiter_ptr)
+
424 {
+
425 *delimiter_ptr = '\n';
+
426 delimiter_ptr = strchr(delimiter_ptr, delimiter);
+
427 }
+
428 }
+
429 else
+
430 cur_node->attributes = NULL;
+
431
+
432 cur_node->next = NULL;
+
433 node_complete = true;
+
434 }
+
435
+
436 if (!root)
+
437 return NULL;
+
438
+
439 if (!node_complete)
+
440 {
+
441 free_list(&root);
+
442 return NULL;
+
443 }
+
444
+
445 return root;
+
446}
+
+
Header file for the Canfigger configuration parser.
+
void canfigger_free_current_key_node_advance(struct Canfigger **list)
Frees the current key node and advances to the next node in the list.
Definition canfigger.c:114
+
struct Canfigger * canfigger_parse_file(const char *file, const int delimiter)
Parses a configuration file and creates a linked list of key-value pairs.
Definition canfigger.c:330
+
Structure to represent a key-value pair with attributes in the configuration.
Definition canfigger.h:60
+
Structure to hold attribute details of a configuration key.
Definition canfigger.h:44
+
+ + + + diff --git a/docs/canfigger_8h.html b/docs/canfigger_8h.html index f59b75e..7ff8935 100644 --- a/docs/canfigger_8h.html +++ b/docs/canfigger_8h.html @@ -23,7 +23,7 @@ -
canfigger v0.3.0 +
canfigger v0.3.x
Lightweight config file parser library
@@ -113,6 +113,8 @@

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

+ +

Definition in file canfigger.h.


Data Structure Documentation

◆ attributes

@@ -126,6 +128,8 @@

diff --git a/docs/files.html b/docs/files.html index abda14e..e95eae0 100644 --- a/docs/files.html +++ b/docs/files.html @@ -23,7 +23,7 @@ @@ -77,7 +77,9 @@
Here is a list of all documented files with brief descriptions:
Data Fields
@@ -164,6 +168,8 @@

◆& @@ -107,11 +107,11 @@
82
-
void canfigger_free_current_key_node_advance(struct Canfigger **list)
Frees the current key node and advances to the next node in the list.
Definition canfigger.c:115
-
struct Canfigger * canfigger_parse_file(const char *file, const int delimiter)
Parses a configuration file and creates a linked list of key-value pairs.
Definition canfigger.c:330
-
void canfigger_free_current_attr_str_advance(struct attributes *attributes, char **attr)
Frees the current attribute string and advances to the next attribute.
Definition canfigger.c:86
-
Structure to represent a key-value pair with attributes in the configuration.
Definition canfigger.h:60
-
Structure to hold attribute details of a configuration key.
Definition canfigger.h:44
+
void canfigger_free_current_key_node_advance(struct Canfigger **list)
Frees the current key node and advances to the next node in the list.
Definition canfigger.c:114
+
struct Canfigger * canfigger_parse_file(const char *file, const int delimiter)
Parses a configuration file and creates a linked list of key-value pairs.
Definition canfigger.c:330
+
void canfigger_free_current_attr_str_advance(struct attributes *attributes, char **attr)
Frees the current attribute string and advances to the next attribute.
Definition canfigger.c:75
+
Structure to represent a key-value pair with attributes in the configuration.
Definition canfigger.h:60
+
Structure to hold attribute details of a configuration key.
Definition canfigger.h:44
@@ -82,7 +82,7 @@
int
main(int argc, char *argv[])
{
-
char *default_filename = "../examplerc";
+
char *default_filename = SOURCE_DIR "/examplerc";
char *filename_ptr = default_filename;
if (argc == 2)
@@ -108,6 +108,9 @@
if (!config)
return -1;
+
// i is only used for testing
+
int i = 0;
+
while (config != NULL)
{
//
@@ -118,7 +121,12 @@
config->value != NULL ? config->value : "NULL");
//
-
// Process attributes if necessary
+
// Process attributes if necessary. If you know there are no attributes
+
// for the current node, you can skip this, and there is no reason in
+
// this case to call canfigger_free_current_attr_str_advance().
+
//
+
// attr must be declared and initialized before using it as an
+
// argument to canfigger_free_current_attr_str_advance().
char *attr = NULL;
//
// Pass '&addr' to this function and it will get assigned an
@@ -137,15 +145,21 @@
// Move to the next node and automatically free the current node
putchar('\n');
+
+
i++;
}
+
// This should be the number of keys in the example config
+
if (i != 6)
+
return -1;
+
return 0;
}
Header file for the Canfigger configuration parser.
-
void canfigger_free_current_key_node_advance(struct Canfigger **list)
Frees the current key node and advances to the next node in the list.
Definition canfigger.c:115
-
struct Canfigger * canfigger_parse_file(const char *file, const int delimiter)
Parses a configuration file and creates a linked list of key-value pairs.
Definition canfigger.c:330
-
void canfigger_free_current_attr_str_advance(struct attributes *attributes, char **attr)
Frees the current attribute string and advances to the next attribute.
Definition canfigger.c:86
-
Structure to represent a key-value pair with attributes in the configuration.
Definition canfigger.h:60
+
void canfigger_free_current_key_node_advance(struct Canfigger **list)
Frees the current key node and advances to the next node in the list.
Definition canfigger.c:114
+
struct Canfigger * canfigger_parse_file(const char *file, const int delimiter)
Parses a configuration file and creates a linked list of key-value pairs.
Definition canfigger.c:330
+
void canfigger_free_current_attr_str_advance(struct attributes *attributes, char **attr)
Frees the current attribute string and advances to the next attribute.
Definition canfigger.c:75
+
Structure to represent a key-value pair with attributes in the configuration.
Definition canfigger.h:60
Data Fields
@@ -218,39 +224,15 @@

Parameters
- +
attributesPointer to the attributes structure of the current node.
Currentattribute that will get reassigned after the function call.
attrCurrent attribute that will get reassigned after the function call.
Examples
example.c.
-
87{
-
88 if (!attributes)
-
89 {
-
90 *attr = NULL;
-
91 return;
-
92 }
-
93
-
94 if (attributes->current && attributes->iter_ptr)
-
95 free(attributes->current);
-
96
-
97 if (!attributes->iter_ptr)
-
98 {
-
99 free(attributes->current);
-
100 attributes->current = NULL;
-
101 *attr = NULL;
-
102 return;
-
103 }
-
104
-
105 attributes->iter_ptr = grab_str_segment(attributes->iter_ptr,
-
106 &attributes->current,
-
107 '\n');
-
108
-
109 *attr = attributes->current;
-
110 return;
-
111}
-
Structure to hold attribute details of a configuration key.
Definition canfigger.h:44
-
+ +

Definition at line 75 of file canfigger.c.

+ @@ -277,45 +259,9 @@

Examples
example.c.
-
116{
-
117 if (*node)
-
118 {
-
119 if ((*node)->attributes)
-
120 {
-
121 if ((*node)->attributes->current)
-
122 {
-
123 free((*node)->attributes->current);
-
124 (*node)->attributes->current = NULL;
-
125 }
-
126
-
127 if ((*node)->attributes->str)
-
128 {
-
129 free((*node)->attributes->str);
-
130 (*node)->attributes->str = NULL;
-
131 }
-
132
-
133 free((*node)->attributes);
-
134 (*node)->attributes = NULL;
-
135 }
-
136
-
137 if ((*node)->value)
-
138 {
-
139 free((*node)->value);
-
140 (*node)->value = NULL;
-
141 }
-
142
-
143 free((*node)->key);
-
144 (*node)->key = NULL;
-
145
-
146 struct Canfigger *temp_node = (*node)->next;
-
147 free(*node);
-
148 *node = temp_node;
-
149 }
-
150
-
151 return;
-
152}
-
Structure to represent a key-value pair with attributes in the configuration.
Definition canfigger.h:60
-
+ +

Definition at line 114 of file canfigger.c.

+ @@ -348,123 +294,9 @@

Returns
Pointer to the head of the linked list of configuration entries.
Examples
example.c.
-
331{
-
332 struct Canfigger *root = NULL, *cur_node = NULL;
-
333
-
334 char *buffer = read_entire_file(file);
-
335 if (buffer == NULL)
-
336 return NULL;
-
337
-
338 char file_contents[strlen(buffer) + 1];
-
339 memcpy(file_contents, buffer, sizeof file_contents);
-
340 free(buffer);
-
341
-
342 struct line line;
-
343 line.start = file_contents;
-
344 line.end = strchr(line.start, '\n');
-
345
-
346 bool node_complete;
-
347
-
348 while (line.end)
-
349 {
-
350 line.len = line.end - line.start;
-
351 char tmp_line[line.len + 1];
-
352 memcpy(tmp_line, line.start, line.len);
-
353 tmp_line[line.len] = '\0';
-
354
-
355 // Used in the next loop
-
356 if (line.end)
-
357 {
-
358 line.start = line.end + 1;
-
359 line.end = strchr(line.start, '\n');
-
360 }
-
361
-
362 char *line_ptr = tmp_line;
-
363 truncate_whitespace(line_ptr);
-
364
-
365 while (isspace(*line_ptr))
-
366 line_ptr = erase_lead_char(*line_ptr, line_ptr);
-
367
-
368 if (*line_ptr == '\0' || *line_ptr == '#')
-
369 continue;
-
370
-
371 node_complete = false;
-
372 add_key_node(&root, &cur_node);
-
373 if (!cur_node)
-
374 break;
-
375
-
376 // Get key
-
377 cur_node->key = NULL;
-
378 line_ptr = grab_str_segment(line_ptr, &cur_node->key, '=');
-
379 if (!cur_node->key)
-
380 {
-
381 free_incomplete_node(&cur_node);
-
382 break;
-
383 }
-
384
-
385 // Get value
-
386 cur_node->value = NULL;
-
387
-
388 if (line_ptr)
-
389 {
-
390 line_ptr = grab_str_segment(line_ptr, &cur_node->value, delimiter);
-
391 if (!cur_node->value)
-
392 {
-
393 free_incomplete_node(&cur_node);
-
394 break;
-
395 }
-
396 }
-
397
-
398 // Handle attributes
-
399 if (line_ptr)
-
400 {
-
401 cur_node->attributes = malloc_wrap(sizeof(struct attributes));
-
402 if (!cur_node->attributes)
-
403 {
-
404 free_incomplete_node(&cur_node);
-
405 break;
-
406 }
-
407
-
408 struct attributes *attr_ptr = cur_node->attributes;
-
409 attr_ptr->current = NULL;
-
410
-
411 attr_ptr->str = strdup_wrap(line_ptr);
-
412 if (!attr_ptr->str)
-
413 {
-
414 free_incomplete_node(&cur_node);
-
415 break;
-
416 }
-
417
-
418 attr_ptr->iter_ptr = attr_ptr->str;
-
419
-
420 // Change the delimiter, which will be used later
-
421 // in canfigger_free_current_attr_str_advance()
-
422 char *delimiter_ptr = strchr(attr_ptr->iter_ptr, delimiter);
-
423 while(delimiter_ptr)
-
424 {
-
425 *delimiter_ptr = '\n';
-
426 delimiter_ptr = strchr(delimiter_ptr, delimiter);
-
427 }
-
428 }
-
429 else
-
430 cur_node->attributes = NULL;
-
431
-
432 cur_node->next = NULL;
-
433 node_complete = true;
-
434 }
-
435
-
436 if (!root)
-
437 return NULL;
-
438
-
439 if (!node_complete)
-
440 {
-
441 free_list(&root);
-
442 return NULL;
-
443 }
-
444
-
445 return root;
-
446}
-
+ +

Definition at line 330 of file canfigger.c.

+ diff --git a/docs/canfigger_8h_source.html b/docs/canfigger_8h_source.html index 67b0936..f7a3012 100644 --- a/docs/canfigger_8h_source.html +++ b/docs/canfigger_8h_source.html @@ -23,7 +23,7 @@

-
canfigger v0.3.0 +
canfigger v0.3.x
Lightweight config file parser library
-
canfigger v0.3.0 +
canfigger v0.3.x
Lightweight config file parser library
+ + + + + +
+
canfigger v0.3.x +
+
Lightweight config file parser library
+
+ + + + + + + + + + + +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
example.c
+
+
+
1#include <stdio.h>
+
2
+
3#include "canfigger.h"
+
4
+
5int
+
6main(int argc, char *argv[])
+
7{
+
8 char *default_filename = SOURCE_DIR "/examplerc";
+
9 char *filename_ptr = default_filename;
+
10
+
11 if (argc == 2)
+
12 filename_ptr = argv[1];
+
13
+
14 if (argc > 2)
+
15 {
+
16 fputs("This example program only accepts a single argument:\n\n", stderr);
+
17 fprintf(stderr, "%s <config-file>\n\n", argv[0]);
+
18 return -1;
+
19 }
+
20
+
21 //
+
22 // Get a linked list containing the parsed config file. Each node contains
+
23 // a key (or a "setting", or an "option"), a value and attributes (if they
+
24 // are provided in your program's configuration file.
+
25 //
+
26 // The second argument is based on what the config file uses to separate
+
27 // the attributes.
+
28 //
+
29 struct Canfigger *config = canfigger_parse_file(filename_ptr, ',');
+
30
+
31 if (!config)
+
32 return -1;
+
33
+
34 // i is only used for testing
+
35 int i = 0;
+
36
+
37 while (config != NULL)
+
38 {
+
39 //
+
40 // The value member of the node must be checked for NULL
+
41 // before using it.
+
42 //
+
43 printf("Key: %s, Value: %s\n", config->key,
+
44 config->value != NULL ? config->value : "NULL");
+
45
+
46 //
+
47 // Process attributes if necessary. If you know there are no attributes
+
48 // for the current node, you can skip this, and there is no reason in
+
49 // this case to call canfigger_free_current_attr_str_advance().
+
50 //
+
51 // attr must be declared and initialized before using it as an
+
52 // argument to canfigger_free_current_attr_str_advance().
+
53 char *attr = NULL;
+
54 //
+
55 // Pass '&addr' to this function and it will get assigned an
+
56 // attribute, or NULL if there are none.
+
57 canfigger_free_current_attr_str_advance(config->attributes, &attr);
+
58 while (attr)
+
59 {
+
60 printf("Attribute: %s\n", attr);
+
61
+
62 //
+
63 // Get the next attribute in the list (if there is one).
+
64 //
+
65 canfigger_free_current_attr_str_advance(config->attributes, &attr);
+
66 }
+
67
+
68 // Move to the next node and automatically free the current node
+ +
70 putchar('\n');
+
71
+
72 i++;
+
73 }
+
74
+
75 // This should be the number of keys in the example config
+
76 if (i != 6)
+
77 return -1;
+
78
+
79 return 0;
+
80}
+
Header file for the Canfigger configuration parser.
+
void canfigger_free_current_key_node_advance(struct Canfigger **list)
Frees the current key node and advances to the next node in the list.
Definition canfigger.c:114
+
struct Canfigger * canfigger_parse_file(const char *file, const int delimiter)
Parses a configuration file and creates a linked list of key-value pairs.
Definition canfigger.c:330
+
void canfigger_free_current_attr_str_advance(struct attributes *attributes, char **attr)
Frees the current attribute string and advances to the next attribute.
Definition canfigger.c:75
+
Structure to represent a key-value pair with attributes in the configuration.
Definition canfigger.h:60
+
+ + + + diff --git a/docs/examples.html b/docs/examples.html index 9d3a3fb..78aa805 100644 --- a/docs/examples.html +++ b/docs/examples.html @@ -23,7 +23,7 @@

-
canfigger v0.3.0 +
canfigger v0.3.x
Lightweight config file parser library
-
canfigger v0.3.0 +
canfigger v0.3.x
Lightweight config file parser library
- + + +
 canfigger.hHeader file for the Canfigger configuration parser
 canfigger.c
 canfigger.hHeader file for the Canfigger configuration parser
 example.c
diff --git a/docs/globals.html b/docs/globals.html index cad66d1..1d394c4 100644 --- a/docs/globals.html +++ b/docs/globals.html @@ -23,7 +23,7 @@ -
canfigger v0.3.0 +
canfigger v0.3.x
Lightweight config file parser library
diff --git a/docs/globals_func.html b/docs/globals_func.html index ff36217..3c77fb3 100644 --- a/docs/globals_func.html +++ b/docs/globals_func.html @@ -23,7 +23,7 @@ -
canfigger v0.3.0 +
canfigger v0.3.x
Lightweight config file parser library
diff --git a/docs/index.html b/docs/index.html index 6417543..fe667fa 100644 --- a/docs/index.html +++ b/docs/index.html @@ -23,7 +23,7 @@ -
canfigger v0.3.0 +
canfigger v0.3.x
Lightweight config file parser library
@@ -75,9 +75,9 @@
canfigger
-

![codeql-badge] ![actions-c-badge]

+

![codeql-badge] ![actions-c-badge] ![cirrus-badge]

-canfigger v0.3.0999

+canfigger v0.3.0

Canfigger is a lightweight C language library designed to parse configuration files. It provides functionality to read them and represent their contents as a linked list of key-value pairs, along with associated attributes for each pair.

  • website/API documentation and examples
  • @@ -116,6 +116,10 @@

    Example program

    An example program will be built when you run ninja. It will read examplerc in the source root directory. If you want to try it with a different config file, give example the name of a config file as an argument.

    +Using canfigger in your project

    +

    If canfigger is not available for your operating system or distribution, you can copy the required sources (and the LICENSE file) into your project and add them to your build system. The line include <config.h> from the top of the .c file will need to be removed, as it is normally generated during the Meson setup and only contains version information.

    +

    Alternatively, if your project uses Meson, you can add a wrap file for canfigger in your 'subprojects' directory.

    +

    Projects using canfigger

    • rmw
    • diff --git a/docs/search/all_0.js b/docs/search/all_0.js index 694e604..a48788b 100644 --- a/docs/search/all_0.js +++ b/docs/search/all_0.js @@ -1,4 +1,4 @@ var searchData= [ - ['0999_0',['canfigger v0.3.0999',['../index.html#autotoc_md0',1,'']]] + ['0_0',['canfigger v0.3.0',['../index.html#autotoc_md0',1,'']]] ]; diff --git a/docs/search/all_1.js b/docs/search/all_1.js index 0aae812..52ae696 100644 --- a/docs/search/all_1.js +++ b/docs/search/all_1.js @@ -1,4 +1,4 @@ var searchData= [ - ['3_200999_0',['canfigger v0.3.0999',['../index.html#autotoc_md0',1,'']]] + ['3_200_0',['canfigger v0.3.0',['../index.html#autotoc_md0',1,'']]] ]; diff --git a/docs/search/all_4.js b/docs/search/all_4.js index 7c8f785..71fc6a3 100644 --- a/docs/search/all_4.js +++ b/docs/search/all_4.js @@ -2,10 +2,11 @@ var searchData= [ ['canfigger_0',['Canfigger',['../canfigger_8h.html#structCanfigger',1,'']]], ['canfigger_1',['canfigger',['../index.html',1,'']]], - ['canfigger_2',['Projects using canfigger',['../index.html#autotoc_md6',1,'']]], - ['canfigger_20v0_203_200999_3',['canfigger v0.3.0999',['../index.html#autotoc_md0',1,'']]], - ['canfigger_2eh_4',['canfigger.h',['../canfigger_8h.html',1,'']]], - ['canfigger_5ffree_5fcurrent_5fattr_5fstr_5fadvance_5',['canfigger_free_current_attr_str_advance',['../canfigger_8h.html#ae6d70f9e366beaa126a989bb2b4457b8',1,'canfigger.c']]], - ['canfigger_5ffree_5fcurrent_5fkey_5fnode_5fadvance_6',['canfigger_free_current_key_node_advance',['../canfigger_8h.html#a095f7a89a1f2e3422870165280205a0b',1,'canfigger.c']]], - ['canfigger_5fparse_5ffile_7',['canfigger_parse_file',['../canfigger_8h.html#a37053197894e04e253629a9bdae52da0',1,'canfigger.c']]] + ['canfigger_2',['Projects using canfigger',['../index.html#autotoc_md7',1,'']]], + ['canfigger_20in_20your_20project_3',['Using canfigger in your project',['../index.html#autotoc_md6',1,'']]], + ['canfigger_20v0_203_200_4',['canfigger v0.3.0',['../index.html#autotoc_md0',1,'']]], + ['canfigger_2eh_5',['canfigger.h',['../canfigger_8h.html',1,'']]], + ['canfigger_5ffree_5fcurrent_5fattr_5fstr_5fadvance_6',['canfigger_free_current_attr_str_advance',['../canfigger_8h.html#ae6d70f9e366beaa126a989bb2b4457b8',1,'canfigger.c']]], + ['canfigger_5ffree_5fcurrent_5fkey_5fnode_5fadvance_7',['canfigger_free_current_key_node_advance',['../canfigger_8h.html#a095f7a89a1f2e3422870165280205a0b',1,'canfigger.c']]], + ['canfigger_5fparse_5ffile_8',['canfigger_parse_file',['../canfigger_8h.html#a37053197894e04e253629a9bdae52da0',1,'canfigger.c']]] ]; diff --git a/docs/search/all_8.js b/docs/search/all_8.js index 3deaa9e..3086cfd 100644 --- a/docs/search/all_8.js +++ b/docs/search/all_8.js @@ -1,5 +1,4 @@ var searchData= [ - ['program_0',['Example program',['../index.html#autotoc_md5',1,'']]], - ['projects_20using_20canfigger_1',['Projects using canfigger',['../index.html#autotoc_md6',1,'']]] + ['in_20your_20project_0',['Using canfigger in your project',['../index.html#autotoc_md6',1,'']]] ]; diff --git a/docs/search/all_9.js b/docs/search/all_9.js index 8712813..88532f9 100644 --- a/docs/search/all_9.js +++ b/docs/search/all_9.js @@ -1,4 +1,6 @@ var searchData= [ - ['tests_0',['Tests',['../index.html#autotoc_md4',1,'']]] + ['program_0',['Example program',['../index.html#autotoc_md5',1,'']]], + ['project_1',['Using canfigger in your project',['../index.html#autotoc_md6',1,'']]], + ['projects_20using_20canfigger_2',['Projects using canfigger',['../index.html#autotoc_md7',1,'']]] ]; diff --git a/docs/search/all_a.js b/docs/search/all_a.js index f0e8d0e..8712813 100644 --- a/docs/search/all_a.js +++ b/docs/search/all_a.js @@ -1,4 +1,4 @@ var searchData= [ - ['using_20canfigger_0',['Projects using canfigger',['../index.html#autotoc_md6',1,'']]] + ['tests_0',['Tests',['../index.html#autotoc_md4',1,'']]] ]; diff --git a/docs/search/all_b.js b/docs/search/all_b.js index ce8c0f9..11dabf4 100644 --- a/docs/search/all_b.js +++ b/docs/search/all_b.js @@ -1,4 +1,5 @@ var searchData= [ - ['v0_203_200999_0',['canfigger v0.3.0999',['../index.html#autotoc_md0',1,'']]] + ['using_20canfigger_0',['Projects using canfigger',['../index.html#autotoc_md7',1,'']]], + ['using_20canfigger_20in_20your_20project_1',['Using canfigger in your project',['../index.html#autotoc_md6',1,'']]] ]; diff --git a/docs/search/all_c.js b/docs/search/all_c.js new file mode 100644 index 0000000..f08a3ba --- /dev/null +++ b/docs/search/all_c.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['v0_203_200_0',['canfigger v0.3.0',['../index.html#autotoc_md0',1,'']]] +]; diff --git a/docs/search/all_d.js b/docs/search/all_d.js new file mode 100644 index 0000000..887f056 --- /dev/null +++ b/docs/search/all_d.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['your_20project_0',['Using canfigger in your project',['../index.html#autotoc_md6',1,'']]] +]; diff --git a/docs/search/searchdata.js b/docs/search/searchdata.js index 2e270cb..183ca1f 100644 --- a/docs/search/searchdata.js +++ b/docs/search/searchdata.js @@ -1,6 +1,6 @@ var indexSectionsWithContent = { - 0: "03abcdefptuv", + 0: "03abcdefiptuvy", 1: "ac", 2: "c", 3: "c", diff --git a/doxygen/Doxyfile b/doxygen/Doxyfile index 089ff4a..b3f6072 100644 --- a/doxygen/Doxyfile +++ b/doxygen/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = "canfigger" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = v0.3.0 +PROJECT_NUMBER = v0.3.x # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -1187,14 +1187,14 @@ FORTRAN_COMMENT_AFTER = 72 # also VERBATIM_HEADERS is set to NO. # The default value is: NO. -SOURCE_BROWSER = NO +SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body of functions, # multi-line macros, enums or list initialized variables directly into the # documentation. # The default value is: NO. -INLINE_SOURCES = YES +INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and diff --git a/example.c b/example.c index 5c18fa7..fbfcd96 100644 --- a/example.c +++ b/example.c @@ -1,6 +1,5 @@ #include -#include "test.h" // Used for canfigger test, not normally needed #include "canfigger.h" int @@ -45,7 +44,12 @@ main(int argc, char *argv[]) config->value != NULL ? config->value : "NULL"); // - // Process attributes if necessary + // Process attributes if necessary. If you know there are no attributes + // for the current node, you can skip this, and there is no reason in + // this case to call canfigger_free_current_attr_str_advance(). + // + // attr must be declared and initialized before using it as an + // argument to canfigger_free_current_attr_str_advance(). char *attr = NULL; // // Pass '&addr' to this function and it will get assigned an @@ -69,7 +73,8 @@ main(int argc, char *argv[]) } // This should be the number of keys in the example config - assert(i == 6); + if (i != 6) + return -1; return 0; } diff --git a/meson.build b/meson.build index e1e9572..fbb2eca 100644 --- a/meson.build +++ b/meson.build @@ -1,12 +1,12 @@ project( 'canfigger', 'c', - version: '0.3.0999', + version: '0.3.0', meson_version : '>= 0.48.0', default_options: [ 'warning_level=3', - 'b_sanitize=address,undefined', - 'b_lundef=false' +# 'b_sanitize=address,undefined', +# 'b_lundef=false' ] ) @@ -70,7 +70,6 @@ if get_option('build_examples') 'example', 'example.c', dependencies: canfigger_dep, - include_directories: 'tests', c_args: '-DSOURCE_DIR="@0@"'.format(meson.current_source_dir()) ) endif diff --git a/tests/meson.build b/tests/meson.build index a0cc9a2..079886b 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -3,12 +3,13 @@ incdir = include_directories('..') main_lib = declare_dependency(link_with : buildtarget) test_cases = [ - 'parse_file', + 'colons', 'file_open_err', 'german', - 'colons', - 'unicode', 'multiple_attributes', + 'parse_file', + 'skip_attributes', + 'unicode', ] foreach case : test_cases diff --git a/tests/skip_attributes.c b/tests/skip_attributes.c new file mode 100644 index 0000000..d5f80cd --- /dev/null +++ b/tests/skip_attributes.c @@ -0,0 +1,23 @@ +#include "test.h" + +// When built with sanitize enabled, this test will fail if all structs and +// and members aren't freed before exiting. + +int +main(void) +{ + // call the primary library function to read your config file + struct Canfigger *list = canfigger_parse_file(SOURCE_DIR "/multiple_attributes.conf", ','); + assert (list); + + int i = 0; + while (list) + { + canfigger_free_current_key_node_advance(&list); + i++; + } + + assert(i == 3); + + return 0; +}