summaryrefslogtreecommitdiff
path: root/src/sp_config_utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sp_config_utils.c')
-rw-r--r--src/sp_config_utils.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/src/sp_config_utils.c b/src/sp_config_utils.c
new file mode 100644
index 0000000..e05e95e
--- /dev/null
+++ b/src/sp_config_utils.c
@@ -0,0 +1,211 @@
1#include "php_snuffleupagus.h"
2
3static int validate_int(const char *value);
4static int validate_str(const char *value);
5
6static sp_pure int validate_int(const char *value) {
7 for (size_t i = 0; i < strlen(value); i++) {
8 if (!isdigit(value[i])) {
9 return -1;
10 }
11 }
12 return 0;
13}
14
15static sp_pure int validate_str(const char *value) {
16 int balance = 0; // ghetto [] validation
17
18 if (!strchr(value, '[')) {
19 return 0;
20 }
21
22 for (size_t i = 0; i < strlen(value); i++) {
23 if (value[i] == '[') {
24 balance++;
25 } else if (value[i] == ']') {
26 balance--;
27 }
28 if (balance < 0) {
29 return -1;
30 }
31 }
32 return balance != 0;
33}
34
35int parse_keywords(sp_config_functions *funcs, char *line) {
36 int value_len = 0;
37 const char *original_line = line;
38 for (size_t i = 0; funcs[i].func; i++) {
39 if (!strncmp(funcs[i].token, line, strlen(funcs[i].token))) {
40 line += strlen(funcs[i].token);
41 value_len = funcs[i].func(line, funcs[i].token, funcs[i].retval) + 1;
42 if (value_len == 0) { // bad parameter
43 return -1;
44 }
45 line += value_len;
46 i = -1; // we start the loop again
47 }
48 }
49 while (*line == ';' || *line == '\t' || *line == ' ') {
50 line++;
51 }
52
53 if (*line == '#') {
54 return 0;
55 }
56
57 if (*line) {
58 sp_log_err("config", "Trailing chars '%s' at the end of '%s'.", line,
59 original_line);
60 return -1;
61 }
62 return 0;
63}
64
65static char *get_string(size_t *consumed, char *restrict line,
66 const char *restrict keyword) {
67 enum { IN_ESCAPE, NONE } state = NONE;
68 char *original_line = line;
69 size_t j = 0;
70
71 char *ret = NULL;
72 if (NULL == line) {
73 goto err;
74 }
75
76 ret = pecalloc(sizeof(char), strlen(original_line) + 1, 1);
77
78 /* The first char of a string is always '"', since they MUST be quoted. */
79 if ('"' == *line) {
80 line++;
81 } else {
82 goto err;
83 }
84
85 for (size_t i = 0; line[i] && j < strlen(original_line) - 2; i++) {
86 switch (line[i]) {
87 case '"':
88 /* A double quote at this point is either:
89 - at the very end of the string.
90 - escaped
91 */
92 if ((state == NONE) && (line[i + 1] == SP_TOKEN_END_PARAM)) {
93 /* The `+2` if for
94 1. the terminal double-quote
95 2. the SP_TOKEN_END_PARAM
96 */
97 *consumed = i + 2;
98 return ret;
99 } else if (state == IN_ESCAPE) {
100 break; // we're on an escped double quote
101 } else {
102 goto err;
103 }
104 case '\\':
105 if (state == NONE) {
106 state = IN_ESCAPE;
107 continue;
108 }
109 default:
110 break;
111 }
112 if (state == IN_ESCAPE) {
113 state = NONE;
114 }
115 ret[j++] = line[i];
116 }
117err:
118 sp_log_err("error",
119 "There is an issue with the parsing of '%s': it doesn't look like a valid string.",
120 original_line ? original_line : "NULL");
121 line = NULL;
122 return NULL;
123}
124
125static char *get_misc(char *restrict line, const char *restrict keyword) {
126 size_t i = 0;
127 char *ret = pecalloc(sizeof(char), 1024, 1);
128
129 while (i < 1024 - 1 && line[i] && line[i] != SP_TOKEN_END_PARAM) {
130 ret[i] = line[i];
131 i++;
132 }
133
134 if (line[i] != SP_TOKEN_END_PARAM) {
135 if (i >= 1024 - 1) {
136 sp_log_err("config", "The following line is too long: %s.", line);
137 } else {
138 sp_log_err("config", "Missing closing %c in line %s.", SP_TOKEN_END_PARAM,
139 line);
140 }
141 return NULL;
142 } else if (i == 0) {
143 sp_log_err("config", "The keyword %s%c is expecting a parameter.",
144 keyword, SP_TOKEN_END_PARAM);
145 return NULL;
146 }
147 return ret;
148}
149
150char *get_param(size_t *consumed, char *restrict line, sp_type type,
151 const char *restrict keyword) {
152 char *retval = NULL;
153 if (type == SP_TYPE_STR) {
154 retval = get_string(consumed, line, keyword);
155 } else {
156 retval = get_misc(line, keyword);
157 *consumed = retval ? strlen(retval) : 0;
158 }
159
160 if (retval) {
161 if (type == SP_TYPE_STR && 0 == validate_str(retval)) {
162 return retval;
163 } else if (type == SP_TYPE_INT && 0 == validate_int(retval)) {
164 return retval;
165 }
166 }
167 return NULL;
168}
169
170// FIXME this is leaking like hell @blotus
171int array_to_list(char **name_ptr, sp_node_t **keys) {
172 int in_key = 0;
173 size_t i = 0;
174 char *name = *name_ptr;
175 char *key_name = ecalloc(strlen(name) + 1, 1); // im way too lazy for
176 // now
177 char *tmp = ecalloc(strlen(name) + 1, 1);
178
179 for (i = 0; name[i] != '['; i++) {
180 tmp[i] = name[i];
181 }
182 tmp[i] = 0;
183
184 for (size_t j = 0; name[i]; i++) {
185 const char c = name[i];
186 if (c == '[') {
187 if (in_key == 0) {
188 in_key = 1;
189 } else {
190 efree(key_name);
191 return -1;
192 }
193 } else if (c == ']') {
194 if (in_key == 0) {
195 efree(key_name);
196 return -1;
197 } else {
198 in_key = 0;
199 j = 0;
200 sp_list_insert(*keys, pestrdup(key_name, 1));
201 memset(key_name, 0, strlen(name) + 1);
202 }
203 } else if (in_key == 1) {
204 key_name[j] = c;
205 j++;
206 }
207 }
208 efree(key_name);
209 *name_ptr = pestrdup(tmp, 1);
210 return in_key;
211}