diff options
Diffstat (limited to 'src/tree.c')
-rw-r--r-- | src/tree.c | 773 |
1 files changed, 773 insertions, 0 deletions
diff --git a/src/tree.c b/src/tree.c new file mode 100644 index 0000000..52d38c0 --- /dev/null +++ b/src/tree.c | |||
@@ -0,0 +1,773 @@ | |||
1 | /* grecs - Gray's Extensible Configuration System | ||
2 | Copyright (C) 2007-2011 Sergey Poznyakoff | ||
3 | |||
4 | Grecs is free software; you can redistribute it and/or modify it | ||
5 | under the terms of the GNU General Public License as published by the | ||
6 | Free Software Foundation; either version 3 of the License, or (at your | ||
7 | option) any later version. | ||
8 | |||
9 | Grecs is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with Grecs. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #ifdef HAVE_CONFIG_H | ||
18 | # include <config.h> | ||
19 | #endif | ||
20 | #include <sys/types.h> | ||
21 | #include <sys/socket.h> | ||
22 | #include <sys/time.h> | ||
23 | #include <sys/un.h> | ||
24 | #include <netinet/in.h> | ||
25 | #include <arpa/inet.h> | ||
26 | #include <netdb.h> | ||
27 | #include <stdlib.h> | ||
28 | #include "grecs.h" | ||
29 | |||
30 | struct grecs_node * | ||
31 | grecs_node_create(enum grecs_node_type type, grecs_locus_t *loc) | ||
32 | { | ||
33 | struct grecs_node *np = grecs_zalloc(sizeof(*np)); | ||
34 | np->type = type; | ||
35 | if (loc) | ||
36 | np->locus = *loc; | ||
37 | return np; | ||
38 | } | ||
39 | |||
40 | void | ||
41 | grecs_node_bind(struct grecs_node *master, struct grecs_node *node, int dn) | ||
42 | { | ||
43 | struct grecs_node *np; | ||
44 | |||
45 | if (dn) { | ||
46 | if (!master->down) | ||
47 | master->down = node; | ||
48 | else { | ||
49 | for (np = master->down; np->next; np = np->next) | ||
50 | ; | ||
51 | np->next = node; | ||
52 | } | ||
53 | for (; node; node = node->next) | ||
54 | node->up = master; | ||
55 | } else { | ||
56 | if (!master->next) | ||
57 | master->next = node; | ||
58 | else { | ||
59 | for (np = master->next; np->next; np = np->next) | ||
60 | ; | ||
61 | np->next = node; | ||
62 | } | ||
63 | node->up = master->up; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | |||
68 | static enum grecs_tree_recurse_res | ||
69 | _tree_recurse(struct grecs_node *node, grecs_tree_recursor_t recfun, | ||
70 | void *data) | ||
71 | { | ||
72 | enum grecs_tree_recurse_res res; | ||
73 | #define CKRES() \ | ||
74 | switch (res) { \ | ||
75 | case grecs_tree_recurse_fail: \ | ||
76 | case grecs_tree_recurse_stop: \ | ||
77 | return res; \ | ||
78 | default: \ | ||
79 | break; \ | ||
80 | } | ||
81 | |||
82 | for (; node; node = node->next) { | ||
83 | if (node->type == grecs_node_stmt) { | ||
84 | res = recfun(grecs_tree_recurse_set, node, data); | ||
85 | CKRES(); | ||
86 | } else { | ||
87 | switch (recfun(grecs_tree_recurse_pre, node, data)) { | ||
88 | case grecs_tree_recurse_ok: | ||
89 | res = _tree_recurse(node->down, recfun, data); | ||
90 | CKRES(); | ||
91 | res = recfun(grecs_tree_recurse_post, node, | ||
92 | data); | ||
93 | CKRES(); | ||
94 | break; | ||
95 | case grecs_tree_recurse_fail: | ||
96 | return grecs_tree_recurse_fail; | ||
97 | case grecs_tree_recurse_stop: | ||
98 | return grecs_tree_recurse_stop; | ||
99 | case grecs_tree_recurse_skip: | ||
100 | break; | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | return grecs_tree_recurse_ok; | ||
105 | #undef CKRES | ||
106 | } | ||
107 | |||
108 | int | ||
109 | grecs_tree_recurse(struct grecs_node *node, grecs_tree_recursor_t recfun, | ||
110 | void *data) | ||
111 | { | ||
112 | switch (_tree_recurse(node, recfun, data)) { | ||
113 | case grecs_tree_recurse_ok: | ||
114 | case grecs_tree_recurse_stop: | ||
115 | return 0; | ||
116 | default: | ||
117 | break; | ||
118 | } | ||
119 | return 1; | ||
120 | } | ||
121 | |||
122 | void | ||
123 | grecs_node_free(struct grecs_node *node) | ||
124 | { | ||
125 | /*FIXME: value*/ | ||
126 | free(node); | ||
127 | } | ||
128 | |||
129 | void | ||
130 | grecs_tree_free(struct grecs_node *node) | ||
131 | { | ||
132 | while (node) { | ||
133 | struct grecs_node *next = node->next; | ||
134 | if (node->down) | ||
135 | grecs_tree_free(node->down); | ||
136 | grecs_node_free(node); | ||
137 | node = next; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | |||
142 | |||
143 | static int | ||
144 | fake_callback(enum grecs_callback_command cmd, | ||
145 | grecs_locus_t *locus, | ||
146 | void *varptr, | ||
147 | grecs_value_t *value, | ||
148 | void *cb_data) | ||
149 | { | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static struct grecs_keyword fake = { | ||
154 | "*", | ||
155 | NULL, | ||
156 | NULL, | ||
157 | grecs_type_void, | ||
158 | NULL, | ||
159 | 0, | ||
160 | fake_callback, | ||
161 | NULL, | ||
162 | &fake | ||
163 | }; | ||
164 | |||
165 | static struct grecs_keyword * | ||
166 | find_keyword(struct grecs_keyword *cursect, const char *ident) | ||
167 | { | ||
168 | struct grecs_keyword *kwp; | ||
169 | |||
170 | if (cursect && cursect != &fake) { | ||
171 | for (kwp = cursect->kwd; kwp->ident; kwp++) | ||
172 | if (strcmp(kwp->ident, ident) == 0) | ||
173 | return kwp; | ||
174 | } else { | ||
175 | return &fake; | ||
176 | } | ||
177 | return NULL; | ||
178 | } | ||
179 | |||
180 | static void * | ||
181 | target_ptr(struct grecs_keyword *kwp, char *base) | ||
182 | { | ||
183 | if (kwp->varptr) | ||
184 | base = (char*) kwp->varptr + kwp->offset; | ||
185 | else if (base) | ||
186 | base += kwp->offset; | ||
187 | |||
188 | return base; | ||
189 | } | ||
190 | |||
191 | static int | ||
192 | string_to_bool(const char *string, int *pval, grecs_locus_t *locus) | ||
193 | { | ||
194 | if (strcmp(string, "yes") == 0 | ||
195 | || strcmp(string, "true") == 0 | ||
196 | || strcmp(string, "t") == 0 | ||
197 | || strcmp(string, "1") == 0) | ||
198 | *pval = 1; | ||
199 | else if (strcmp(string, "no") == 0 | ||
200 | || strcmp(string, "false") == 0 | ||
201 | || strcmp(string, "nil") == 0 | ||
202 | || strcmp(string, "0") == 0) | ||
203 | *pval = 0; | ||
204 | else { | ||
205 | grecs_error(locus, 0, | ||
206 | _("%s: not a valid boolean value"), | ||
207 | string); | ||
208 | return 1; | ||
209 | } | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static int | ||
214 | string_to_host(struct in_addr *in, const char *string, grecs_locus_t *locus) | ||
215 | { | ||
216 | if (inet_aton(string, in) == 0) { | ||
217 | struct hostent *hp; | ||
218 | |||
219 | hp = gethostbyname(string); | ||
220 | if (hp == NULL) | ||
221 | return 1; | ||
222 | memcpy(in, hp->h_addr, sizeof(struct in_addr)); | ||
223 | } | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int | ||
228 | string_to_sockaddr(struct grecs_sockaddr *sp, const char *string, | ||
229 | grecs_locus_t *locus) | ||
230 | { | ||
231 | if (string[0] == '/') { | ||
232 | struct sockaddr_un s_un; | ||
233 | if (strlen(string) >= sizeof(s_un.sun_path)) { | ||
234 | grecs_error(locus, 0, | ||
235 | _("%s: UNIX socket name too long"), | ||
236 | string); | ||
237 | return 1; | ||
238 | } | ||
239 | s_un.sun_family = AF_UNIX; | ||
240 | strcpy(s_un.sun_path, string); | ||
241 | sp->len = sizeof(s_un); | ||
242 | sp->sa = grecs_malloc(sp->len); | ||
243 | memcpy(sp->sa, &s_un, sp->len); | ||
244 | } else { | ||
245 | char *p = strchr(string, ':'); | ||
246 | size_t len; | ||
247 | struct sockaddr_in sa; | ||
248 | |||
249 | sa.sin_family = AF_INET; | ||
250 | if (p) | ||
251 | len = p - string; | ||
252 | else | ||