parser.l 19.4 KB
Newer Older
1
/* -*-C-*-
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 * IDL Compiler
 *
 * Copyright 2002 Ove Kaaven
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 26 27

nl	\r?\n
ws	[ \f\t\r]
cident	[a-zA-Z_][0-9a-zA-Z_]*
28 29 30
u_suffix	(u|U)
l_suffix	(l|L)
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 39
%x ATTR
%x PP_LINE
40
%x PP_PRAGMA
41
%x SQUOTE
42 43 44

%{

45
#include "config.h"
46
#include "wine/port.h"
47

48 49 50 51 52
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
Huw Davies's avatar
Huw Davies committed
53
#include <errno.h>
54
#include <limits.h>
55

56 57 58
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
59
#define YY_NO_UNISTD_H
60
#endif
61 62 63 64

#include "widl.h"
#include "utils.h"
#include "parser.h"
65
#include "wine/wpp.h"
66

67
#include "parser.tab.h"
68 69 70 71 72 73 74 75 76

static void addcchar(char c);
static char *get_buffered_cstring(void);

static char *cbuffer;
static int cbufidx;
static int cbufalloc = 0;

static int kw_token(const char *kw);
77
static int attr_token(const char *kw);
78

79 80
static warning_list_t *disabled_warnings = NULL;

81 82 83
#define MAX_IMPORT_DEPTH 10
struct {
  YY_BUFFER_STATE state;
84 85
  char *input_name;
  int   line_number;
86 87 88 89
  char *temp_name;
} import_stack[MAX_IMPORT_DEPTH];
int import_stack_ptr = 0;

90 91
/* converts an integer in string form to an unsigned long and prints an error
 * on overflow */
92
static unsigned int xstrtoul(const char *nptr, char **endptr, int base)
93
{
94
    unsigned long val;
95 96

    errno = 0;
97 98
    val = strtoul(nptr, endptr, base);
    if ((val == ULONG_MAX && errno == ERANGE) || ((unsigned int)val != val))
99
        error_loc("integer constant %s is too large\n", nptr);
100
    return val;
101 102
}

103
UUID *parse_uuid(const char *u)
104
{
105
  UUID* uuid = xmalloc(sizeof(UUID));
106 107
  char b[3];
  /* it would be nice to use UuidFromStringA */
108 109 110
  uuid->Data1 = strtoul(u, NULL, 16);
  uuid->Data2 = strtoul(u+9, NULL, 16);
  uuid->Data3 = strtoul(u+14, NULL, 16);
111
  b[2] = 0;
112 113 114 115 116 117 118 119
  memcpy(b, u+19, 2); uuid->Data4[0] = strtoul(b, NULL, 16);
  memcpy(b, u+21, 2); uuid->Data4[1] = strtoul(b, NULL, 16);
  memcpy(b, u+24, 2); uuid->Data4[2] = strtoul(b, NULL, 16);
  memcpy(b, u+26, 2); uuid->Data4[3] = strtoul(b, NULL, 16);
  memcpy(b, u+28, 2); uuid->Data4[4] = strtoul(b, NULL, 16);
  memcpy(b, u+30, 2); uuid->Data4[5] = strtoul(b, NULL, 16);
  memcpy(b, u+32, 2); uuid->Data4[6] = strtoul(b, NULL, 16);
  memcpy(b, u+34, 2); uuid->Data4[7] = strtoul(b, NULL, 16);
120 121 122
  return uuid;
}

123 124 125 126 127 128 129 130
%}

/*
 **************************************************************************
 * The flexer starts here
 **************************************************************************
 */
