| /* -*-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 ) |
| { |
| int len = strlen( str ); |
| char *tmp = xmalloc( len + 1 ); |
| |
| strcpy( tmp, 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 */ |
| } |
| else if (token == aIDENTIFIER) |
| { |
| if (len > 255) |
| { |
| warning( "truncating identifier that exceeds 255 character limit\n" ); |
| tmp[255] = 0; |
| } |
| } |
| |
| yylval->str = tmp; |
| return token; |
| } |
| |
| static int token_num( const char *yytext, YYSTYPE *yylval, int is_hex ) |
| { |
| yylval->integer.value = xstrtoul( yytext, NULL, 0 ); |
| yylval->integer.is_hex = is_hex; |
| yylval->integer.is_long = !!strchr(yytext, 'l'); |
| yylval->integer.is_unsigned = !!strchr(yytext, 'u'); |
| return is_hex ? aHEXNUM : aNUM; |
| } |
| |
| 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}+[uU]?[lL]? { return token_num( yytext, yylval, TRUE ); } |
| [0-9]+[uU]?[lL]? { return token_num( yytext, yylval, FALSE ); } |
| |
| 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++ = ' '; |
| *line++ = '^'; |
| for (i = where->first_column + 1; i < where->last_column; i++) *line++ = '~'; |
| *line = '\0'; |
| 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; |
| } |