////////////////////////////////////////////////////////////////////////////// //Copyright 2008 // Andrew Gacek, Steven Holte, Gopalan Nadathur, Xiaochu Qi, Zach Snow ////////////////////////////////////////////////////////////////////////////// // This file is part of Teyjus. // // // // Teyjus 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 of the License, or // // (at your option) any later version. // // // // Teyjus 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 Teyjus. If not, see . // ////////////////////////////////////////////////////////////////////////////// /******************************************************************************/ /* File instrgen-c.h. This files contains function declarations for generating*/ /* files instructions.h and instructions.c */ /******************************************************************************/ #include #include #include #include "instrgen-c.h" #include "../util/util.h" #define INDENT1 " " #define INDENT1_LEN 4u #define PREFIX "INSTR_" #define PREFIX_LEN 6u #define CATPREFIX "INSTR_CAT_" #define CATPREFIX_LEN 10u #define DEF "#define " #define DEF_LEN 8u /*************************************************************************/ /* instructions.h */ /*************************************************************************/ #define COMMENTS_BEG_H \ "/****************************************************************************/\n/* File instructions.h. */ \n/* This file defines instruction operand types, instruction categories and */ \n/* instruction opcode. */ \n/****************************************************************************/ \n" #define COMPDEF_BEG_H "#ifndef INSTRUCTIONS_H\n#define INSTRUCTIONS_H\n" #define COMPDEF_END_H "#endif //INSTRUCTIONS_H\n" #define INCLUDE_H \ "#include \"../simulator/mctypes.h\" //to be changed \n#include \"../simulator/dataformats.h\" //to be changed \n" /* OPERAND TYPES */ #define OPTYPES_COMMENTS_H \ "/****************************************************************************/\n/* OPERAND TYPES */ \n/****************************************************************************/ \n\n" #define OPTYPES_COMMENTS_H_LEN 300 #define OPERAND_TYPE_BEG \ "/* possible types of instruction operands */ \ntypedef enum INSTR_OperandType \n{\n" #define OPERAND_TYPE_BEG_LEN 200 #define OPERAND_TYPE_END "} INSTR_OperandType;\n\n" #define OPERAND_TYPE_END_LEN 30 static char* opTypes = NULL; static char* opTypeMaps = NULL ; void cgenOpTypes(char *name, char* typeName, char* types, char* comments, int last) { char* myOpTypes = opTypes; char* myOpTypeMaps = opTypeMaps; size_t length; size_t commentLen = comments ? strlen(comments) : 0u; length = (opTypes ? strlen(opTypes) : 0u) + INDENT1_LEN + PREFIX_LEN + strlen(name) + (comments ? strlen(comments) : 0u) + 30u; opTypes = UTIL_mallocStr(length); if (myOpTypes) { strcpy(opTypes, myOpTypes); strcat(opTypes, INDENT1); } else strcpy(opTypes, INDENT1); if (comments) { strcat(opTypes, "//"); strcat(opTypes, comments); strcat(opTypes, "\n"); strcat(opTypes, INDENT1); } strcat(opTypes, PREFIX); strcat(opTypes, name); if (last) strcat(opTypes, "\n"); else strcat(opTypes, ",\n"); if (myOpTypes) free(myOpTypes); if (typeName) { length = (opTypeMaps ? strlen(opTypeMaps) : 0u) + PREFIX_LEN + strlen(types) + strlen(typeName) + 30u; opTypeMaps = UTIL_mallocStr(length); if (myOpTypeMaps) { strcpy(opTypeMaps, myOpTypeMaps); strcat(opTypeMaps, "typedef "); } else strcpy(opTypeMaps, "typedef "); strcat(opTypeMaps, types); strcat(opTypeMaps, " "); strcat(opTypeMaps, PREFIX); strcat(opTypeMaps, typeName); strcat(opTypeMaps, ";\n"); if (myOpTypeMaps) free(myOpTypeMaps); } } #define OPTYPEMAP_COMMENT \ "/**************************************************************************/ \n/* Types for instruction operants */ \n/**************************************************************************/ \n\n" #define OPTYPEMAP_COMMENT_LEN 300 static char *opcodeType = NULL; void cgenOpCodeType(char* optype) { size_t length = PREFIX_LEN + strlen(optype) + 50; opcodeType = UTIL_mallocStr(length); strcpy(opcodeType, "typedef "); strcat(opcodeType, optype); strcat(opcodeType, " "); strcat(opcodeType, PREFIX); strcat(opcodeType, "OpCode;\n"); } static char *opsH = NULL; void cgenOpsH() //assume neither opTypes nor opTypeMaps is empty { size_t length = OPTYPES_COMMENTS_H_LEN + OPERAND_TYPE_BEG_LEN + OPTYPEMAP_COMMENT_LEN + OPERAND_TYPE_END_LEN + strlen(opTypes) + strlen(opTypeMaps) + strlen(opcodeType) + 50u; opsH = UTIL_mallocStr(length); strcpy(opsH, OPTYPES_COMMENTS_H); strcat(opsH, OPERAND_TYPE_BEG); strcat(opsH, opTypes); strcat(opsH, OPERAND_TYPE_END); strcat(opsH, OPTYPEMAP_COMMENT); strcat(opsH, opcodeType); strcat(opsH, opTypeMaps); free(opTypes); free(opcodeType); free(opTypeMaps); } /* INSTRUCTION CATEGORIES */ #define INSTRCAT_COMMENTS_H \ "/***************************************************************************/ \n/* INSTRUCTION CATEGORIES */ \n/***************************************************************************/ \n" #define INSTRCAT_COMMENTS_H_LEN 300 #define INSTRCAT_TYPE_BEG \ " /* The names of instruction categories no longer include padding bytes. */\n/* Thus we do not need to maintain two sets of names for different machine */ \n/* architectures. */ \ntypedef enum INSTR_InstrCategory \n{\n" #define INSTRCAT_TYPE_BEG_LEN 350 #define INSTRCAT_TYPE_END "} INSTR_InstrCategory;\n\n" #define INSTRCAT_TYPE_END_LEN 50 static char *instrcat_type = NULL; static char *instrLen = NULL; static char *oneInstrLen = NULL; static int catNum = 0; void cgenOneInstrCatH(char* name, int last) { char *myInstrCat = instrcat_type, *myInstrLen = instrLen; size_t length = (myInstrCat ? strlen(myInstrCat) : 0u) + strlen(name) + CATPREFIX_LEN + INDENT1_LEN + 10u; instrcat_type = UTIL_mallocStr(length); if (myInstrCat) { strcpy(instrcat_type, myInstrCat); strcat(instrcat_type, INDENT1); } else strcpy(instrcat_type, INDENT1); strcat(instrcat_type, CATPREFIX); strcat(instrcat_type, name); strcat(instrcat_type, " = "); strcat(instrcat_type, UTIL_itoa(catNum)); if (last) strcat(instrcat_type, "\n"); else strcat(instrcat_type, ",\n"); catNum++; if (myInstrCat) free(myInstrCat); //assume oneInstrLen cannot be empty length = (myInstrLen ? strlen(myInstrLen) : 0u) + strlen(name) + CATPREFIX_LEN + 10u + strlen(oneInstrLen); instrLen = UTIL_mallocStr(length); if (myInstrLen) { strcpy(instrLen, myInstrLen); strcat(instrLen, "//"); } else strcpy(instrLen, "//"); strcat(instrLen, CATPREFIX); strcat(instrLen, name); strcat(instrLen, "\n"); strcat(instrLen, oneInstrLen); free(oneInstrLen); oneInstrLen = NULL; if (myInstrLen) free(myInstrLen); } #define INSTRLEN_COMMENTS \ "/**************************************************************************/ \n/* Macros defines instruction lengths and distances between op code and */ \n/* operands. */ \n/* The assumption is that the op code occupies 1 byte. */ \n/**************************************************************************/ \n\n" #define INSTRLEN_COMMENTS_LEN 450u void cgenInstrLength(char* name, char* len) { char *myInstrLen = oneInstrLen; size_t length = (myInstrLen ? strlen(myInstrLen) : 0u) + DEF_LEN + PREFIX_LEN + strlen(name) + strlen(len) + 10u; oneInstrLen = UTIL_mallocStr(length); if (myInstrLen) { strcpy(oneInstrLen, myInstrLen); strcat(oneInstrLen, DEF); } else strcpy(oneInstrLen, DEF); strcat(oneInstrLen, PREFIX); strcat(oneInstrLen, name); strcat(oneInstrLen, " "); strcat(oneInstrLen, len); strcat(oneInstrLen, "\n"); free(myInstrLen); } #define OPTYPE_TAB_H \ "/****************************************************************************/\n/* OPERAND TYPES TABLE */ \n/****************************************************************************/ \n \n//the operand types array in a given entry \nINSTR_OperandType* INSTR_operandTypes(INSTR_InstrCategory index); \n" #define OPTYPE_TAB_H_LEN 500 static char *instrCatH = NULL; void cgenInstrCatH(char* callI1Len) { size_t length = strlen(instrcat_type) + strlen(instrLen) + INSTRCAT_TYPE_BEG_LEN + INSTRCAT_TYPE_END_LEN + INSTRCAT_COMMENTS_H_LEN + INSTRLEN_COMMENTS_LEN + OPTYPE_TAB_H_LEN + 160u; instrCatH = UTIL_mallocStr(length); strcpy(instrCatH, INSTRCAT_COMMENTS_H); strcat(instrCatH, INSTRCAT_TYPE_BEG); strcat(instrCatH, instrcat_type); strcat(instrCatH, INSTRCAT_TYPE_END); strcat(instrCatH, DEF); strcat(instrCatH, "INSTR_NUM_INSTR_CATS "); strcat(instrCatH, UTIL_itoa(catNum)); strcat(instrCatH, "\n\n"); strcat(instrCatH, DEF); strcat(instrCatH, "INSTR_CALL_I1_LEN "); strcat(instrCatH, callI1Len); strcat(instrCatH, "\n\n"); strcat(instrCatH, INSTRLEN_COMMENTS); strcat(instrCatH, instrLen); strcat(instrCatH, "\n"); strcat(instrCatH, OPTYPE_TAB_H); free(instrcat_type); free(instrLen); } #define INSTR_COMMENTS_H \ "/***************************************************************************/ \n/* OPCODES OF INSTRUCTIONS */ \n/***************************************************************************/ \n" #define INSTR_COMMENTS_H_LEN 250 static char* instrH = NULL; void cgenOneInstrH(char* comments, char* opCode, char* instrName) { char* myInstrH = instrH; size_t length = (myInstrH ? strlen(myInstrH) : 0u) + strlen(instrName) + strlen(opCode) + DEF_LEN + CATPREFIX_LEN + (comments ? strlen(comments) : 0u) + 10u; instrH = UTIL_mallocStr(length); if (myInstrH) { strcpy(instrH, myInstrH); if (comments) { strcat(instrH, "//"); strcat(instrH, comments); strcat(instrH, "\n"); strcat(instrH, DEF); } else strcat(instrH, DEF); } else { if (comments) { strcpy(instrH, "//"); strcat(instrH, comments); strcat(instrH, "\n"); strcat(instrH, DEF); } else strcpy(instrH, DEF); } strcat(instrH, instrName); strcat(instrH, " "); strcat(instrH, opCode); strcat(instrH, "\n"); if (myInstrH) free(myInstrH); } #define INSTRTAB_H \ "/***************************************************************************/ \n/* INSTRUCTION INFORMATION TABLE */ \n/***************************************************************************/ \nINSTR_InstrCategory INSTR_instrType(int index); //instr type in a given entry \nchar* INSTR_instrName(int index); //instr name in a given entry \nint INSTR_instrSize(int index); //instr size in a given entry \n" #define INSTRTAB_H_LEN 500 char* instrOpc = NULL; void cgenInstrH(char* numInstr) { size_t length = INSTR_COMMENTS_H_LEN + strlen(instrH) + DEF_LEN + strlen(numInstr) + INSTRTAB_H_LEN + 20u; instrOpc = UTIL_mallocStr(length); strcpy(instrOpc, INSTR_COMMENTS_H); strcat(instrOpc, instrH); strcat(instrOpc, "\n\n"); strcat(instrOpc, DEF); strcat(instrOpc, "INSTR_NUM_INSTRS"); strcat(instrOpc, " "); strcat(instrOpc, numInstr); strcat(instrOpc, "\n\n"); strcat(instrOpc, INSTRTAB_H); free(instrH); } /* dump instructions.h" */ void cspitCInstructionsH(char * root) { FILE* outFile; char * filename = malloc(strlen(root) + 32); strcpy(filename, root); strcat(filename, "tables/instructions.h"); outFile = UTIL_fopenW(filename); fprintf(outFile, "%s\n%s\n%s\n", COMMENTS_BEG_H, COMPDEF_BEG_H, INCLUDE_H); fprintf(outFile, "%s\n", opsH); fprintf(outFile, "%s\n", instrCatH); fprintf(outFile, "%s\n", instrOpc); fprintf(outFile, "%s\n", COMPDEF_END_H); UTIL_fclose(outFile); free(opsH); free(instrCatH); free(instrOpc); free(filename); } /*************************************************************************/ /* instructions.c */ /*************************************************************************/ #define COMMENTS_BEG_C \ "/****************************************************************************/\n/* */ \n/* File instructions.c. This file defines the operand types table and */ \n/* the instruction information table. */ \n/* */ \n/****************************************************************************/ \n\n" #define INCLUDE_C "#include \"instructions.h\"\n" /*OPERAND TYPE TABLE */ #define OPTYPE_TAB_COMMENTS \ "/****************************************************************************/\n/* OPERAND TYPES TABLE */ \n/****************************************************************************/ \n\n" #define OPTYPE_TAB_COMMENTS_LEN 250 #define MAX_OP_COMMENTS \ "/* Max number of operand that could be taken by instructions including the */\n/* padding bytes and one to terminate the list. (machine dependent) */ \n" #define MAX_OP_COMMENTS_LEN 200 #define OPTYPE_TAB_TYPE \ "/* this array is indexed by instruction category. For each category, \n INSTR_operandTypeTab contains a string of values indicating the type \n of the operand at that position, terminated by INSTR_X. This \n information is useful when parsing instruction streams. */ \ntypedef INSTR_OperandType \n INSTR_OperandTypeTab[INSTR_NUM_INSTR_CATS][INSTR_MAX_OPERAND]; \n\n" #define OPTYPE_TAB_TYPE_LEN 500 #define OPTYPE_TAB_BEG "INSTR_OperandTypeTab INSTR_operandTypeTable ={\n" #define OPTYPE_TAB_BEG_LEN 80 #define OPTYPE_TAB_END "};\n\n" #define OPTYPE_TAB_END_LEN 10 static char* optypeTabEntry = NULL; void cgenInstrFormat(char* opType, int last) { char* mytabEntry = optypeTabEntry; size_t length = (mytabEntry ? strlen(mytabEntry) : 0u) + PREFIX_LEN + strlen(opType) + 5u; optypeTabEntry = UTIL_mallocStr(length); if (mytabEntry) { strcpy(optypeTabEntry, mytabEntry); strcat(optypeTabEntry, PREFIX); } else strcpy(optypeTabEntry, PREFIX); strcat(optypeTabEntry, opType); if (!last) strcat(optypeTabEntry, ", "); if (mytabEntry) free(mytabEntry); } static char* optypeTab = NULL; //assume optypeEntry is not empty void cgenOneInstrCatC(char* name, int last) { char* myoptypeTab = optypeTab; size_t length = (myoptypeTab ? strlen(myoptypeTab) : 0u) + INDENT1_LEN*2 + strlen(optypeTabEntry) + strlen(name) + 10u + CATPREFIX_LEN; optypeTab = UTIL_mallocStr(length); if (myoptypeTab) { strcpy(optypeTab, myoptypeTab); strcat(optypeTab, INDENT1); } else strcpy(optypeTab, INDENT1); strcat(optypeTab, "//"); strcat(optypeTab, CATPREFIX); strcat(optypeTab, name); strcat(optypeTab, "\n"); strcat(optypeTab, INDENT1); strcat(optypeTab, "{"); strcat(optypeTab, optypeTabEntry); if (last) strcat(optypeTab, "}\n"); else strcat(optypeTab, "},\n"); free(optypeTabEntry); optypeTabEntry = NULL; if (myoptypeTab) free(myoptypeTab); } #define OPTYPE_FUNC \ "INSTR_OperandType* INSTR_operandTypes(INSTR_InstrCategory index) \n{ \n return INSTR_operandTypeTable[index]; \n}\n" #define OPTYPE_FUNC_LEN 250 static char* opTypeC = NULL; void cgenInstrCatC(char* max_op){ size_t length = OPTYPE_TAB_COMMENTS_LEN + MAX_OP_COMMENTS_LEN + OPTYPE_TAB_TYPE_LEN + OPTYPE_TAB_BEG_LEN + OPTYPE_TAB_END_LEN + strlen(optypeTab) + OPTYPE_FUNC_LEN + strlen(max_op) + 100u; opTypeC = UTIL_mallocStr(length); strcpy(opTypeC, OPTYPE_TAB_COMMENTS); strcat(opTypeC, MAX_OP_COMMENTS); strcat(opTypeC, "#define INSTR_MAX_OPERAND "); strcat(opTypeC, max_op); strcat(opTypeC, "\n\n"); strcat(opTypeC, OPTYPE_TAB_TYPE); strcat(opTypeC, OPTYPE_TAB_BEG); strcat(opTypeC, optypeTab); strcat(opTypeC, OPTYPE_TAB_END); strcat(opTypeC, OPTYPE_FUNC); } //dynamic string array type typedef struct StringArray { char **array; unsigned int length; } StringArray; static StringArray instrTab; void cinitInstrC(int numInstrs) { instrTab.length = numInstrs; instrTab.array = (char**)UTIL_malloc(sizeof(char*)*numInstrs); } void cgenOneInstrC(int opcode, char* name, char* cat, char* len, int last) { size_t length = strlen(name) + strlen(cat) + strlen(len) + PREFIX_LEN + CATPREFIX_LEN + 20u + INDENT1_LEN ; char* myText = UTIL_mallocStr(length); strcpy(myText, INDENT1); strcat(myText, "{\""); strcat(myText, name); strcat(myText, "\", "); strcat(myText, CATPREFIX); strcat(myText, cat); strcat(myText, ", "); strcat(myText, PREFIX); strcat(myText, len); if (last) strcat(myText, "}\n"); else strcat(myText, "},\n"); instrTab.array[opcode] = myText; } #define INSTR_TAB_C_COMMENTS \ "/****************************************************************************/\n/* INSTRUCTION INFORMATION TABLE */ \n/****************************************************************************/ \n" #define INSTR_TAB_C_COMMENTS_LEN 250 #define INSTR_TAB_TYPE \ "typedef struct //entry of the instruction info table \n{ \n char* name; \n INSTR_InstrCategory type; \n int size; \n} INSTR_InstrInfoTab_; \n\ntypedef INSTR_InstrInfoTab_ INSTR_InstrInfoTab[INSTR_NUM_INSTRS]; \n\n" #define INSTR_TAB_TYPE_LEN 600 #define INSTR_TAB_BEG "INSTR_InstrInfoTab INSTR_instrInfoTable ={\n" #define INSTR_TAB_BEG_LEN 80 #define INSTR_TAB_END "};\n\n" #define INSTR_TAB_END_LEN 10 #define INSTR_TAB_FUNC_C \ "/* Accessing functions */ \nINSTR_InstrCategory INSTR_instrType(int index) \n{ \n return (INSTR_instrInfoTable[index]).type; \n} \n\nchar* INSTR_instrName(int index) \n{ \n return (INSTR_instrInfoTable[index]).name; \n} \n\nint INSTR_instrSize(int index) \n{ \n return (INSTR_instrInfoTable[index]).size; \n}\n\n" #define INSTR_TAB_FUNC_C_LEN 1000 static char* instrC = NULL; void cgenInstrC() { size_t i, length; char *myText = NULL, *myText2; for (i = 0; i < instrTab.length; i++) { if (instrTab.array[i]) { length = (myText ? strlen(myText) : 0u) + strlen(instrTab.array[i]); myText2 = UTIL_mallocStr(length + 100u); if (myText) { strcpy(myText2, myText); strcat(myText2, instrTab.array[i]); } else strcpy(myText2, instrTab.array[i]); free(instrTab.array[i]); free(myText); myText = myText2; } } free(instrTab.array); length = INSTR_TAB_C_COMMENTS_LEN + INSTR_TAB_TYPE_LEN + INSTR_TAB_BEG_LEN + INSTR_TAB_END_LEN + INSTR_TAB_FUNC_C_LEN + strlen(myText); instrC = UTIL_mallocStr(length); strcpy(instrC, INSTR_TAB_C_COMMENTS); strcat(instrC, INSTR_TAB_TYPE); strcat(instrC, INSTR_TAB_BEG); strcat(instrC, myText); strcat(instrC, INSTR_TAB_END); strcat(instrC, INSTR_TAB_FUNC_C); free(myText); } /* dump instructions.c" */ void cspitCInstructionsC(char * root) { FILE* outFile; char * filename = malloc(strlen(root) + 32); strcpy(filename, root); strcat(filename, "tables/instructions.c"); outFile = UTIL_fopenW(filename); fprintf(outFile, "%s\n%s\n", COMMENTS_BEG_C, INCLUDE_C); fprintf(outFile, "%s\n", opTypeC); fprintf(outFile, "%s\n", instrC); UTIL_fclose(outFile); free(opTypeC); free(instrC); free(filename); } /* simdispatch.c */ #define SIMPREFIX "SINSTR_" #define SIMPREFIX_LEN 7 #define SIMDIS_COMMENTS \ "/***************************************************************************/ \n/* */ \n/* File simdispatch.c. The instruction dispatch table used by the */ \n/* simulator is defined here as an array of function pointers, each of */ \n/* which refers to a function realizing a corresponding instruction. */ \n/* These functions are defined in the file ./siminstr.c. */ \n/***************************************************************************/ \n\n" #define SIMDIS_COMMENTS_LEN 600 #define SIMDIS_INCLUDE \ "#include \"../tables/instructions.h\" //to be modified \n#include \"siminstr.h\" \n#include \"simdispatch.h\"\n\n" #define SIMDIS_INCLUDE_LEN 250 #define SIMDIS_TAB_BEG \ "SDP_InstrFunctionPtr SDP_dispatchTable[INSTR_NUM_INSTRS] = {\n" #define SIMDIS_TAB_BEG_LEN 80 #define SIMDIS_TAB_END "};\n" #define SIMDIS_TAB_END_LEN 10 static StringArray dispatchTab; void cinitSimDispatch(int size) { dispatchTab.length = size; dispatchTab.array = (char**)UTIL_malloc(sizeof(char*)*size); } void cgenOneSimDispatch(int ind, char* instr, int last) { size_t length = strlen(instr) + SIMPREFIX_LEN + INDENT1_LEN + 10u; char* myText = UTIL_mallocStr(length); strcpy(myText, INDENT1); strcat(myText, SIMPREFIX); strcat(myText, instr); if (last) strcat(myText, "\n"); else strcat(myText, ",\n"); dispatchTab.array[ind] = myText; } static char* dispatch = NULL; void cgenSimDispatch() { size_t i, length; char *myText = NULL, *myText2; for(i = 0; i < dispatchTab.length; i++) { if (dispatchTab.array[i]){ length = (myText ? strlen(myText) : 0)+strlen(dispatchTab.array[i]); myText2 = UTIL_mallocStr(length); if (myText){ strcpy(myText2, myText); strcat(myText2, dispatchTab.array[i]); } else strcpy(myText2, dispatchTab.array[i]); free(dispatchTab.array[i]); free(myText); myText = myText2; } } free(dispatchTab.array); length = SIMDIS_COMMENTS_LEN + SIMDIS_INCLUDE_LEN + SIMDIS_TAB_BEG_LEN + SIMDIS_TAB_BEG_LEN + SIMDIS_TAB_END_LEN + strlen(myText); dispatch = UTIL_mallocStr(length); strcpy(dispatch, SIMDIS_COMMENTS); strcat(dispatch, SIMDIS_INCLUDE); strcat(dispatch, SIMDIS_TAB_BEG); strcat(dispatch, myText); strcat(dispatch, SIMDIS_TAB_END); free(myText); } void cspitSimDispatch(char * root) { FILE* outFile; char * filename = malloc(strlen(root) + 32); strcpy(filename, root); strcat(filename, "simulator/simdispatch.c"); outFile = UTIL_fopenW(filename); fprintf(outFile, "%s\n", dispatch); free(dispatch); UTIL_fclose(outFile); free(filename); }