/* -*-C-*-
 * 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
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

%option bison-bridge
%option bison-locations
%option stack
%option noinput nounput noyy_top_state
%option noyywrap
%option 8bit never-interactive prefix="parser_"

ws    [ \f\t\r]
hd    [0-9a-fA-F]
uuid  {hd}{8}-{hd}{4}-{hd}{4}-{hd}{4}-{hd}{12}

%x ATTR
%x PP_LINE
%x PP_FILE
%x PP_PRAGMA

%{

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#define YY_NO_UNISTD_H

#include "widl.h"
#include "utils.h"
#include "parser.h"
#include "wpp_private.h"

#define YYerror PARSER_error
#define YYSTYPE PARSER_STYPE
#define YYLTYPE PARSER_LTYPE
#define YYUNDEF PARSER_UNDEF
#define yyerror parser_error

#include "parser.tab.h"

static void reset_location( struct location *where, const char *input_name );
static void update_location( struct location *where, const char *yytext );
static void end_of_line( struct location *where );

#define YY_USER_INIT    reset_location( yylloc, input_name )
#define YY_USER_ACTION  update_location( yylloc, yytext );

static void switch_to_acf(void);

static warning_list_t *disabled_warnings = NULL;

struct import_state
{
    YY_BUFFER_STATE buffer;
    char *input_name;
    struct location where;
    struct list entry;
};
static struct list import_stack = LIST_INIT( import_stack );
int parse_only = 0;

struct import
{
    const char *name;
    struct list entry;
};
static struct list imports = LIST_INIT( imports );
static struct location previous_location;

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

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

static int token_uuid( const char *str, YYSTYPE *yylval )
{
    struct uuid *uuid;
    char tmp[3] = {0};

    if (*str == '\"') str++;

    uuid = xmalloc( sizeof(*uuid) );
    uuid->Data1 = strtoul( str , NULL, 16 );
    uuid->Data2 = strtoul( str + 9, NULL, 16 );
    uuid->Data3 = strtoul( str + 14, NULL, 16 );
    memcpy( tmp, str + 19, 2 );
    uuid->Data4[0] = strtoul( tmp, NULL, 16 );
    memcpy( tmp, str + 21, 2 );
    uuid->Data4[1] = strtoul( tmp, NULL, 16 );
    memcpy( tmp, str + 24, 2 );
    uuid->Data4[2] = strtoul( tmp, NULL, 16 );
    memcpy( tmp, str + 26, 2 );
    uuid->Data4[3] = strtoul( tmp, NULL, 16 );
    memcpy( tmp, str + 28, 2 );
    uuid->Data4[4] = strtoul( tmp, NULL, 16 );
    memcpy( tmp, str + 30, 2 );
    uuid->Data4[5] = strtoul( tmp, NULL, 16 );
    memcpy( tmp, str + 32, 2 );
    uuid->Data4[6] = strtoul( tmp, NULL, 16 );
    memcpy( tmp, str + 34, 2 );
    uuid->Data4[7] = strtoul( tmp, NULL, 16 );

    yylval->uuid = uuid;
    return aUUID;
}

static int token_str( int token, const char *str, YYSTYPE *yylval )
{
    char *tmp = xstrdup( str );

    if (token == aWSTRING || token == aSTRING || token == aSQSTRING)
    {
        char *src, *dst;
        src = dst = ++tmp; /* skip first quote */
        while (*src)
        {
            if (*src == '\\') src++;
            *dst++ = *src++;
        }
        dst[-1] = 0; /* strip last quote */
    }

    yylval->str = tmp;
    return token;
}

static int token_num( int token, const char *yytext, YYSTYPE *yylval )
{
    yylval->num = xstrtoul( yytext, NULL, 0 );
    return token;
}

static int token_ident( const char *str, YYSTYPE *yylval )
{
    return token_str( is_type( str ) ? aKNOWNTYPE : aIDENTIFIER, str, yylval );
}

static int token_winrt( int token, const char *str, YYSTYPE *yylval )
{
    if (winrt_mode) return token;
    return token_ident( str, yylval );
}

static void winrt_enable( int ns_prefix )
{
    if (!list_empty( &import_stack ) && !winrt_mode) error_loc( "WinRT IDL file imported in non-winrt mode.\n" );

    use_abi_namespace = ns_prefix;
    winrt_mode = TRUE;
}

%}

/*
 **************************************************************************
 * The flexer starts here
 **************************************************************************
 */