%%
131
<INITIAL>^{ws}*\#{ws}*pragma{ws}+ yy_push_state(PP_PRAGMA);
132 133
<INITIAL,ATTR>^{ws}*\#{ws}*	yy_push_state(PP_LINE);
<PP_LINE>[^\n]*         {
134 135 136 137 138
                            int lineno;
                            char *cptr, *fname;
                            yy_pop_state();
                            lineno = (int)strtol(yytext, &cptr, 10);
                            if(!lineno)
139
                                error_loc("Malformed '#...' line-directive; invalid linenumber\n");
140 141
                            fname = strchr(cptr, '"');
                            if(!fname)
142
                                error_loc("Malformed '#...' line-directive; missing filename\n");
143 144 145
                            fname++;
                            cptr = strchr(fname, '"');
                            if(!cptr)
146
                                error_loc("Malformed '#...' line-directive; missing terminating \"\n");
147 148 149 150
                            *cptr = '\0';
                            line_number = lineno - 1;  /* We didn't read the newline */
                            input_name = xstrdup(fname);
                        }
151
<PP_PRAGMA>midl_echo[^\n]*  yyless(9); yy_pop_state(); return tCPPQUOTE;
152 153 154 155 156
<PP_PRAGMA>winrt[^\n]*  {
                            if(import_stack_ptr) {
                                if(!winrt_mode)
                                    error_loc("winrt IDL file imported in non-winrt mode\n");
                            }else {
157 158
                                const char *ptr = yytext+5;

159
                                winrt_mode = TRUE;
160 161 162 163 164

                                while(isspace(*ptr))
                                    ptr++;
                                if(!strncmp(ptr, "ns_prefix", 9) && (!*(ptr += 9) || isspace(*ptr)))
                                    use_abi_namespace = TRUE;
165 166 167
                            }
                            yy_pop_state();
                        }
168
<PP_PRAGMA>[^\n]*       parser_lval.str = xstrdup(yytext); yy_pop_state(); return aPRAGMA;
169
<INITIAL>^{ws}*midl_pragma{ws}+warning return tPRAGMA_WARNING;
170
<INITIAL,ATTR>\"	yy_push_state(QUOTE); cbufidx = 0;
171 172
<QUOTE>\"		{
				yy_pop_state();
173
				parser_lval.str = get_buffered_cstring();
174 175
				return aSTRING;
			}
176
<INITIAL,ATTR>L\"	yy_push_state(WSTRQUOTE); cbufidx = 0;
177 178 179 180 181
<WSTRQUOTE>\"		{
				yy_pop_state();
				parser_lval.str = get_buffered_cstring();
				return aWSTRING;
			}
182 183 184 185 186 187 188
<INITIAL,ATTR>\'	yy_push_state(SQUOTE); cbufidx = 0;
<SQUOTE>\'		{
				yy_pop_state();
				parser_lval.str = get_buffered_cstring();
				return aSQSTRING;
			}
<QUOTE,WSTRQUOTE,SQUOTE>\\\\	|
189
<QUOTE,WSTRQUOTE>\\\"	addcchar(yytext[1]);
190 191 192
<SQUOTE>\\\'	addcchar(yytext[1]);
<QUOTE,WSTRQUOTE,SQUOTE>\\.	addcchar('\\'); addcchar(yytext[1]);
<QUOTE,WSTRQUOTE,SQUOTE>.	addcchar(yytext[0]);
193 194 195 196
<INITIAL,ATTR>\[	yy_push_state(ATTR); return '[';
<ATTR>\]		yy_pop_state(); return ']';
<ATTR>{cident}		return attr_token(yytext);
<ATTR>{uuid}			{
197
				parser_lval.uuid = parse_uuid(yytext);
198 199
				return aUUID;
			}
200
<INITIAL,ATTR>{hex}	{
201
				parser_lval.num = xstrtoul(yytext, NULL, 0);
202 203
				return aHEXNUM;
			}
204
<INITIAL,ATTR>{int}	{
205
				parser_lval.num = xstrtoul(yytext, NULL, 0);
206 207
				return aNUM;
			}
208 209 210 211
<INITIAL>{double}	{
				parser_lval.dbl = strtod(yytext, NULL);
				return aDOUBLE;
			}
