dhclient - Try harder to re-initialize parsing state.
[dragonfly.git] / sbin / dhclient / conflex.c
1 /*      $OpenBSD: src/sbin/dhclient/conflex.c,v 1.14 2011/12/10 17:36:40 krw Exp $      */
2
3 /* Lexical scanner for dhclient config file... */
4
5 /*
6  * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of The Internet Software Consortium nor the names
19  *    of its contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * This software has been written for the Internet Software Consortium
37  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38  * Enterprises.  To learn more about the Internet Software Consortium,
39  * see ``http://www.vix.com/isc''.  To learn more about Vixie
40  * Enterprises, see ``http://www.vix.com''.
41  */
42
43 #include <ctype.h>
44
45 #include "dhcpd.h"
46 #include "dhctoken.h"
47
48 int lexline;
49 int lexchar;
50 char *token_line;
51 char *prev_line;
52 char *cur_line;
53 char *tlname;
54
55 static char line1[81];
56 static char line2[81];
57 static uint lpos;
58 static int line;
59 static int tlpos;
60 static int tline;
61 static int token;
62 static int ugflag;
63 static char *tval;
64 static char tokbuf[1500];
65
66 static int get_char(FILE *);
67 static int get_token(FILE *);
68 static void skip_to_eol(FILE *);
69 static int read_string(FILE *);
70 static int read_number(int, FILE *);
71 static int read_num_or_name(int, FILE *);
72 int kw_cmp(const void *, const void *);
73 static int intern(char *, int);
74
75 void
76 new_parse(char *name)
77 {
78         /*
79          * Initialize all parsing state, as we are starting to parse a
80          * new file, 'name'.
81          */
82
83         bzero(line1, sizeof(line1));
84         bzero(line2, sizeof(line2));
85         bzero(tokbuf, sizeof(tokbuf));
86
87         lpos = line = 1;
88         tlpos = tline = token = ugflag = 0;
89         tval = NULL;
90
91         lexline = lexchar = 0;
92         cur_line = line1;
93         prev_line = line2;
94         token_line = cur_line;
95         tlname = name;
96
97         warnings_occurred = 0;
98 }
99
100 static int
101 get_char(FILE *cfile)
102 {
103         int c = getc(cfile);
104         if (!ugflag) {
105                 if (c == '\n') {
106                         if (cur_line == line1) {
107                                 cur_line = line2;
108                                 prev_line = line1;
109                         } else {
110                                 cur_line = line2;
111                                 prev_line = line1;
112                         }
113                         line++;
114                         lpos = 1;
115                         cur_line[0] = 0;
116                 } else if (c != EOF) {
117                         if (lpos < sizeof(line1)) {
118                                 cur_line[lpos - 1] = c;
119                                 cur_line[lpos] = 0;
120                         }
121                         lpos++;
122                 }
123         } else
124                 ugflag = 0;
125         return (c);
126 }
127
128 static int
129 get_token(FILE *cfile)
130 {
131         int             c, ttok;
132         static char     tb[2];
133         int             l, p;
134
135         do {
136                 l = line;
137                 p = lpos;
138
139                 c = get_char(cfile);
140
141                 if (isascii(c) && isspace(c))
142                         continue;
143                 if (c == '#') {
144                         skip_to_eol(cfile);
145                         continue;
146                 }
147                 if (c == '"') {
148                         lexline = l;
149                         lexchar = p;
150                         ttok = read_string(cfile);
151                         break;
152                 }
153                 if ((isascii(c) && isdigit(c)) || c == '-') {
154                         lexline = l;
155                         lexchar = p;
156                         ttok = read_number(c, cfile);
157                         break;
158                 } else if (isascii(c) && isalpha(c)) {
159                         lexline = l;
160                         lexchar = p;
161                         ttok = read_num_or_name(c, cfile);
162                         break;
163                 } else {
164                         lexline = l;
165                         lexchar = p;
166                         tb[0] = c;
167                         tb[1] = 0;
168                         tval = tb;
169                         ttok = c;
170                         break;
171                 }
172         } while (1);
173         return (ttok);
174 }
175
176 int
177 next_token(char **rval, FILE *cfile)
178 {
179         int     rv;
180
181         if (token) {
182                 if (lexline != tline)
183                         token_line = cur_line;
184                 lexchar = tlpos;
185                 lexline = tline;
186                 rv = token;
187                 token = 0;
188         } else {
189                 rv = get_token(cfile);
190                 token_line = cur_line;
191         }
192         if (rval)
193                 *rval = tval;
194
195         return (rv);
196 }
197
198 int
199 peek_token(char **rval, FILE *cfile)
200 {
201         int     x;
202
203         if (!token) {
204                 tlpos = lexchar;
205                 tline = lexline;
206                 token = get_token(cfile);
207                 if (lexline != tline)
208                         token_line = prev_line;
209                 x = lexchar;
210                 lexchar = tlpos;
211                 tlpos = x;
212                 x = lexline;
213                 lexline = tline;
214                 tline = x;
215         }
216         if (rval)
217                 *rval = tval;
218
219         return (token);
220 }
221
222 static void
223 skip_to_eol(FILE *cfile)
224 {
225         int     c;
226
227         do {
228                 c = get_char(cfile);
229                 if (c == EOF)
230                         return;
231                 if (c == '\n')
232                         return;
233         } while (1);
234 }
235
236 static int
237 read_string(FILE *cfile)
238 {
239         uint    i;
240         int     c, bs = 0;
241
242         for (i = 0; i < sizeof(tokbuf); i++) {
243                 c = get_char(cfile);
244                 if (c == EOF) {
245                         parse_warn("eof in string constant");
246                         break;
247                 }
248                 if (bs) {
249                         bs = 0;
250                         tokbuf[i] = c;
251                 } else if (c == '\\')
252                         bs = 1;
253                 else if (c == '"')
254                         break;
255                 else
256                         tokbuf[i] = c;
257         }
258         /*
259          * Normally, I'd feel guilty about this, but we're talking about
260          * strings that'll fit in a DHCP packet here...
261          */
262         if (i == sizeof(tokbuf)) {
263                 parse_warn("string constant larger than internal buffer");
264                 i--;
265         }
266         tokbuf[i] = 0;
267         tval = tokbuf;
268         return (TOK_STRING);
269 }
270
271 static int
272 read_number(int c, FILE *cfile)
273 {
274         uint    i = 0;
275         int     seenx = 0, token = TOK_NUMBER;
276
277         tokbuf[i++] = c;
278         for (; i < sizeof(tokbuf); i++) {
279                 c = get_char(cfile);
280                 if (!seenx && c == 'x')
281                         seenx = 1;
282                 else if (!isascii(c) || !isxdigit(c)) {
283                         ungetc(c, cfile);
284                         ugflag = 1;
285                         break;
286                 }
287                 tokbuf[i] = c;
288         }
289         if (i == sizeof(tokbuf)) {
290                 parse_warn("numeric token larger than internal buffer");
291                 i--;
292         }
293         tokbuf[i] = 0;
294         tval = tokbuf;
295
296         return (token);
297 }
298
299 static int
300 read_num_or_name(int c, FILE *cfile)
301 {
302         uint    i = 0;
303         int     rv = TOK_NUMBER_OR_NAME;
304
305         tokbuf[i++] = c;
306         for (; i < sizeof(tokbuf); i++) {
307                 c = get_char(cfile);
308                 if (!isascii(c) || (c != '-' && c != '_' && !isalnum(c))) {
309                         ungetc(c, cfile);
310                         ugflag = 1;
311                         break;
312                 }
313                 if (!isxdigit(c))
314                         rv = TOK_NAME;
315                 tokbuf[i] = c;
316         }
317         if (i == sizeof(tokbuf)) {
318                 parse_warn("token larger than internal buffer");
319                 i--;
320         }
321         tokbuf[i] = 0;
322         tval = tokbuf;
323
324         return (intern(tval, rv));
325 }
326
327 static const struct keywords {
328         const char      *k_name;
329         int             k_val;
330 } keywords[] = {
331         { "alias",                              TOK_ALIAS },
332         { "append",                             TOK_APPEND },
333         { "backoff-cutoff",                     TOK_BACKOFF_CUTOFF },
334         { "bootp",                              TOK_BOOTP },
335         { "default",                            TOK_DEFAULT },
336         { "deny",                               TOK_DENY },
337         { "ethernet",                           TOK_ETHERNET },
338         { "expire",                             TOK_EXPIRE },
339         { "fddi",                               TOK_FDDI },
340         { "filename",                           TOK_FILENAME },
341         { "fixed-address",                      TOK_FIXED_ADDR },
342         { "hardware",                           TOK_HARDWARE },
343         { "initial-interval",                   TOK_INITIAL_INTERVAL },
344         { "interface",                          TOK_INTERFACE },
345         { "lease",                              TOK_LEASE },
346         { "link-timeout",                       TOK_LINK_TIMEOUT },
347         { "media",                              TOK_MEDIA },
348         { "medium",                             TOK_MEDIUM },
349         { "option",                             TOK_OPTION },
350         { "prepend",                            TOK_PREPEND },
351         { "rebind",                             TOK_REBIND },
352         { "reboot",                             TOK_REBOOT },
353         { "reject",                             TOK_REJECT },
354         { "renew",                              TOK_RENEW },
355         { "request",                            TOK_REQUEST },
356         { "require",                            TOK_REQUIRE },
357         { "retry",                              TOK_RETRY },
358         { "script",                             TOK_SCRIPT },
359         { "select-timeout",                     TOK_SELECT_TIMEOUT },
360         { "send",                               TOK_SEND },
361         { "server-name",                        TOK_SERVER_NAME },
362         { "supersede",                          TOK_SUPERSEDE },
363         { "timeout",                            TOK_TIMEOUT },
364         { "token-ring",                         TOK_TOKEN_RING }
365 };
366
367 int
368 kw_cmp(const void *k, const void *e)
369 {
370         return (strcasecmp(k, ((const struct keywords *)e)->k_name));
371 }
372
373 static int
374 intern(char *atom, int dfv)
375 {
376         const struct keywords *p;
377
378         p = bsearch(atom, keywords, sizeof(keywords)/sizeof(keywords[0]),
379             sizeof(keywords[0]), kw_cmp);
380         if (p)
381                 return (p->k_val);
382         return (dfv);
383 }