%%
<PP_PRAGMA>{
    midl_echo/"("                               {
                                                    yy_pop_state();
                                                    yylloc->first_line -= 1;
                                                    return tCPPQUOTE;
                                                }
    winrt{ws}+ns_prefix[^\n]*                   {
                                                    yy_pop_state();
                                                    yylloc->first_line -= 1;
                                                    winrt_enable( TRUE );
                                                }
    winrt[^\n]*                                 {
                                                    yy_pop_state();
                                                    yylloc->first_line -= 1;
                                                    winrt_enable( FALSE );
                                                }
    [^\n]*                                      {
                                                    yy_pop_state();
                                                    yylloc->first_line -= 1;
                                                    return token_str( aPRAGMA, yytext, yylval );
                                                }
}
<PP_LINE>[0-9]+{ws}*                            {
                                                    yylloc->first_line = strtoul( yytext, NULL, 10 ) - 1;
                                                    yylloc->last_line = yylloc->first_line;
                                                    yy_pop_state();
                                                    yy_push_state(PP_FILE);
                                                }
<PP_FILE>\"(\\[^n]|[^"\\\n])*\"{ws}*            {
                                                    input_name = xstrdup( yytext + 1 );
                                                    *strchr( input_name, '"' ) = 0;
                                                    yylloc->input_name = input_name;
                                                }
