1 %top {
2 /* Include this before everything else, for various large-file definitions */
3 #include "config.h"
4 }
5 
6 /*
7  * We want a reentrant scanner.
8  */
9 %option reentrant
10 
11 /*
12  * We don't use input, so don't generate code for it.
13  */
14 %option noinput
15 
16 /*
17  * We don't use unput, so don't generate code for it.
18  */
19 %option nounput
20 
21 /*
22  * We don't read interactively from the terminal.
23  */
24 %option never-interactive
25 
26 /*
27  * The language we're scanning is case-insensitive.
28  */
29 %option caseless
30 
31 /*
32  * We use start condition stacks.
33  */
34 %option stack
35 
36 /*
37  * We want to stop processing when we get to the end of the input.
38  */
39 %option noyywrap
40 
41 /*
42  * The type for the state we keep for a scanner.
43  */
44 %option extra-type="DiamDict_scanner_state_t *"
45 
46 /*
47  * Prefix scanner routines with "DiamDict_" rather than "yy", so this scanner
48  * can coexist with other scanners.
49  */
50 %option prefix="DiamDict_"
51 
52 %option outfile="diam_dict.c"
53 
54 /*
55  * We have to override the memory allocators so that we don't get
56  * "unused argument" warnings from the yyscanner argument (which
57  * we don't use, as we have a global memory allocator).
58  *
59  * We provide, as macros, our own versions of the routines generated by Flex,
60  * which just call malloc()/realloc()/free() (as the Flex versions do),
61  * discarding the extra argument.
62  */
63 %option noyyalloc
64 %option noyyrealloc
65 %option noyyfree
66 
67 %{
68 	/*
69 	 ** diam_dict.h
70 	 ** Diameter Dictionary Import Routines
71 	 **
72 	 ** (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
73 	 **
74 	 ** This library is free software; you can redistribute it and/or
75 	 ** modify it under the terms of the GNU Library General Public
76 	 ** License as published by the Free Software Foundation; either
77 	 ** version 2 of the License, or (at your option) any later version.
78 	 **
79 	 ** This library is distributed in the hope that it will be useful,
80 	 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
81 	 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
82 	 ** Library General Public License for more details.
83 	 **
84 	 ** You should have received a copy of the GNU Library General Public
85 	 ** License along with this library; if not, write to the Free Software
86 	 ** Foundation, Inc., 51 Franklin Street, Fifth Floor,
87 	 ** Boston, MA  02110-1301, USA.
88 	 **
89 	 ** See draft-frascone-xml-dictionary for the syntax of the
90 	 ** dictionary.
91 	 */
92 
93 #include <glib.h>
94 #include <stdio.h>
95 #include <string.h>
96 #include <errno.h>
97 #include <stdlib.h>
98 #include <stdarg.h>
99 #include "diam_dict.h"
100 #include <epan/to_str.h>
101 #include <wsutil/file_util.h>
102 
103 /*
104  * Disable diagnostics in the code generated by Flex.
105  */
106 DIAG_OFF_FLEX
107 
108 typedef struct entity_t {
109 	char* name;
110 	char* file;
111 	struct entity_t* next;
112 } entity_t;
113 
114 #define ATTR_UINT(cont) do { D(("attr_uint " #cont "\t" )); yyextra->attr_uint = &(cont); yy_push_state(GET_UINT_ATTR, yyscanner); } while(0)
115 #define ATTR_STR(cont) do { D(("attr_str " #cont "\t" )); yyextra->attr_str = &(cont); yy_push_state(GET_ATTR, yyscanner); } while(0)
116 #define IGNORE() do { D(("ignore: %s\t",yytext)); yy_push_state(IGNORE_ATTR, yyscanner); } while(0)
117 
118 #define D(args) ddict_debug args
119 
120 #define MAX_INCLUDE_DEPTH 10
121 #define YY_INPUT(buf,result,max_size) { result = yyextra->current_yyinput(buf,max_size,yyscanner); }
122 #define YY_USER_INIT { \
123 	DiamDict_scanner_state_t *scanner_state = DiamDict_get_extra(yyscanner); \
124 	BEGIN(scanner_state->start_state); \
125 }
126 #define ECHO
127 #define APPEND(txt,len) append_to_buffer(txt,len,yyextra)
128 
129 typedef struct {
130 	const char* sys_dir;
131 
132 	char* write_ptr;
133 	char* read_ptr;
134 
135 	char* strbuf;
136 	unsigned size_strbuf;
137 	unsigned len_strbuf;
138 
139 	ddict_t* dict;
140 
141 	ddict_application_t* appl;
142 	ddict_avp_t* avp;
143 	ddict_enum_t* enumitem;
144 	ddict_gavp_t* gavp;
145 	ddict_typedefn_t* typedefn;
146 	ddict_cmd_t* cmd;
147 	ddict_vendor_t* vnd;
148 	ddict_xmlpi_t* xmlpi;
149 
150 	ddict_application_t* last_appl;
151 	ddict_avp_t* last_avp;
152 	ddict_enum_t* last_enumitem;
153 	ddict_gavp_t* last_gavp;
154 	ddict_typedefn_t* last_typedefn;
155 	ddict_cmd_t* last_cmd;
156 	ddict_vendor_t* last_vnd;
157 	ddict_xmlpi_t* last_xmlpi;
158 
159 	entity_t *ents;
160 
161 	char** attr_str;
162 	unsigned* attr_uint;
163 
164 	size_t (*current_yyinput)(char*,size_t,yyscan_t);
165 	int (*current_close)(FILE *fh);
166 
167 	YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
168 	int include_stack_ptr;
169 
170 	int start_state;
171 } DiamDict_scanner_state_t;
172 
173 static void ddict_debug(const char* fmt, ...) G_GNUC_PRINTF(1, 2);
174 static void append_to_buffer(const char* txt, unsigned len, DiamDict_scanner_state_t *statep);
175 static FILE* ddict_open(const char*, const char*);
176 
177 /*
178  * Sleazy hack to suppress compiler warnings in yy_fatal_error().
179  */
180 #define YY_EXIT_FAILURE ((void)yyscanner, 2)
181 
182 /*
183  * Macros for the allocators, to discard the extra argument.
184  */
185 #define DiamDict_alloc(size, yyscanner)		(void *)malloc(size)
186 #define DiamDict_realloc(ptr, size, yyscanner)	(void *)realloc((char *)(ptr), (size))
187 #define DiamDict_free(ptr, yyscanner)		free((char *)ptr)
188 
189 %}
190 
191 
192 xmlpi_start [[:blank:] \r\n]*<\?[[:blank:] \r\n]*
193 xmlpi_end [[:blank:] \r\n]*\?>[[:blank:] \r\n]*
194 xmlpi_key_attr [[:blank:] \r\n]*key[[:blank:] \r\n]*=[[:blank:] \r\n]*\042
195 xmlpi_value_attr [[:blank:] \r\n]*value[[:blank:] \r\n]*=[[:blank:] \r\n]*\042
196 
197 comment_start [[:blank:] \r\n]*<!--[[:blank:] \r\n]*
198 comment_end [[:blank:] \r\n]*-->[[:blank:] \r\n]*
199 open_tag [[:blank:] \r\n]*<[[:blank:] \r\n]*
200 end_tag [[:blank:] \r\n]*\/>[[:blank:] \r\n]*
201 close_tag [[:blank:] \r\n]*>[[:blank:] \r\n]*
202 open_closetag [[:blank:] \r\n]*<\/[[:blank:] \r\n]*
203 equals [[:blank:] \r\n]*=[[:blank:] \r\n]*
204 whitespace [[:blank:] \r\n]*
205 dquoted \042[^\042]*\042
206 
207 doctype [[:blank:] \r\n]*<!DOCTYPE[^\[]*\[[[:blank:] \r\n]*
208 doctype_end [[:blank:] \r\n]*\][[:blank:] \r\n]*>[[:blank:] \r\n]*
209 
210 start_entity [[:blank:] \r\n]*<\!ENTITY[[:blank:] \r\n]*
211 system [[:blank:] \r\n]*SYSTEM[[:blank:] \r\n]*\042
212 entityname [a-z0-9-]+
213 ndquot [^\042]+
214 end_entity \042[[:blank:] \r\n]*>[[:blank:] \r\n]*
215 
216 entity \&[a-z0-9-]+;
217 
218 any .
219 
220 
221 
222 
223 stop >
224 stop_end \/>
225 dquot \042
226 number [-]?[0-9]*
227 
228 dictionary_start <dictionary>
229 dictionary_end <\/dictionary>
230 
231 base_start <base[^>*]*>
232 base_end <\/base>
233 
234 application_start <application
235 application_end<\/application>
236 
237 command_start <command
238 command_end<\/command>
239 
240 typedefn_start <typedefn
241 
242 avp_start <avp
243 avp_end <\/avp>
244 
245 type_start <type
246 enum_start <enum
247 
248 grouped_start <grouped>
249 grouped_end <\/grouped>
250 
251 vendor_start <vendor
252 vendor_end<\/vendor>
253 
254 gavp_start <gavp
255 
256 ignored_attr [a-z0-9-]+=
257 ignored_quoted \042[^\042]*\042
258 
259 name_attr name=\042
260 id_attr id=\042
261 code_attr code=\042
262 vendor_attr vendor-id=\042
263 typename_attr type-name=\042
264 typeparent_attr type-parent=\042
265 description_attr description=\042
266 
267 
268 
269 %S LOADING LOADING_COMMENT LOADING_XMLPI ENTITY GET_SYSTEM GET_FILE END_ENTITY
270 %S GET_ATTR GET_UINT_ATTR END_ATTR OUTSIDE IN_DICT IN_APPL IN_AVP APPL_ATTRS IGNORE_ATTR
271 %S TYPE_ATTRS GAVP_ATTRS ENUM_ATTRS AVP_ATTRS VENDOR_ATTRS COMMAND_ATTRS TYPEDEFN_ATTRS
272 %S XMLPI_ATTRS XMLPI_GETKEY XMLPI_GETVAL XMLPI_ENDATTR
273 %%
274 <LOADING>{doctype} ;
275 <LOADING>{doctype_end} ;
276 
277 <LOADING>{comment_start} BEGIN LOADING_COMMENT;
278 <LOADING_COMMENT>. ;
279 <LOADING_COMMENT>{comment_end} BEGIN LOADING;
280 
281 <LOADING>{xmlpi_start} BEGIN LOADING_XMLPI;
282 <LOADING_XMLPI>{whitespace} ;
283 <LOADING_XMLPI>{entityname} {
284 	yyextra->xmlpi = g_new(ddict_xmlpi_t,1);
285 	yyextra->xmlpi->name = g_strdup(yytext);
286 	yyextra->xmlpi->key = NULL;
287 	yyextra->xmlpi->value = NULL;
288 	yyextra->xmlpi->next = NULL;
289 
290 	if (!yyextra->dict->xmlpis)
291 		yyextra->last_xmlpi = yyextra->dict->xmlpis = yyextra->xmlpi;
292 	else
293 		yyextra->last_xmlpi = yyextra->last_xmlpi->next = yyextra->xmlpi;
294 
295 	BEGIN XMLPI_ATTRS;
296 }
297 
298 <XMLPI_ATTRS>{xmlpi_key_attr} BEGIN XMLPI_GETKEY;
299 <XMLPI_GETKEY>{ndquot} { yyextra->xmlpi->key = g_strdup(yytext); BEGIN XMLPI_ATTRS; }
300 
301 <XMLPI_ATTRS>{xmlpi_value_attr} BEGIN XMLPI_GETVAL;
302 <XMLPI_GETVAL>{ndquot} { yyextra->xmlpi->value = g_strdup(yytext); BEGIN XMLPI_ATTRS; }
303 
304 <XMLPI_ATTRS>.
305 <XMLPI_ATTRS>{xmlpi_end} BEGIN LOADING;
306 
307 
308 <LOADING>{start_entity} BEGIN ENTITY;
309 <ENTITY>{entityname} {
310 	entity_t* e = g_new(entity_t,1);
311 	e->name = g_strdup(yytext);
312 	e->next = yyextra->ents;
313 	yyextra->ents = e;
314 	BEGIN GET_SYSTEM;
315 	};
316 <GET_SYSTEM>{system} BEGIN GET_FILE;
317 <GET_FILE>{ndquot} {
318 		yyextra->ents->file = g_strdup(yytext);
319 		BEGIN END_ENTITY;
320 	}
321 <END_ENTITY>{end_entity} BEGIN LOADING;
322 
323 <LOADING>{open_tag} APPEND("<",1);
324 
325 <LOADING>{close_tag} APPEND(">",1);
326 
327 <LOADING>{end_tag} APPEND("/>",2);
328 
329 <LOADING>{open_closetag} APPEND("</",2);
330 
331 <LOADING>{whitespace} APPEND(" ",1);
332 
333 <LOADING>{dquoted} APPEND(yytext, (unsigned) yyleng);
334 
335 <LOADING>{equals} APPEND("=",1);
336 
337 <LOADING>{any} APPEND(yytext, (unsigned) yyleng);
338 
339 <LOADING>{entity} {
340 	char* p = ++yytext;
341 	entity_t* e;
342 
343 	while(*p != ';') p++;
344 
345 	*p = '\0';
346 
347 	D(("looking for entity: %s\n",yytext));
348 
349 	if ( yyextra->include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
350 		fprintf(stderr, "included files nested to deeply\n");
351 		yyterminate();
352 	}
353 
354 	for (e = yyextra->ents; e; e = e->next) {
355 		if (strcmp(e->name,yytext) == 0) {
356 			yyin = ddict_open(yyextra->sys_dir,e->file);
357 			D(("entity: %s filename: %s yyin: %p\n",e->name,e->file,(void*)yyin));
358 			if (!yyin) {
359 				if (errno)
360 					fprintf(stderr, "Could not open file: '%s', error: %s\n", e->file, g_strerror(errno) );
361 				else
362 					fprintf(stderr, "Could not open file: '%s', error unknown (errno == 0)\n", e->file );
363 				yyterminate();
364 			} else {
365 				yyextra->include_stack[yyextra->include_stack_ptr++] = YY_CURRENT_BUFFER;
366 				yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner), yyscanner);
367 				BEGIN LOADING;
368 			}
369 			break;
370 		}
371 	}
372 
373 	if (!e) {
374 		fprintf(stderr, "Could not find entity: '%s'\n", yytext );
375 		yyterminate();
376 	}
377 
378 }
379 
380 <<EOF>> {
381 	if (!yyin) yyterminate();
382 
383 	yyextra->current_close(yyin);
384 	D(("closing: %p %i\n",(void*)yyin,yyextra->include_stack_ptr));
385 
386 	if ( --yyextra->include_stack_ptr < 0 ) {
387 		D(("DONE READING\n"));
388 		yyin = NULL;
389 		yyterminate();
390 	} else {
391 		yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner);
392 		yy_switch_to_buffer(yyextra->include_stack[yyextra->include_stack_ptr], yyscanner);
393 		BEGIN LOADING;
394 	}
395 }
396 
397 
398 <GET_ATTR>{ndquot} {
399 	*(yyextra->attr_str) = g_strdup(yytext);
400 	D(("%s\n",yytext));
401 	yyextra->attr_str = NULL;
402 	BEGIN END_ATTR;
403 }
404 
405 <GET_UINT_ATTR>{number} {
406 	*(yyextra->attr_uint) = (unsigned) strtoul(yytext,NULL,10);
407 	D(("%s\n",yytext););
408 	yyextra->attr_uint = NULL;
409 	BEGIN END_ATTR;
410 }
411 
412 <END_ATTR>{dquot} {	yy_pop_state(yyscanner); }
413 
414 <IGNORE_ATTR>. {
415 	/* XXX: should go?*/
416 	D(("{%s}",yytext));
417 }
418 
419 <IGNORE_ATTR>{ignored_quoted} {
420 	D(("=>%s<=\n",yytext));
421 	yy_pop_state(yyscanner);
422 }
423 
424 <OUTSIDE>{dictionary_start} {
425 	D(("dictionary_start\n"));
426 
427 	BEGIN IN_DICT;
428 }
429 
430 <IN_DICT>{base_start} {
431 	D(("base_start\n"));
432 	BEGIN IN_APPL;
433 }
434 
435 <IN_DICT>{application_start} {
436 	D(("application_start\n"));
437 
438 	yyextra->appl = g_new(ddict_application_t,1);
439 	yyextra->appl->name = NULL;
440 	yyextra->appl->code = 0;
441 	yyextra->appl->next = NULL;
442 
443 	if (!yyextra->dict->applications)
444 		yyextra->last_appl = yyextra->dict->applications = yyextra->appl;
445 	else
446 		yyextra->last_appl = yyextra->last_appl->next = yyextra->appl;
447 
448 	BEGIN APPL_ATTRS;
449 }
450 
451 <APPL_ATTRS>{name_attr} { ATTR_STR(yyextra->appl->name); }
452 <APPL_ATTRS>{id_attr} { ATTR_UINT(yyextra->appl->code); }
453 
454 <APPL_ATTRS>{stop} BEGIN IN_APPL;
455 <APPL_ATTRS>{stop_end} BEGIN IN_DICT;
456 
457 <IN_APPL>{command_end}			;
458 
459 <IN_APPL>{command_start}		{
460 	D(("command_start\n"));
461 
462 	yyextra->cmd = g_new(ddict_cmd_t,1);
463 	yyextra->cmd->name = NULL;
464 	yyextra->cmd->vendor = NULL;
465 	yyextra->cmd->code = 0;
466 	yyextra->cmd->next = NULL;
467 
468 	if (!yyextra->dict->cmds)
469 		yyextra->last_cmd = yyextra->dict->cmds = yyextra->cmd;
470 	else
471 		yyextra->last_cmd = yyextra->last_cmd->next = yyextra->cmd;
472 
473 	BEGIN COMMAND_ATTRS;
474 }
475 
476 <COMMAND_ATTRS>{name_attr}		{ ATTR_STR(yyextra->cmd->name); }
477 <COMMAND_ATTRS>{vendor_attr}		{ ATTR_STR(yyextra->cmd->vendor); }
478 <COMMAND_ATTRS>{code_attr}		{ ATTR_UINT(yyextra->cmd->code); }
479 <COMMAND_ATTRS>{stop}			|
480 <COMMAND_ATTRS>{stop_end}		{ BEGIN IN_APPL; }
481 
482 <IN_DICT>{vendor_start} {
483 	D(("vendor_start\n"));
484 
485 	yyextra->vnd = g_new(ddict_vendor_t,1);
486 	yyextra->vnd->name = NULL;
487 	yyextra->vnd->code = 0;
488 	yyextra->vnd->next = NULL;
489 
490 	if (!yyextra->dict->vendors)
491 		yyextra->last_vnd = yyextra->dict->vendors = yyextra->vnd;
492 	else
493 		yyextra->last_vnd = yyextra->last_vnd->next = yyextra->vnd;
494 
495 	BEGIN VENDOR_ATTRS;
496 }
497 
498 <VENDOR_ATTRS>{name_attr}		{ ATTR_STR(yyextra->vnd->desc); }
499 <VENDOR_ATTRS>{vendor_attr}		{ ATTR_STR(yyextra->vnd->name); }
500 <VENDOR_ATTRS>{code_attr}		{ ATTR_UINT(yyextra->vnd->code); }
501 <VENDOR_ATTRS>{stop}			{ BEGIN IN_APPL; }
502 <VENDOR_ATTRS>{stop_end}		{ BEGIN IN_DICT; }
503 
504 <IN_APPL>{typedefn_start} {
505 	D(("typedefn_start\n"));
506 
507 	yyextra->typedefn = g_new(ddict_typedefn_t,1);
508 	yyextra->typedefn->name = NULL;
509 	yyextra->typedefn->parent = NULL;
510 	yyextra->typedefn->next = NULL;
511 
512 	if (!yyextra->dict->typedefns)
513 		yyextra->last_typedefn = yyextra->dict->typedefns = yyextra->typedefn;
514 	else
515 		yyextra->last_typedefn = yyextra->last_typedefn->next = yyextra->typedefn;
516 
517 	BEGIN TYPEDEFN_ATTRS;
518 }
519 
520 <TYPEDEFN_ATTRS>{typename_attr}		{ ATTR_STR(yyextra->typedefn->name); }
521 <TYPEDEFN_ATTRS>{typeparent_attr}	{ ATTR_STR(yyextra->typedefn->parent); }
522 <TYPEDEFN_ATTRS>{stop}			|
523 <TYPEDEFN_ATTRS>{stop_end}		{ BEGIN IN_APPL; }
524 
525 
526 <IN_APPL>{avp_start}	{
527 	D(("avp_start\n"));
528 
529 	yyextra->avp = g_new(ddict_avp_t,1);
530 	yyextra->avp->name = NULL;
531 	yyextra->avp->description = NULL;
532 	yyextra->avp->vendor = NULL;
533 	yyextra->avp->code = 0;
534 	yyextra->avp->type = NULL;
535 	yyextra->avp->enums = NULL;
536 	yyextra->avp->gavps = NULL;
537 	yyextra->avp->next = NULL;
538 
539 	if (! yyextra->dict->avps )
540 		yyextra->last_avp = yyextra->dict->avps = yyextra->avp;
541 	else
542 		yyextra->last_avp = yyextra->last_avp->next = yyextra->avp;
543 
544 	BEGIN AVP_ATTRS;
545 }
546 
547 <AVP_ATTRS>{name_attr}			{ ATTR_STR(yyextra->avp->name); }
548 <AVP_ATTRS>{description_attr}		{ ATTR_STR(yyextra->avp->description); }
549 <AVP_ATTRS>{vendor_attr}		{ ATTR_STR(yyextra->avp->vendor); }
550 <AVP_ATTRS>{code_attr}			{ ATTR_UINT(yyextra->avp->code); }
551 <AVP_ATTRS>{stop}			{ BEGIN IN_AVP;  }
552 <AVP_ATTRS>{stop_end}			{ BEGIN IN_APPL; }
553 
554 
555 <IN_AVP>{grouped_start} { yyextra->avp->type = g_strdup("Grouped"); };
556 <IN_AVP>{grouped_end} ;
557 
558 <IN_AVP>{type_start} { BEGIN TYPE_ATTRS; }
559 <TYPE_ATTRS>{typename_attr}			{ ATTR_STR(yyextra->avp->type); }
560 
561 <IN_AVP>{gavp_start} {
562 	D(("gavp_start\n"));
563 
564 	yyextra->gavp = g_new(ddict_gavp_t,1);
565 	yyextra->gavp->name = NULL;
566 	yyextra->gavp->code = 0;
567 	yyextra->gavp->next = NULL;
568 
569 	if (!yyextra->avp->gavps)
570 		yyextra->last_gavp = yyextra->avp->gavps = yyextra->gavp;
571 	else
572 		yyextra->last_gavp = yyextra->last_gavp->next = yyextra->gavp;
573 
574 	BEGIN GAVP_ATTRS;
575 }
576 
577 
578 <GAVP_ATTRS>{name_attr}			{ ATTR_STR(yyextra->gavp->name); }
579 
580 
581 <IN_AVP>{enum_start} {
582 	D(("enum_start\n"));
583 
584 	yyextra->enumitem = g_new(ddict_enum_t,1);
585 	yyextra->enumitem->name = NULL;
586 	yyextra->enumitem->code = 0;
587 	yyextra->enumitem->next = NULL;
588 
589 	if (!yyextra->avp->enums)
590 		yyextra->last_enumitem = yyextra->avp->enums = yyextra->enumitem;
591 	else
592 		yyextra->last_enumitem = yyextra->last_enumitem->next = yyextra->enumitem;
593 
594 	BEGIN ENUM_ATTRS;
595 }
596 
597 
598 <ENUM_ATTRS>{name_attr}			{ ATTR_STR(yyextra->enumitem->name); }
599 <ENUM_ATTRS>{code_attr}			{ ATTR_UINT(yyextra->enumitem->code); }
600 
601 <TYPE_ATTRS,GAVP_ATTRS,ENUM_ATTRS>{stop}		{ BEGIN IN_AVP; }
602 <TYPE_ATTRS,GAVP_ATTRS,ENUM_ATTRS>{stop_end}		{ BEGIN IN_AVP; }
603 
604 <IN_AVP>{avp_end} { D(("avp_end\n")); BEGIN IN_APPL; }
605 
606 <IN_APPL>{application_end} {
607 	D(("application_end\n")); BEGIN IN_DICT;
608 }
609 <IN_APPL>{stop_end} {
610 	D(("application_stop_end\n")); BEGIN IN_DICT;
611 }
612 <IN_APPL>{vendor_end} {
613 	D(("vendor_end\n")); BEGIN IN_DICT;
614 }
615 <IN_APPL>{base_end} {
616 	D(("base_end\n")); BEGIN IN_DICT;
617 }
618 
619 <IN_DICT>{dictionary_end} {
620 	yyterminate();
621 }
622 
623 <AVP_ATTRS,ENUM_ATTRS,GAVP_ATTRS,TYPE_ATTRS,TYPEDEFN_ATTRS,VENDOR_ATTRS,APPL_ATTRS,COMMAND_ATTRS>{ignored_attr} IGNORE();
624 
625 <OUTSIDE>. ;
626 
627 %%
628 
629 /*
630  * Turn diagnostics back on, so we check the code that we've written.
631  */
632 DIAG_ON_FLEX
633 
634 static int debugging  = 0;
635 
636 static void ddict_debug(const char* fmt, ...) {
637 	va_list ap;
638 
639 	va_start(ap, fmt);
640 	if (debugging) vfprintf(stderr, fmt, ap);
641 	va_end(ap);
642 
643 	fflush(stderr);
644 }
645 
646 /*
647  * Sleazy hack to avoid unused function warnings for yy_top_state.
648  */
649 extern void ddict_unused(yyscan_t yyscanner);
650 
651 void
652 ddict_unused(yyscan_t yyscanner)
653 {
654 	yy_top_state(yyscanner);
655 }
656 
657 static void
658 append_to_buffer(const char* txt, unsigned len, DiamDict_scanner_state_t *statep)
659 {
660 
661 	if (statep->strbuf == NULL) {
662 		statep->strbuf = (char*)g_malloc(statep->size_strbuf);
663 		statep->read_ptr = statep->strbuf;
664 		statep->write_ptr = statep->strbuf;
665 	}
666 
667 	if (statep->len_strbuf + len >= statep->size_strbuf) {
668 		statep->strbuf = (char*)g_realloc(statep->strbuf,statep->size_strbuf *= 2);
669 		statep->read_ptr = statep->strbuf;
670 	}
671 
672 	statep->write_ptr = statep->strbuf + statep->len_strbuf;
673 	memcpy(statep->write_ptr, txt, len + 1);
674 	statep->len_strbuf += len;
675 }
676 
677 static size_t
678 file_input(char* buf, size_t max, yyscan_t scanner)
679 {
680 	FILE *in = yyget_in(scanner);
681 	size_t read_cnt;
682 
683 	read_cnt = fread(buf,1,max,in);
684 
685 	if ( read_cnt == max ) {
686 		return max;
687 	} else if (read_cnt > 0) {
688 		return read_cnt;
689 	} else {
690 		return YY_NULL;
691 	}
692 }
693 
694 
695 static size_t
696 string_input(char* buf, size_t max, yyscan_t scanner)
697 {
698 	DiamDict_scanner_state_t *statep = yyget_extra(scanner);
699 
700 	if (statep->read_ptr >= statep->write_ptr ) {
701 		return YY_NULL;
702 	} else if ( statep->read_ptr + max > statep->write_ptr ) {
703 		max = statep->write_ptr - statep->read_ptr;
704 	}
705 
706 	memcpy(buf,statep->read_ptr,max);
707 	statep->read_ptr += max;
708 
709 	return max;
710 }
711 
712 /*
713  * If we're reading from a string, yyin is set to stdin, and we don't
714  * want to close that.
715  */
716 static int
717 string_close(FILE *fh _U_)
718 {
719 	return 0;
720 }
721 
722 static FILE *
723 ddict_open(const char* system_directory, const char* filename)
724 {
725 	FILE* fh;
726 	char* fname;
727 	if (system_directory) {
728 		fname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
729 		    system_directory,filename);
730 	} else {
731 		fname = g_strdup(filename);
732 	}
733 
734 	fh = ws_fopen(fname,"r");
735 
736 	D(("fname: %s fh: %p\n",fname,(void*)fh));
737 
738 	g_free(fname);
739 
740 
741 	return fh;
742 }
743 
744 ddict_t *
745 ddict_scan(const char* system_directory, const char* filename, int dbg)
746 {
747 	DiamDict_scanner_state_t state;
748 	FILE *in;
749 	yyscan_t scanner;
750 
751 	debugging = dbg;
752 
753 	state.sys_dir = system_directory;
754 
755 	state.write_ptr = NULL;
756 	state.read_ptr = NULL;
757 
758 	state.strbuf = NULL;
759 	state.size_strbuf = 8192;
760 	state.len_strbuf = 0;
761 
762 	state.dict = g_new(ddict_t,1);
763 	state.dict->applications = NULL;
764 	state.dict->vendors = NULL;
765 	state.dict->cmds = NULL;
766 	state.dict->typedefns = NULL;
767 	state.dict->avps = NULL;
768 	state.dict->xmlpis = NULL;
769 
770 	state.appl = NULL;
771 	state.avp = NULL;
772 	state.enumitem = NULL;
773 	state.gavp = NULL;
774 	state.typedefn = NULL;
775 	state.cmd = NULL;
776 	state.vnd = NULL;
777 	state.xmlpi = NULL;
778 
779 	state.last_appl = NULL;
780 	state.last_avp = NULL;
781 	state.last_enumitem = NULL;
782 	state.last_gavp = NULL;
783 	state.last_typedefn = NULL;
784 	state.last_cmd = NULL;
785 	state.last_vnd = NULL;
786 	state.last_xmlpi = NULL;
787 
788 	state.ents = NULL;
789 
790 	state.attr_str = NULL;
791 	state.attr_uint = NULL;
792 
793 	/*
794 	 * Pass 1.
795 	 *
796 	 * Reads the file, does some work, and stores a modified version
797 	 * of the file contents in memory.
798 	 */
799 	state.current_yyinput = file_input;
800 	state.current_close = fclose;
801 	state.include_stack_ptr = 0;
802 
803 	in = ddict_open(system_directory,filename);
804 
805 	if (in == NULL) {
806 		D(("unable to open %s: %s\n", filename, g_strerror(errno)));
807 		g_free(state.dict);
808 		return NULL;
809 	}
810 
811 	if (DiamDict_lex_init(&scanner) != 0) {
812 		/* Note: cannot be reached since memory allocation failure terminates early */
813 		D(("Can't initialize scanner: %s\n", g_strerror(errno)));
814 		fclose(in);
815 		g_free(state.dict);
816 		return NULL;
817 	}
818 
819 	DiamDict_set_in(in, scanner);
820 
821 	/* Associate the state with the scanner */
822 	DiamDict_set_extra(&state, scanner);
823 
824 	state.start_state = LOADING;
825 	DiamDict_lex(scanner);
826 
827 	DiamDict_lex_destroy(scanner);
828 	/*
829 	 * XXX - can the lexical analyzer terminate without closing
830 	 * all open input files?
831 	 */
832 
833 	D(("\n---------------\n%s\n------- %u -------\n",state.strbuf,state.len_strbuf));
834 
835 	/*
836 	 * Pass 2.
837 	 *
838 	 * Reads the modified version of the file contents and does the
839 	 * rest of the work.
840 	 */
841 	state.current_yyinput = string_input;
842 	state.current_close = string_close;
843 
844 	if (DiamDict_lex_init(&scanner) != 0) {
845 		/* Note: cannot be reached since memory allocation failure terminates early */
846 		D(("Can't initialize scanner: %s\n", g_strerror(errno)));
847 		g_free(state.dict);
848 		g_free(state.strbuf);
849 		return NULL;
850 	}
851 
852 	/* Associate the state with the scanner */
853 	DiamDict_set_extra(&state, scanner);
854 
855 	state.start_state = OUTSIDE;
856 	DiamDict_lex(scanner);
857 
858 	DiamDict_lex_destroy(scanner);
859 	{
860 		entity_t *e, *en;
861 
862 		for (e = state.ents; e; e = en) {
863 			en = e->next;
864 			g_free(e->name);
865 			g_free(e->file);
866 			g_free(e);
867 		}
868 	}
869 	g_free(state.strbuf);
870 
871 	return state.dict;
872 }
873 
874 void
875 ddict_free(ddict_t* d)
876 {
877 	ddict_application_t *p, *pn;
878 	ddict_vendor_t *v, *vn;
879 	ddict_cmd_t *c, *cn;
880 	ddict_typedefn_t *t, *tn;
881 	ddict_avp_t *a, *an;
882 	ddict_xmlpi_t *x, *xn;
883 
884 #define FREE_NAMEANDOBJ(n) do { g_free(n->name); g_free(n); } while(0)
885 
886 	for (p = d->applications; p; p = pn ) {
887 		pn = p->next;
888 		FREE_NAMEANDOBJ(p);
889 	}
890 
891 	for (v = d->vendors; v; v = vn) {
892 		vn = v->next;
893 		g_free(v->desc);
894 		FREE_NAMEANDOBJ(v);
895 	}
896 
897 	for (c = d->cmds; c; c = cn ) {
898 		cn = c->next;
899 		g_free(c->vendor);
900 		FREE_NAMEANDOBJ(c);
901 	}
902 
903 	for (t = d->typedefns; t; t = tn) {
904 		tn = t->next;
905 		g_free(t->parent);
906 		FREE_NAMEANDOBJ(t);
907 	}
908 
909 	for (a = d->avps; a; a = an) {
910 		ddict_gavp_t* g, *gn;
911 		ddict_enum_t* e, *en;
912 		an = a->next;
913 
914 		for (g = a->gavps; g; g = gn) {
915 			gn = g->next;
916 			FREE_NAMEANDOBJ(g);
917 		}
918 
919 		for (e = a->enums; e; e = en) {
920 			en = e->next;
921 			FREE_NAMEANDOBJ(e);
922 		}
923 
924 		g_free(a->vendor);
925 		g_free(a->type);
926 		g_free(a->description);
927 		FREE_NAMEANDOBJ(a);
928 	}
929 
930 	for (x = d->xmlpis; x; x = xn) {
931 		xn = x->next;
932 		g_free(x->key);
933 		g_free(x->value);
934 		FREE_NAMEANDOBJ(x);
935 	}
936 
937 	g_free(d);
938 }
939 
940 void
941 ddict_print(FILE* fh, ddict_t* d)
942 {
943 	ddict_application_t* p;
944 	ddict_vendor_t* v;
945 	ddict_cmd_t* c;
946 	ddict_typedefn_t* t;
947 	ddict_avp_t* a;
948 
949 
950 	for (p = d->applications; p; p = p->next) {
951 		fprintf(fh,"Application: %s[%u]:\n",
952 				p->name ? p->name : "-",
953 				p->code);
954 	}
955 
956 	for (v = d->vendors; v; v = v->next) {
957 		fprintf(fh,"Vendor: %s[%u]:\n",
958 				v->name ? v->name : "-",
959 				v->code);
960 	}
961 
962 	for (c = d->cmds; c; c = c->next) {
963 		fprintf(fh,"Command: %s[%u] \n",
964 				c->name ? c->name : "-",
965 				c->code);
966 	}
967 
968 	for (t = d->typedefns; t; t = t->next) {
969 		fprintf(fh,"Type: %s -> %s \n",
970 				t->name ? t->name : "-",
971 				t->parent ? t->parent : "" );
972 	}
973 
974 	for (a = d->avps; a; a = a->next) {
975 		ddict_gavp_t* g;
976 		ddict_enum_t* e;
977 		fprintf(fh,"AVP: %s[%u:%s] %s %s\n",
978 				a->name ? a->name : "-",
979 				a->code,
980 				a->vendor ? a->vendor : "None",
981 				a->type ? a->type : "-",
982 				a->description ? a->description : "");
983 
984 		for (g = a->gavps; g; g = g->next) {
985 			fprintf(fh,"\tGAVP: %s\n",
986 					g->name ? g->name : "-" );
987 		}
988 
989 		for (e = a->enums; e; e = e->next) {
990 			fprintf(fh,"\tEnum: %s[%u]\n",
991 					e->name ? e->name : "-",
992 					e->code);
993 		}
994 	}
995 }
996 
997 #ifdef TEST_DIAM_DICT_STANDALONE
998 int
999 main(int argc, char** argv)
1000 {
1001 	ddict_t* d;
1002 	char* dname = NULL;
1003 	char* fname;
1004 	int i = 1;
1005 
1006 	switch (argc) {
1007 		case 3:
1008 			dname = argv[i++];
1009 		case 2:
1010 			fname = argv[i];
1011 			break;
1012 		default:
1013 			fprintf(stderr,"%s: usage [dictionary_dir] dictionary_filename\n",argv[0]);
1014 			return 1;
1015 	}
1016 
1017 	d = ddict_scan(dname,fname,1);
1018 	if (d == NULL) {
1019 		fprintf(stderr, "Can't open dictionary\n");
1020 		return 2;
1021 	}
1022 
1023 	ddict_print(stdout, d);
1024 
1025 	return 0;
1026 }
1027 #endif
1028