9e119751d4d4818e189fbe5d6c4a4f0a650d01ce
[dragonfly.git] / contrib / ldns / parse.c
1 /*
2  * a generic (simple) parser. Use to parse rr's, private key
3  * information and /etc/resolv.conf files
4  *
5  * a Net::DNS like library for C
6  * LibDNS Team @ NLnet Labs
7  * (c) NLnet Labs, 2005-2006
8  * See the file LICENSE for the license
9  */
10 #include <ldns/config.h>
11 #include <ldns/ldns.h>
12
13 #include <limits.h>
14 #include <strings.h>
15
16 ldns_lookup_table ldns_directive_types[] = {
17         { LDNS_DIR_TTL, "$TTL" },
18         { LDNS_DIR_ORIGIN, "$ORIGIN" },
19         { LDNS_DIR_INCLUDE, "$INCLUDE" },
20         { 0, NULL }
21 };
22
23 /* add max_limit here? */
24 ssize_t
25 ldns_fget_token(FILE *f, char *token, const char *delim, size_t limit)
26 {
27         return ldns_fget_token_l(f, token, delim, limit, NULL);
28 }
29
30 ssize_t
31 ldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *line_nr)
32 {
33         int c, prev_c;
34         int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
35         int com, quoted;
36         char *t;
37         size_t i;
38         const char *d;
39         const char *del;
40
41         /* standard delimeters */
42         if (!delim) {
43                 /* from isspace(3) */
44                 del = LDNS_PARSE_NORMAL;
45         } else {
46                 del = delim;
47         }
48
49         p = 0;
50         i = 0;
51         com = 0;
52         quoted = 0;
53         prev_c = 0;
54         t = token;
55         if (del[0] == '"') {
56                 quoted = 1;
57         }
58         while ((c = getc(f)) != EOF) {
59                 if (c == '(' && prev_c != '\\' && !quoted) {
60                         /* this only counts for non-comments */
61                         if (com == 0) {
62                                 p++;
63                         }
64                         prev_c = c;
65                         continue;
66                 }
67
68                 if (c == ')' && prev_c != '\\' && !quoted) {
69                         /* this only counts for non-comments */
70                         if (com == 0) {
71                                 p--;
72                         }
73                         prev_c = c;
74                         continue;
75                 }
76
77                 if (p < 0) {
78                         /* more ) then ( - close off the string */
79                         *t = '\0';
80                         return 0;
81                 }
82
83                 /* do something with comments ; */
84                 if (c == ';' && quoted == 0) {
85                         if (prev_c != '\\') {
86                                 com = 1;
87                         }
88                 }
89                 if (c == '\"' && com == 0 && prev_c != '\\') {
90                         quoted = 1 - quoted;
91                 }
92
93                 if (c == '\n' && com != 0) {
94                         /* comments */
95                         com = 0;
96                         *t = ' ';
97                         if (line_nr) {
98                                 *line_nr = *line_nr + 1;
99                         }
100                         if (p == 0 && i > 0) {
101                                 goto tokenread;
102                         } else {
103                                 prev_c = c;
104                                 continue;
105                         }
106                 }
107
108                 if (com == 1) {
109                         *t = ' ';
110                         prev_c = c;
111                         continue;
112                 }
113
114
115                 if (c == '\n' && p != 0 && t > token) {
116                         /* in parentheses */
117                         if (line_nr) {
118                                 *line_nr = *line_nr + 1;
119                         }
120                         *t++ = ' ';
121                         prev_c = c;
122                         continue;
123                 }
124
125                 /* check if we hit the delim */
126                 for (d = del; *d; d++) {
127                         if (c == *d && i > 0 && prev_c != '\\') {
128                                 if (c == '\n' && line_nr) {
129                                         *line_nr = *line_nr + 1;
130                                 }
131                                 goto tokenread;
132                         }
133                 }
134                 if (c != '\0' && c != '\n') {
135                         *t++ = c;
136                         i++;
137                 }
138                 if (limit > 0 && i >= limit) {
139                         *t = '\0';
140                         return -1;
141                 }
142                 if (c == '\\' && prev_c == '\\')
143                         prev_c = 0;
144                 else    prev_c = c;
145         }
146         *t = '\0';
147         if (c == EOF) {
148                 return (ssize_t)i;
149         }
150
151         if (i == 0) {
152                 /* nothing read */
153                 return -1;
154         }
155         if (p != 0) {
156                 return -1;
157         }
158         return (ssize_t)i;
159
160 tokenread:
161         ldns_fskipcs_l(f, delim, line_nr);
162         *t = '\0';
163         if (p != 0) {
164                 return -1;
165         }
166
167         return (ssize_t)i;
168 }
169
170 ssize_t
171 ldns_fget_keyword_data(FILE *f, const char *keyword, const char *k_del, char *data,
172                const char *d_del, size_t data_limit)
173 {
174        return ldns_fget_keyword_data_l(f, keyword, k_del, data, d_del,
175                        data_limit, NULL);
176 }
177
178 ssize_t
179 ldns_fget_keyword_data_l(FILE *f, const char *keyword, const char *k_del, char *data,
180                const char *d_del, size_t data_limit, int *line_nr)
181 {
182        /* we assume: keyword|sep|data */
183        char *fkeyword;
184        ssize_t i;
185
186        fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN);
187        if(!fkeyword)
188                return -1;
189
190        i = ldns_fget_token(f, fkeyword, k_del, LDNS_MAX_KEYWORDLEN);
191        if(i==0 || i==-1) {
192                LDNS_FREE(fkeyword);
193                return -1;
194        }
195
196        /* case??? i instead of strlen? */
197        if (strncmp(fkeyword, keyword, LDNS_MAX_KEYWORDLEN - 1) == 0) {
198                /* whee! */
199                /* printf("%s\n%s\n", "Matching keyword", fkeyword); */
200                i = ldns_fget_token_l(f, data, d_del, data_limit, line_nr);
201                LDNS_FREE(fkeyword);
202                return i;
203        } else {
204                /*printf("no match for %s (read: %s)\n", keyword, fkeyword);*/
205                LDNS_FREE(fkeyword);
206                return -1;
207        }
208 }
209
210
211 ssize_t
212 ldns_bget_token(ldns_buffer *b, char *token, const char *delim, size_t limit)
213 {
214         int c, lc;
215         int p; /* 0 -> no parenthese seen, >0 nr of ( seen */
216         int com, quoted;
217         char *t;
218         size_t i;
219         const char *d;
220         const char *del;
221
222         /* standard delimiters */
223         if (!delim) {
224                 /* from isspace(3) */
225                 del = LDNS_PARSE_NORMAL;
226         } else {
227                 del = delim;
228         }
229
230         p = 0;
231         i = 0;
232         com = 0;
233         quoted = 0;
234         t = token;
235         lc = 0;
236         if (del[0] == '"') {
237                 quoted = 1;
238         }
239
240         while ((c = ldns_bgetc(b)) != EOF) {
241                 if (c == '(' && lc != '\\' && !quoted) {
242                         /* this only counts for non-comments */
243                         if (com == 0) {
244                                 p++;
245                         }
246                         lc = c;
247                         continue;
248                 }
249
250                 if (c == ')' && lc != '\\' && !quoted) {
251                         /* this only counts for non-comments */
252                         if (com == 0) {
253                                 p--;
254                         }
255                         lc = c;
256                         continue;
257                 }
258
259                 if (p < 0) {
260                         /* more ) then ( */
261                         *t = '\0';
262                         return 0;
263                 }
264
265                 /* do something with comments ; */
266                 if (c == ';' && quoted == 0) {
267                         if (lc != '\\') {
268                                 com = 1;
269                         }
270                 }
271                 if (c == '"' && com == 0 && lc != '\\') {
272                         quoted = 1 - quoted;
273                 }
274
275                 if (c == '\n' && com != 0) {
276                         /* comments */
277                         com = 0;
278                         *t = ' ';
279                         lc = c;
280                         continue;
281                 }
282
283                 if (com == 1) {
284                         *t = ' ';
285                         lc = c;
286                         continue;
287                 }
288
289                 if (c == '\n' && p != 0) {
290                         /* in parentheses */
291                         *t++ = ' ';
292                         lc = c;
293                         continue;
294                 }
295
296                 /* check if we hit the delim */
297                 for (d = del; *d; d++) {
298                         if (c == *d && lc != '\\') {
299                                 goto tokenread;
300                         }
301                 }
302
303                 *t++ = c;
304                 i++;
305                 if (limit > 0 && i >= limit) {
306                         *t = '\0';
307                         return -1;
308                 }
309
310                 if (c == '\\' && lc == '\\') {
311                         lc = 0;
312                 } else {
313                         lc = c;
314                 }
315         }
316         *t = '\0';
317         if (i == 0) {
318                 /* nothing read */
319                 return -1;
320         }
321         if (p != 0) {
322                 return -1;
323         }
324         return (ssize_t)i;
325
326 tokenread:
327         ldns_bskipcs(b, delim);
328         *t = '\0';
329
330         if (p != 0) {
331                 return -1;
332         }
333         return (ssize_t)i;
334 }
335
336 void
337 ldns_bskipc(ldns_buffer *buffer, char c)
338 {
339         while (c == (char) ldns_buffer_read_u8_at(buffer, ldns_buffer_position(buffer))) {
340                 if (ldns_buffer_available_at(buffer,
341                                         buffer->_position + sizeof(char), sizeof(char))) {
342                         buffer->_position += sizeof(char);
343                 } else {
344                         return;
345                 }
346         }
347 }
348
349 void
350 ldns_bskipcs(ldns_buffer *buffer, const char *s)
351 {
352         bool found;
353         char c;
354         const char *d;
355
356         while(ldns_buffer_available_at(buffer, buffer->_position, sizeof(char))) {
357                 c = (char) ldns_buffer_read_u8_at(buffer, buffer->_position);
358                 found = false;
359                 for (d = s; *d; d++) {
360                         if (*d == c) {
361                                 found = true;
362                         }
363                 }
364                 if (found && buffer->_limit > buffer->_position) {
365                         buffer->_position += sizeof(char);
366                 } else {
367                         return;
368                 }
369         }
370 }
371
372 void
373 ldns_fskipc(FILE *fp, char c)
374 {
375         fp = fp;
376         c = c;
377 }
378
379
380 void
381 ldns_fskipcs(FILE *fp, const char *s)
382 {
383         ldns_fskipcs_l(fp, s, NULL);
384 }
385
386 void
387 ldns_fskipcs_l(FILE *fp, const char *s, int *line_nr)
388 {
389         bool found;
390         int c;
391         const char *d;
392
393         while ((c = fgetc(fp)) != EOF) {
394                 if (line_nr && c == '\n') {
395                         *line_nr = *line_nr + 1;
396                 }
397                 found = false;
398                 for (d = s; *d; d++) {
399                         if (*d == c) {
400                                 found = true;
401                         }
402                 }
403                 if (!found) {
404                         /* with getc, we've read too far */
405                         ungetc(c, fp);
406                         return;
407                 }
408         }
409 }
410
411 ssize_t
412 ldns_bget_keyword_data(ldns_buffer *b, const char *keyword, const char *k_del, char
413 *data, const char *d_del, size_t data_limit)
414 {
415        /* we assume: keyword|sep|data */
416        char *fkeyword;
417        ssize_t i;
418
419        fkeyword = LDNS_XMALLOC(char, LDNS_MAX_KEYWORDLEN);
420        if(!fkeyword)
421                return -1; /* out of memory */
422
423        i = ldns_bget_token(b, fkeyword, k_del, data_limit);
424        if(i==0 || i==-1) {
425                LDNS_FREE(fkeyword);
426                return -1; /* nothing read */
427        }
428
429        /* case??? */
430        if (strncmp(fkeyword, keyword, strlen(keyword)) == 0) {
431                LDNS_FREE(fkeyword);
432                /* whee, the match! */
433                /* retrieve it's data */
434                i = ldns_bget_token(b, data, d_del, 0);
435                return i;
436        } else {
437                LDNS_FREE(fkeyword);
438                return -1;
439        }
440 }
441