<PP_FILE>[^"][^\n]*                             { yy_pop_state(); }

<ATTR>{
    \]                                          { yy_pop_state(); return ']'; }

    ({uuid}|\"{uuid}\")                         { return token_uuid( yytext, yylval ); }
    activatable                                 { return token_winrt( tACTIVATABLE, yytext, yylval ); }
    aggregatable                                { return tAGGREGATABLE; }
    agile                                       { return token_winrt( tAGILE, yytext, yylval ); }
    all_nodes                                   { return tALLNODES; }
    allocate                                    { return tALLOCATE; }
    annotation                                  { return tANNOTATION; }
    apartment                                   { return tAPARTMENT; }
    appobject                                   { return tAPPOBJECT; }
    async                                       { return tASYNC; }
    async_uuid                                  { return tASYNCUUID; }
    auto_handle                                 { return tAUTOHANDLE; }
    bindable                                    { return tBINDABLE; }
    both                                        { return tBOTH; }
    broadcast                                   { return tBROADCAST; }
    byte_count                                  { return tBYTECOUNT; }
    call_as                                     { return tCALLAS; }
    callback                                    { return tCALLBACK; }
    code                                        { return tCODE; }
    comm_status                                 { return tCOMMSTATUS; }
    composable                                  { return token_winrt( tCOMPOSABLE, yytext, yylval ); }
    context_handle                              { return tCONTEXTHANDLE; }
    context_handle_noserialize                  { return tCONTEXTHANDLENOSERIALIZE; }
    context_handle_serialize                    { return tCONTEXTHANDLENOSERIALIZE; }
    contract                                    { return token_winrt( tCONTRACT, yytext, yylval ); }
    contractversion                             { return token_winrt( tCONTRACTVERSION, yytext, yylval ); }
    control                                     { return tCONTROL; }
    custom                                      { return tCUSTOM; }
    decode                                      { return tDECODE; }
    default_overload                            { return tDEFAULT_OVERLOAD; }
    defaultbind                                 { return tDEFAULTBIND; }
    defaultcollelem                             { return tDEFAULTCOLLELEM; }
    defaultvalue                                { return tDEFAULTVALUE; }
    defaultvtable                               { return tDEFAULTVTABLE; }
    deprecated                                  { return token_winrt( tDEPRECATED, yytext, yylval ); }
    disable_consistency_check                   { return tDISABLECONSISTENCYCHECK; }
    displaybind                                 { return tDISPLAYBIND; }
    dllname                                     { return tDLLNAME; }
    dont_free                                   { return tDONTFREE; }
    dual                                        { return tDUAL; }
    enable_allocate                             { return tENABLEALLOCATE; }
    encode                                      { return tENCODE; }
    endpoint                                    { return tENDPOINT; }
    entry                                       { return tENTRY; }
    eventadd                                    { return token_winrt( tEVENTADD, yytext, yylval ); }
    eventremove                                 { return token_winrt( tEVENTREMOVE, yytext, yylval ); }
    exclusiveto                                 { return token_winrt( tEXCLUSIVETO, yytext, yylval ); }
    explicit_handle                             { return tEXPLICITHANDLE; }
    fault_status                                { return tFAULTSTATUS; }
    flags                                       { return token_winrt( tFLAGS, yytext, yylval ); }
    force_allocate                              { return tFORCEALLOCATE; }
    free                                        { return tFREE; }
    handle                                      { return tHANDLE; }
    helpcontext                                 { return tHELPCONTEXT; }
    helpfile                                    { return tHELPFILE; }
    helpstring                                  { return tHELPSTRING; }
    helpstringcontext                           { return tHELPSTRINGCONTEXT; }
    helpstringdll                               { return tHELPSTRINGDLL; }
    hidden                                      { return tHIDDEN; }
    id                                          { return tID; }
    idempotent                                  { return tIDEMPOTENT; }
    ignore                                      { return tIGNORE; }
    iid_is                                      { return tIIDIS; }
    immediatebind                               { return tIMMEDIATEBIND; }
    implicit_handle                             { return tIMPLICITHANDLE; }
    in                                          { return tIN; }
    in_line                                     { return tIN_LINE; }
    input_sync                                  { return tINPUTSYNC; }
    lcid                                        { return tLCID; }
    length_is                                   { return tLENGTHIS; }
    licensed                                    { return tLICENSED; }
    local                                       { return tLOCAL; }
    marshaling_behavior                         { return token_winrt( tMARSHALINGBEHAVIOR, yytext, yylval ); }
    maybe                                       { return tMAYBE; }
    message                                     { return tMESSAGE; }
    mta                                         { return tMTA; }
    neutral                                     { return tNEUTRAL; }
    nocode                                      { return tNOCODE; }
    nonbrowsable                                { return tNONBROWSABLE; }
    noncreatable                                { return tNONCREATABLE; }
    none                                        { return token_winrt( tNONE, yytext, yylval ); }
    nonextensible                               { return tNONEXTENSIBLE; }
    notify                                      { return tNOTIFY; }
    notify_flag                                 { return tNOTIFYFLAG; }
    object                                      { return tOBJECT; }
    odl                                         { return tODL; }
    oleautomation                               { return tOLEAUTOMATION; }
    optimize                                    { return tOPTIMIZE; }
    optional                                    { return tOPTIONAL; }
    out                                         { return tOUT; }
    overload                                    { return tOVERLOAD; }
    partial_ignore                              { return tPARTIALIGNORE; }
    pointer_default                             { return tPOINTERDEFAULT; }
    progid                                      { return tPROGID; }
    propget                                     { return tPROPGET; }
    propput                                     { return tPROPPUT; }
    propputref                                  { return tPROPPUTREF; }
    protected                                   { return tPROTECTED; }
    proxy                                       { return tPROXY; }
    ptr                                         { return tPTR; }
    public                                      { return tPUBLIC; }
    range                                       { return tRANGE; }
    readonly                                    { return tREADONLY; }
    ref                                         { return tREF; }
    represent_as                                { return tREPRESENTAS; }
    requestedit                                 { return tREQUESTEDIT; }
    restricted                                  { return tRESTRICTED; }
    retval                                      { return tRETVAL; }
    single                                      { return tSINGLE; }
    single_node                                 { return tSINGLENODE; }
    size_is                                     { return tSIZEIS; }
    source                                      { return tSOURCE; }
    standard                                    { return token_winrt( tSTANDARD, yytext, yylval ); }
    static                                      { return token_winrt( tSTATIC, yytext, yylval ); }
    strict_context_handle                       { return tSTRICTCONTEXTHANDLE; }
    string                                      { return tSTRING; }
    switch_is                                   { return tSWITCHIS; }
    switch_type                                 { return tSWITCHTYPE; }
    threading                                   { return tTHREADING; }
    transmit_as                                 { return tTRANSMITAS; }
    uidefault                                   { return tUIDEFAULT; }
    unique                                      { return tUNIQUE; }
    user_marshal                                { return tUSERMARSHAL; }
    usesgetlasterror                            { return tUSESGETLASTERROR; }
    uuid                                        { return tUUID; }
    v1_enum                                     { return tV1ENUM; }
    vararg                                      { return tVARARG; }
    version                                     { return tVERSION; }
    vi_progid                                   { return tVIPROGID; }
    wire_marshal                                { return tWIREMARSHAL; }
}

<INITIAL>{
    ^{ws}*\#{ws}*pragma{ws}+                    { yy_push_state( PP_PRAGMA ); }
    ^{ws}*midl_pragma{ws}+warning               { return tPRAGMA_WARNING; }

    [0-9]+\.[0-9]+([eE][+-]?[0-9]+)*            {
                                                    yylval->dbl = strtod( yytext, NULL );
                                                    return aDOUBLE;
                                                }
}

SAFEARRAY{ws}*/\(	return tSAFEARRAY;

<INITIAL,ATTR>{
    ^{ws}*\#{ws}*                               { yy_push_state(PP_LINE); }
    \[                                          { yy_push_state(ATTR); return '['; }

    FALSE                                       { return tFALSE; }
    NULL                                        { return tNULL; }
    TRUE                                        { return tTRUE; }
    _?_?cdecl                                   { return token_str( tCDECL, "__cdecl", yylval ); }
    _?_?pascal                                  { return token_str( tPASCAL, "__pascal", yylval ); }
    _?_?stdcall                                 { return token_str( tSTDCALL, "__stdcall", yylval ); }
    __?fastcall                                 { return token_str( tFASTCALL, "__fastcall", yylval ); }
    __int32                                     { return tINT32; }
    __int3264                                   { return tINT3264; }
    __int64                                     { return tINT64; }
    apicontract                                 { return token_winrt( tAPICONTRACT, yytext, yylval ); }
    boolean                                     { return tBOOLEAN; }
    byte                                        { return tBYTE; }
    case                                        { return tCASE; }
    char                                        { return tCHAR; }
    coclass                                     { return tCOCLASS; }
    const                                       { return tCONST; }
    cpp_quote                                   { return tCPPQUOTE; }
    declare                                     { return token_winrt( tDECLARE, yytext, yylval ); }
    default                                     { return tDEFAULT; }
    delegate                                    { return token_winrt( tDELEGATE, yytext, yylval ); }
    dispinterface                               { return tDISPINTERFACE; }
    double                                      { return tDOUBLE; }
    enum                                        { return tENUM; }
    error_status_t                              { return tERRORSTATUST; }
    extern                                      { return tEXTERN; }
    float                                       { return tFLOAT; }
    handle_t                                    { return tHANDLET; }
    hyper                                       { return tHYPER; }
    import                                      { return tIMPORT; }
    importlib                                   { return tIMPORTLIB; }
    inline                                      { return tINLINE; }
    int                                         { return tINT; }
    interface                                   { return tINTERFACE; }
    library                                     { return tLIBRARY; }
    long                                        { return tLONG; }
    methods                                     { return tMETHODS; }
    module                                      { return tMODULE; }
    namespace                                   { return token_winrt( tNAMESPACE, yytext, yylval ); }
    properties                                  { return tPROPERTIES; }
    register                                    { return tREGISTER; }
    requires                                    { return token_winrt( tREQUIRES, yytext, yylval ); }
    runtimeclass                                { return token_winrt( tRUNTIMECLASS, yytext, yylval ); }
    short                                       { return tSHORT; }
    signed                                      { return tSIGNED; }
    sizeof                                      { return tSIZEOF; }
    small                                       { return tSMALL; }
    static                                      { return tSTATIC; }
    struct                                      { return tSTRUCT; }
    switch                                      { return tSWITCH; }
    typedef                                     { return tTYPEDEF; }
    union                                       { return tUNION; }
    unsigned                                    { return tUNSIGNED; }
    void                                        { return tVOID; }
    wchar_t                                     { return tWCHAR; }

    [a-zA-Z_][0-9a-zA-Z_]*                      { return token_ident( yytext, yylval ); }

    0[xX]{hd}+([lL][uU]?|[uU][lL]?)?            { return token_num( aHEXNUM, yytext, yylval ); }
    [0-9]+([lL][uU]?|[uU][lL]?)?                { return token_num( aNUM, yytext, yylval ); }

    L\"(\\.|[^"\\])*\"                          { return token_str( aWSTRING, yytext + 1, yylval ); }
    \"(\\.|[^"\\])*\"                           { return token_str( aSTRING, yytext, yylval ); }
    \'(\\.|[^'\\])*\'                           { return token_str( aSQSTRING, yytext, yylval ); }

    \n                                          { end_of_line( yylloc ); }
    {ws}                                        {}
    \<\<                                        { return SHL; }
    \>\>                                        { return SHR; }
    \-\>                                        { return MEMBERPTR; }
    ==                                          { return EQUALITY; }
    !=                                          { return INEQUALITY; }
    \>=                                         { return GREATEREQUAL; }
    \<=                                         { return LESSEQUAL; }
    \|\|                                        { return LOGICALOR; }
    &&                                          { return LOGICALAND; }
    \.\.\.                                      { return ELLIPSIS; }
    .                                           { return yytext[0]; }
}