212
SAFEARRAY{ws}*/\(	return tSAFEARRAY;
213
{cident}		return kw_token(yytext);
214 215 216 217
<INITIAL,ATTR>\n	line_number++;
<INITIAL,ATTR>{ws}
<INITIAL,ATTR>\<\<	return SHL;
<INITIAL,ATTR>\>\>	return SHR;
218
<INITIAL,ATTR>\-\>	return MEMBERPTR;
219 220 221 222 223 224
<INITIAL,ATTR>==	return EQUALITY;
<INITIAL,ATTR>!=	return INEQUALITY;
<INITIAL,ATTR>\>=	return GREATEREQUAL;
<INITIAL,ATTR>\<=	return LESSEQUAL;
<INITIAL,ATTR>\|\|	return LOGICALOR;
<INITIAL,ATTR>&&	return LOGICALAND;
225
<INITIAL,ATTR>\.\.\.	return ELLIPSIS;
226
<INITIAL,ATTR>.		return yytext[0];
227
<<EOF>>			{
228
				if (import_stack_ptr)
229
					return aEOF;
230 231 232 233
				else yyterminate();
			}
%%

234 235
#ifndef parser_wrap
int parser_wrap(void)
236 237 238 239 240
{
	return 1;
}
#endif

241
struct keyword {
242 243
	const char *kw;
	int token;
244 245
};

246
/* This table MUST be alphabetically sorted on the kw field */
247
static const struct keyword keywords[] = {
248
	{"FALSE",			tFALSE},
249
	{"NULL",			tNULL},
250
	{"TRUE",			tTRUE},
251
	{"__cdecl",			tCDECL},
252
	{"__fastcall",			tFASTCALL},
253
	{"__int3264",			tINT3264},
254
	{"__int64",			tINT64},
255
	{"__pascal",			tPASCAL},
256
	{"__stdcall",			tSTDCALL},
257 258 259
	{"_cdecl",			tCDECL},
	{"_fastcall",			tFASTCALL},
	{"_pascal",			tPASCAL},
260 261 262 263
	{"_stdcall",			tSTDCALL},
	{"boolean",			tBOOLEAN},
	{"byte",			tBYTE},
	{"case",			tCASE},
264
	{"cdecl",			tCDECL},
265 266 267 268 269
	{"char",			tCHAR},
	{"coclass",			tCOCLASS},
	{"const",			tCONST},
	{"cpp_quote",			tCPPQUOTE},
	{"default",			tDEFAULT},
270
	{"dispinterface",		tDISPINTERFACE},
271 272
	{"double",			tDOUBLE},
	{"enum",			tENUM},
273
	{"error_status_t",		tERRORSTATUST},
274 275
	{"extern",			tEXTERN},
	{"float",			tFLOAT},
276
	{"handle_t",			tHANDLET},
277
	{"hyper",			tHYPER},
278 279
	{"import",			tIMPORT},
	{"importlib",			tIMPORTLIB},
280
	{"inline",			tINLINE},
281 282
	{"int",				tINT},
	{"interface",			tINTERFACE},
283
	{"library",			tLIBRARY},
284
	{"long",			tLONG},
285 286
	{"methods",			tMETHODS},
	{"module",			tMODULE},
287
	{"namespace",			tNAMESPACE},
288
	{"pascal",			tPASCAL},
289
	{"properties",			tPROPERTIES},
290
	{"register",			tREGISTER},
291 292 293
	{"short",			tSHORT},
	{"signed",			tSIGNED},
	{"sizeof",			tSIZEOF},
294
        {"small",			tSMALL},
295
	{"static",			tSTATIC},
296
	{"stdcall",			tSTDCALL},
297 298 299 300 301 302 303 304
	{"struct",			tSTRUCT},
	{"switch",			tSWITCH},
	{"typedef",			tTYPEDEF},
	{"union",			tUNION},
	{"unsigned",			tUNSIGNED},
	{"void",			tVOID},
	{"wchar_t",			tWCHAR},
};
305
#define NKEYWORDS (sizeof(keywords)/sizeof(keywords[0]))
306

307 308 309
/* keywords only recognized in attribute lists
 * This table MUST be alphabetically sorted on the kw field
 */
310 311 312 313
static const struct keyword attr_keywords[] =
{
        {"aggregatable",                tAGGREGATABLE},
        {"allocate",                    tALLOCATE},
314
        {"annotation",                  tANNOTATION},
315
        {"apartment",                   tAPARTMENT},
316 317 318 319 320
        {"appobject",                   tAPPOBJECT},
        {"async",                       tASYNC},
        {"async_uuid",                  tASYNCUUID},
        {"auto_handle",                 tAUTOHANDLE},
        {"bindable",                    tBINDABLE},
321
        {"both",                        tBOTH},
322 323 324
        {"broadcast",                   tBROADCAST},
        {"byte_count",                  tBYTECOUNT},
        {"call_as",                     tCALLAS},
325 326 327
        {"callback",                    tCALLBACK},
        {"code",                        tCODE},
        {"comm_status",                 tCOMMSTATUS},
328 329 330
        {"context_handle",              tCONTEXTHANDLE},
        {"context_handle_noserialize",  tCONTEXTHANDLENOSERIALIZE},
        {"context_handle_serialize",    tCONTEXTHANDLENOSERIALIZE},
331
        {"control",                     tCONTROL},
332 333
        {"decode",                      tDECODE},
        {"defaultbind",                 tDEFAULTBIND},
334 335 336
        {"defaultcollelem",             tDEFAULTCOLLELEM},
        {"defaultvalue",                tDEFAULTVALUE},
        {"defaultvtable",               tDEFAULTVTABLE},
337
        {"disable_consistency_check",   tDISABLECONSISTENCYCHECK},
338 339 340
        {"displaybind",                 tDISPLAYBIND},
        {"dllname",                     tDLLNAME},
        {"dual",                        tDUAL},
341 342
        {"enable_allocate",             tENABLEALLOCATE},
        {"encode",                      tENCODE},
343 344 345
        {"endpoint",                    tENDPOINT},
        {"entry",                       tENTRY},
        {"explicit_handle",             tEXPLICITHANDLE},
346 347
        {"fault_status",                tFAULTSTATUS},
        {"force_allocate",              tFORCEALLOCATE},
348
        {"free",                        tFREE},
349 350 351 352 353 354 355 356 357
        {"handle",                      tHANDLE},
        {"helpcontext",                 tHELPCONTEXT},
        {"helpfile",                    tHELPFILE},
        {"helpstring",                  tHELPSTRING},
        {"helpstringcontext",           tHELPSTRINGCONTEXT},
        {"helpstringdll",               tHELPSTRINGDLL},
        {"hidden",                      tHIDDEN},
        {"id",                          tID},
        {"idempotent",                  tIDEMPOTENT},
358
        {"ignore",                      tIGNORE},
359 360 361 362
        {"iid_is",                      tIIDIS},
        {"immediatebind",               tIMMEDIATEBIND},
        {"implicit_handle",             tIMPLICITHANDLE},
        {"in",                          tIN},
363
        {"in_line",                     tIN_LINE},
364 365 366
        {"input_sync",                  tINPUTSYNC},
        {"lcid",                        tLCID},
        {"length_is",                   tLENGTHIS},
367
        {"licensed",                    tLICENSED},
368
        {"local",                       tLOCAL},
369 370
        {"maybe",                       tMAYBE},
        {"message",                     tMESSAGE},
371
        {"neutral",                     tNEUTRAL},
372
        {"nocode",                      tNOCODE},
373 374 375
        {"nonbrowsable",                tNONBROWSABLE},
        {"noncreatable",                tNONCREATABLE},
        {"nonextensible",               tNONEXTENSIBLE},
376 377
        {"notify",                      tNOTIFY},
        {"notify_flag",                 tNOTIFYFLAG},
378 379 380
        {"object",                      tOBJECT},
        {"odl",                         tODL},
        {"oleautomation",               tOLEAUTOMATION},
381
        {"optimize",                    tOPTIMIZE},
382 383
        {"optional",                    tOPTIONAL},
        {"out",                         tOUT},
384
        {"partial_ignore",              tPARTIALIGNORE},
385
        {"pointer_default",             tPOINTERDEFAULT},
386
        {"progid",                      tPROGID},
387 388 389
        {"propget",                     tPROPGET},
        {"propput",                     tPROPPUT},
        {"propputref",                  tPROPPUTREF},
390
        {"proxy",                       tPROXY},
391 392 393 394 395
        {"ptr",                         tPTR},
        {"public",                      tPUBLIC},
        {"range",                       tRANGE},
        {"readonly",                    tREADONLY},
        {"ref",                         tREF},
396
        {"represent_as",                tREPRESENTAS},
397 398 399
        {"requestedit",                 tREQUESTEDIT},
        {"restricted",                  tRESTRICTED},
        {"retval",                      tRETVAL},
400
        {"single",                      tSINGLE},
401 402
        {"size_is",                     tSIZEIS},
        {"source",                      tSOURCE},
403
        {"strict_context_handle",       tSTRICTCONTEXTHANDLE},
404 405 406
        {"string",                      tSTRING},
        {"switch_is",                   tSWITCHIS},
        {"switch_type",                 tSWITCHTYPE},
407
        {"threading",                   tTHREADING},
408
        {"transmit_as",                 tTRANSMITAS},
409
        {"uidefault",                   tUIDEFAULT},
410
        {"unique",                      tUNIQUE},
411 412
        {"user_marshal",                tUSERMARSHAL},
        {"usesgetlasterror",            tUSESGETLASTERROR},
413 414 415 416
        {"uuid",                        tUUID},
        {"v1_enum",                     tV1ENUM},
        {"vararg",                      tVARARG},
        {"version",                     tVERSION},
417
        {"vi_progid",                   tVIPROGID},
418 419 420
        {"wire_marshal",                tWIREMARSHAL},
};

421 422 423 424 425 426 427
/* attributes TODO:
    custom
    first_is
    last_is
    max_is
    min_is
*/
428

429
#define KWP(p) ((const struct keyword *)(p))
430 431 432 433 434

static int kw_cmp_func(const void *s1, const void *s2)
{
	return strcmp(KWP(s1)->kw, KWP(s2)->kw);
}
435 436 437

static int kw_token(const char *kw)
{
438 439 440
	struct keyword key, *kwp;
	key.kw = kw;
	kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func);
441
	if (kwp && (winrt_mode || kwp->token != tNAMESPACE)) {
442
		parser_lval.str = xstrdup(kwp->kw);
443 444
		return kwp->token;
	}
445
	parser_lval.str = xstrdup(kw);
446 447 448
	return is_type(kw) ? aKNOWNTYPE : aIDENTIFIER;
}

