summaryrefslogtreecommitdiff
path: root/lib/include/libcfg.h
blob: 8096f1be68b5406bbfd610d371bc0d6f50003ca6 (plain)
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
/* SPDX-License-Identifier: GPL-3.0-or-later */
/*
 * Copyright (C) 2018 - David Oberhollenzer
 *
 * 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
 * (at your option) 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 <https://www.gnu.org/licenses/>.
 */
#ifndef LIBCONFIG_H
#define LIBCONFIG_H

#include <stdbool.h>
#include <stddef.h>

typedef struct {
	int fd;			/* input file descriptor */
	const char *argstr;	/* if not NULL, read from this instead */

	const char *filename;	/* input file name */
	size_t lineno;		/* current line number */

	size_t i;		/* buffer offset */
	char buffer[256];	/* current line, null-terminated */

	int argc;
	const char *const *argv;

	bool string;		/* inside a string? */
	bool escape;		/* reading an escape sequence? */
	bool comment;		/* inside a comment */
} rdline_t;

typedef struct {
	/* keyword to map the callback to */
	const char *key;

	/*
		If set, allow grouping repetitions of the keyword in a single
		multi line '{' ... '}' block. The callback is called for each
		line.
	 */
	unsigned int allow_block : 1;

	int (*handle)(void *obj, char *arg, rdline_t *rd, int flags);
} cfg_param_t;

/*
	Initialize the config line scanner.

	The scanner reads from the provided fd. The filename is used for
	error reporting. An argument count and vector can be set for argument
	substitution in rdline.
*/
void rdline_init(rdline_t *t, int fd, const char *filename,
		 int argc, const char *const *argv);

/*
	Read from file until end-of-file or a line feed is encountered.

	Returns -1 on failure, +1 if end of file was reached,
	0 if data was read successfully.

	The following transformations are applied:
	 - Space characters are replaced with regular white space characters.
	 - Sequences of space characters are truncated to a single space.
	 - A '#' sign is interpreted as the start of a comment and removed,
	   together with everything that follows.
	 - Padding spaces are removed from the line.
	 - If a '"' is encounterd, the above rules are disabled, until a
	   after the matching '"' is read. A '"' can be escaped by preceeding
	   it with a backslash.
	 - If a second, coresponding '"' is not found, processing fails.
	 - If a '%' character is encountered, the next character is expected
	   to be a single digit index into argv. If it is not a digit or
	   outside the bounds set by argc, processing fails. On success,
	   the argv value is inserted and processed as described above.
	 - A '%' character can be escaped by writing '%%' or, if inside
	   a double quite string, by writing \%.
	 - An attempt to use such an indexed argument inside an argument
	   expansion, results in failure.
	 - If the resulting line is empty, processing is restarted.
*/
int rdline(rdline_t *t);

/*
	Remove double quotes ('"') from a string and substitute escape
	sequences in between double quotes.
*/
int unescape(char *src);

/*
	Replace spaces in 'str' with null bytes. Tread strings (started and
	terminated with double-quotes which can be escaped) as a single block.
	Such strings are run through unescap(). All elements are tightly
	packed together and the function returns the number of consecutive
	argument strings that are now inside 'str'.

	Returns a negative value if unescape() fails, a string is not
	termianted or two such strings touch each other without a white
	space in between.
*/
int pack_argv(char *str);

/*
	Split the current input line into a space seperted keyword
	(alphabetical characters only) and a value (the rest of the line).

	If errors are encounted, prints a diagnostic message to stderr and
	returns -1. On success, zero is returned.
 */
int splitkv(rdline_t *rd, char **k, char **v);

/*
	Parse a configuration file containing '<keyword> [arguments...]' lines.
	The cfgobj and flags are passed to the callback in the params array.

	Returns zero on success.
 */
int rdcfg(void *cfgobj, rdline_t *rd, const cfg_param_t *params, size_t count,
	  int flags);

#endif /* LIBCONFIG_H */