xref: /reactos/sdk/tools/widl/parser.l (revision 9393fc32)
1 /* -*-C-*-
2  * IDL Compiler
3  *
4  * Copyright 2002 Ove Kaaven
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 %option stack
22 %option noinput nounput noyy_top_state
23 %option 8bit never-interactive prefix="parser_"
24 
25 nl	\r?\n
26 ws	[ \f\t\r]
27 cident	[a-zA-Z_][0-9a-zA-Z_]*
28 u_suffix	(u|U)
29 l_suffix	(l|L)
30 int	[0-9]+({l_suffix}?{u_suffix}?|{u_suffix}?{l_suffix}?)?
31 hexd	[0-9a-fA-F]
32 hex	0(x|X){hexd}+({l_suffix}?{u_suffix}?|{u_suffix}?{l_suffix}?)?
33 uuid	{hexd}{8}-{hexd}{4}-{hexd}{4}-{hexd}{4}-{hexd}{12}
34 double	[0-9]+\.[0-9]+([eE][+-]?[0-9]+)*
35 
36 %x QUOTE
37 %x WSTRQUOTE
38 %x ATTR
39 %x PP_LINE
40 %x PP_PRAGMA
41 %x SQUOTE
42 
43 %{
44 
45 #include "config.h"
46 #include "wine/port.h"
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <ctype.h>
52 #include <assert.h>
53 #include <errno.h>
54 #include <limits.h>
55 
56 #ifdef HAVE_UNISTD_H
57 #include <unistd.h>
58 #else
59 #define YY_NO_UNISTD_H
60 #endif
61 
62 #include "widl.h"
63 #include "utils.h"
64 #include "parser.h"
65 #include "wine/wpp.h"
66 
67 #include "parser.tab.h"
68 
69 static void addcchar(char c);
70 static char *get_buffered_cstring(void);
71 
72 static char *cbuffer;
73 static int cbufidx;
74 static int cbufalloc = 0;
75 
76 static int kw_token(const char *kw);
77 static int attr_token(const char *kw);
78 
79 static void switch_to_acf(void);
80 
81 static warning_list_t *disabled_warnings = NULL;
82 
83 #define MAX_IMPORT_DEPTH 20
84 struct {
85   YY_BUFFER_STATE state;
86   char *input_name;
87   int   line_number;
88   char *temp_name;
89 } import_stack[MAX_IMPORT_DEPTH];
90 int import_stack_ptr = 0;
91 
92 /* converts an integer in string form to an unsigned long and prints an error
93  * on overflow */
94 static unsigned int xstrtoul(const char *nptr, char **endptr, int base)
95 {
96     unsigned long val;
97 
98     errno = 0;
99     val = strtoul(nptr, endptr, base);
100     if ((val == ULONG_MAX && errno == ERANGE) || ((unsigned int)val != val))
101         error_loc("integer constant %s is too large\n", nptr);
102     return val;
103 }
104 
105 UUID *parse_uuid(const char *u)
106 {
107   UUID* uuid = xmalloc(sizeof(UUID));
108   char b[3];
109   /* it would be nice to use UuidFromStringA */
110   uuid->Data1 = strtoul(u, NULL, 16);
111   uuid->Data2 = strtoul(u+9, NULL, 16);
112   uuid->Data3 = strtoul(u+14, NULL, 16);
113   b[2] = 0;
114   memcpy(b, u+19, 2); uuid->Data4[0] = strtoul(b, NULL, 16);
115   memcpy(b, u+21, 2); uuid->Data4[1] = strtoul(b, NULL, 16);
116   memcpy(b, u+24, 2); uuid->Data4[2] = strtoul(b, NULL, 16);
117   memcpy(b, u+26, 2); uuid->Data4[3] = strtoul(b, NULL, 16);
118   memcpy(b, u+28, 2); uuid->Data4[4] = strtoul(b, NULL, 16);
119   memcpy(b, u+30, 2); uuid->Data4[5] = strtoul(b, NULL, 16);
120   memcpy(b, u+32, 2); uuid->Data4[6] = strtoul(b, NULL, 16);
121   memcpy(b, u+34, 2); uuid->Data4[7] = strtoul(b, NULL, 16);
122   return uuid;
123 }
124 
125 %}
126 
127 /*
128  **************************************************************************
129  * The flexer starts here
130  **************************************************************************
131  */
132 %%
133 <INITIAL>^{ws}*\#{ws}*pragma{ws}+ yy_push_state(PP_PRAGMA);
134 <INITIAL,ATTR>^{ws}*\#{ws}*	yy_push_state(PP_LINE);
135 <PP_LINE>[^\n]*         {
136                             int lineno;
137                             char *cptr, *fname;
138                             yy_pop_state();
139                             lineno = (int)strtol(yytext, &cptr, 10);
140                             if(!lineno)
141                                 error_loc("Malformed '#...' line-directive; invalid linenumber\n");
142                             fname = strchr(cptr, '"');
143                             if(!fname)
144                                 error_loc("Malformed '#...' line-directive; missing filename\n");
145                             fname++;
146                             cptr = strchr(fname, '"');
147                             if(!cptr)
148                                 error_loc("Malformed '#...' line-directive; missing terminating \"\n");
149                             *cptr = '\0';
150                             line_number = lineno - 1;  /* We didn't read the newline */
151                             input_name = xstrdup(fname);
152                         }
153 <PP_PRAGMA>midl_echo[^\n]*  yyless(9); yy_pop_state(); return tCPPQUOTE;
154 <PP_PRAGMA>winrt[^\n]*  {
155                             if(import_stack_ptr) {
156                                 if(!winrt_mode)
157                                     error_loc("winrt IDL file imported in non-winrt mode\n");
158                             }else {
159                                 const char *ptr = yytext+5;
160 
161                                 winrt_mode = TRUE;
162 
163                                 while(isspace(*ptr))
164                                     ptr++;
165                                 if(!strncmp(ptr, "ns_prefix", 9) && (!*(ptr += 9) || isspace(*ptr)))
166                                     use_abi_namespace = TRUE;
167                             }
168                             yy_pop_state();
169                         }
170 <PP_PRAGMA>[^\n]*       parser_lval.str = xstrdup(yytext); yy_pop_state(); return aPRAGMA;
171 <INITIAL>^{ws}*midl_pragma{ws}+warning return tPRAGMA_WARNING;
172 <INITIAL,ATTR>\"	yy_push_state(QUOTE); cbufidx = 0;
173 <QUOTE>\"		{
174 				yy_pop_state();
175 				parser_lval.str = get_buffered_cstring();
176 				return aSTRING;
177 			}
178 <INITIAL,ATTR>L\"	yy_push_state(WSTRQUOTE); cbufidx = 0;
179 <WSTRQUOTE>\"		{
180 				yy_pop_state();
181 				parser_lval.str = get_buffered_cstring();
182 				return aWSTRING;
183 			}
184 <INITIAL,ATTR>\'	yy_push_state(SQUOTE); cbufidx = 0;
185 <SQUOTE>\'		{
186 				yy_pop_state();
187 				parser_lval.str = get_buffered_cstring();
188 				return aSQSTRING;
189 			}
190 <QUOTE,WSTRQUOTE,SQUOTE>\\\\	|
191 <QUOTE,WSTRQUOTE>\\\"	addcchar(yytext[1]);
192 <SQUOTE>\\\'	addcchar(yytext[1]);
193 <QUOTE,WSTRQUOTE,SQUOTE>\\.	addcchar('\\'); addcchar(yytext[1]);
194 <QUOTE,WSTRQUOTE,SQUOTE>.	addcchar(yytext[0]);
195 <INITIAL,ATTR>\[	yy_push_state(ATTR); return '[';
196 <ATTR>\]		yy_pop_state(); return ']';
197 <ATTR>{cident}		return attr_token(yytext);
198 <ATTR>{uuid}			{
199 				parser_lval.uuid = parse_uuid(yytext);
200 				return aUUID;
201 			}
202 <INITIAL,ATTR>{hex}	{
203 				parser_lval.num = xstrtoul(yytext, NULL, 0);
204 				return aHEXNUM;
205 			}
206 <INITIAL,ATTR>{int}	{
207 				parser_lval.num = xstrtoul(yytext, NULL, 0);
208 				return aNUM;
209 			}
210 <INITIAL>{double}	{
211 				parser_lval.dbl = strtod(yytext, NULL);
212 				return aDOUBLE;
213 			}
214 SAFEARRAY{ws}*/\(	return tSAFEARRAY;
215 {cident}		return kw_token(yytext);
216 <INITIAL,ATTR>\n	line_number++;
217 <INITIAL,ATTR>{ws}
218 <INITIAL,ATTR>\<\<	return SHL;
219 <INITIAL,ATTR>\>\>	return SHR;
220 <INITIAL,ATTR>\-\>	return MEMBERPTR;
221 <INITIAL,ATTR>==	return EQUALITY;
222 <INITIAL,ATTR>!=	return INEQUALITY;
223 <INITIAL,ATTR>\>=	return GREATEREQUAL;
224 <INITIAL,ATTR>\<=	return LESSEQUAL;
225 <INITIAL,ATTR>\|\|	return LOGICALOR;
226 <INITIAL,ATTR>&&	return LOGICALAND;
227 <INITIAL,ATTR>\.\.\.	return ELLIPSIS;
228 <INITIAL,ATTR>.		return yytext[0];
229 <<EOF>>			{
230                             if (import_stack_ptr)
231                                 return aEOF;
232                             if (acf_name)
233                             {
234                                 switch_to_acf();
235                                 return aACF;
236                             }
237                             yyterminate();
238 			}
239 %%
240 
241 #ifndef parser_wrap
242 int parser_wrap(void)
243 {
244 	return 1;
245 }
246 #endif
247 
248 struct keyword {
249 	const char *kw;
250 	int token;
251 };
252 
253 /* This table MUST be alphabetically sorted on the kw field */
254 static const struct keyword keywords[] = {
255 	{"FALSE",			tFALSE},
256 	{"NULL",			tNULL},
257 	{"TRUE",			tTRUE},
258 	{"__cdecl",			tCDECL},
259 	{"__fastcall",			tFASTCALL},
260 	{"__int32",			tINT32},
261 	{"__int3264",			tINT3264},
262 	{"__int64",			tINT64},
263 	{"__pascal",			tPASCAL},
264 	{"__stdcall",			tSTDCALL},
265 	{"_cdecl",			tCDECL},
266 	{"_fastcall",			tFASTCALL},
267 	{"_pascal",			tPASCAL},
268 	{"_stdcall",			tSTDCALL},
269 	{"boolean",			tBOOLEAN},
270 	{"byte",			tBYTE},
271 	{"case",			tCASE},
272 	{"cdecl",			tCDECL},
273 	{"char",			tCHAR},
274 	{"coclass",			tCOCLASS},
275 	{"const",			tCONST},
276 	{"cpp_quote",			tCPPQUOTE},
277 	{"default",			tDEFAULT},
278 	{"dispinterface",		tDISPINTERFACE},
279 	{"double",			tDOUBLE},
280 	{"enum",			tENUM},
281 	{"error_status_t",		tERRORSTATUST},
282 	{"extern",			tEXTERN},
283 	{"float",			tFLOAT},
284 	{"handle_t",			tHANDLET},
285 	{"hyper",			tHYPER},
286 	{"import",			tIMPORT},
287 	{"importlib",			tIMPORTLIB},
288 	{"inline",			tINLINE},
289 	{"int",				tINT},
290 	{"interface",			tINTERFACE},
291 	{"library",			tLIBRARY},
292 	{"long",			tLONG},
293 	{"methods",			tMETHODS},
294 	{"module",			tMODULE},
295 	{"namespace",			tNAMESPACE},
296 	{"pascal",			tPASCAL},
297 	{"properties",			tPROPERTIES},
298 	{"register",			tREGISTER},
299 	{"short",			tSHORT},
300 	{"signed",			tSIGNED},
301 	{"sizeof",			tSIZEOF},
302         {"small",			tSMALL},
303 	{"static",			tSTATIC},
304 	{"stdcall",			tSTDCALL},
305 	{"struct",			tSTRUCT},
306 	{"switch",			tSWITCH},
307 	{"typedef",			tTYPEDEF},
308 	{"union",			tUNION},
309 	{"unsigned",			tUNSIGNED},
310 	{"void",			tVOID},
311 	{"wchar_t",			tWCHAR},
312 };
313 #define NKEYWORDS (sizeof(keywords)/sizeof(keywords[0]))
314 
315 /* keywords only recognized in attribute lists
316  * This table MUST be alphabetically sorted on the kw field
317  */
318 static const struct keyword attr_keywords[] =
319 {
320         {"aggregatable",                tAGGREGATABLE},
321         {"all_nodes",                   tALLNODES},
322         {"allocate",                    tALLOCATE},
323         {"annotation",                  tANNOTATION},
324         {"apartment",                   tAPARTMENT},
325         {"appobject",                   tAPPOBJECT},
326         {"async",                       tASYNC},
327         {"async_uuid",                  tASYNCUUID},
328         {"auto_handle",                 tAUTOHANDLE},
329         {"bindable",                    tBINDABLE},
330         {"both",                        tBOTH},
331         {"broadcast",                   tBROADCAST},
332         {"byte_count",                  tBYTECOUNT},
333         {"call_as",                     tCALLAS},
334         {"callback",                    tCALLBACK},
335         {"code",                        tCODE},
336         {"comm_status",                 tCOMMSTATUS},
337         {"context_handle",              tCONTEXTHANDLE},
338         {"context_handle_noserialize",  tCONTEXTHANDLENOSERIALIZE},
339         {"context_handle_serialize",    tCONTEXTHANDLENOSERIALIZE},
340         {"control",                     tCONTROL},
341         {"decode",                      tDECODE},
342         {"defaultbind",                 tDEFAULTBIND},
343         {"defaultcollelem",             tDEFAULTCOLLELEM},
344         {"defaultvalue",                tDEFAULTVALUE},
345         {"defaultvtable",               tDEFAULTVTABLE},
346         {"disable_consistency_check",   tDISABLECONSISTENCYCHECK},
347         {"displaybind",                 tDISPLAYBIND},
348         {"dllname",                     tDLLNAME},
349         {"dont_free",                   tDONTFREE},
350         {"dual",                        tDUAL},
351         {"enable_allocate",             tENABLEALLOCATE},
352         {"encode",                      tENCODE},
353         {"endpoint",                    tENDPOINT},
354         {"entry",                       tENTRY},
355         {"explicit_handle",             tEXPLICITHANDLE},
356         {"fault_status",                tFAULTSTATUS},
357         {"force_allocate",              tFORCEALLOCATE},
358         {"free",                        tFREE},
359         {"handle",                      tHANDLE},
360         {"helpcontext",                 tHELPCONTEXT},
361         {"helpfile",                    tHELPFILE},
362         {"helpstring",                  tHELPSTRING},
363         {"helpstringcontext",           tHELPSTRINGCONTEXT},
364         {"helpstringdll",               tHELPSTRINGDLL},
365         {"hidden",                      tHIDDEN},
366         {"id",                          tID},
367         {"idempotent",                  tIDEMPOTENT},
368         {"ignore",                      tIGNORE},
369         {"iid_is",                      tIIDIS},
370         {"immediatebind",               tIMMEDIATEBIND},
371         {"implicit_handle",             tIMPLICITHANDLE},
372         {"in",                          tIN},
373         {"in_line",                     tIN_LINE},
374         {"input_sync",                  tINPUTSYNC},
375         {"lcid",                        tLCID},
376         {"length_is",                   tLENGTHIS},
377         {"licensed",                    tLICENSED},
378         {"local",                       tLOCAL},
379         {"maybe",                       tMAYBE},
380         {"message",                     tMESSAGE},
381         {"neutral",                     tNEUTRAL},
382         {"nocode",                      tNOCODE},
383         {"nonbrowsable",                tNONBROWSABLE},
384         {"noncreatable",                tNONCREATABLE},
385         {"nonextensible",               tNONEXTENSIBLE},
386         {"notify",                      tNOTIFY},
387         {"notify_flag",                 tNOTIFYFLAG},
388         {"object",                      tOBJECT},
389         {"odl",                         tODL},
390         {"oleautomation",               tOLEAUTOMATION},
391         {"optimize",                    tOPTIMIZE},
392         {"optional",                    tOPTIONAL},
393         {"out",                         tOUT},
394         {"partial_ignore",              tPARTIALIGNORE},
395         {"pointer_default",             tPOINTERDEFAULT},
396         {"progid",                      tPROGID},
397         {"propget",                     tPROPGET},
398         {"propput",                     tPROPPUT},
399         {"propputref",                  tPROPPUTREF},
400         {"proxy",                       tPROXY},
401         {"ptr",                         tPTR},
402         {"public",                      tPUBLIC},
403         {"range",                       tRANGE},
404         {"readonly",                    tREADONLY},
405         {"ref",                         tREF},
406         {"represent_as",                tREPRESENTAS},
407         {"requestedit",                 tREQUESTEDIT},
408         {"restricted",                  tRESTRICTED},
409         {"retval",                      tRETVAL},
410         {"single",                      tSINGLE},
411         {"single_node",                 tSINGLENODE},
412         {"size_is",                     tSIZEIS},
413         {"source",                      tSOURCE},
414         {"strict_context_handle",       tSTRICTCONTEXTHANDLE},
415         {"string",                      tSTRING},
416         {"switch_is",                   tSWITCHIS},
417         {"switch_type",                 tSWITCHTYPE},
418         {"threading",                   tTHREADING},
419         {"transmit_as",                 tTRANSMITAS},
420         {"uidefault",                   tUIDEFAULT},
421         {"unique",                      tUNIQUE},
422         {"user_marshal",                tUSERMARSHAL},
423         {"usesgetlasterror",            tUSESGETLASTERROR},
424         {"uuid",                        tUUID},
425         {"v1_enum",                     tV1ENUM},
426         {"vararg",                      tVARARG},
427         {"version",                     tVERSION},
428         {"vi_progid",                   tVIPROGID},
429         {"wire_marshal",                tWIREMARSHAL},
430 };
431 
432 /* attributes TODO:
433     custom
434     first_is
435     last_is
436     max_is
437     min_is
438 */
439 
440 #define KWP(p) ((const struct keyword *)(p))
441 
442 static int kw_cmp_func(const void *s1, const void *s2)
443 {
444 	return strcmp(KWP(s1)->kw, KWP(s2)->kw);
445 }
446 
447 static int kw_token(const char *kw)
448 {
449 	struct keyword key, *kwp;
450 	key.kw = kw;
451 	kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
452 	if (kwp && (winrt_mode || kwp->token != tNAMESPACE)) {
453 		parser_lval.str = xstrdup(kwp->kw);
454 		return kwp->token;
455 	}
456 	parser_lval.str = xstrdup(kw);
457 	return is_type(kw) ? aKNOWNTYPE : aIDENTIFIER;
458 }
459 
460 static int attr_token(const char *kw)
461 {
462         struct keyword key, *kwp;
463         key.kw = kw;
464         kwp = bsearch(&key, attr_keywords, sizeof(attr_keywords)/sizeof(attr_keywords[0]),
465                       sizeof(attr_keywords[0]), kw_cmp_func);
466         if (kwp) {
467             parser_lval.str = xstrdup(kwp->kw);
468             return kwp->token;
469         }
470         return kw_token(kw);
471 }
472 
473 static void addcchar(char c)
474 {
475 	if(cbufidx >= cbufalloc)
476 	{
477 		cbufalloc += 1024;
478 		cbuffer = xrealloc(cbuffer, cbufalloc * sizeof(cbuffer[0]));
479 		if(cbufalloc > 65536)
480 			parser_warning("Reallocating string buffer larger than 64kB\n");
481 	}
482 	cbuffer[cbufidx++] = c;
483 }
484 
485 static char *get_buffered_cstring(void)
486 {
487 	addcchar(0);
488 	return xstrdup(cbuffer);
489 }
490 
491 void pop_import(void)
492 {
493 	int ptr = import_stack_ptr-1;
494 
495 	fclose(yyin);
496 	yy_delete_buffer( YY_CURRENT_BUFFER );
497 	yy_switch_to_buffer( import_stack[ptr].state );
498 	if (temp_name) {
499 		unlink(temp_name);
500 		free(temp_name);
501 	}
502 	temp_name = import_stack[ptr].temp_name;
503 	input_name = import_stack[ptr].input_name;
504 	line_number = import_stack[ptr].line_number;
505 	import_stack_ptr--;
506 }
507 
508 struct imports {
509     char *name;
510     struct imports *next;
511 } *first_import;
512 
513 int do_import(char *fname)
514 {
515     FILE *f;
516     char *path, *name;
517     struct imports *import;
518     int ptr = import_stack_ptr;
519     int ret, fd;
520 
521     import = first_import;
522     while (import && strcmp(import->name, fname))
523         import = import->next;
524     if (import) return 0; /* already imported */
525 
526     import = xmalloc(sizeof(struct imports));
527     import->name = xstrdup(fname);
528     import->next = first_import;
529     first_import = import;
530 
531     /* don't search for a file name with a path in the include directories,
532      * for compatibility with MIDL */
533     if (strchr( fname, '/' ) || strchr( fname, '\\' ))
534         path = xstrdup( fname );
535     else if (!(path = wpp_find_include( fname, input_name )))
536         error_loc("Unable to open include file %s\n", fname);
537 
538     if (import_stack_ptr == MAX_IMPORT_DEPTH)
539         error_loc("Exceeded max import depth\n");
540 
541     import_stack[ptr].temp_name = temp_name;
542     import_stack[ptr].input_name = input_name;
543     import_stack[ptr].line_number = line_number;
544     import_stack_ptr++;
545     input_name = path;
546     line_number = 1;
547 
548     name = xstrdup( "widl.XXXXXX" );
549     if((fd = mkstemps( name, 0 )) == -1)
550         error("Could not generate a temp name from %s\n", name);
551 
552     temp_name = name;
553     if (!(f = fdopen(fd, "wt")))
554         error("Could not open fd %s for writing\n", name);
555 
556     ret = wpp_parse( path, f );
557     fclose( f );
558     if (ret) exit(1);
559 
560     if((f = fopen(temp_name, "r")) == NULL)
561         error_loc("Unable to open %s\n", temp_name);
562 
563     import_stack[ptr].state = YY_CURRENT_BUFFER;
564     yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
565     return 1;
566 }
567 
568 void abort_import(void)
569 {
570 	int ptr;
571 
572 	for (ptr=0; ptr<import_stack_ptr; ptr++)
573 		unlink(import_stack[ptr].temp_name);
574 }
575 
576 static void switch_to_acf(void)
577 {
578     int ptr = import_stack_ptr;
579     int ret, fd;
580     char *name;
581     FILE *f;
582 
583     assert(import_stack_ptr == 0);
584 
585     input_name = acf_name;
586     acf_name = NULL;
587     line_number = 1;
588 
589     name = xstrdup( "widl.XXXXXX" );
590     if((fd = mkstemps( name, 0 )) == -1)
591         error("Could not generate a temp name from %s\n", name);
592 
593     temp_name = name;
594     if (!(f = fdopen(fd, "wt")))
595         error("Could not open fd %s for writing\n", name);
596 
597     ret = wpp_parse(input_name, f);
598     fclose(f);
599     if (ret) exit(1);
600 
601     if((f = fopen(temp_name, "r")) == NULL)
602         error_loc("Unable to open %s\n", temp_name);
603 
604     import_stack[ptr].state = YY_CURRENT_BUFFER;
605     yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
606 }
607 
608 static void warning_disable(int warning)
609 {
610     warning_t *warning_entry;
611     LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
612         if(warning_entry->num == warning)
613             return;
614     warning_entry = xmalloc( sizeof(*warning_entry) );
615     warning_entry->num = warning;
616     list_add_tail(disabled_warnings, &warning_entry->entry);
617 }
618 
619 static void warning_enable(int warning)
620 {
621     warning_t *warning_entry;
622     LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
623         if(warning_entry->num == warning)
624         {
625             list_remove(&warning_entry->entry);
626             free(warning_entry);
627             break;
628         }
629 }
630 
631 int do_warning(char *toggle, warning_list_t *wnum)
632 {
633     warning_t *warning, *next;
634     int ret = 1;
635     if(!disabled_warnings)
636     {
637         disabled_warnings = xmalloc( sizeof(*disabled_warnings) );
638         list_init( disabled_warnings );
639     }
640 
641     if(!strcmp(toggle, "disable"))
642         LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry)
643             warning_disable(warning->num);
644     else if(!strcmp(toggle, "enable"))
645         LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry)
646             warning_enable(warning->num);
647     else
648         ret = 0;
649 
650     LIST_FOR_EACH_ENTRY_SAFE(warning, next, wnum, warning_t, entry)
651         free(warning);
652     return ret;
653 }
654 
655 int is_warning_enabled(int warning)
656 {
657     warning_t *warning_entry;
658     if(!disabled_warnings)
659         return 1;
660     LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
661         if(warning_entry->num == warning)
662             return 0;
663     return 1;
664 }
665