9a4f242271c114e40653f69910018449c9a2ed67
[obnox/wireshark/wip.git] / epan / radius_dict.l
1 /*
2  * We don't use unput, so don't generate code for it.
3  */
4 %option nounput
5
6 /*
7  * We don't read from the terminal.
8  */
9 %option never-interactive
10
11 /*
12  * The language we're scanning is case-insensitive.
13  */
14 %option caseless
15
16 /*
17  * Prefix scanner routines with "Radius" rather than "yy", so this scanner
18  * can coexist with other scanners.
19  */
20 %option prefix="Radius"
21
22 %option outfile="radius_dict.c"
23
24 %{
25         /* radius_dict.l
26         *
27         * RADIUS dictionary parser
28         *
29         * $Id$
30         *
31         * Wireshark - Network traffic analyzer
32         * By Gerald Combs <gerald@wireshark.org>
33         * Copyright 1998 Gerald Combs
34         *
35         * This program is free software; you can redistribute it and/or
36         * modify it under the terms of the GNU General Public License
37         * as published by the Free Software Foundation; either version 2
38         * of the License, or (at your option) any later version.
39         *
40         * This program is distributed in the hope that it will be useful,
41         * but WITHOUT ANY WARRANTY; without even the implied warranty of
42         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
43         * GNU General Public License for more details.
44         *
45         * You should have received a copy of the GNU General Public License
46         * along with this program; if not, write to the Free Software
47         * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
48         */
49
50 #ifdef HAVE_CONFIG_H
51 #include "config.h"
52 #endif
53
54 #include <glib.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <errno.h>
59 #include <epan/packet.h>
60 #include <epan/dissectors/packet-radius.h>
61 #include "radius_dict_lex.h"
62 #include <wsutil/file_util.h>
63
64 #ifdef _WIN32
65 /* disable Windows VC compiler warning "signed/unsigned mismatch" associated  */
66 /* with YY_INPUT code generated by flex versions such as 2.5.35.              */
67 #pragma warning (disable:4018)
68 #endif
69
70 #define ECHO
71 #define MAX_INCLUDE_DEPTH 10
72
73         void add_vendor(const gchar* name, guint32 vendor_id, guint vendor_type_octets, guint vendor_length_octets, gboolean vendor_has_flags);
74         void add_value(const gchar* attrib_name,const  gchar* value_repr, long value);
75         void add_tlv(const gchar* name, const  gchar* code, radius_attr_dissector_t type, const gchar* current_attr);
76         void add_attribute(const gchar*,const  gchar*, radius_attr_dissector_t,const  gchar*, gboolean, gboolean, const gchar*);
77
78         static YY_BUFFER_STATE include_stack[10];
79         static int include_stack_ptr = 0;
80
81         static radius_dictionary_t* dict = NULL;
82         static GHashTable* value_strings = NULL; /* GArray(value_string) by attribute name */
83
84         static gchar* attr_name = NULL;
85         static gchar* attr_id = NULL;
86         static radius_attr_dissector_t* attr_type = NULL;
87         static gchar* attr_vendor = NULL;
88         static gchar* vendor_name = NULL;
89         static guint32 vendor_id = 0;
90         static guint vendor_type_octets = 1;
91         static guint vendor_length_octets = 1;
92         static gboolean vendor_has_flags = FALSE;
93         static gchar* value_repr = NULL;
94         static gboolean encrypted = FALSE;
95         static gboolean has_tag = FALSE;
96         static gchar* current_vendor = NULL;
97         static gchar* current_attr = NULL;
98
99         static GString* error = NULL;
100         static gchar* directory = NULL;
101         static int linenums[] = {1,1,1,1,1,1,1,1,1,1};
102         static gchar* fullpaths[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
103
104 %}
105
106 /* Note: FreeRadius allows VENDOR, ATTRIBUTE and VALUE names to contain any non-blank character.
107  *       Using a negated "blank character class" pattern below for those names fails for some reason
108  *       so for now the patterns for each name type include those characters found for the corresponding
109  *       name types in the FreeRadius dictionaries.
110  */
111
112 %START WS_OUT VENDOR VENDOR_W_NAME ATTR ATTR_W_NAME ATTR_W_ID ATTR_W_TYPE ATTR_W_VENDOR VALUE VALUE_W_ATTR VALUE_W_NAME INCLUDE JUNK BEGIN_VENDOR END_VENDOR VENDOR_W_ID VENDOR_W_FORMAT VENDOR_W_TYPE_OCTETS VENDOR_W_LENGTH_OCTETS VENDOR_W_CONTINUATION BEGIN_TLV END_TLV
113 %%
114 [:blank:]   ;
115 #[^\n]*         ;
116
117 <JUNK>.*\qn             ;
118
119 <WS_OUT>VENDOR { BEGIN VENDOR; }
120 <WS_OUT>ATTRIBUTE { BEGIN ATTR; }
121 <WS_OUT>VALUE { BEGIN VALUE; }
122 <WS_OUT>\$INCLUDE { BEGIN INCLUDE; }
123 <WS_OUT>BEGIN-VENDOR { BEGIN BEGIN_VENDOR; }
124 <WS_OUT>END-VENDOR { BEGIN END_VENDOR; }
125 <WS_OUT>BEGIN-TLV { BEGIN BEGIN_TLV; }
126 <WS_OUT>END-TLV { BEGIN END_TLV; }
127
128 <BEGIN_VENDOR>[0-9a-z_-]+ {
129     if (current_vendor) {
130         g_free(current_vendor);
131     }
132     current_vendor = g_strdup(yytext);
133     BEGIN WS_OUT;
134 }
135 <END_VENDOR>[^\n]* {
136     if (current_vendor) {
137         g_free(current_vendor);
138         current_vendor = NULL;
139     }
140     BEGIN WS_OUT;
141 }
142
143 <BEGIN_TLV>[0-9a-z_-]+ {
144     if (current_attr) {
145         g_free(current_attr);
146     }
147     current_attr = g_strdup(yytext);
148     BEGIN WS_OUT;
149 }
150 <END_TLV>[^\n]* {
151     if (current_attr) {
152         g_free(current_attr);
153         current_attr = NULL;
154     }
155     BEGIN WS_OUT;
156 }
157
158 <VENDOR>[0-9a-z_-]+   {
159     vendor_name = g_strdup(yytext);
160     vendor_type_octets = 1;
161     vendor_length_octets = 1;
162     vendor_has_flags = FALSE;
163     BEGIN VENDOR_W_NAME;
164 }
165 <VENDOR_W_NAME>[0-9]+   {
166     vendor_id = strtol(yytext,NULL,10);
167     BEGIN VENDOR_W_ID;
168 }
169 <VENDOR_W_NAME>0x[0-9a-f]+   {
170     vendor_id = strtol(yytext,NULL,16);
171     BEGIN VENDOR_W_ID;
172 }
173 <VENDOR_W_ID>format= {
174     BEGIN VENDOR_W_FORMAT;
175 }
176 <VENDOR_W_FORMAT>[124] {
177     vendor_type_octets = strtol(yytext,NULL,10);
178     BEGIN VENDOR_W_TYPE_OCTETS;
179 }
180 <VENDOR_W_TYPE_OCTETS>,[012] {
181     vendor_length_octets = strtol(yytext+1,NULL,10);
182     BEGIN VENDOR_W_LENGTH_OCTETS;
183 }
184 <VENDOR_W_LENGTH_OCTETS>,c {
185     vendor_has_flags = TRUE;
186     BEGIN VENDOR_W_CONTINUATION;
187 }
188 <VENDOR_W_FORMAT>\n |
189 <VENDOR_W_TYPE_OCTETS>\n |
190 <VENDOR_W_LENGTH_OCTETS>\n |
191 <VENDOR_W_CONTINUATION>\n |
192 <VENDOR_W_ID>\n {
193     add_vendor(vendor_name, vendor_id, vendor_type_octets, vendor_length_octets, vendor_has_flags);
194     g_free(vendor_name);
195     BEGIN WS_OUT;
196 }
197
198 <ATTR>[0-9a-z_/.-]+                     { attr_name = g_strdup(yytext); encrypted = FALSE; has_tag = FALSE; BEGIN ATTR_W_NAME; }
199 <ATTR_W_NAME>[0-9]+                     { attr_id = g_strdup(yytext);  BEGIN ATTR_W_ID;}
200 <ATTR_W_NAME>0x[0-9a-f]+                { attr_id = g_strdup_printf("%u",(int)strtoul(yytext,NULL,16)); BEGIN ATTR_W_ID;}
201 <ATTR_W_ID>integer                      { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
202 <ATTR_W_ID>string                       { attr_type = radius_string;  BEGIN ATTR_W_TYPE; }
203 <ATTR_W_ID>octets                       { attr_type = radius_octets;  BEGIN ATTR_W_TYPE; }
204 <ATTR_W_ID>ipaddr                       { attr_type = radius_ipaddr;  BEGIN ATTR_W_TYPE; }
205 <ATTR_W_ID>ipv6addr                     { attr_type = radius_ipv6addr;  BEGIN ATTR_W_TYPE; }
206 <ATTR_W_ID>ipv6prefix                   { attr_type = radius_ipv6prefix;  BEGIN ATTR_W_TYPE; }
207 <ATTR_W_ID>ipxnet                       { attr_type = radius_ipxnet;  BEGIN ATTR_W_TYPE; }
208 <ATTR_W_ID>date                         { attr_type = radius_date;  BEGIN ATTR_W_TYPE; }
209 <ATTR_W_ID>abinary                      { attr_type = radius_abinary;  BEGIN ATTR_W_TYPE; }
210 <ATTR_W_ID>ether                        { attr_type = radius_ether;  BEGIN ATTR_W_TYPE; }
211 <ATTR_W_ID>ifid                         { attr_type = radius_ifid;  BEGIN ATTR_W_TYPE; }
212 <ATTR_W_ID>byte                         { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
213 <ATTR_W_ID>short                        { attr_type = radius_integer;  BEGIN ATTR_W_TYPE; }
214 <ATTR_W_ID>signed                       { attr_type = radius_signed;  BEGIN ATTR_W_TYPE; }
215 <ATTR_W_ID>combo-ip                     { attr_type = radius_combo_ip;  BEGIN ATTR_W_TYPE; }
216 <ATTR_W_ID>tlv                          { attr_type = radius_tlv;  BEGIN ATTR_W_TYPE; }
217 <ATTR_W_ID>[0-9a-z_-]+                  { attr_type = radius_octets;  BEGIN ATTR_W_TYPE; }
218 <ATTR_W_TYPE>has_tag[,]?                { has_tag = TRUE; }
219 <ATTR_W_TYPE>encrypt=1[,]?              { encrypted=TRUE; }
220 <ATTR_W_TYPE>[0-9a-z_-]+=([^\n]*)       ;
221 <ATTR_W_TYPE>[0-9a-z_-]+                {
222     attr_vendor = g_strdup(yytext);
223     add_attribute(attr_name,attr_id,attr_type,attr_vendor,encrypted,has_tag,current_attr);
224     g_free(attr_id);
225     g_free(attr_vendor);
226     g_free(attr_name);
227     attr_id = NULL;
228     attr_vendor = NULL;
229     attr_name = NULL;
230     BEGIN WS_OUT;
231 }
232 <ATTR_W_TYPE>\n                                         {
233     add_attribute(attr_name,attr_id,attr_type,current_vendor,encrypted,has_tag,current_attr);
234     g_free(attr_id);
235     g_free(attr_name);
236     linenums[include_stack_ptr]++;
237     has_tag = FALSE;
238     encrypted=FALSE;
239     BEGIN WS_OUT;
240 }
241 <ATTR_W_VENDOR>\n                                       {
242     add_attribute(attr_name,attr_id,attr_type,attr_vendor,encrypted,has_tag,current_attr);
243     g_free(attr_id);
244     g_free(attr_vendor);
245     g_free(attr_name);
246     linenums[include_stack_ptr]++;
247     BEGIN WS_OUT;
248 };
249
250 <VALUE>[0-9a-z_/-]+                                     { attr_name = g_strdup(yytext); BEGIN VALUE_W_ATTR; }
251 <VALUE_W_ATTR>[^[:blank:]]+                     { value_repr = g_strdup(yytext); BEGIN VALUE_W_NAME; }
252 <VALUE_W_NAME>[0-9]+                            { add_value(attr_name,value_repr,strtol(yytext,NULL,10));  g_free(attr_name); g_free(value_repr); BEGIN WS_OUT;}
253 <VALUE_W_NAME>0x[0-9a-f]+                       { add_value(attr_name,value_repr,strtol(yytext,NULL,16));  g_free(attr_name); g_free(value_repr); BEGIN WS_OUT;}
254
255 <INCLUDE>[^[:blank:]\n]+   {
256         if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
257                 g_string_append_printf(error, "$INCLUDE files nested to deeply\n");
258                 yyterminate();
259         }
260
261         include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER;
262
263         fullpaths[include_stack_ptr] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
264             directory,yytext);
265
266         yyin = ws_fopen( fullpaths[include_stack_ptr], "r" );
267
268         if (!yyin) {
269                 if (errno) {
270                         g_string_append_printf(error, "Could not open file: '%s', error: %s\n", fullpaths[include_stack_ptr], strerror(errno) );
271                         yyterminate();
272                 }
273         } else {
274                 linenums[include_stack_ptr] = 1;
275                 yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE ) );
276         }
277
278
279         BEGIN WS_OUT;
280 }
281
282 <<EOF>> {
283
284         fclose(yyin);
285         yyin = NULL;
286
287         if ( --include_stack_ptr < 0 ) {
288                 yyterminate();
289         } else {
290                 g_free(fullpaths[include_stack_ptr+1]);
291                 fullpaths[include_stack_ptr+1] = NULL;
292
293                 yy_delete_buffer( YY_CURRENT_BUFFER );
294                 yy_switch_to_buffer(include_stack[include_stack_ptr]);
295         }
296
297         BEGIN WS_OUT;
298 }
299
300 \n      { linenums[include_stack_ptr]++; BEGIN WS_OUT; }
301
302
303 %%
304
305 void add_vendor(const gchar* name, guint32 vendor_id, guint vendor_type_octets, guint vendor_length_octets, gboolean vendor_has_flags) {
306         radius_vendor_info_t* v;
307
308         v = g_hash_table_lookup(dict->vendors_by_id, GUINT_TO_POINTER(vendor_id));
309
310         if (!v) {
311                 v = g_malloc(sizeof(radius_vendor_info_t));
312                 v->attrs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
313                 v->code = vendor_id;
314                 v->ett = -1;
315                 v->name = NULL;
316         }
317         /* Assume that the dictionary knows the 'ground truth' about the
318          * type/length/has_flags information and thus allow the dictionary to
319          * overwrite these values even for vendors that have already been loaded.
320          */
321         v->type_octets = vendor_type_octets;
322         v->length_octets = vendor_length_octets;
323         v->has_flags = vendor_has_flags;
324
325         if (v->name)
326                 g_free((gpointer) v->name);
327         v->name = g_strdup(name);
328
329         g_hash_table_insert(dict->vendors_by_id,GUINT_TO_POINTER(v->code),v);
330         g_hash_table_insert(dict->vendors_by_name, (gpointer) v->name, v);
331 }
332
333 void add_attribute(const gchar* name, const  gchar* codestr, radius_attr_dissector_t type, const  gchar* vendor_name, gboolean crypt, gboolean tagged, const gchar* current_attr) {
334         radius_attr_info_t* a;
335         GHashTable* by_id;
336         guint32 code;
337
338
339         if (current_attr){
340                 add_tlv(name, codestr, type, current_attr);
341                 return;
342         }
343
344
345         if (vendor_name) {
346                 radius_vendor_info_t* v;
347                 v = g_hash_table_lookup(dict->vendors_by_name,vendor_name);
348
349                 if (! v) {
350                         g_string_append_printf(error, "Vendor: '%s', does not exist in %s:%i \n", vendor_name, fullpaths[include_stack_ptr], linenums[include_stack_ptr] );
351                         BEGIN JUNK;
352                         return;
353                 } else {
354                         by_id = v->attrs_by_id;
355                 }
356         } else {
357                 by_id = dict->attrs_by_id;
358         }
359
360         code=strtol(codestr, NULL, 10);
361
362         a=g_hash_table_lookup(by_id, GUINT_TO_POINTER(code));
363
364         if (!a) {
365                 a = g_malloc(sizeof(radius_attr_info_t));
366                 a->name = NULL;
367                 a->dissector = NULL;
368         }
369
370         a->code = code;
371         a->encrypt = crypt;
372         a->tagged =  tagged;
373         a->type = type;
374         a->vs = NULL;
375         a->hf = -1;
376         a->hf64 = -1;
377         a->hf_tag = -1;
378         a->hf_len = -1;
379         a->ett = -1;
380         a->tlvs_by_id = NULL;
381
382         if (a->name)
383                 g_free((gpointer) a->name);
384         a->name = g_strdup(name);
385
386         g_hash_table_insert(by_id, GUINT_TO_POINTER(code),a);
387         g_hash_table_insert(dict->attrs_by_name,(gpointer) (a->name),a);
388 }
389
390 void add_tlv(const gchar* name, const  gchar* codestr, radius_attr_dissector_t type, const gchar* current_attr) {
391         radius_attr_info_t* a;
392         radius_attr_info_t* s;
393         guint32 code;
394
395         a = g_hash_table_lookup(dict->attrs_by_name, current_attr);
396
397         if (! a) {
398                 g_string_sprintfa(error, "Attr: '%s', does not exist in %s:%i \n", current_attr, fullpaths[include_stack_ptr], linenums[include_stack_ptr]);
399                 BEGIN JUNK;
400                 return;
401         }
402
403         if (type == radius_tlv) {
404                 g_string_sprintfa(error, "sub-TLV: '%s', sub-TLV's type is specified as tlv in %s:%i \n", name, fullpaths[include_stack_ptr], linenums[include_stack_ptr]);
405                 BEGIN JUNK;
406                 return;
407         }
408
409
410         if (! a->tlvs_by_id) {
411                 a->tlvs_by_id = g_hash_table_new(g_direct_hash,g_direct_equal);
412         }
413
414         code=strtol(codestr, NULL, 10);
415
416         s = g_hash_table_lookup(a->tlvs_by_id, GUINT_TO_POINTER(code));
417
418         if (!s) {
419                 s = g_malloc(sizeof(radius_attr_info_t));
420                 s->name = NULL;
421                 s->dissector = NULL;
422         }
423
424         s->code = code;
425         s->type = type;
426         s->encrypt = FALSE;
427         s->tagged = FALSE;
428         s->dissector = NULL;
429         s->vs = NULL;
430         s->hf = -1;
431         s->hf64 = -1;
432         s->hf_tag = -1;
433         s->hf_len = -1;
434         s->ett = -1;
435         s->tlvs_by_id = NULL;
436
437         if (s->name)
438                 g_free((gpointer) s->name);
439         s->name = g_strdup(name);
440
441         g_hash_table_insert(a->tlvs_by_id,GUINT_TO_POINTER(s->code),s);
442         g_hash_table_insert(dict->tlvs_by_name,(gpointer) (s->name),s);
443 }
444
445 void add_value(const gchar* attrib_name, const gchar* value_repr, long value) {
446         value_string v;
447         GArray* a = g_hash_table_lookup(value_strings,attrib_name);
448
449         if (! a) {
450                 a = g_array_new(TRUE,TRUE,sizeof(value_string));
451                 g_hash_table_insert(value_strings,g_strdup(attrib_name),a);
452         }
453
454         v.value = value;
455         v.strptr = g_strdup(value_repr);
456
457         g_array_append_val(a,v);
458 }
459
460 static void setup_tlvs(gpointer k _U_, gpointer v, gpointer p _U_) {
461         radius_attr_info_t* s = v;
462         gpointer key;
463
464         union {
465                 GArray* a;
466                 gpointer p;
467         } vs;
468
469         if (g_hash_table_lookup_extended(value_strings, s->name, &key, &vs.p)) {
470                 s->vs = (value_string*)(void *)vs.a->data;
471                 g_array_free(vs.a, FALSE);
472                 g_hash_table_remove(value_strings, key);
473                 g_free(key);
474         }
475 }
476
477 static void setup_attrs(gpointer k _U_, gpointer v, gpointer p _U_) {
478         radius_attr_info_t* a = v;
479         gpointer key;
480
481         union {
482                 GArray* a;
483                 gpointer p;
484         } vs;
485
486         if (g_hash_table_lookup_extended(value_strings,a->name,&key,&vs.p) ) {
487                 a->vs = (value_string*)(void *)vs.a->data;
488                 g_array_free(vs.a,FALSE);
489                 g_hash_table_remove(value_strings,key);
490                 g_free(key);
491         }
492
493         if (a->tlvs_by_id) {
494                 g_hash_table_foreach(a->tlvs_by_id, setup_tlvs, p);
495         }
496 }
497
498 static void setup_vendors(gpointer k _U_, gpointer v, gpointer p) {
499         radius_vendor_info_t* vnd = v;
500
501         g_hash_table_foreach(vnd->attrs_by_id,setup_attrs,p);
502 }
503
504 static gboolean destroy_value_strings(gpointer k, gpointer v, gpointer p _U_) {
505         value_string* vs = (value_string*)(void *)(((GArray*)v)->data);
506
507         g_free(k);
508
509         for (;vs->strptr;vs++) {
510                 g_free((void*)vs->strptr);
511         }
512
513         g_array_free(v,TRUE);
514         return TRUE;
515 }
516
517 static gboolean destroy_tlvs(gpointer k _U_, gpointer v, gpointer p _U_) {
518         radius_attr_info_t* s = v;
519         int i;
520
521         g_free((gpointer) (s->name));
522
523         if (s->vs) {
524                 for(i=0; s->vs[i].strptr; i++) {
525                         g_free((void *)s->vs[i].strptr);
526                 }
527                 g_free((void *)s->vs);
528         }
529         g_free(s);
530         return TRUE;
531 }
532
533 static gboolean destroy_attrs(gpointer k _U_, gpointer v, gpointer p _U_) {
534         radius_attr_info_t* a = v;
535         int i;
536
537         g_free((gpointer) (a->name));
538         if (a->tlvs_by_id) {
539                 g_hash_table_foreach_remove(a->tlvs_by_id, destroy_tlvs, p);
540                 g_hash_table_destroy(a->tlvs_by_id);
541         }
542
543         if (a->vs) {
544                 for(i=0; a->vs[i].strptr; i++) {
545                         g_free((void *)a->vs[i].strptr);
546                 }
547                 g_free((void *)a->vs);
548         }
549         g_free(a);
550         return TRUE;
551 }
552
553 static gboolean destroy_vendors(gpointer k _U_, gpointer v, gpointer p) {
554         radius_vendor_info_t* vnd = v;
555         g_free( (gpointer) vnd->name);
556         g_hash_table_foreach_remove(vnd->attrs_by_id,destroy_attrs,p);
557         g_hash_table_destroy(vnd->attrs_by_id);
558         g_free(vnd);
559         return TRUE;
560 }
561
562 static void destroy_dict(radius_dictionary_t* d) {
563         g_hash_table_foreach_remove(d->attrs_by_id,destroy_attrs,NULL);
564         g_hash_table_foreach_remove(d->vendors_by_id,destroy_vendors,NULL);
565         g_hash_table_destroy(d->vendors_by_id);
566         g_hash_table_destroy(d->attrs_by_id);
567         g_hash_table_destroy(d->vendors_by_name);
568         g_hash_table_destroy(d->attrs_by_name);
569         g_free(d);
570 }
571
572 gboolean radius_load_dictionary (radius_dictionary_t* d, gchar* dir, const gchar* filename, gchar** err_str) {
573         int i;
574
575         dict = d;
576         directory = dir;
577
578         fullpaths[include_stack_ptr] = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
579             directory,filename);
580
581         error = g_string_new("");
582
583         yyin = ws_fopen(fullpaths[include_stack_ptr],"r");
584
585         if (!yyin) {
586                 g_string_append_printf(error, "Could not open file: '%s', error: %s\n", fullpaths[include_stack_ptr], strerror(errno) );
587                 g_free(fullpaths[include_stack_ptr]);
588                 *err_str = error->str;
589                 g_string_free(error,FALSE);
590                 return FALSE;
591         }
592
593         value_strings = g_hash_table_new(g_str_hash,g_str_equal);
594
595         BEGIN WS_OUT;
596
597         yylex();
598
599         if (yyin != NULL) fclose(yyin);
600         yyin = NULL;
601
602         for (i=0; i < 10; i++) {
603                 if (fullpaths[i]) g_free(fullpaths[i]);
604         }
605
606         g_hash_table_foreach(dict->attrs_by_id,setup_attrs,NULL);
607         g_hash_table_foreach(dict->vendors_by_id,setup_vendors,NULL);
608         g_hash_table_foreach_remove(value_strings,destroy_value_strings,NULL);
609
610         if (error->len > 0) {
611                  *err_str = error->str;
612                 g_string_free(error,FALSE);
613                 destroy_dict(dict);
614                 return FALSE;
615         } else {
616                 *err_str = NULL;
617                 g_string_free(error,TRUE);
618                 return TRUE;
619         }
620 }
621
622 /*
623  * We want to stop processing when we get to the end of the input.
624  * (%option noyywrap is not used because if used then
625  * some flex versions (eg: 2.5.35) generate code which causes
626  * warnings by the Windows VC compiler).
627  */
628
629 int yywrap(void) {
630     return 1;
631 }