1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
/*
* Copyright (c) 2021 Yaroslav de la Peña Smirnov
*
* Released under the GNU Lesser General Public License, version 2.1 only.
* For more information see `LICENSE' or visit
* https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
*/
#ifndef PARCINI_H
#define PARCINI_H
#include <stdio.h>
#include <stdbool.h>
#include <sys/types.h>
/* You can choose to use a different character for comments (e.g. ';') at
* compile time */
#ifndef PARCINI_COMMENT_CHAR
#define PARCINI_COMMENT_CHAR '#'
#endif
/*
* An opaque structure that represents an instance of a "parcini" ini parser,
* used to parse a stream.
*/
typedef struct parcini parcini_t;
/*
* All possible values to be returned by parcini_parse_next_line.
*/
enum parcini_result {
/* A line with only whitespace and/or a comment */
PARCINI_EMPTY_LINE,
/* There are no more lines to parse */
PARCINI_EOF,
/* A section. parcini_line.key shall be NULL and parcini_line.value.type
* shalle be PARCINI_VALUE_NONE */
PARCINI_SECTION,
/* Key/value. parcini_line.key contains the name of the key, and
* parcini_line.value contains the type and actual value. */
PARCINI_KEYVALUE,
/* A call to malloc/realloc failed. errno might be set */
PARCINI_MEMORY_ERROR,
/* An error other than EOF occured when attempting to read the stream. errno
* might be set */
PARCINI_STREAM_ERROR,
/* What seemed to start as a key is incorrectly formated, and thus couldn't
* be parsed correctly. */
PARCINI_KEY_PARSE_ERROR,
/* Where a value should have followed a key, there is none, or it is
* incorrectly formated, and thus couldn't be parsed correctly. */
PARCINI_VALUE_PARSE_ERROR,
/* The value is an integer number that couldn't be parsed correctly due to
* it being out of the range of a long int */
PARCINI_VALUE_RANGE_ERROR,
/* What seemed to be a line containing a section name, wasn't formatted
* correctly and thus couldn't be parsed. */
PARCINI_SECTION_PARSE_ERROR,
};
enum parcini_value_type {
/* There is no value */
PARCINI_VALUE_NONE,
/* The value is long int */
PARCINI_VALUE_INTEGER,
/* The value is bool */
PARCINI_VALUE_BOOLEAN,
/* The value is pointer to char */
PARCINI_VALUE_STRING,
};
/*
* A tagged union-like structure representing a parsed value. Accessing a .value
* member for which the type is not set is undefined behaviour (beware of the
* char *, it could segfault your program).
*/
struct parcini_value {
enum parcini_value_type type;
union {
long int integer;
bool boolean;
char *string;
} value;
};
/*
* This structure should be passed as a pointer to parcini_parse_next_line so
* that it is filled with the parsed information. The pointers here MUST NOT be
* manually freed. See function parcini_parse_next_line for more details.
*/
struct parcini_line {
size_t lineno;
char *section;
char *key;
struct parcini_value value;
};
/*
* Helper function to handle a value that was parsed by parcini. Pass a pointer
* of a parcini_value, and the expected type. If the parcini_value typematches
* the expected type, then *dst is set to the provided value casting it to the
* correct type.
*
* IMPORTANT: in the case of "string" values, you need to pass a pointer to a
* char pointer (i.e. char **), and the memory in the string value is copied
* over to the char *. That means, that if some memory was already allocated in
* the passed pointer, there could be a memory leak if you don't free that
* memory before, unless you have another pointer to that same memory elsewhere.
*/
bool parcini_value_handle(const struct parcini_value *,
const enum parcini_value_type expected, void *dst);
/*
* Parse the next line in the stream returning the kind of result/error of
* parsing and filling the parcini_line structure with the information that was
* extracted from the line, as well as the current section (including after
* parsing a key/value line) and line number.
*
* If you need the information returned to last after the next call to this
* function, or after the destruction of the parcini_t parser instance, then you
* should copy it to a different variable/pointer before parsing the next
* line/freeing your parser instance. This data also MUST NOT be manually freed
* by the caller.
*/
enum parcini_result parcini_parse_next_line(parcini_t *, struct parcini_line *);
/*
* Main function through which you initialize a parcini_t parser object, before
* you can parse the stream line by line.
*/
parcini_t *parcini_init(FILE *stream);
/*
* Helper function to open a file and then initialize a parcini_t object with
* said as the source stream. Returns NULL if the file couldn't be opened.
*/
parcini_t *parcini_from_file(const char *fpath);
/*
* Helper function to initialize a parcini_t object with said string of said
* size open as a stream.
*/
parcini_t *parcini_from_string(const char *, const size_t);
/*
* Free all memory related to the parcini_t instance. IMPORTANT: this will also
* close the stream passed to parcini_init, so if you manually opened a file and
* then passed it to parcini_init, it WILL NOT be valid after a call to
* parcini_destroy.
*/
void parcini_destroy(parcini_t *);
#endif
|