xref: /reactos/sdk/tools/widl/parser.l (revision 0f92924a)
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         {"allocate",                    tALLOCATE},
322         {"annotation",                  tANNOTATION},
323         {"apartment",                   tAPARTMENT},
324         {"appobject",                   tAPPOBJECT},
325         {"async",                       tASYNC},
326         {"async_uuid",                  tASYNCUUID},
327         {"auto_handle",                 tAUTOHANDLE},
328         {"bindable",                    tBINDABLE},
329         {"both",                        tBOTH},
330         {"broadcast",                   tBROADCAST},
331         {"byte_count",                  tBYTECOUNT},
332         {"call_as",                     tCALLAS},
333         {"callback",                    tCALLBACK},
334         {"code",                        tCODE},
335         {"comm_status",                 tCOMMSTATUS},
336         {"context_handle",              tCONTEXTHANDLE},
337         {"context_handle_noserialize",  tCONTEXTHANDLENOSERIALIZE},
338         {"context_handle_serialize",    tCONTEXTHANDLENOSERIALIZE},
339         {"control",                     tCONTROL},
340         {"decode",                      tDECODE},
341         {"defaultbind",                 tDEFAULTBIND},
342         {"defaultcollelem",             tDEFAULTCOLLELEM},
343         {"defaultvalue",                tDEFAULTVALUE},
344         {"defaultvtable",               tDEFAULTVTABLE},
345         {"disable_consistency_check",   tDISABLECONSISTENCYCHECK},
346         {"displaybind",                 tDISPLAYBIND},
347         {"dllname",                     tDLLNAME},
348         {"dual",                        tDUAL},
349         {"enable_allocate",             tENABLEALLOCATE},
350         {"encode",                      tENCODE},
351         {"endpoint",                    tENDPOINT},
352         {"entry",                       tENTRY},
353         {"explicit_handle",             tEXPLICITHANDLE},
354         {"fault_status",                tFAULTSTATUS},
355         {"force_allocate",              tFORCEALLOCATE},
356         {"free",                        tFREE},
357         {"handle",                      tHANDLE},
358         {"helpcontext",                 tHELPCONTEXT},
359         {"helpfile",                    tHELPFILE},
360         {"helpstring",                  tHELPSTRING},
361         {"helpstringcontext",           tHELPSTRINGCONTEXT},
362         {"helpstringdll",               tHELPSTRINGDLL},
363         {"hidden",                      tHIDDEN},
364         {"id",                          tID},
365         {"idempotent",                  tIDEMPOTENT},
366         {"ignore",                      tIGNORE},
367         {"iid_is",                      tIIDIS},
368         {"immediatebind",               tIMMEDIATEBIND},
369         {"implicit_handle",             tIMPLICITHANDLE},
370         {"in",                          tIN},
371         {"in_line",                     tIN_LINE},
372         {"input_sync",                  tINPUTSYNC},
373         {"lcid",                        tLCID},
374         {"length_is",                   tLENGTHIS},
375         {"licensed",                    tLICENSED},
376         {"local",                       tLOCAL},
377         {"maybe",                       tMAYBE},
378         {"message",                     tMESSAGE},
379         {"neutral",                     tNEUTRAL},
380         {"nocode",                      tNOCODE},
381         {"nonbrowsable",                tNONBROWSABLE},
382         {"noncreatable",                tNONCREATABLE},
383         {"nonextensible",               tNONEXTENSIBLE},
384         {"notify",                      tNOTIFY},
385         {"notify_flag",                 tNOTIFYFLAG},
386         {"object",                      tOBJECT},
387         {"odl",                         tODL},
388         {"oleautomation",               tOLEAUTOMATION},
389         {"optimize",                    tOPTIMIZE},
390         {"optional",                    tOPTIONAL},
391         {"out",                         tOUT},
392         {"partial_ignore",              tPARTIALIGNORE},
393         {"pointer_default",             tPOINTERDEFAULT},
394         {"progid",                      tPROGID},
395         {"propget",                     tPROPGET},
396         {"propput",                     tPROPPUT},
397         {"propputref",                  tPROPPUTREF},
398         {"proxy",                       tPROXY},
399         {"ptr",                         tPTR},
400         {"public",                      tPUBLIC},
401         {"range",                       tRANGE},
402         {"readonly",                    tREADONLY},
403         {"ref",                         tREF},
404         {"represent_as",                tREPRESENTAS},
405         {"requestedit",                 tREQUESTEDIT},
406         {"restricted",                  tRESTRICTED},
407         {"retval",                      tRETVAL},
408         {"single",                      tSINGLE},
409         {"size_is",                     tSIZEIS},
410         {"source",                      tSOURCE},
411         {"strict_context_handle",       tSTRICTCONTEXTHANDLE},
412         {"string",                      tSTRING},
413         {"switch_is",                   tSWITCHIS},
414         {"switch_type",                 tSWITCHTYPE},
415         {"threading",                   tTHREADING},
416         {"transmit_as",                 tTRANSMITAS},
417         {"uidefault",                   tUIDEFAULT},
418         {"unique",                      tUNIQUE},
419         {"user_marshal",                tUSERMARSHAL},
420         {"usesgetlasterror",            tUSESGETLASTERROR},
421         {"uuid",                        tUUID},
422         {"v1_enum",                     tV1ENUM},
423         {"vararg",                      tVARARG},
424         {"version",                     tVERSION},
425         {"vi_progid",                   tVIPROGID},
426         {"wire_marshal",                tWIREMARSHAL},
427 };
428 
429 /* attributes TODO:
430     custom
431     first_is
432     last_is
433     max_is
434     min_is
435 */
436 
437 #define KWP(p) ((const struct keyword *)(p))
438 
439 static int kw_cmp_func(const void *s1, const void *s2)
440 {
441 	return strcmp(KWP(s1)->kw, KWP(s2)->kw);
442 }
443 
444 static int kw_token(const char *kw)
445 {
446 	struct keyword key, *kwp;
447 	key.kw = kw;
448 	kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
449 	if (kwp && (winrt_mode || kwp->token != tNAMESPACE)) {
450 		parser_lval.str = xstrdup(kwp->kw);
451 		return kwp->token;
452 	}
453 	parser_lval.str = xstrdup(kw);
454 	return is_type(kw) ? aKNOWNTYPE : aIDENTIFIER;
455 }
456 
457 static int attr_token(const char *kw)
458 {
459         struct keyword key, *kwp;
460         key.kw = kw;
461         kwp = bsearch(&key, attr_keywords, sizeof(attr_keywords)/sizeof(attr_keywords[0]),
462                       sizeof(attr_keywords[0]), kw_cmp_func);
463         if (kwp) {
464             parser_lval.str = xstrdup(kwp->kw);
465             return kwp->token;
466         }
467         return kw_token(kw);
468 }
469 
470 static void addcchar(char c)
471 {
472 	if(cbufidx >= cbufalloc)
473 	{
474 		cbufalloc += 1024;
475 		cbuffer = xrealloc(cbuffer, cbufalloc * sizeof(cbuffer[0]));
476 		if(cbufalloc > 65536)
477 			parser_warning("Reallocating string buffer larger than 64kB\n");
478 	}
479 	cbuffer[cbufidx++] = c;
480 }
481 
482 static char *get_buffered_cstring(void)
483 {
484 	addcchar(0);
485 	return xstrdup(cbuffer);
486 }
487 
488 void pop_import(void)
489 {
490 	int ptr = import_stack_ptr-1;
491 
492 	fclose(yyin);
493 	yy_delete_buffer( YY_CURRENT_BUFFER );
494 	yy_switch_to_buffer( import_stack[ptr].state );
495 	if (temp_name) {
496 		unlink(temp_name);
497 		free(temp_name);
498 	}
499 	temp_name = import_stack[ptr].temp_name;
500 	input_name = import_stack[ptr].input_name;
501 	line_number = import_stack[ptr].line_number;
502 	import_stack_ptr--;
503 }
504 
505 struct imports {
506     char *name;
507     struct imports *next;
508 } *first_import;
509 
510 int do_import(char *fname)
511 {
512     FILE *f;
513     char *path, *name;
514     struct imports *import;
515     int ptr = import_stack_ptr;
516     int ret, fd;
517 
518     import = first_import;
519     while (import && strcmp(import->name, fname))
520         import = import->next;
521     if (import) return 0; /* already imported */
522 
523     import = xmalloc(sizeof(struct imports));
524     import->name = xstrdup(fname);
525     import->next = first_import;
526     first_import = import;
527 
528     /* don't search for a file name with a path in the include directories,
529      * for compatibility with MIDL */
530     if (strchr( fname, '/' ) || strchr( fname, '\\' ))
531         path = xstrdup( fname );
532     else if (!(path = wpp_find_include( fname, input_name )))
533         error_loc("Unable to open include file %s\n", fname);
534 
535     if (import_stack_ptr == MAX_IMPORT_DEPTH)
536         error_loc("Exceeded max import depth\n");
537 
538     import_stack[ptr].temp_name = temp_name;
539     import_stack[ptr].input_name = input_name;
540     import_stack[ptr].line_number = line_number;
541     import_stack_ptr++;
542     input_name = path;
543     line_number = 1;
544 
545     name = xstrdup( "widl.XXXXXX" );
546     if((fd = mkstemps( name, 0 )) == -1)
547         error("Could not generate a temp name from %s\n", name);
548 
549     temp_name = name;
550     if (!(f = fdopen(fd, "wt")))
551         error("Could not open fd %s for writing\n", name);
552 
553     ret = wpp_parse( path, f );
554     fclose( f );
555     if (ret) exit(1);
556 
557     if((f = fopen(temp_name, "r")) == NULL)
558         error_loc("Unable to open %s\n", temp_name);
559 
560     import_stack[ptr].state = YY_CURRENT_BUFFER;
561     yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
562     return 1;
563 }
564 
565 void abort_import(void)
566 {
567 	int ptr;
568 
569 	for (ptr=0; ptr<import_stack_ptr; ptr++)
570 		unlink(import_stack[ptr].temp_name);
571 }
572 
573 static void switch_to_acf(void)
574 {
575     int ptr = import_stack_ptr;
576     int ret, fd;
577     char *name;
578     FILE *f;
579 
580     assert(import_stack_ptr == 0);
581 
582     input_name = acf_name;
583     acf_name = NULL;
584     line_number = 1;
585 
586     name = xstrdup( "widl.XXXXXX" );
587     if((fd = mkstemps( name, 0 )) == -1)
588         error("Could not generate a temp name from %s\n", name);
589 
590     temp_name = name;
591     if (!(f = fdopen(fd, "wt")))
592         error("Could not open fd %s for writing\n", name);
593 
594     ret = wpp_parse(input_name, f);
595     fclose(f);
596     if (ret) exit(1);
597 
598     if((f = fopen(temp_name, "r")) == NULL)
599         error_loc("Unable to open %s\n", temp_name);
600 
601     import_stack[ptr].state = YY_CURRENT_BUFFER;
602     yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
603 }
604 
605 static void warning_disable(int warning)
606 {
607     warning_t *warning_entry;
608     LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
609         if(warning_entry->num == warning)
610             return;
611     warning_entry = xmalloc( sizeof(*warning_entry) );
612     warning_entry->num = warning;
613     list_add_tail(disabled_warnings, &warning_entry->entry);
614 }
615 
616 static void warning_enable(int warning)
617 {
618     warning_t *warning_entry;
619     LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
620         if(warning_entry->num == warning)
621         {
622             list_remove(&warning_entry->entry);
623             free(warning_entry);
624             break;
625         }
626 }
627 
628 int do_warning(char *toggle, warning_list_t *wnum)
629 {
630     warning_t *warning, *next;
631     int ret = 1;
632     if(!disabled_warnings)
633     {
634         disabled_warnings = xmalloc( sizeof(*disabled_warnings) );
635         list_init( disabled_warnings );
636     }
637 
638     if(!strcmp(toggle, "disable"))
639         LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry)
640             warning_disable(warning->num);
641     else if(!strcmp(toggle, "enable"))
642         LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry)
643             warning_enable(warning->num);
644     else
645         ret = 0;
646 
647     LIST_FOR_EACH_ENTRY_SAFE(warning, next, wnum, warning_t, entry)
648         free(warning);
649     return ret;
650 }
651 
652 int is_warning_enabled(int warning)
653 {
654     warning_t *warning_entry;
655     if(!disabled_warnings)
656         return 1;
657     LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
658         if(warning_entry->num == warning)
659             return 0;
660     return 1;
661 }
662