449 450 451 452 453 454 455 456 457 458 459 460 461
static int attr_token(const char *kw)
{
        struct keyword key, *kwp;
        key.kw = kw;
        kwp = bsearch(&key, attr_keywords, sizeof(attr_keywords)/sizeof(attr_keywords[0]),
                      sizeof(attr_keywords[0]), kw_cmp_func);
        if (kwp) {
            parser_lval.str = xstrdup(kwp->kw);
            return kwp->token;
        }
        return kw_token(kw);
}

462 463 464 465 466 467 468
static void addcchar(char c)
{
	if(cbufidx >= cbufalloc)
	{
		cbufalloc += 1024;
		cbuffer = xrealloc(cbuffer, cbufalloc * sizeof(cbuffer[0]));
		if(cbufalloc > 65536)
469
			parser_warning("Reallocating string buffer larger than 64kB\n");
470 471 472 473 474 475 476 477 478 479
	}
	cbuffer[cbufidx++] = c;
}

static char *get_buffered_cstring(void)
{
	addcchar(0);
	return xstrdup(cbuffer);
}

480
void pop_import(void)
481 482 483 484 485 486 487 488 489 490 491
{
	int ptr = import_stack_ptr-1;

	fclose(yyin);
	yy_delete_buffer( YY_CURRENT_BUFFER );
	yy_switch_to_buffer( import_stack[ptr].state );
	if (temp_name) {
		unlink(temp_name);
		free(temp_name);
	}
	temp_name = import_stack[ptr].temp_name;
492 493
	input_name = import_stack[ptr].input_name;
	line_number = import_stack[ptr].line_number;
494 495 496 497 498 499 500 501
	import_stack_ptr--;
}

