Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:29:52 dillon 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         { (char *)0,            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(s)
194         char    *s;
195 {
196         char    *t;
197
198         t = strdup(s);
199
200         if (!t) {
201                 fprintf(stderr, "%s: strdup failed\n", prog);
202                 exit(1);
203         }
204
205         return(t);
206 }
207
208
209 /*
210  * Push a character back onto the input stream.
211  *
212  * Arguments:
213  *      c       character to be pushed
214  *
215  * Returns:
216  *      none
217  *
218  */
219 static void
220 push_char(c)
221         char    c;
222 {
223         if (c == '\n')
224                 parse_line--;
225
226         ungetc(c, cfg_file);
227 }
228
229
230 /*
231  * Initialize the character class table.
232  *
233  * Set each entry in the character class table to the class
234  * corresponding to the character.
235  *
236  * Arguments:
237  *      tbl     pointer to table to be initialized
238  *
239  * Returns:
240  *      None
241  */
242 static void
243 init_class_tbl(tbl)
244         char *tbl;
245 {
246         int     i;
247         char    c;
248
249         /*
250          * Set up the table for all ASCII characters
251          */
252         for (i=0; isascii((char)i); i++) {
253                 /*
254                  * Clear entry
255                  */
256                 tbl[i] = CHAR_INVALID;
257
258                 /*
259                  * Set entries depending on character type
260                  */
261                 c = (char)i;
262                 if (c == 'a' || c == 'b' || c == 'c' ||
263                                 c == 'd' || c == 'e' || c == 'f' ||
264                                 c == 'A' || c == 'B' || c == 'C' ||
265                                 c == 'D' || c == 'E' || c == 'F')
266                         tbl[i] = CHAR_HEX_DIGIT;
267                 else if (c == 'x' || c == 'X')
268                         tbl[i] = CHAR_X;
269                 else if (isalpha(c))
270                         tbl[i] = CHAR_ALPHA;
271                 else if (c == '0')
272                         tbl[i] = CHAR_0;
273                 else if (isdigit(c))
274                         tbl[i] = CHAR_DIGIT;
275                 else if (c == '\n')
276                         tbl[i] = CHAR_EOL;
277                 else if (c == ' ' || c == '\t')
278                         tbl[i] = CHAR_SPACE;
279                 else if (c == '#')
280                         tbl[i] = CHAR_HASH;
281                 else if (c == '*')
282                         tbl[i] = CHAR_ASTERISK;
283                 else if (c == '.')
284                         tbl[i] = CHAR_DECIMAL;
285                 else if (c == '/')
286                         tbl[i] = CHAR_SLASH;
287                 else if (c == ';' || c == '{' || c == '}')
288                         tbl[i] = CHAR_SPECIAL;
289                 else if (c == '-' || c == '_' || c == '&' || c == '@' ||
290                                 c == '~')
291                         tbl[i] = CHAR_MISC;
292         }
293 }
294
295
296 /*
297  * Get the class of a character.
298  *
299  * Arguments:
300  *      c       character being scanned
301  *
302  * Returns:
303  *      int     character class
304  */
305 static int
306 char_class(c)
307         char    c;
308 {
309         int     class = CHAR_INVALID;
310
311         if (c == EOF) {
312                 class = CHAR_EOF;
313         } else if (c < 0 || !isascii(c)) {
314                 class = CHAR_INVALID;
315         } else {
316                 class = class_tbl[(int)c];
317         }
318
319         return(class);
320 }
321
322
323 /*
324  * Print an error message when the scanner finds an error
325  *
326  * Arguments:
327  *      c       character on which the error was recognized
328  *      state   scanner state at error
329  *
330  * Returns:
331  *      None
332  */
333 static void
334 scan_error(c, state)
335         char    c;
336         int     state;
337 {
338         /*
339          * Check for invalid character
340          */
341         if (char_class(c) == CHAR_INVALID) {
342                 parse_error("Invalid character 0x%x encountered",
343                         c);
344                 return;
345         }
346
347         /*
348          * Check for unexpected EOF
349          */
350         if (char_class(c) == CHAR_EOF) {
351                 parse_error("Unexpected end of file");
352                 return;
353         }
354
355         /*
356          * Error depends on state
357          */
358         switch(state) {
359         case TS_INIT:
360                 parse_error("Syntax error at '%c'", c);
361                 break;
362         case TS_ALPHA:
363         case TS_INT_1:
364         case TS_INT:
365         case TS_SLASH_1:
366         case TS_COMMENT:
367         case TS_COMMENT_1:
368         case TS_FLUSH:
369                 parse_error("Syntax error");
370                 break;
371         case TS_HEX:
372         case TS_HEX_1:
373                 parse_error("Syntax error in hex string");
374                 break;
375         }
376 }
377
378
379 /*
380  * Assemble a token
381  *
382  * Read a character at a time from the input file, assembling the
383  * characters into tokens as specified by the token scanner state
384  * table.  Return the completed token.
385  *
386  * Arguments:
387  *      None
388  *
389  * Returns:
390  *      token   the type of the token found
391  */
392 int
393 yylex()
394 {
395         int             i, state;
396         char            c, token_buffer[TOK_MAX_LEN];
397
398         /*
399          * Initialize
400          */
401         if (class_tbl['A'] != CHAR_HEX_DIGIT)
402                 init_class_tbl(class_tbl);
403         state = TS_INIT;
404         UM_ZERO(token_buffer, sizeof(token_buffer));
405         UM_ZERO(&yylval, sizeof(yylval));
406
407         /*
408          * Handle a character at a time until a token is built
409          */
410         while(1) {
411                 /*
412                  * Read a character from the input file.
413                  */
414                 c = (char)getc(cfg_file);
415                 if (c == '\n') {
416                         parse_line++;
417                 }
418
419 #ifdef NOTDEF
420                 printf("token_state: state=%d, char=%c, class=%d, action=%d, next=%d\n",
421                                 state,
422                                 c,
423                                 char_class(c),
424                                 token_state_tbl[char_class][state].action,
425                                 token_state_tbl[char_class][state].next);
426 #endif
427
428                 /*
429                  * Perform an action based on the state table
430                  */
431                 switch(token_state_tbl[char_class(c)][state].action) {
432                 case 0:
433                         /*
434                          * Ignore the character
435                          */
436                         break;
437                 case 1:
438                         /*
439                          * Add character to buffer
440                          */
441                         if (strlen(token_buffer) < TOK_MAX_LEN) {
442                                 token_buffer[strlen(token_buffer)] = c;
443                         }
444                         break;
445                 case 2:
446                         /*
447                          * Error--print a message and start over
448                          */
449                         scan_error(c, state);
450                         break;
451                 case 3:
452                         /*
453                          * Return special character
454                          */
455                         return(c);
456                         break;
457                 case 4:
458                         /*
459                          * Clear the token buffer
460                          */
461                         UM_ZERO(token_buffer, sizeof(token_buffer));
462                         break;
463                 case 5:
464                         /*
465                          * Not used
466                          */
467                         break;
468                 case 6:
469                         /*
470                          * Return character token
471                          */
472                         push_char(c);
473
474                         /*
475                          * Check for reserved words
476                          */
477                         for (i=0; rsvd_word_tbl[i].word; i++) {
478                                 if (strcasecmp(token_buffer,
479                                                 rsvd_word_tbl[i].word) == 0)
480                                         break;
481                         }
482                         if (rsvd_word_tbl[i].word) {
483                                 return(rsvd_word_tbl[i].token);
484                         }
485
486                         /*
487                          * Word isn't reserved, return alpha string
488                          */
489                         yylval.tv_alpha = copy_buffer(token_buffer);
490                         return(TOK_NAME);
491                         break;
492                 case 7:
493                         /*
494                          * Return hex string (ATM address)
495                          */
496                         push_char(c);
497                         yylval.tv_hex = copy_buffer(token_buffer);
498                         return(TOK_HEX);
499                         break;
500                 case 8:
501                         /*
502                          * Return integer
503                          */
504                         push_char(c);
505                         yylval.tv_int = atoi(token_buffer);
506                         return(TOK_INTEGER);
507                         break;
508                 case 9:
509                         /*
510                          * Return EOF
511                          */
512                         return(0);
513                         break;
514                 default:
515                         fprintf(stderr, "Invalid action indicator, state=%d, char=0x%02x\n",
516                                         state, c);
517                         break;
518                 }
519
520                 /*
521                  * Set the next state and bump to the next character
522                  */
523                 state = token_state_tbl[char_class(c)][state].next;
524         }
525 }