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