struct imports {
	char *name;
	struct imports *next;
} *first_import;

502
int do_import(char *fname)
503 504
{
	FILE *f;
505
	char *path, *name;
506 507
	struct imports *import;
	int ptr = import_stack_ptr;
508
	int ret, fd;
509 510 511 512

	import = first_import;
	while (import && strcmp(import->name, fname))
		import = import->next;
513
	if (import) return 0; /* already imported */
514 515 516 517 518 519

	import = xmalloc(sizeof(struct imports));
	import->name = xstrdup(fname);
	import->next = first_import;
	first_import = import;

520 521 522
        /* don't search for a file name with a path in the include directories,
         * for compatibility with MIDL */
        if (strchr( fname, '/' ) || strchr( fname, '\\' ))
523
            path = xstrdup( fname );
524
        else if (!(path = wpp_find_include( fname, input_name )))
525
            error_loc("Unable to open include file %s\n", fname);
526 527

	import_stack[ptr].temp_name = temp_name;
528 529
	import_stack[ptr].input_name = input_name;
	import_stack[ptr].line_number = line_number;
530
	import_stack_ptr++;
531 532
        input_name = path;
        line_number = 1;
533

534 535 536 537 538 539 540 541 542 543
        name = xstrdup( "widl.XXXXXX" );
        if((fd = mkstemps( name, 0 )) == -1)
            error("Could not generate a temp name from %s\n", name);

        temp_name = name;
        if (!(f = fdopen(fd, "wt")))
            error("Could not open fd %s for writing\n", name);

        ret = wpp_parse( path, f );
        fclose( f );
544 545 546
        if (ret) exit(1);

	if((f = fopen(temp_name, "r")) == NULL)
547
		error_loc("Unable to open %s\n", temp_name);
548 549 550

	import_stack[ptr].state = YY_CURRENT_BUFFER;
	yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE));