<<EOF>>			{
                            if (!list_empty( &import_stack ))
                                return aEOF;
                            if (acf_name)
                            {
                                switch_to_acf();
                                return aACF;
                            }
                            yyterminate();
			}
%%

static void print_imports(void)
{
    struct import_state *state, *next;

    if (list_empty( &import_stack )) return;

    fprintf( stderr, "In file included from " );
    LIST_FOR_EACH_ENTRY_SAFE_REV( state, next, &import_stack, struct import_state, entry )
    {
        if (&next->entry == &import_stack) break;
        fprintf( stderr, "%s:%d,\n", state->input_name, state->where.first_line );
        fprintf( stderr, "                 from ");
    }
    fprintf( stderr, "%s:%d:\n", state->input_name, state->where.first_line );
}

struct location pop_import(void)
{
    struct list *entry = list_head( &import_stack );
    struct import_state *state;
    struct location where;
    assert( entry );

    state = LIST_ENTRY( entry, struct import_state, entry );
    list_remove( &state->entry );
    parse_only = !list_empty( &import_stack );

    if (yyin) fclose( yyin );
    yy_delete_buffer( YY_CURRENT_BUFFER );
    yy_switch_to_buffer( state->buffer );

    input_name = state->input_name;
    where = state->where;
    free( state );
    return where;
}

