| /* do not edit automatically generated by mc from mcComp. */ |
| /* Copyright (C) 2015-2025 Free Software Foundation, Inc. |
| This file is part of GNU Modula-2. |
| |
| GNU Modula-2 is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GNU Modula-2 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 General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include <stdbool.h> |
| # if !defined (PROC_D) |
| # define PROC_D |
| typedef void (*PROC_t) (void); |
| typedef struct { PROC_t proc; } PROC; |
| # endif |
| |
| # if !defined (TRUE) |
| # define TRUE (1==1) |
| # endif |
| |
| # if !defined (FALSE) |
| # define FALSE (1==0) |
| # endif |
| |
| # include "Gmcrts.h" |
| #if defined(__cplusplus) |
| # undef NULL |
| # define NULL 0 |
| #endif |
| #define _mcComp_C |
| |
| #include "GmcComp.h" |
| # include "GFIO.h" |
| # include "Glibc.h" |
| # include "Gdecl.h" |
| # include "GsymbolKey.h" |
| # include "GSYSTEM.h" |
| # include "GmcReserved.h" |
| # include "GmcSearch.h" |
| # include "GmcLexBuf.h" |
| # include "GmcFileName.h" |
| # include "GmcPreprocess.h" |
| # include "GFormatStrings.h" |
| # include "Gmcflex.h" |
| # include "Gmcp1.h" |
| # include "Gmcp2.h" |
| # include "Gmcp3.h" |
| # include "Gmcp4.h" |
| # include "Gmcp5.h" |
| # include "GmcComment.h" |
| # include "GmcError.h" |
| # include "GnameKey.h" |
| # include "GmcPrintf.h" |
| # include "GmcQuiet.h" |
| # include "GDynamicStrings.h" |
| # include "GmcOptions.h" |
| |
| # define Debugging false |
| typedef struct mcComp_parserFunction_p mcComp_parserFunction; |
| |
| typedef struct mcComp_openFunction_p mcComp_openFunction; |
| |
| typedef bool (*mcComp_parserFunction_t) (void); |
| struct mcComp_parserFunction_p { mcComp_parserFunction_t proc; }; |
| |
| typedef bool (*mcComp_openFunction_t) (decl_node, bool); |
| struct mcComp_openFunction_p { mcComp_openFunction_t proc; }; |
| |
| static unsigned int currentPass; |
| |
| /* |
| compile - check, s, is non NIL before calling doCompile. |
| */ |
| |
| extern "C" void mcComp_compile (DynamicStrings_String s); |
| |
| /* |
| getPassNo - return the pass no. |
| */ |
| |
| extern "C" unsigned int mcComp_getPassNo (void); |
| |
| /* |
| doCompile - translate file, s, using a 6 pass technique. |
| */ |
| |
| static void doCompile (DynamicStrings_String s); |
| |
| /* |
| examineCompilationUnit - opens the source file to obtain the module name and kind of module. |
| */ |
| |
| static decl_node examineCompilationUnit (void); |
| |
| /* |
| peepInto - peeps into source, s, and initializes a definition/implementation or |
| program module accordingly. |
| */ |
| |
| static decl_node peepInto (DynamicStrings_String s); |
| |
| /* |
| initParser - returns the node of the module found in the source file. |
| */ |
| |
| static decl_node initParser (DynamicStrings_String s); |
| |
| /* |
| p1 - wrap the pass procedure with the correct parameter values. |
| */ |
| |
| static void p1 (decl_node n); |
| |
| /* |
| p2 - wrap the pass procedure with the correct parameter values. |
| */ |
| |
| static void p2 (decl_node n); |
| |
| /* |
| p3 - wrap the pass procedure with the correct parameter values. |
| */ |
| |
| static void p3 (decl_node n); |
| |
| /* |
| p4 - wrap the pass procedure with the correct parameter values. |
| */ |
| |
| static void p4 (decl_node n); |
| |
| /* |
| p5 - wrap the pass procedure with the correct parameter values. |
| */ |
| |
| static void p5 (decl_node n); |
| |
| /* |
| doOpen - |
| */ |
| |
| static bool doOpen (decl_node n, DynamicStrings_String symName, DynamicStrings_String fileName, bool exitOnFailure); |
| |
| /* |
| openDef - try and open the definition module source file. |
| Returns true/false if successful/unsuccessful or |
| exitOnFailure. |
| */ |
| |
| static bool openDef (decl_node n, bool exitOnFailure); |
| |
| /* |
| openMod - try and open the implementation/program module source file. |
| Returns true/false if successful/unsuccessful or |
| exitOnFailure. |
| */ |
| |
| static bool openMod (decl_node n, bool exitOnFailure); |
| |
| /* |
| pass - |
| */ |
| |
| static void pass (unsigned int no, decl_node n, mcComp_parserFunction f, decl_isNodeF isnode, mcComp_openFunction open); |
| |
| /* |
| doPass - |
| */ |
| |
| static void doPass (bool parseDefs, bool parseMain, unsigned int no, symbolKey_performOperation p, const char *desc_, unsigned int _desc_high); |
| |
| /* |
| setToPassNo - |
| */ |
| |
| static void setToPassNo (unsigned int n); |
| |
| /* |
| init - initialise data structures for this module. |
| */ |
| |
| static void init (void); |
| |
| |
| /* |
| doCompile - translate file, s, using a 6 pass technique. |
| */ |
| |
| static void doCompile (DynamicStrings_String s) |
| { |
| decl_node n; |
| |
| n = initParser (s); |
| doPass (true, true, 1, (symbolKey_performOperation) {(symbolKey_performOperation_t) p1}, (const char *) "lexical analysis, modules, root decls and C preprocessor", 56); |
| doPass (true, true, 2, (symbolKey_performOperation) {(symbolKey_performOperation_t) p2}, (const char *) "[all modules] type equivalence and enumeration types", 52); |
| doPass (true, true, 3, (symbolKey_performOperation) {(symbolKey_performOperation_t) p3}, (const char *) "[all modules] import lists, types, variables and procedure declarations", 71); |
| doPass (true, true, 4, (symbolKey_performOperation) {(symbolKey_performOperation_t) p4}, (const char *) "[all modules] constant expressions", 34); |
| if (! (decl_isDef (n))) |
| { |
| /* avoid gcc warning by using compound statement even if not strictly necessary. */ |
| if (decl_isImp (n)) |
| { |
| mcQuiet_qprintf0 ((const char *) "Parse implementation module\\n", 29); |
| doPass (false, true, 5, (symbolKey_performOperation) {(symbolKey_performOperation_t) p5}, (const char *) "[implementation module] build code tree for all procedures and module initializations", 85); |
| } |
| else |
| { |
| mcQuiet_qprintf0 ((const char *) "Parse program module\\n", 22); |
| doPass (false, true, 5, (symbolKey_performOperation) {(symbolKey_performOperation_t) p5}, (const char *) "[program module] build code tree for all procedures and module initializations", 78); |
| } |
| } |
| mcQuiet_qprintf0 ((const char *) "walk tree converting it to C/C++\\n", 34); |
| decl_out (); |
| } |
| |
| |
| /* |
| examineCompilationUnit - opens the source file to obtain the module name and kind of module. |
| */ |
| |
| static decl_node examineCompilationUnit (void) |
| { |
| /* stop if we see eof, ';' or '[' */ |
| while (((mcLexBuf_currenttoken != mcReserved_eoftok) && (mcLexBuf_currenttoken != mcReserved_semicolontok)) && (mcLexBuf_currenttoken != mcReserved_lsbratok)) |
| { |
| if (mcLexBuf_currenttoken == mcReserved_definitiontok) |
| { |
| mcLexBuf_getToken (); |
| if (mcLexBuf_currenttoken == mcReserved_moduletok) |
| { |
| /* avoid dangling else. */ |
| mcLexBuf_getToken (); |
| if (mcLexBuf_currenttoken == mcReserved_fortok) |
| { |
| mcLexBuf_getToken (); |
| if (mcLexBuf_currenttoken == mcReserved_stringtok) |
| { |
| mcLexBuf_getToken (); |
| } |
| else |
| { |
| mcflex_mcError (DynamicStrings_string (DynamicStrings_InitString ((const char *) "expecting language string after FOR keyword", 43))); |
| libc_exit (1); |
| } |
| } |
| if (mcLexBuf_currenttoken == mcReserved_identtok) |
| { |
| return decl_lookupDef (nameKey_makekey (mcLexBuf_currentstring)); |
| } |
| } |
| else |
| { |
| mcflex_mcError (DynamicStrings_string (DynamicStrings_InitString ((const char *) "MODULE missing after DEFINITION keyword", 39))); |
| } |
| } |
| else if (mcLexBuf_currenttoken == mcReserved_implementationtok) |
| { |
| /* avoid dangling else. */ |
| mcLexBuf_getToken (); |
| if (mcLexBuf_currenttoken == mcReserved_moduletok) |
| { |
| /* avoid dangling else. */ |
| mcLexBuf_getToken (); |
| if (mcLexBuf_currenttoken == mcReserved_identtok) |
| { |
| return decl_lookupImp (nameKey_makekey (mcLexBuf_currentstring)); |
| } |
| } |
| else |
| { |
| mcflex_mcError (DynamicStrings_string (DynamicStrings_InitString ((const char *) "MODULE missing after IMPLEMENTATION keyword", 43))); |
| } |
| } |
| else if (mcLexBuf_currenttoken == mcReserved_moduletok) |
| { |
| /* avoid dangling else. */ |
| mcLexBuf_getToken (); |
| if (mcLexBuf_currenttoken == mcReserved_identtok) |
| { |
| return decl_lookupModule (nameKey_makekey (mcLexBuf_currentstring)); |
| } |
| } |
| mcLexBuf_getToken (); |
| } |
| mcflex_mcError (DynamicStrings_string (DynamicStrings_InitString ((const char *) "failed to find module name", 26))); |
| libc_exit (1); |
| ReturnException ("../../gcc/m2/mc/mcComp.def", 20, 1); |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| peepInto - peeps into source, s, and initializes a definition/implementation or |
| program module accordingly. |
| */ |
| |
| static decl_node peepInto (DynamicStrings_String s) |
| { |
| decl_node n; |
| DynamicStrings_String fileName; |
| |
| fileName = mcPreprocess_preprocessModule (s); |
| if (mcLexBuf_openSource (fileName)) |
| { |
| n = examineCompilationUnit (); |
| decl_setSource (n, nameKey_makekey (DynamicStrings_string (fileName))); |
| decl_setMainModule (n); |
| mcLexBuf_closeSource (); |
| mcLexBuf_reInitialize (); |
| return n; |
| } |
| else |
| { |
| mcPrintf_fprintf1 (FIO_StdErr, (const char *) "failed to open %s\\n", 19, (const unsigned char *) &s, (sizeof (s)-1)); |
| libc_exit (1); |
| } |
| ReturnException ("../../gcc/m2/mc/mcComp.def", 20, 1); |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| initParser - returns the node of the module found in the source file. |
| */ |
| |
| static decl_node initParser (DynamicStrings_String s) |
| { |
| mcQuiet_qprintf1 ((const char *) "Compiling: %s\\n", 15, (const unsigned char *) &s, (sizeof (s)-1)); |
| return peepInto (s); |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| p1 - wrap the pass procedure with the correct parameter values. |
| */ |
| |
| static void p1 (decl_node n) |
| { |
| if (decl_isDef (n)) |
| { |
| /* avoid dangling else. */ |
| pass (1, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp1_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isDef}, (mcComp_openFunction) {(mcComp_openFunction_t) openDef}); |
| if ((decl_hasHidden (n)) && (mcOptions_getExtendedOpaque ())) |
| { |
| pass (1, decl_lookupImp (decl_getSymName (n)), (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp1_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImp}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod}); |
| } |
| } |
| else |
| { |
| pass (1, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp1_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImpOrModule}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod}); |
| } |
| } |
| |
| |
| /* |
| p2 - wrap the pass procedure with the correct parameter values. |
| */ |
| |
| static void p2 (decl_node n) |
| { |
| if (decl_isDef (n)) |
| { |
| /* avoid dangling else. */ |
| pass (2, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp2_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isDef}, (mcComp_openFunction) {(mcComp_openFunction_t) openDef}); |
| if ((decl_hasHidden (n)) && (mcOptions_getExtendedOpaque ())) |
| { |
| pass (2, decl_lookupImp (decl_getSymName (n)), (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp2_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImp}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod}); |
| } |
| } |
| else |
| { |
| pass (2, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp2_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImpOrModule}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod}); |
| } |
| } |
| |
| |
| /* |
| p3 - wrap the pass procedure with the correct parameter values. |
| */ |
| |
| static void p3 (decl_node n) |
| { |
| if (decl_isDef (n)) |
| { |
| /* avoid dangling else. */ |
| pass (3, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp3_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isDef}, (mcComp_openFunction) {(mcComp_openFunction_t) openDef}); |
| if ((decl_hasHidden (n)) && (mcOptions_getExtendedOpaque ())) |
| { |
| pass (3, decl_lookupImp (decl_getSymName (n)), (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp3_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImp}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod}); |
| } |
| } |
| else |
| { |
| pass (3, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp3_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImpOrModule}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod}); |
| } |
| } |
| |
| |
| /* |
| p4 - wrap the pass procedure with the correct parameter values. |
| */ |
| |
| static void p4 (decl_node n) |
| { |
| if (decl_isDef (n)) |
| { |
| /* avoid dangling else. */ |
| pass (4, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp4_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isDef}, (mcComp_openFunction) {(mcComp_openFunction_t) openDef}); |
| if ((decl_hasHidden (n)) && (mcOptions_getExtendedOpaque ())) |
| { |
| pass (4, decl_lookupImp (decl_getSymName (n)), (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp4_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImp}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod}); |
| } |
| } |
| else |
| { |
| pass (4, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp4_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImpOrModule}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod}); |
| } |
| } |
| |
| |
| /* |
| p5 - wrap the pass procedure with the correct parameter values. |
| */ |
| |
| static void p5 (decl_node n) |
| { |
| pass (5, n, (mcComp_parserFunction) {(mcComp_parserFunction_t) mcp5_CompilationUnit}, (decl_isNodeF) {(decl_isNodeF_t) decl_isImpOrModule}, (mcComp_openFunction) {(mcComp_openFunction_t) openMod}); |
| } |
| |
| |
| /* |
| doOpen - |
| */ |
| |
| static bool doOpen (decl_node n, DynamicStrings_String symName, DynamicStrings_String fileName, bool exitOnFailure) |
| { |
| DynamicStrings_String postProcessed; |
| |
| mcQuiet_qprintf2 ((const char *) " Module %-20s : %s\\n", 22, (const unsigned char *) &symName, (sizeof (symName)-1), (const unsigned char *) &fileName, (sizeof (fileName)-1)); |
| postProcessed = mcPreprocess_preprocessModule (fileName); |
| decl_setSource (n, nameKey_makekey (DynamicStrings_string (postProcessed))); |
| decl_setCurrentModule (n); |
| if (mcLexBuf_openSource (postProcessed)) |
| { |
| return true; |
| } |
| mcPrintf_fprintf1 (FIO_StdErr, (const char *) "failed to open %s\\n", 19, (const unsigned char *) &fileName, (sizeof (fileName)-1)); |
| if (exitOnFailure) |
| { |
| libc_exit (1); |
| } |
| return false; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| openDef - try and open the definition module source file. |
| Returns true/false if successful/unsuccessful or |
| exitOnFailure. |
| */ |
| |
| static bool openDef (decl_node n, bool exitOnFailure) |
| { |
| nameKey_Name sourceName; |
| DynamicStrings_String symName; |
| DynamicStrings_String fileName; |
| |
| sourceName = decl_getSource (n); |
| symName = DynamicStrings_InitStringCharStar (nameKey_keyToCharStar (decl_getSymName (n))); |
| if (sourceName == nameKey_NulName) |
| { |
| /* avoid dangling else. */ |
| if (! (mcSearch_findSourceDefFile (symName, &fileName))) |
| { |
| mcPrintf_fprintf1 (FIO_StdErr, (const char *) "failed to find definition module %s.def\\n", 41, (const unsigned char *) &symName, (sizeof (symName)-1)); |
| if (exitOnFailure) |
| { |
| libc_exit (1); |
| } |
| } |
| } |
| else |
| { |
| fileName = DynamicStrings_InitStringCharStar (nameKey_keyToCharStar (sourceName)); |
| } |
| return doOpen (n, symName, fileName, exitOnFailure); |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| openMod - try and open the implementation/program module source file. |
| Returns true/false if successful/unsuccessful or |
| exitOnFailure. |
| */ |
| |
| static bool openMod (decl_node n, bool exitOnFailure) |
| { |
| nameKey_Name sourceName; |
| DynamicStrings_String symName; |
| DynamicStrings_String fileName; |
| |
| sourceName = decl_getSource (n); |
| symName = DynamicStrings_InitStringCharStar (nameKey_keyToCharStar (decl_getSymName (n))); |
| if (sourceName == nameKey_NulName) |
| { |
| /* avoid dangling else. */ |
| if (! (mcSearch_findSourceModFile (symName, &fileName))) |
| { |
| if (decl_isImp (n)) |
| { |
| mcPrintf_fprintf1 (FIO_StdErr, (const char *) "failed to find implementation module %s.mod\\n", 45, (const unsigned char *) &symName, (sizeof (symName)-1)); |
| } |
| else |
| { |
| mcPrintf_fprintf1 (FIO_StdErr, (const char *) "failed to find program module %s.mod\\n", 38, (const unsigned char *) &symName, (sizeof (symName)-1)); |
| } |
| if (exitOnFailure) |
| { |
| libc_exit (1); |
| } |
| } |
| } |
| else |
| { |
| fileName = DynamicStrings_InitStringCharStar (nameKey_keyToCharStar (sourceName)); |
| } |
| return doOpen (n, symName, fileName, exitOnFailure); |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| |
| /* |
| pass - |
| */ |
| |
| static void pass (unsigned int no, decl_node n, mcComp_parserFunction f, decl_isNodeF isnode, mcComp_openFunction open) |
| { |
| if (((*isnode.proc) (n)) && (! (decl_isVisited (n)))) |
| { |
| decl_setVisited (n); |
| if ((*open.proc) (n, true)) |
| { |
| if (! ((*f.proc) ())) |
| { |
| mcError_writeFormat0 ((const char *) "compilation failed", 18); |
| mcLexBuf_closeSource (); |
| return; |
| } |
| mcLexBuf_closeSource (); |
| } |
| } |
| } |
| |
| |
| /* |
| doPass - |
| */ |
| |
| static void doPass (bool parseDefs, bool parseMain, unsigned int no, symbolKey_performOperation p, const char *desc_, unsigned int _desc_high) |
| { |
| DynamicStrings_String descs; |
| char desc[_desc_high+1]; |
| |
| /* make a local copy of each unbounded array. */ |
| memcpy (desc, desc_, _desc_high+1); |
| |
| setToPassNo (no); |
| descs = DynamicStrings_InitString ((const char *) desc, _desc_high); |
| mcQuiet_qprintf2 ((const char *) "Pass %d: %s\\n", 13, (const unsigned char *) &no, (sizeof (no)-1), (const unsigned char *) &descs, (sizeof (descs)-1)); |
| decl_foreachDefModuleDo ((symbolKey_performOperation) {(symbolKey_performOperation_t) decl_unsetVisited}); |
| decl_foreachModModuleDo ((symbolKey_performOperation) {(symbolKey_performOperation_t) decl_unsetVisited}); |
| if (parseMain) |
| { |
| decl_unsetVisited (decl_getMainModule ()); |
| if (parseDefs && (decl_isImp (decl_getMainModule ()))) |
| { |
| /* we need to parse the definition module of a corresponding implementation module. */ |
| (*p.proc) (reinterpret_cast <void *> (decl_lookupDef (decl_getSymName (decl_getMainModule ())))); |
| } |
| (*p.proc) (reinterpret_cast <void *> (decl_getMainModule ())); |
| } |
| if (parseDefs) |
| { |
| decl_foreachDefModuleDo (p); |
| } |
| mcError_flushWarnings (); |
| mcError_flushErrors (); |
| setToPassNo (0); |
| } |
| |
| |
| /* |
| setToPassNo - |
| */ |
| |
| static void setToPassNo (unsigned int n) |
| { |
| currentPass = n; |
| } |
| |
| |
| /* |
| init - initialise data structures for this module. |
| */ |
| |
| static void init (void) |
| { |
| setToPassNo (0); |
| } |
| |
| |
| /* |
| compile - check, s, is non NIL before calling doCompile. |
| */ |
| |
| extern "C" void mcComp_compile (DynamicStrings_String s) |
| { |
| if (s != NULL) |
| { |
| doCompile (s); |
| } |
| } |
| |
| |
| /* |
| getPassNo - return the pass no. |
| */ |
| |
| extern "C" unsigned int mcComp_getPassNo (void) |
| { |
| return currentPass; |
| /* static analysis guarentees a RETURN statement will be used before here. */ |
| __builtin_unreachable (); |
| } |
| |
| extern "C" void _M2_mcComp_init (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[]) |
| { |
| init (); |
| } |
| |
| extern "C" void _M2_mcComp_fini (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[]) |
| { |
| } |