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