void push_import( const char *import_name, struct location *where )
{
    struct import_state *state;
    struct import *import;
    FILE *file;

    state = xmalloc( sizeof(struct import_state ));
    list_add_head( &import_stack, &state->entry );
    parse_only = !list_empty( &import_stack );

    state->buffer = YY_CURRENT_BUFFER;
    state->input_name = input_name;
    state->where = *where;
    input_name = NULL;

    /* reset buffer for <<EOF>>, in case import fails or already imported */
    yy_scan_string( "" );

    LIST_FOR_EACH_ENTRY( import, &imports, struct import, entry )
        if (!strcmp( import->name, import_name )) return;  /* already imported */
    if (!strcmp( idl_name, import_name )) return;  /* already imported */

    import = xmalloc( sizeof(struct import) );
    import->name = xstrdup( import_name );
    list_add_tail( &imports, &import->entry );

    input_name = find_input_file( import_name, state->input_name );
    file = open_input_file( input_name );
    reset_location( where, input_name );

    yy_switch_to_buffer( yy_create_buffer( file, YY_BUF_SIZE ) );
}

static void switch_to_acf(void)
{
    FILE *file;

    if (yyin) fclose( yyin );
    yy_delete_buffer( YY_CURRENT_BUFFER );

    input_name = xstrdup( acf_name );
    file = open_input_file( input_name );
    acf_name = NULL;

    yy_switch_to_buffer( yy_create_buffer( file, YY_BUF_SIZE ) );
}

void close_all_inputs(void)
{
    while (!list_empty( &import_stack )) pop_import();
    if (yyin) fclose( yyin );
}

static void reset_location( struct location *where, const char *input_name )
{
    where->first_line = 1;
    where->last_line = 1;
    where->first_column = 1;
    where->last_column = 1;
    where->input_name = xstrdup( input_name );
}

static void update_location( struct location *where, const char *yytext )
{
    int len = strlen( yytext );
    previous_location = *where;
    where->first_column = where->last_column;
    where->last_column += len;
}

static void end_of_line( struct location *where )
{
    where->first_line++;
    where->last_line++;
    where->first_column = 1;
    where->last_column = 1;
}

void init_location( struct location *where, const struct location *begin, const struct location *end )
{
    if (!begin) begin = &previous_location;
    *where = *begin;

    if (end)
    {
        where->last_line   = end->last_line;
        where->last_column = end->last_column;
    }
    else
    {
        where->first_line   = begin->last_line;
        where->first_column = begin->last_column;
    }
}

static void diagnostic( const struct location *where, const char *type, const char *message )
{
    char buffer[1024], *line = NULL;
    FILE *file;
    int i;

    if (!where) where = &previous_location;

    print_imports();

    fprintf( stderr, "%s:%d:%d: %s: %s\n", where->input_name, where->first_line, where->first_column, type, message );

    if (!where->input_name || !(file = fopen( where->input_name, "r" ))) return;
    for (i = 0; i < where->first_line; i++) if (!(line = fgets( buffer, sizeof(buffer), file ))) break;
    fclose( file );
    if (!line) return;
    fprintf( stderr, "%s", line );

    line = buffer;
    for (i = 0; i < where->first_column - 1; i++) line += sprintf( line, " " );
    line += sprintf( line, "^" );
    for (i = where->first_column + 1; i < where->last_column; i++) line += sprintf( line, "~" );
    fprintf( stderr, "%s\n", buffer );
}

void parser_error( const struct location *where, const char *message )
{
    diagnostic( where, "error", message );
}

void parser_warning( const struct location *where, const char *message )
{
    diagnostic( where, "warning", message );
}

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(const 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") || !strcmp(toggle, "default"))
        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;
}
