]>
Commit | Line | Data |
---|---|---|
82fc7be7 MM |
1 | /* |
2 | * BIRD -- Configuration Lexer | |
3 | * | |
31b3e1bb | 4 | * (c) 1998--1999 Martin Mares <mj@ucw.cz> |
82fc7be7 MM |
5 | * |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
7 | */ | |
8 | ||
9 | %{ | |
cc12cf05 | 10 | #undef REJECT /* Avoid name clashes */ |
82fc7be7 MM |
11 | |
12 | #include <errno.h> | |
13 | #include <stdlib.h> | |
14 | #include <string.h> | |
cc12cf05 | 15 | #include <stdarg.h> |
82fc7be7 MM |
16 | |
17 | #include "nest/bird.h" | |
944f008a MM |
18 | #include "nest/route.h" |
19 | #include "filter/filter.h" | |
82fc7be7 MM |
20 | #include "conf/conf.h" |
21 | #include "conf/cf-parse.tab.h" | |
22 | ||
23 | static struct keyword { | |
24 | byte *name; | |
25 | int value; | |
26 | struct keyword *next; | |
27 | } keyword_list[] = { | |
49e7e5ee | 28 | #include "conf/keywords.h" |
82fc7be7 MM |
29 | { NULL, -1 } }; |
30 | ||
31 | #define KW_HASH_SIZE 64 | |
c9aae7f4 MM |
32 | static struct keyword *kw_hash[KW_HASH_SIZE]; |
33 | static int kw_hash_inited; | |
34 | ||
82fc7be7 MM |
35 | #define SYM_HASH_SIZE 128 |
36 | #define SYM_MAX_LEN 32 | |
37 | ||
c8f61a01 MM |
38 | struct sym_scope { |
39 | struct sym_scope *next; /* Next on scope stack */ | |
40 | struct symbol *name; /* Name of this scope */ | |
41 | int active; /* Currently entered */ | |
42 | }; | |
43 | static struct sym_scope *conf_this_scope; | |
44 | ||
31b3e1bb MM |
45 | int conf_lino; |
46 | ||
82fc7be7 MM |
47 | static int cf_hash(byte *c); |
48 | static struct symbol *cf_find_sym(byte *c, unsigned int h0); | |
49 | ||
b35d72ac | 50 | linpool *cfg_mem; |
82fc7be7 MM |
51 | |
52 | int (*cf_read_hook)(byte *buf, unsigned int max); | |
53 | ||
54 | #define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max); | |
55 | #define YY_NO_UNPUT | |
56 | #define YY_FATAL_ERROR(msg) cf_error(msg) | |
57 | ||
58 | %} | |
59 | ||
60 | %option noyywrap | |
61 | ||
bc2fb680 | 62 | %x COMMENT CCOMM CLI |
82fc7be7 MM |
63 | |
64 | ALPHA [a-zA-Z_] | |
65 | DIGIT [0-9] | |
66 | XIGIT [0-9a-fA-F] | |
67 | ALNUM [a-zA-Z_0-9] | |
68 | WHITE [ \t] | |
69 | ||
70 | %% | |
71 | ||
72 | {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ { | |
dce26783 MM |
73 | #ifdef IPV6 |
74 | if (ipv4_pton_u32(yytext, &cf_lval.i32)) | |
75 | return RTRID; | |
76 | cf_error("Invalid IPv4 address %s", yytext); | |
77 | #else | |
82fc7be7 MM |
78 | if (ip_pton(yytext, &cf_lval.a)) |
79 | return IPA; | |
dce26783 MM |
80 | cf_error("Invalid IP address %s", yytext); |
81 | #endif | |
82 | } | |
83 | ||
84 | ({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) { | |
85 | #ifdef IPV6 | |
86 | if (ip_pton(yytext, &cf_lval.a)) | |
87 | return IPA; | |
88 | cf_error("Invalid IP address %s", yytext); | |
89 | #else | |
90 | cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported"); | |
91 | #endif | |
82fc7be7 MM |
92 | } |
93 | ||
94 | 0x{DIGIT}+ { | |
95 | char *e; | |
96 | long int l; | |
97 | errno = 0; | |
98 | l = strtoul(yytext+2, &e, 16); | |
99 | if (e && *e || errno == ERANGE || (long int)(int) l != l) | |
100 | cf_error("Number out of range"); | |
101 | cf_lval.i = l; | |
102 | return NUM; | |
103 | } | |
104 | ||
105 | {DIGIT}+ { | |
106 | char *e; | |
107 | long int l; | |
108 | errno = 0; | |
109 | l = strtoul(yytext, &e, 10); | |
110 | if (e && *e || errno == ERANGE || (long int)(int) l != l) | |
111 | cf_error("Number out of range"); | |
112 | cf_lval.i = l; | |
113 | return NUM; | |
114 | } | |
115 | ||
116 | {ALPHA}{ALNUM}* { | |
117 | unsigned int h = cf_hash(yytext); | |
118 | struct keyword *k = kw_hash[h & (KW_HASH_SIZE-1)]; | |
119 | while (k) | |
120 | { | |
121 | if (!strcmp(k->name, yytext)) | |
944f008a MM |
122 | { |
123 | if (k->value > 0) | |
124 | return k->value; | |
125 | else | |
126 | { | |
127 | cf_lval.i = -k->value; | |
128 | return ENUM; | |
129 | } | |
130 | } | |
82fc7be7 MM |
131 | k=k->next; |
132 | } | |
133 | cf_lval.s = cf_find_sym(yytext, h); | |
134 | return SYM; | |
135 | } | |
136 | ||
bc2fb680 MM |
137 | <CLI>! { |
138 | BEGIN(INITIAL); | |
139 | return CLI_MARKER; | |
140 | } | |
141 | ||
38506f71 | 142 | [={}:;,()+*/%-<>~\[\]] { |
82fc7be7 MM |
143 | return yytext[0]; |
144 | } | |
145 | ||
146 | ["][^"\n]*["] { | |
147 | cf_lval.t = yytext+1; | |
49e4a4d1 | 148 | yytext[yyleng-1] = 0; |
82fc7be7 MM |
149 | return TEXT; |
150 | } | |
151 | ||
152 | ["][^"\n]*\n cf_error("Unterminated string"); | |
153 | ||
154 | <INITIAL,COMMENT><<EOF>> return END; | |
155 | ||
156 | {WHITE}+ | |
157 | ||
7f400d1c | 158 | \n conf_lino++; |
82fc7be7 | 159 | |
72614174 | 160 | # BEGIN(COMMENT); |
82fc7be7 | 161 | |
72614174 | 162 | \/\* BEGIN(CCOMM); |
82fc7be7 MM |
163 | |
164 | . cf_error("Unknown character"); | |
165 | ||
166 | <COMMENT>\n { | |
31b3e1bb | 167 | conf_lino++; |
82fc7be7 MM |
168 | BEGIN(INITIAL); |
169 | } | |
170 | ||
171 | <COMMENT>. | |
172 | ||
173 | <CCOMM>\*\/ BEGIN(INITIAL); | |
31b3e1bb | 174 | <CCOMM>\n conf_lino++; |
82fc7be7 MM |
175 | <CCOMM>\/\* cf_error("Comment nesting not supported"); |
176 | <CCOMM><<EOF>> cf_error("Unterminated comment"); | |
177 | <CCOMM>. | |
178 | ||
179 | %% | |
180 | ||
181 | static int | |
182 | cf_hash(byte *c) | |
183 | { | |
184 | unsigned int h = 13; | |
185 | ||
186 | while (*c) | |
187 | h = (h * 37) + *c++; | |
188 | return h; | |
189 | } | |
190 | ||
191 | static struct symbol * | |
192 | cf_find_sym(byte *c, unsigned int h0) | |
193 | { | |
194 | unsigned int h = h0 & (SYM_HASH_SIZE-1); | |
c9aae7f4 | 195 | struct symbol *s, **ht; |
82fc7be7 MM |
196 | int l; |
197 | ||
c9aae7f4 MM |
198 | if (ht = new_config->sym_hash) |
199 | { | |
200 | for(s = ht[h]; s; s=s->next) | |
201 | if (!strcmp(s->name, c) && s->scope->active) | |
202 | return s; | |
203 | } | |
204 | if (new_config->sym_fallback) | |
205 | { | |
206 | /* We know only top-level scope is active */ | |
207 | for(s = new_config->sym_fallback[h]; s; s=s->next) | |
c8f61a01 | 208 | if (!strcmp(s->name, c) && s->scope->active) |
bc2fb680 | 209 | return s; |
c9aae7f4 MM |
210 | } |
211 | if (!ht) | |
212 | ht = new_config->sym_hash = cfg_allocz(SYM_HASH_SIZE * sizeof(struct keyword *)); | |
82fc7be7 MM |
213 | l = strlen(c); |
214 | if (l > SYM_MAX_LEN) | |
215 | cf_error("Symbol too long"); | |
49e4a4d1 | 216 | s = cfg_alloc(sizeof(struct symbol) + l); |
c9aae7f4 MM |
217 | s->next = ht[h]; |
218 | ht[h] = s; | |
c8f61a01 | 219 | s->scope = conf_this_scope; |
82fc7be7 MM |
220 | s->class = SYM_VOID; |
221 | s->def = NULL; | |
0b62c3a7 | 222 | s->aux = 0; |
82fc7be7 MM |
223 | strcpy(s->name, c); |
224 | return s; | |
225 | } | |
226 | ||
4107df1d MM |
227 | struct symbol * |
228 | cf_find_symbol(byte *c) | |
229 | { | |
230 | return cf_find_sym(c, cf_hash(c)); | |
231 | } | |
232 | ||
8450be97 | 233 | struct symbol * |
4ba84ebc | 234 | cf_default_name(char *prefix, int *counter) |
8450be97 MM |
235 | { |
236 | char buf[32]; | |
237 | struct symbol *s; | |
238 | ||
239 | do | |
240 | { | |
4ba84ebc | 241 | sprintf(buf, "%s%d", prefix, ++(*counter)); |
8450be97 MM |
242 | s = cf_find_sym(buf, cf_hash(buf)); |
243 | if (!s) cf_error("Unable to generate default name"); | |
244 | } | |
245 | while (s->class != SYM_VOID); | |
246 | return s; | |
247 | } | |
248 | ||
4107df1d MM |
249 | void |
250 | cf_define_symbol(struct symbol *sym, int type, void *def) | |
251 | { | |
252 | if (sym->class) | |
253 | cf_error("Symbol already defined"); | |
254 | sym->class = type; | |
255 | sym->def = def; | |
256 | } | |
257 | ||
c9aae7f4 MM |
258 | static void |
259 | cf_lex_init_kh(void) | |
260 | { | |
261 | struct keyword *k; | |
262 | ||
263 | for(k=keyword_list; k->name; k++) | |
264 | { | |
265 | unsigned h = cf_hash(k->name) & (KW_HASH_SIZE-1); | |
266 | k->next = kw_hash[h]; | |
267 | kw_hash[h] = k; | |
268 | } | |
269 | kw_hash_inited = 1; | |
270 | } | |
271 | ||
82fc7be7 | 272 | void |
bc2fb680 | 273 | cf_lex_init(int is_cli) |
82fc7be7 | 274 | { |
c9aae7f4 MM |
275 | if (!kw_hash_inited) |
276 | cf_lex_init_kh(); | |
31b3e1bb | 277 | conf_lino = 1; |
bc2fb680 MM |
278 | yyrestart(NULL); |
279 | if (is_cli) | |
280 | BEGIN(CLI); | |
281 | else | |
282 | BEGIN(INITIAL); | |
c8f61a01 MM |
283 | conf_this_scope = cfg_allocz(sizeof(struct sym_scope)); |
284 | conf_this_scope->active = 1; | |
82fc7be7 MM |
285 | } |
286 | ||
c8f61a01 MM |
287 | void |
288 | cf_push_scope(struct symbol *sym) | |
289 | { | |
290 | struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope)); | |
291 | ||
292 | s->next = conf_this_scope; | |
293 | conf_this_scope = s; | |
294 | s->active = 1; | |
295 | s->name = sym; | |
296 | } | |
297 | ||
298 | void | |
299 | cf_pop_scope(void) | |
300 | { | |
301 | conf_this_scope->active = 0; | |
302 | conf_this_scope = conf_this_scope->next; | |
303 | ASSERT(conf_this_scope); | |
304 | } |