551
	return 1;
552 553 554 555 556 557 558 559 560
}

void abort_import(void)
{
	int ptr;

	for (ptr=0; ptr<import_stack_ptr; ptr++)
		unlink(import_stack[ptr].temp_name);
}
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618

static void warning_disable(int warning)
{
    warning_t *warning_entry;
    LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
        if(warning_entry->num == warning)
            return;
    warning_entry = xmalloc( sizeof(*warning_entry) );
    warning_entry->num = warning;
    list_add_tail(disabled_warnings, &warning_entry->entry);
}

static void warning_enable(int warning)
{
    warning_t *warning_entry;
    LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
        if(warning_entry->num == warning)
        {
            list_remove(&warning_entry->entry);
            free(warning_entry);
            break;
        }
}

int do_warning(char *toggle, warning_list_t *wnum)
{
    warning_t *warning, *next;
    int ret = 1;
    if(!disabled_warnings)
    {
        disabled_warnings = xmalloc( sizeof(*disabled_warnings) );
        list_init( disabled_warnings );
    }

    if(!strcmp(toggle, "disable"))
        LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry)
            warning_disable(warning->num);
    else if(!strcmp(toggle, "enable"))
        LIST_FOR_EACH_ENTRY(warning, wnum, warning_t, entry)
            warning_enable(warning->num);
    else
        ret = 0;

    LIST_FOR_EACH_ENTRY_SAFE(warning, next, wnum, warning_t, entry)
        free(warning);
    return ret;
}

int is_warning_enabled(int warning)
{
    warning_t *warning_entry;
    if(!disabled_warnings)
        return 1;
    LIST_FOR_EACH_ENTRY(warning_entry, disabled_warnings, warning_t, entry)
        if(warning_entry->num == warning)
            return 0;
    return 1;
}