regen pidl all: rm epan/dissectors/pidl/*-stamp; pushd epan/dissectors/pidl/ && make...
[wireshark-sm.git] / epan / diam_dict.l
blob95ae53c38a8d45593e332964916926c037e176c5
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_"
54  * We have to override the memory allocators so that we don't get
55  * "unused argument" warnings from the yyscanner argument (which
56  * we don't use, as we have a global memory allocator).
57  *
58  * We provide, as macros, our own versions of the routines generated by Flex,
59  * which just call malloc()/realloc()/free() (as the Flex versions do),
60  * discarding the extra argument.
61  */
62 %option noyyalloc
63 %option noyyrealloc
64 %option noyyfree
67         /*
68          ** diam_dict.h
69          ** Diameter Dictionary Import Routines
70          **
71          ** (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
72          **
73          ** This library is free software; you can redistribute it and/or
74          ** modify it under the terms of the GNU Library General Public
75          ** License as published by the Free Software Foundation; either
76          ** version 2 of the License, or (at your option) any later version.
77          **
78          ** This library is distributed in the hope that it will be useful,
79          ** but WITHOUT ANY WARRANTY; without even the implied warranty of
80          ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
81          ** Library General Public License for more details.
82          **
83          ** You should have received a copy of the GNU Library General Public
84          ** License along with this library; if not, write to the Free Software
85          ** Foundation, Inc., 51 Franklin Street, Fifth Floor,
86          ** Boston, MA  02110-1301, USA.
87          **
88          ** See draft-frascone-xml-dictionary for the syntax of the
89          ** dictionary.
90          */
92 #include <glib.h>
93 #include <stdio.h>
94 #include <string.h>
95 #include <errno.h>
96 #include <stdlib.h>
97 #include <stdarg.h>
98 #include "diam_dict.h"
99 #include <epan/to_str.h>
100 #include <wsutil/file_util.h>
103  * Disable diagnostics in the code generated by Flex.
104  */
105 DIAG_OFF_FLEX()
107 typedef struct entity_t {
108         char* name;
109         char* file;
110         struct entity_t* next;
111 } entity_t;
113 #define ATTR_UINT(cont) do { D(("attr_uint " #cont "\t" )); yyextra->attr_uint = &(cont); yy_push_state(GET_UINT_ATTR, yyscanner); } while(0)
114 #define ATTR_STR(cont) do { D(("attr_str " #cont "\t" )); yyextra->attr_str = &(cont); yy_push_state(GET_ATTR, yyscanner); } while(0)
115 #define IGNORE() do { D(("ignore: %s\t",yytext)); yy_push_state(IGNORE_ATTR, yyscanner); } while(0)
117 #define D(args) ddict_debug args
119 #define MAX_INCLUDE_DEPTH 10
120 #define YY_INPUT(buf,result,max_size) { result = yyextra->current_yyinput(buf,max_size,yyscanner); }
121 #define YY_USER_INIT { \
122         DiamDict_scanner_state_t *scanner_state = DiamDict_get_extra(yyscanner); \
123         BEGIN(scanner_state->start_state); \
125 #define ECHO
126 #define APPEND(txt,len) append_to_buffer(txt,len,yyextra)
128 typedef struct {
129         const char* sys_dir;
131         char* write_ptr;
132         char* read_ptr;
134         char* strbuf;
135         unsigned size_strbuf;
136         unsigned len_strbuf;
138         ddict_t* dict;
140         ddict_application_t* appl;
141         ddict_avp_t* avp;
142         ddict_enum_t* enumitem;
143         ddict_gavp_t* gavp;
144         ddict_typedefn_t* typedefn;
145         ddict_cmd_t* cmd;
146         ddict_vendor_t* vnd;
147         ddict_xmlpi_t* xmlpi;
149         ddict_application_t* last_appl;
150         ddict_avp_t* last_avp;
151         ddict_enum_t* last_enumitem;
152         ddict_gavp_t* last_gavp;
153         ddict_typedefn_t* last_typedefn;
154         ddict_cmd_t* last_cmd;
155         ddict_vendor_t* last_vnd;
156         ddict_xmlpi_t* last_xmlpi;
158         entity_t *ents;
160         char** attr_str;
161         unsigned* attr_uint;
163         size_t (*current_yyinput)(char*,size_t,yyscan_t);
164         int (*current_close)(FILE *fh);
166         YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
167         int include_stack_ptr;
169         int start_state;
170 } DiamDict_scanner_state_t;
172 static void ddict_debug(const char* fmt, ...) G_GNUC_PRINTF(1, 2);
173 static void append_to_buffer(const char* txt, unsigned len, DiamDict_scanner_state_t *statep);
174 static FILE* ddict_open(const char*, const char*);
177  * Sleazy hack to suppress compiler warnings in yy_fatal_error().
178  */
179 #define YY_EXIT_FAILURE ((void)yyscanner, 2)
182  * Macros for the allocators, to discard the extra argument.
183  */
184 #define DiamDict_alloc(size, yyscanner)         (void *)malloc(size)
185 #define DiamDict_realloc(ptr, size, yyscanner)  (void *)realloc((char *)(ptr), (size))
186 #define DiamDict_free(ptr, yyscanner)           free((char *)ptr)
191 xmlpi_start [[:blank:] \r\n]*<\?[[:blank:] \r\n]*
192 xmlpi_end [[:blank:] \r\n]*\?>[[:blank:] \r\n]*
193 xmlpi_key_attr [[:blank:] \r\n]*key[[:blank:] \r\n]*=[[:blank:] \r\n]*\042
194 xmlpi_value_attr [[:blank:] \r\n]*value[[:blank:] \r\n]*=[[:blank:] \r\n]*\042
196 comment_start [[:blank:] \r\n]*<!--[[:blank:] \r\n]*
197 comment_end [[:blank:] \r\n]*-->[[:blank:] \r\n]*
198 open_tag [[:blank:] \r\n]*<[[:blank:] \r\n]*
199 end_tag [[:blank:] \r\n]*\/>[[:blank:] \r\n]*
200 close_tag [[:blank:] \r\n]*>[[:blank:] \r\n]*
201 open_closetag [[:blank:] \r\n]*<\/[[:blank:] \r\n]*
202 equals [[:blank:] \r\n]*=[[:blank:] \r\n]*
203 whitespace [[:blank:] \r\n]*
204 dquoted \042[^\042]*\042
206 doctype [[:blank:] \r\n]*<!DOCTYPE[^\[]*\[[[:blank:] \r\n]*
207 doctype_end [[:blank:] \r\n]*\][[:blank:] \r\n]*>[[:blank:] \r\n]*
209 start_entity [[:blank:] \r\n]*<\!ENTITY[[:blank:] \r\n]*
210 system [[:blank:] \r\n]*SYSTEM[[:blank:] \r\n]*\042
211 entityname [a-z0-9-]+
212 ndquot [^\042]+
213 end_entity \042[[:blank:] \r\n]*>[[:blank:] \r\n]*
215 entity \&[a-z0-9-]+;
217 any .
222 stop >
223 stop_end \/>
224 dquot \042
225 number [-]?[0-9]*
227 dictionary_start <dictionary>
228 dictionary_end <\/dictionary>
230 base_start <base[^>*]*>
231 base_end <\/base>
233 application_start <application
234 application_end<\/application>
236 command_start <command
237 command_end<\/command>
239 typedefn_start <typedefn
241 avp_start <avp
242 avp_end <\/avp>
244 type_start <type
245 enum_start <enum
247 grouped_start <grouped>
248 grouped_end <\/grouped>
250 vendor_start <vendor
251 vendor_end<\/vendor>
253 gavp_start <gavp
255 ignored_attr [a-z0-9-]+=
256 ignored_quoted \042[^\042]*\042
258 name_attr name=\042
259 id_attr id=\042
260 code_attr code=\042
261 vendor_attr vendor-id=\042
262 typename_attr type-name=\042
263 typeparent_attr type-parent=\042
264 description_attr description=\042
268 %S LOADING LOADING_COMMENT LOADING_XMLPI ENTITY GET_SYSTEM GET_FILE END_ENTITY
269 %S GET_ATTR GET_UINT_ATTR END_ATTR OUTSIDE IN_DICT IN_APPL IN_AVP APPL_ATTRS IGNORE_ATTR
270 %S TYPE_ATTRS GAVP_ATTRS ENUM_ATTRS AVP_ATTRS VENDOR_ATTRS COMMAND_ATTRS TYPEDEFN_ATTRS
271 %S XMLPI_ATTRS XMLPI_GETKEY XMLPI_GETVAL XMLPI_ENDATTR
273 <LOADING>{doctype} ;
274 <LOADING>{doctype_end} ;
276 <LOADING>{comment_start} BEGIN LOADING_COMMENT;
277 <LOADING_COMMENT>. ;
278 <LOADING_COMMENT>{comment_end} BEGIN LOADING;
280 <LOADING>{xmlpi_start} BEGIN LOADING_XMLPI;
281 <LOADING_XMLPI>{whitespace} ;
282 <LOADING_XMLPI>{entityname} {
283         yyextra->xmlpi = g_new(ddict_xmlpi_t,1);
284         yyextra->xmlpi->name = g_strdup(yytext);
285         yyextra->xmlpi->key = NULL;
286         yyextra->xmlpi->value = NULL;
287         yyextra->xmlpi->next = NULL;
289         if (!yyextra->dict->xmlpis)
290                 yyextra->last_xmlpi = yyextra->dict->xmlpis = yyextra->xmlpi;
291         else
292                 yyextra->last_xmlpi = yyextra->last_xmlpi->next = yyextra->xmlpi;
294         BEGIN XMLPI_ATTRS;
297 <XMLPI_ATTRS>{xmlpi_key_attr} BEGIN XMLPI_GETKEY;
298 <XMLPI_GETKEY>{ndquot} { yyextra->xmlpi->key = g_strdup(yytext); BEGIN XMLPI_ATTRS; }
300 <XMLPI_ATTRS>{xmlpi_value_attr} BEGIN XMLPI_GETVAL;
301 <XMLPI_GETVAL>{ndquot} { yyextra->xmlpi->value = g_strdup(yytext); BEGIN XMLPI_ATTRS; }
303 <XMLPI_ATTRS>.
304 <XMLPI_ATTRS>{xmlpi_end} BEGIN LOADING;
307 <LOADING>{start_entity} BEGIN ENTITY;
308 <ENTITY>{entityname} {
309         entity_t* e = g_new(entity_t,1);
310         e->name = g_strdup(yytext);
311         e->next = yyextra->ents;
312         yyextra->ents = e;
313         BEGIN GET_SYSTEM;
314         };
315 <GET_SYSTEM>{system} BEGIN GET_FILE;
316 <GET_FILE>{ndquot} {
317                 yyextra->ents->file = g_strdup(yytext);
318                 BEGIN END_ENTITY;
319         }
320 <END_ENTITY>{end_entity} BEGIN LOADING;
322 <LOADING>{open_tag} APPEND("<",1);
324 <LOADING>{close_tag} APPEND(">",1);
326 <LOADING>{end_tag} APPEND("/>",2);
328 <LOADING>{open_closetag} APPEND("</",2);
330 <LOADING>{whitespace} APPEND(" ",1);
332 <LOADING>{dquoted} APPEND(yytext, (unsigned) yyleng);
334 <LOADING>{equals} APPEND("=",1);
336 <LOADING>{any} APPEND(yytext, (unsigned) yyleng);
338 <LOADING>{entity} {
339         char* p = ++yytext;
340         entity_t* e;
342         while(*p != ';') p++;
344         *p = '\0';
346         D(("looking for entity: %s\n",yytext));
348         if ( yyextra->include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
349                 fprintf(stderr, "included files nested to deeply\n");
350                 yyterminate();
351         }
353         for (e = yyextra->ents; e; e = e->next) {
354                 if (strcmp(e->name,yytext) == 0) {
355                         yyin = ddict_open(yyextra->sys_dir,e->file);
356                         D(("entity: %s filename: %s yyin: %p\n",e->name,e->file,(void*)yyin));
357                         if (!yyin) {
358                                 if (errno)
359                                         fprintf(stderr, "Could not open file: '%s', error: %s\n", e->file, g_strerror(errno) );
360                                 else
361                                         fprintf(stderr, "Could not open file: '%s', error unknown (errno == 0)\n", e->file );
362                                 yyterminate();
363                         } else {
364                                 yyextra->include_stack[yyextra->include_stack_ptr++] = YY_CURRENT_BUFFER;
365                                 yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE, yyscanner), yyscanner);
366                                 BEGIN LOADING;
367                         }
368                         break;
369                 }
370         }
372         if (!e) {
373                 fprintf(stderr, "Could not find entity: '%s'\n", yytext );
374                 yyterminate();
375         }
379 <<EOF>> {
380         if (!yyin) yyterminate();
382         yyextra->current_close(yyin);
383         D(("closing: %p %i\n",(void*)yyin,yyextra->include_stack_ptr));
385         if ( --yyextra->include_stack_ptr < 0 ) {
386                 D(("DONE READING\n"));
387                 yyin = NULL;
388                 yyterminate();
389         } else {
390                 yy_delete_buffer( YY_CURRENT_BUFFER, yyscanner);
391                 yy_switch_to_buffer(yyextra->include_stack[yyextra->include_stack_ptr], yyscanner);
392                 BEGIN LOADING;
393         }
397 <GET_ATTR>{ndquot} {
398         *(yyextra->attr_str) = g_strdup(yytext);
399         D(("%s\n",yytext));
400         yyextra->attr_str = NULL;
401         BEGIN END_ATTR;
404 <GET_UINT_ATTR>{number} {
405         *(yyextra->attr_uint) = (unsigned) strtoul(yytext,NULL,10);
406         D(("%s\n",yytext););
407         yyextra->attr_uint = NULL;
408         BEGIN END_ATTR;
411 <END_ATTR>{dquot} {     yy_pop_state(yyscanner); }
413 <IGNORE_ATTR>. {
414         /* XXX: should go?*/
415         D(("{%s}",yytext));
418 <IGNORE_ATTR>{ignored_quoted} {
419         D(("=>%s<=\n",yytext));
420         yy_pop_state(yyscanner);
423 <OUTSIDE>{dictionary_start} {
424         D(("dictionary_start\n"));
426         BEGIN IN_DICT;
429 <IN_DICT>{base_start} {
430         D(("base_start\n"));
431         BEGIN IN_APPL;
434 <IN_DICT>{application_start} {
435         D(("application_start\n"));
437         yyextra->appl = g_new(ddict_application_t,1);
438         yyextra->appl->name = NULL;
439         yyextra->appl->code = 0;
440         yyextra->appl->next = NULL;
442         if (!yyextra->dict->applications)
443                 yyextra->last_appl = yyextra->dict->applications = yyextra->appl;
444         else
445                 yyextra->last_appl = yyextra->last_appl->next = yyextra->appl;
447         BEGIN APPL_ATTRS;
450 <APPL_ATTRS>{name_attr} { ATTR_STR(yyextra->appl->name); }
451 <APPL_ATTRS>{id_attr} { ATTR_UINT(yyextra->appl->code); }
453 <APPL_ATTRS>{stop} BEGIN IN_APPL;
454 <APPL_ATTRS>{stop_end} BEGIN IN_DICT;
456 <IN_APPL>{command_end}                  ;
458 <IN_APPL>{command_start}                {
459         D(("command_start\n"));
461         yyextra->cmd = g_new(ddict_cmd_t,1);
462         yyextra->cmd->name = NULL;
463         yyextra->cmd->vendor = NULL;
464         yyextra->cmd->code = 0;
465         yyextra->cmd->next = NULL;
467         if (!yyextra->dict->cmds)
468                 yyextra->last_cmd = yyextra->dict->cmds = yyextra->cmd;
469         else
470                 yyextra->last_cmd = yyextra->last_cmd->next = yyextra->cmd;
472         BEGIN COMMAND_ATTRS;
475 <COMMAND_ATTRS>{name_attr}              { ATTR_STR(yyextra->cmd->name); }
476 <COMMAND_ATTRS>{vendor_attr}            { ATTR_STR(yyextra->cmd->vendor); }
477 <COMMAND_ATTRS>{code_attr}              { ATTR_UINT(yyextra->cmd->code); }
478 <COMMAND_ATTRS>{stop}                   |
479 <COMMAND_ATTRS>{stop_end}               { BEGIN IN_APPL; }
481 <IN_DICT>{vendor_start} {
482         D(("vendor_start\n"));
484         yyextra->vnd = g_new(ddict_vendor_t,1);
485         yyextra->vnd->name = NULL;
486         yyextra->vnd->code = 0;
487         yyextra->vnd->next = NULL;
489         if (!yyextra->dict->vendors)
490                 yyextra->last_vnd = yyextra->dict->vendors = yyextra->vnd;
491         else
492                 yyextra->last_vnd = yyextra->last_vnd->next = yyextra->vnd;
494         BEGIN VENDOR_ATTRS;
497 <VENDOR_ATTRS>{name_attr}               { ATTR_STR(yyextra->vnd->desc); }
498 <VENDOR_ATTRS>{vendor_attr}             { ATTR_STR(yyextra->vnd->name); }
499 <VENDOR_ATTRS>{code_attr}               { ATTR_UINT(yyextra->vnd->code); }
500 <VENDOR_ATTRS>{stop}                    { BEGIN IN_APPL; }
501 <VENDOR_ATTRS>{stop_end}                { BEGIN IN_DICT; }
503 <IN_APPL>{typedefn_start} {
504         D(("typedefn_start\n"));
506         yyextra->typedefn = g_new(ddict_typedefn_t,1);
507         yyextra->typedefn->name = NULL;
508         yyextra->typedefn->parent = NULL;
509         yyextra->typedefn->next = NULL;
511         if (!yyextra->dict->typedefns)
512                 yyextra->last_typedefn = yyextra->dict->typedefns = yyextra->typedefn;
513         else
514                 yyextra->last_typedefn = yyextra->last_typedefn->next = yyextra->typedefn;
516         BEGIN TYPEDEFN_ATTRS;
519 <TYPEDEFN_ATTRS>{typename_attr}         { ATTR_STR(yyextra->typedefn->name); }
520 <TYPEDEFN_ATTRS>{typeparent_attr}       { ATTR_STR(yyextra->typedefn->parent); }
521 <TYPEDEFN_ATTRS>{stop}                  |
522 <TYPEDEFN_ATTRS>{stop_end}              { BEGIN IN_APPL; }
525 <IN_APPL>{avp_start}    {
526         D(("avp_start\n"));
528         yyextra->avp = g_new(ddict_avp_t,1);
529         yyextra->avp->name = NULL;
530         yyextra->avp->description = NULL;
531         yyextra->avp->vendor = NULL;
532         yyextra->avp->code = 0;
533         yyextra->avp->type = NULL;
534         yyextra->avp->enums = NULL;
535         yyextra->avp->gavps = NULL;
536         yyextra->avp->next = NULL;
538         if (! yyextra->dict->avps )
539                 yyextra->last_avp = yyextra->dict->avps = yyextra->avp;
540         else
541                 yyextra->last_avp = yyextra->last_avp->next = yyextra->avp;
543         BEGIN AVP_ATTRS;
546 <AVP_ATTRS>{name_attr}                  { ATTR_STR(yyextra->avp->name); }
547 <AVP_ATTRS>{description_attr}           { ATTR_STR(yyextra->avp->description); }
548 <AVP_ATTRS>{vendor_attr}                { ATTR_STR(yyextra->avp->vendor); }
549 <AVP_ATTRS>{code_attr}                  { ATTR_UINT(yyextra->avp->code); }
550 <AVP_ATTRS>{stop}                       { BEGIN IN_AVP;  }
551 <AVP_ATTRS>{stop_end}                   { BEGIN IN_APPL; }
554 <IN_AVP>{grouped_start} { yyextra->avp->type = g_strdup("Grouped"); };
555 <IN_AVP>{grouped_end} ;
557 <IN_AVP>{type_start} { BEGIN TYPE_ATTRS; }
558 <TYPE_ATTRS>{typename_attr}                     { ATTR_STR(yyextra->avp->type); }
560 <IN_AVP>{gavp_start} {
561         D(("gavp_start\n"));
563         yyextra->gavp = g_new(ddict_gavp_t,1);
564         yyextra->gavp->name = NULL;
565         yyextra->gavp->code = 0;
566         yyextra->gavp->next = NULL;
568         if (!yyextra->avp->gavps)
569                 yyextra->last_gavp = yyextra->avp->gavps = yyextra->gavp;
570         else
571                 yyextra->last_gavp = yyextra->last_gavp->next = yyextra->gavp;
573         BEGIN GAVP_ATTRS;
577 <GAVP_ATTRS>{name_attr}                 { ATTR_STR(yyextra->gavp->name); }
580 <IN_AVP>{enum_start} {
581         D(("enum_start\n"));
583         yyextra->enumitem = g_new(ddict_enum_t,1);
584         yyextra->enumitem->name = NULL;
585         yyextra->enumitem->code = 0;
586         yyextra->enumitem->next = NULL;
588         if (!yyextra->avp->enums)
589                 yyextra->last_enumitem = yyextra->avp->enums = yyextra->enumitem;
590         else
591                 yyextra->last_enumitem = yyextra->last_enumitem->next = yyextra->enumitem;
593         BEGIN ENUM_ATTRS;
597 <ENUM_ATTRS>{name_attr}                 { ATTR_STR(yyextra->enumitem->name); }
598 <ENUM_ATTRS>{code_attr}                 { ATTR_UINT(yyextra->enumitem->code); }
600 <TYPE_ATTRS,GAVP_ATTRS,ENUM_ATTRS>{stop}                { BEGIN IN_AVP; }
601 <TYPE_ATTRS,GAVP_ATTRS,ENUM_ATTRS>{stop_end}            { BEGIN IN_AVP; }
603 <IN_AVP>{avp_end} { D(("avp_end\n")); BEGIN IN_APPL; }
605 <IN_APPL>{application_end} {
606         D(("application_end\n")); BEGIN IN_DICT;
608 <IN_APPL>{stop_end} {
609         D(("application_stop_end\n")); BEGIN IN_DICT;
611 <IN_APPL>{vendor_end} {
612         D(("vendor_end\n")); BEGIN IN_DICT;
614 <IN_APPL>{base_end} {
615         D(("base_end\n")); BEGIN IN_DICT;
618 <IN_DICT>{dictionary_end} {
619         yyterminate();
622 <AVP_ATTRS,ENUM_ATTRS,GAVP_ATTRS,TYPE_ATTRS,TYPEDEFN_ATTRS,VENDOR_ATTRS,APPL_ATTRS,COMMAND_ATTRS>{ignored_attr} IGNORE();
624 <OUTSIDE>. ;
629  * Turn diagnostics back on, so we check the code that we've written.
630  */
631 DIAG_ON_FLEX()
633 static int debugging  = 0;
635 static void ddict_debug(const char* fmt, ...) {
636         va_list ap;
638         va_start(ap, fmt);
639         if (debugging) vfprintf(stderr, fmt, ap);
640         va_end(ap);
642         fflush(stderr);
646  * Sleazy hack to avoid unused function warnings for yy_top_state.
647  */
648 extern void ddict_unused(yyscan_t yyscanner);
650 void
651 ddict_unused(yyscan_t yyscanner)
653         yy_top_state(yyscanner);
656 static void
657 append_to_buffer(const char* txt, unsigned len, DiamDict_scanner_state_t *statep)
660         if (statep->strbuf == NULL) {
661                 statep->strbuf = (char*)g_malloc(statep->size_strbuf);
662                 statep->read_ptr = statep->strbuf;
663                 statep->write_ptr = statep->strbuf;
664         }
666         if (statep->len_strbuf + len >= statep->size_strbuf) {
667                 statep->strbuf = (char*)g_realloc(statep->strbuf,statep->size_strbuf *= 2);
668                 statep->read_ptr = statep->strbuf;
669         }
671         statep->write_ptr = statep->strbuf + statep->len_strbuf;
672         memcpy(statep->write_ptr, txt, len + 1);
673         statep->len_strbuf += len;
676 static size_t
677 file_input(char* buf, size_t max, yyscan_t scanner)
679         FILE *in = yyget_in(scanner);
680         size_t read_cnt;
682         read_cnt = fread(buf,1,max,in);
684         if ( read_cnt == max ) {
685                 return max;
686         } else if (read_cnt > 0) {
687                 return read_cnt;
688         } else {
689                 return YY_NULL;
690         }
694 static size_t
695 string_input(char* buf, size_t max, yyscan_t scanner)
697         DiamDict_scanner_state_t *statep = yyget_extra(scanner);
699         if (statep->read_ptr >= statep->write_ptr ) {
700                 return YY_NULL;
701         } else if ( statep->read_ptr + max > statep->write_ptr ) {
702                 max = statep->write_ptr - statep->read_ptr;
703         }
705         memcpy(buf,statep->read_ptr,max);
706         statep->read_ptr += max;
708         return max;
712  * If we're reading from a string, yyin is set to stdin, and we don't
713  * want to close that.
714  */
715 static int
716 string_close(FILE *fh _U_)
718         return 0;
721 static FILE *
722 ddict_open(const char* system_directory, const char* filename)
724         FILE* fh;
725         char* fname;
726         if (system_directory) {
727                 fname = ws_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
728                     system_directory,filename);
729         } else {
730                 fname = g_strdup(filename);
731         }
733         fh = ws_fopen(fname,"r");
735         D(("fname: %s fh: %p\n",fname,(void*)fh));
737         g_free(fname);
740         return fh;
743 ddict_t *
744 ddict_scan(const char* system_directory, const char* filename, int dbg)
746         DiamDict_scanner_state_t state;
747         FILE *in;
748         yyscan_t scanner;
750         debugging = dbg;
752         state.sys_dir = system_directory;
754         state.write_ptr = NULL;
755         state.read_ptr = NULL;
757         state.strbuf = NULL;
758         state.size_strbuf = 8192;
759         state.len_strbuf = 0;
761         state.dict = g_new(ddict_t,1);
762         state.dict->applications = NULL;
763         state.dict->vendors = NULL;
764         state.dict->cmds = NULL;
765         state.dict->typedefns = NULL;
766         state.dict->avps = NULL;
767         state.dict->xmlpis = NULL;
769         state.appl = NULL;
770         state.avp = NULL;
771         state.enumitem = NULL;
772         state.gavp = NULL;
773         state.typedefn = NULL;
774         state.cmd = NULL;
775         state.vnd = NULL;
776         state.xmlpi = NULL;
778         state.last_appl = NULL;
779         state.last_avp = NULL;
780         state.last_enumitem = NULL;
781         state.last_gavp = NULL;
782         state.last_typedefn = NULL;
783         state.last_cmd = NULL;
784         state.last_vnd = NULL;
785         state.last_xmlpi = NULL;
787         state.ents = NULL;
789         state.attr_str = NULL;
790         state.attr_uint = NULL;
792         /*
793          * Pass 1.
794          *
795          * Reads the file, does some work, and stores a modified version
796          * of the file contents in memory.
797          */
798         state.current_yyinput = file_input;
799         state.current_close = fclose;
800         state.include_stack_ptr = 0;
802         in = ddict_open(system_directory,filename);
804         if (in == NULL) {
805                 D(("unable to open %s: %s\n", filename, g_strerror(errno)));
806                 g_free(state.dict);
807                 return NULL;
808         }
810         if (DiamDict_lex_init(&scanner) != 0) {
811                 /* Note: cannot be reached since memory allocation failure terminates early */
812                 D(("Can't initialize scanner: %s\n", g_strerror(errno)));
813                 fclose(in);
814                 g_free(state.dict);
815                 return NULL;
816         }
818         DiamDict_set_in(in, scanner);
820         /* Associate the state with the scanner */
821         DiamDict_set_extra(&state, scanner);
823         state.start_state = LOADING;
824         DiamDict_lex(scanner);
826         DiamDict_lex_destroy(scanner);
827         /*
828          * XXX - can the lexical analyzer terminate without closing
829          * all open input files?
830          */
832         D(("\n---------------\n%s\n------- %u -------\n",state.strbuf,state.len_strbuf));
834         /*
835          * Pass 2.
836          *
837          * Reads the modified version of the file contents and does the
838          * rest of the work.
839          */
840         state.current_yyinput = string_input;
841         state.current_close = string_close;
843         if (DiamDict_lex_init(&scanner) != 0) {
844                 /* Note: cannot be reached since memory allocation failure terminates early */
845                 D(("Can't initialize scanner: %s\n", g_strerror(errno)));
846                 g_free(state.dict);
847                 g_free(state.strbuf);
848                 return NULL;
849         }
851         /* Associate the state with the scanner */
852         DiamDict_set_extra(&state, scanner);
854         state.start_state = OUTSIDE;
855         DiamDict_lex(scanner);
857         DiamDict_lex_destroy(scanner);
858         {
859                 entity_t *e, *en;
861                 for (e = state.ents; e; e = en) {
862                         en = e->next;
863                         g_free(e->name);
864                         g_free(e->file);
865                         g_free(e);
866                 }
867         }
868         g_free(state.strbuf);
870         return state.dict;
873 void
874 ddict_free(ddict_t* d)
876         ddict_application_t *p, *pn;
877         ddict_vendor_t *v, *vn;
878         ddict_cmd_t *c, *cn;
879         ddict_typedefn_t *t, *tn;
880         ddict_avp_t *a, *an;
881         ddict_xmlpi_t *x, *xn;
883 #define FREE_NAMEANDOBJ(n) do { g_free(n->name); g_free(n); } while(0)
885         for (p = d->applications; p; p = pn ) {
886                 pn = p->next;
887                 FREE_NAMEANDOBJ(p);
888         }
890         for (v = d->vendors; v; v = vn) {
891                 vn = v->next;
892                 g_free(v->desc);
893                 FREE_NAMEANDOBJ(v);
894         }
896         for (c = d->cmds; c; c = cn ) {
897                 cn = c->next;
898                 g_free(c->vendor);
899                 FREE_NAMEANDOBJ(c);
900         }
902         for (t = d->typedefns; t; t = tn) {
903                 tn = t->next;
904                 g_free(t->parent);
905                 FREE_NAMEANDOBJ(t);
906         }
908         for (a = d->avps; a; a = an) {
909                 ddict_gavp_t* g, *gn;
910                 ddict_enum_t* e, *en;
911                 an = a->next;
913                 for (g = a->gavps; g; g = gn) {
914                         gn = g->next;
915                         FREE_NAMEANDOBJ(g);
916                 }
918                 for (e = a->enums; e; e = en) {
919                         en = e->next;
920                         FREE_NAMEANDOBJ(e);
921                 }
923                 g_free(a->vendor);
924                 g_free(a->type);
925                 g_free(a->description);
926                 FREE_NAMEANDOBJ(a);
927         }
929         for (x = d->xmlpis; x; x = xn) {
930                 xn = x->next;
931                 g_free(x->key);
932                 g_free(x->value);
933                 FREE_NAMEANDOBJ(x);
934         }
936         g_free(d);
939 void
940 ddict_print(FILE* fh, ddict_t* d)
942         ddict_application_t* p;
943         ddict_vendor_t* v;
944         ddict_cmd_t* c;
945         ddict_typedefn_t* t;
946         ddict_avp_t* a;
949         for (p = d->applications; p; p = p->next) {
950                 fprintf(fh,"Application: %s[%u]:\n",
951                                 p->name ? p->name : "-",
952                                 p->code);
953         }
955         for (v = d->vendors; v; v = v->next) {
956                 fprintf(fh,"Vendor: %s[%u]:\n",
957                                 v->name ? v->name : "-",
958                                 v->code);
959         }
961         for (c = d->cmds; c; c = c->next) {
962                 fprintf(fh,"Command: %s[%u] \n",
963                                 c->name ? c->name : "-",
964                                 c->code);
965         }
967         for (t = d->typedefns; t; t = t->next) {
968                 fprintf(fh,"Type: %s -> %s \n",
969                                 t->name ? t->name : "-",
970                                 t->parent ? t->parent : "" );
971         }
973         for (a = d->avps; a; a = a->next) {
974                 ddict_gavp_t* g;
975                 ddict_enum_t* e;
976                 fprintf(fh,"AVP: %s[%u:%s] %s %s\n",
977                                 a->name ? a->name : "-",
978                                 a->code,
979                                 a->vendor ? a->vendor : "None",
980                                 a->type ? a->type : "-",
981                                 a->description ? a->description : "");
983                 for (g = a->gavps; g; g = g->next) {
984                         fprintf(fh,"\tGAVP: %s\n",
985                                         g->name ? g->name : "-" );
986                 }
988                 for (e = a->enums; e; e = e->next) {
989                         fprintf(fh,"\tEnum: %s[%u]\n",
990                                         e->name ? e->name : "-",
991                                         e->code);
992                 }
993         }
996 #ifdef TEST_DIAM_DICT_STANDALONE
998 main(int argc, char** argv)
1000         ddict_t* d;
1001         char* dname = NULL;
1002         char* fname;
1003         int i = 1;
1005         switch (argc) {
1006                 case 3:
1007                         dname = argv[i++];
1008                 case 2:
1009                         fname = argv[i];
1010                         break;
1011                 default:
1012                         fprintf(stderr,"%s: usage [dictionary_dir] dictionary_filename\n",argv[0]);
1013                         return 1;
1014         }
1016         d = ddict_scan(dname,fname,1);
1017         if (d == NULL) {
1018                 fprintf(stderr, "Can't open dictionary\n");
1019                 return 2;
1020         }
1022         ddict_print(stdout, d);
1024         return 0;
1026 #endif