Generally use NULL instead of explicitly casting 0 to some pointer type.
[dragonfly.git] / usr.sbin / atm / scspd / scsp_config_lex.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/usr.sbin/atm/scspd/scsp_config_lex.c,v 1.3 1999/08/28 01:15:32 peter Exp $
27  *      @(#) $DragonFly: src/usr.sbin/atm/scspd/scsp_config_lex.c,v 1.3 2003/11/15 20:33:43 eirikn Exp $
28  */
29
30 /*
31  * Server Cache Synchronization Protocol (SCSP) Support
32  * ----------------------------------------------------
33  *
34  * Parse a configuration file into tokens
35  *
36  */
37
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <net/if.h>
42 #include <netinet/in.h>
43 #include <netatm/port.h> 
44 #include <netatm/queue.h> 
45 #include <netatm/atm.h>
46 #include <netatm/atm_if.h>
47 #include <netatm/atm_sap.h>
48 #include <netatm/atm_sys.h>
49 #include <netatm/atm_ioctl.h>
50   
51 #include <ctype.h>
52 #include <errno.h>
53 #include <libatm.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <syslog.h>
58
59 #include "scsp_msg.h"
60 #include "scsp_if.h"
61 #include "scsp_var.h"
62 #include "scsp_config_parse.h"
63
64 /*
65  * Global variables
66  */
67 int             parse_line = 1;
68
69 /*
70  * Local definitions
71  */
72 #define TOK_MAX_LEN     128
73
74 /*
75  * Character classes
76  */
77 #define CHAR_INVALID    0               /* Not allowed */
78 #define CHAR_ALPHA      1               /* G-W, Y, Z */
79 #define CHAR_HEX_DIGIT  2               /* A-F */
80 #define CHAR_X          3               /* X */
81 #define CHAR_0          4               /* '0' */
82 #define CHAR_DIGIT      5               /* 1-9 */
83 #define CHAR_SPACE      6               /* space, tab */
84 #define CHAR_DECIMAL    7               /* period */
85 #define CHAR_SLASH      8               /* slash */
86 #define CHAR_ASTERISK   9               /* asterisk */
87 #define CHAR_HASH       10              /* pound sign */
88 #define CHAR_SPECIAL    11              /* semicolon, braces */
89 #define CHAR_MISC       12              /* chars allowd in file names */
90 #define CHAR_EOL        13              /* new line */
91 #define CHAR_EOF        14              /* EOF */
92 #define CHAR_CNT        CHAR_EOF + 1
93
94 /*
95  * Character class table (initialized by init_class_tbl())
96  */
97 static char class_tbl[128];
98
99 /*
100  * State table element structure
101  */
102 struct state_entry {
103         int     action;
104         int     next;
105 };
106
107 /*
108  * Scanner states
109  */
110 #define TS_INIT         0
111 #define TS_ALPHA        1
112 #define TS_INT_1        2
113 #define TS_INT          3
114 #define TS_HEX          4
115 #define TS_SLASH_1      5
116 #define TS_COMMENT      6
117 #define TS_COMMENT_1    7
118 #define TS_FLUSH        8
119 #define TS_HEX_1        9
120 #define TS_CNT          TS_HEX_1 + 1
121
122 /*
123  * Token scanner state table
124  */
125 static struct state_entry token_state_tbl[CHAR_CNT][TS_CNT] = {
126 /*          0     1     2     3     4     5     6     7     8     9   */
127 /* bad */{{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{0,6},{0,6},{0,8},{2,0}},
128 /* g-z */{{1,1},{1,1},{1,1},{1,1},{2,0},{1,1},{0,6},{0,6},{0,8},{2,0}},
129 /* a-f */{{1,1},{1,1},{1,1},{1,1},{1,9},{1,1},{0,6},{0,6},{0,8},{1,4}},
130 /*  x  */{{1,1},{1,1},{1,4},{1,4},{2,0},{1,1},{0,6},{0,6},{0,8},{2,0}},
131 /*  0  */{{1,2},{1,1},{1,3},{1,3},{1,9},{1,1},{0,6},{0,6},{0,8},{1,4}},
132 /* 1-9 */{{1,3},{1,1},{1,3},{1,3},{1,9},{1,1},{0,6},{0,6},{0,8},{1,4}},
133 /* sp  */{{0,0},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,8},{2,0}},
134 /*  .  */{{2,0},{1,1},{1,1},{1,1},{1,4},{1,1},{0,6},{0,6},{0,8},{2,0}},
135 /*  /  */{{1,5},{1,1},{1,1},{1,1},{7,0},{4,8},{0,6},{0,0},{0,8},{2,0}},
136 /*  *  */{{2,0},{6,0},{8,0},{8,0},{7,0},{4,6},{0,7},{0,7},{0,8},{2,0}},
137 /*  #  */{{0,8},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,8},{2,0}},
138 /* ;{} */{{3,0},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,8},{2,0}},
139 /* Msc */{{2,0},{1,1},{1,1},{1,1},{2,0},{1,1},{0,6},{0,6},{0,8},{2,0}},
140 /* EOL */{{0,0},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,0},{2,0}},
141 /* EOF */{{9,0},{6,0},{8,0},{8,0},{7,0},{6,0},{2,0},{2,0},{9,0},{2,0}},
142 };
143
144
145 /*
146  * Reserved words
147  */
148 static struct {
149         char    *word;
150         int     token;
151 } rsvd_word_tbl[] = {
152         { "ATMaddr",            TOK_DCS_ADDR },
153         { "ATMARP",             TOK_ATMARP },
154         { "CAReXmitInt",        TOK_DCS_CA_REXMIT_INT },
155         { "CSUSReXmitInt",      TOK_DCS_CSUS_REXMIT_INT },
156         { "CSUReXmitInt",       TOK_DCS_CSU_REXMIT_INT  },
157         { "CSUReXmitMax",       TOK_DCS_CSU_REXMIT_MAX },
158         { "DCS",                TOK_DCS },
159         { "DHCP",               TOK_DHCP },
160         { "familyID",           TOK_FAMILY },
161         { "file",               TOK_LFN },
162         { "hops",               TOK_DCS_HOP_CNT },
163         { "HelloDead",          TOK_DCS_HELLO_DF },
164         { "HelloInt",           TOK_DCS_HELLO_INT },
165         { "ID",                 TOK_DCS_ID },
166         { "LNNI",               TOK_LNNI },
167         { "log",                TOK_LOG },
168         { "MARS",               TOK_MARS },
169         { "netif",              TOK_NETIF },
170         { "NHRP",               TOK_NHRP },
171         { "protocol",           TOK_PROTOCOL },
172         { "server",             TOK_SERVER },
173         { "ServerGroupID",      TOK_SRVGRP },
174         { "syslog",             TOK_SYSLOG },
175         { NULL,                 0 },
176 };
177
178
179 /*
180  * Copy a character string
181  *
182  * Make a copy of a character string, using strdup.  If strdup fails,
183  * meaning we're out of memory, then print an error message and exit.
184  *
185  * Arguments:
186  *      s       string to be copied
187  *
188  * Returns:
189  *      char *  pointer to area provided by strdup
190  *
191  */
192 static char *
193 copy_buffer(char *s)
194 {
195         char    *t;
196
197         t = strdup(s);
198
199         if (!t) {
200                 fprintf(stderr, "%s: strdup failed\n", prog);
201                 exit(1);
202         }
203
204         return(t);
205 }
206
207
208 /*
209  * Push a character back onto the input stream.
210  *
211  * Arguments:
212  *      c       character to be pushed
213  *
214  * Returns:
215  *      none
216  *
217  */
218 static void
219 push_char(char c)
220 {
221         if (c == '\n')
222                 parse_line--;
223
224         ungetc(c, cfg_file);
225 }
226
227
228 /*
229  * Initialize the character class table.
230  *
231  * Set each entry in the character class table to the class
232  * corresponding to the character.
233  *
234  * Arguments:
235  *      tbl     pointer to table to be initialized
236  *
237  * Returns:
238  *      None
239  */
240 static void
241 init_class_tbl(char *tbl)
242 {
243         int     i;
244         char    c;
245
246         /*
247          * Set up the table for all ASCII characters
248          */
249         for (i=0; isascii((char)i); i++) {
250                 /*
251                  * Clear entry
252                  */
253                 tbl[i] = CHAR_INVALID;
254
255                 /*
256                  * Set entries depending on character type
257                  */
258                 c = (char)i;
259                 if (c == 'a' || c == 'b' || c == 'c' ||
260                                 c == 'd' || c == 'e' || c == 'f' ||
261                                 c == 'A' || c == 'B' || c == 'C' ||
262                                 c == 'D' || c == 'E' || c == 'F')
263                         tbl[i] = CHAR_HEX_DIGIT;
264                 else if (c == 'x' || c == 'X')
265                         tbl[i] = CHAR_X;
266                 else if (isalpha(c))
267                         tbl[i] = CHAR_ALPHA;
268                 else if (c == '0')
269                         tbl[i] = CHAR_0;
270                 else if (isdigit(c))
271                         tbl[i] = CHAR_DIGIT;
272                 else if (c == '\n')
273                         tbl[i] = CHAR_EOL;
274                 else if (c == ' ' || c == '\t')
275                         tbl[i] = CHAR_SPACE;
276                 else if (c == '#')
277                         tbl[i] = CHAR_HASH;
278                 else if (c == '*')
279                         tbl[i] = CHAR_ASTERISK;
280                 else if (c == '.')
281                         tbl[i] = CHAR_DECIMAL;
282                 else if (c == '/')
283                         tbl[i] = CHAR_SLASH;
284                 else if (c == ';' || c == '{' || c == '}')
285                         tbl[i] = CHAR_SPECIAL;
286                 else if (c == '-' || c == '_' || c == '&' || c == '@' ||
287                                 c == '~')
288                         tbl[i] = CHAR_MISC;
289         }
290 }
291
292
293 /*
294  * Get the class of a character.
295  *
296  * Arguments:
297  *      c       character being scanned
298  *
299  * Returns:
300  *      int     character class
301  */
302 static int
303 char_class(char c)
304 {
305         int     class = CHAR_INVALID;
306
307         if (c == EOF) {
308                 class = CHAR_EOF;
309         } else if (c < 0 || !isascii(c)) {
310                 class = CHAR_INVALID;
311         } else {
312                 class = class_tbl[(int)c];
313         }
314
315         return(class);
316 }
317
318
319 /*
320  * Print an error message when the scanner finds an error
321  *
322  * Arguments:
323  *      c       character on which the error was recognized
324  *      state   scanner state at error
325  *
326  * Returns:
327  *      None
328  */
329 static void
330 scan_error(char c, int state)
331 {
332         /*
333          * Check for invalid character
334          */
335         if (char_class(c) == CHAR_INVALID) {
336                 parse_error("Invalid character 0x%x encountered",
337                         c);
338                 return;
339         }
340
341         /*
342          * Check for unexpected EOF
343          */
344         if (char_class(c) == CHAR_EOF) {
345                 parse_error("Unexpected end of file");
346                 return;
347         }
348
349         /*
350          * Error depends on state
351          */
352         switch(state) {
353         case TS_INIT:
354                 parse_error("Syntax error at '%c'", c);
355                 break;
356         case TS_ALPHA:
357         case TS_INT_1:
358         case TS_INT:
359         case TS_SLASH_1:
360         case TS_COMMENT:
361         case TS_COMMENT_1:
362         case TS_FLUSH:
363                 parse_error("Syntax error");
364                 break;
365         case TS_HEX:
366         case TS_HEX_1:
367                 parse_error("Syntax error in hex string");
368                 break;
369         }
370 }
371
372
373 /*
374  * Assemble a token
375  *
376  * Read a character at a time from the input file, assembling the
377  * characters into tokens as specified by the token scanner state
378  * table.  Return the completed token.
379  *
380  * Arguments:
381  *      None
382  *
383  * Returns:
384  *      token   the type of the token found
385  */
386 int
387 yylex(void)
388 {
389         int             i, state;
390         char            c, token_buffer[TOK_MAX_LEN];
391
392         /*
393          * Initialize
394          */
395         if (class_tbl['A'] != CHAR_HEX_DIGIT)
396                 init_class_tbl(class_tbl);
397         state = TS_INIT;
398         UM_ZERO(token_buffer, sizeof(token_buffer));
399         UM_ZERO(&yylval, sizeof(yylval));
400
401         /*
402          * Handle a character at a time until a token is built
403          */
404         while(1) {
405                 /*
406                  * Read a character from the input file.
407                  */
408                 c = (char)getc(cfg_file);
409                 if (c == '\n') {
410                         parse_line++;
411                 }
412
413 #ifdef NOTDEF
414                 printf("token_state: state=%d, char=%c, class=%d, action=%d, next=%d\n",
415                                 state,
416                                 c,
417                                 char_class(c),
418                                 token_state_tbl[char_class][state].action,
419                                 token_state_tbl[char_class][state].next);
420 #endif
421
422                 /*
423                  * Perform an action based on the state table
424                  */
425                 switch(token_state_tbl[char_class(c)][state].action) {
426                 case 0:
427                         /*
428                          * Ignore the character
429                          */
430                         break;
431                 case 1:
432                         /*
433                          * Add character to buffer
434                          */
435                         if (strlen(token_buffer) < TOK_MAX_LEN) {
436                                 token_buffer[strlen(token_buffer)] = c;
437                         }
438                         break;
439                 case 2:
440                         /*
441                          * Error--print a message and start over
442                          */
443                         scan_error(c, state);
444                         break;
445                 case 3:
446                         /*
447                          * Return special character
448                          */
449                         return(c);
450                         break;
451                 case 4:
452                         /*
453                          * Clear the token buffer
454                          */
455                         UM_ZERO(token_buffer, sizeof(token_buffer));
456                         break;
457                 case 5:
458                         /*
459                          * Not used
460                          */
461                         break;
462                 case 6:
463                         /*
464                          * Return character token
465                          */
466                         push_char(c);
467
468                         /*
469                          * Check for reserved words
470                          */
471                         for (i=0; rsvd_word_tbl[i].word; i++) {
472                                 if (strcasecmp(token_buffer,
473                                                 rsvd_word_tbl[i].word) == 0)
474                                         break;
475                         }
476                         if (rsvd_word_tbl[i].word) {
477                                 return(rsvd_word_tbl[i].token);
478                         }
479
480                         /*
481                          * Word isn't reserved, return alpha string
482                          */
483                         yylval.tv_alpha = copy_buffer(token_buffer);
484                         return(TOK_NAME);
485                         break;
486                 case 7:
487                         /*
488                          * Return hex string (ATM address)
489                          */
490                         push_char(c);
491                         yylval.tv_hex = copy_buffer(token_buffer);
492                         return(TOK_HEX);
493                         break;
494                 case 8:
495                         /*
496                          * Return integer
497                          */
498                         push_char(c);
499                         yylval.tv_int = atoi(token_buffer);
500                         return(TOK_INTEGER);
501                         break;
502                 case 9:
503                         /*
504                          * Return EOF
505                          */
506                         return(0);
507                         break;
508                 default:
509                         fprintf(stderr, "Invalid action indicator, state=%d, char=0x%02x\n",
510                                         state, c);
511                         break;
512                 }
513
514                 /*
515                  * Set the next state and bump to the next character
516                  */
517                 state = token_state_tbl[char_class(c)][state].next;
518         }
519 }