# HG changeset patch # User Matti Hamalainen # Date 1560618854 -10800 # Node ID d76b0c92769d8c83ec6fe6ede60f493a400de18f # Parent 95f669692b01149432f802c1f8d750122518ec0c Refactor data2inc to be more flexible. diff -r 95f669692b01 -r d76b0c92769d tools/data2inc.c --- a/tools/data2inc.c Sat Jun 15 14:14:40 2019 +0300 +++ b/tools/data2inc.c Sat Jun 15 20:14:14 2019 +0300 @@ -1,7 +1,7 @@ /* * data2inc - Convert binary data to "C"-source or XA-compatible include file * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2003,2009-2012 Tecnic Software productions (TNSP) + * (C) Copyright 2003,2009-2019 Tecnic Software productions (TNSP) * * Please read file 'COPYING' for information on license and distribution. */ @@ -11,64 +11,99 @@ #include "dmmutex.h" -#define RA_LINEBUF (16) +#define SET_DEF_LINELEN 16 +#define SET_MAX_FEXTS 16 + -enum +// +// Types etc +// +typedef struct { - FMT_AUTO = 0, - FMT_C, - FMT_ASM -}; + char *name; + char *desc; + char *fexts[SET_MAX_FEXTS]; + + char *type; + void (*writeHeader) (FILE *fh, const char *name); + void (*writeDecl) (FILE *fh, const size_t len, const char *name); + void (*writeData) (FILE *fh, const Uint8 *buf, const size_t len); + void (*writeFooter) (FILE *fh, const size_t len, const char *name); +} DMOutputFormat; + + +// +// Options +// char *optInFilename = NULL, *optOutFilename = NULL, *optObjName = "default_object", *optDataType = NULL, *optAddLine = NULL; -int optIndentation = -1; -int optFormat = FMT_AUTO; +const DMOutputFormat *setFormat = NULL; +int optIndentation = -1, + optLineLen = SET_DEF_LINELEN; BOOL optHexMode = FALSE, optQuiet = FALSE, optExtraData = FALSE, optFormatting = TRUE; -void (*writeHeader) (FILE *, char *) = NULL; -void (*writeDecl) (FILE *, unsigned int, char *) = NULL; -void (*writeData) (FILE *, Uint8 *, unsigned int) = NULL; -void (*writeFooter) (FILE *, unsigned int, char *) = NULL; - - static const DMOptArg optList[] = { { 0, '?', "help", "Show this help", OPT_NONE }, - { 4, 'A', "format-asm", "Output in XA-compatible asm", OPT_NONE }, - { 5, 'C', "format-c", "Output in ANSI C", OPT_NONE }, { 1, 'n', "name", "Set object name", OPT_ARGREQ }, { 2, 't', "type", "Set datatype (unsigned char/byte)", OPT_ARGREQ }, - { 3, 'a', "add-line", "Add this line to start of file", OPT_ARGREQ }, + { 3, 'f', "format", "Set output format (see list below)", OPT_ARGREQ }, + { 4, 'a', "add-line", "Add this line to start of file", OPT_ARGREQ }, + { 5, 'n', "nitems", "Set number of items per line", OPT_ARGREQ }, { 6, 'x', "hexadecimal", "Use hexadecimal output", OPT_NONE }, { 7, 'q', "quiet", "Do not add comments", OPT_NONE }, - { 8, 'f', "no-formatting", "Disable additional output formatting", OPT_NONE }, + { 8, 'N', "no-formatting", "Disable additional output formatting", OPT_NONE }, { 9, 'i', "indentation", "Set indentation (negative value = tab)", OPT_ARGREQ }, { 10, 'e', "extra-data", "Add object end labels and size in asm output", OPT_NONE }, }; static const int optListN = sizeof(optList) / sizeof(optList[0]); +static const DMOutputFormat dmFormatList[]; +static const int ndmFormatList; void argShowHelp() { dmPrintBanner(stdout, dmProgName, - "[options] [sourcefile] [destfile]"); + "[options] [sourcefile] [destfile]"); dmArgsPrintHelp(stdout, optList, optListN, 0); - printf( + fprintf(stdout, + "\n" + "Available output formats (-f ):\n" + " frmt | Description (filename extensions)\n" + "------+------------------------------------------\n"); + + for (int i = 0; i < ndmFormatList; i++) + { + const DMOutputFormat *fmt = &dmFormatList[i]; + fprintf(stdout, "%-5s | %s (", + fmt->name, fmt->desc); + + for (int n = 0; n < SET_MAX_FEXTS && fmt->fexts[n] != NULL; n++) + { + fprintf(stdout, ".%s%s", + fmt->fexts[n], + (n + 1 < SET_MAX_FEXTS && + fmt->fexts[n + 1] != NULL) ? " " : ""); + } + fprintf(stdout, ")\n"); + } + + fprintf(stdout, "\n" "To convert a data file to a C structure using 'Uint8' as type:\n" - "$ data2inc -C -n variable_name -t Uint8 input.bin output.h\n" + "$ data2inc -n variable_name -t Uint8 input.bin output.h\n" "\n" ); } @@ -92,21 +127,42 @@ break; case 3: + for (int i = 0; i < ndmFormatList; i++) + { + const DMOutputFormat *fmt = &dmFormatList[i]; + if (strcasecmp(fmt->name, optArg) == 0) + { + setFormat = fmt; + return TRUE; + } + } + dmErrorMsg("Invalid format name '%s'.\n", + optArg); + return FALSE; + + case 4: optAddLine = optArg; break; - case 4: - optFormat = FMT_ASM; + case 5: + optLineLen = atoi(optArg); + if (optLineLen < 1) + { + dmErrorMsg("Invalid line length / number of items per line '%s'.\n", + optArg); + return FALSE; + } break; - case 5: - optFormat = FMT_C; - break; + + case 6: optHexMode = TRUE; break; + case 7: optQuiet = TRUE; break; + case 8: optFormatting = FALSE; break; @@ -130,10 +186,10 @@ BOOL argHandleFile(char * currArg) { - if (!optInFilename) + if (optInFilename == NULL) optInFilename = currArg; else - if (!optOutFilename) + if (optOutFilename == NULL) optOutFilename = currArg; else dmErrorMsg("Source and destination filenames already specified, extraneous argument '%s'.\n", currArg); @@ -144,259 +200,306 @@ /* Assembler include data output functions */ -void writeHeader_ASM(FILE * f, char *name) +void writeHeader_ASM(FILE *fh, const char *name) { if (name) - fprintf(f, "; '%s'", name); + fprintf(fh, "; '%s'", name); else - fprintf(f, "; Generated"); - fprintf(f, " by %s v%s\n", + fprintf(fh, "; Generated"); + + fprintf(fh, " by %s v%s\n", dmProgName, dmProgVersion); } -void writeDecl_ASM(FILE * f, unsigned int len, char *name) + +void writeDecl_ASM(FILE *fh, const size_t len, const char *name) { if (optExtraData) - fprintf(f, "%s_size = %u\n", name, len); - fprintf(f, "%s:\n", name); + fprintf(fh, "%s_size = %" DM_PRIu_SIZE_T "\n", name, len); + + fprintf(fh, "%s:\n", name); } -void writeData_ASM(FILE * f, Uint8 * buf, unsigned int len) + +void writeData_ASM(FILE *fh, const Uint8 * buf, const size_t len) { - fprintf(f, "%s ", optDataType); - for (unsigned int i = 0; i < len; i++) + fprintf(fh, "%s ", optDataType); + + for (size_t i = 0; i < len; i++) { if (optFormatting) { if (optHexMode) - fprintf(f, "$%.2x", buf[i]); + fprintf(fh, "$%.2x", buf[i]); else - fprintf(f, "%3d", buf[i]); + fprintf(fh, "%3d", buf[i]); } else { if (optHexMode) - fprintf(f, "$%x", buf[i]); + fprintf(fh, "$%x", buf[i]); else - fprintf(f, "%d", buf[i]); + fprintf(fh, "%d", buf[i]); } - if (i < len - 1) - fprintf(f, ","); + if (i + 1 < len) + fprintf(fh, ","); } } -void writeFooter_ASM(FILE * f, unsigned int len, char *name) + +void writeFooter_ASM(FILE *fh, const size_t len, const char *name) { (void) len; if (optExtraData) - fprintf(f, "%s_end: \n", name); + fprintf(fh, "%s_end: \n", name); else - fprintf(f, "\n"); + fprintf(fh, "\n"); } /* ANSI-C include data output functions */ -void writeHeader_C(FILE * f, char *name) +void writeHeader_C(FILE *fh, const char *name) { if (name) - fprintf(f, "/* '%s' generated", name); + fprintf(fh, "/* '%s' generated", name); else - fprintf(f, "/* Generated"); + fprintf(fh, "/* Generated"); - fprintf(f, " by %s v%s\n" " */\n", + fprintf(fh, " by %s v%s\n" " */\n", dmProgName, dmProgVersion); } -void writeDecl_C(FILE * f, unsigned int len, char *name) + +void writeDecl_C(FILE *fh, const size_t len, const char *name) { - fprintf(f, "%s %s[%u] = {\n", + fprintf(fh, "%s %s[%" DM_PRIu_SIZE_T "] = {\n", optDataType, name, len); - printf("extern %s %s[%u];\n", + printf("extern %s %s[%" DM_PRIu_SIZE_T "];\n", optDataType, name, len); } -void writeData_C(FILE * f, Uint8 * buf, unsigned int len) + +void writeData_C(FILE *fh, const Uint8 *buf, const size_t len) { - unsigned int i; - - for (i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) { if (optFormatting) { if (optHexMode) - fprintf(f, "0x%.2x", buf[i]); + fprintf(fh, "0x%.2x", buf[i]); else - fprintf(f, "%3d", buf[i]); + fprintf(fh, "%3d", buf[i]); } else { if (optHexMode) - fprintf(f, "0x%x", buf[i]); + fprintf(fh, "0x%x", buf[i]); else - fprintf(f, "%d", buf[i]); + fprintf(fh, "%d", buf[i]); } - fprintf(f, ","); + fprintf(fh, ","); } } -void writeFooter_C(FILE * f, unsigned int len, char *name) + +void writeFooter_C(FILE *fh, const size_t len, const char *name) { (void) len; (void) name; - fprintf(f, "};\n"); + + fprintf(fh, "};\n"); } -off_t dmGetFileSize(FILE *f) +static const DMOutputFormat dmFormatList[] = { - off_t len, pos = ftello(f); - fseeko(f, 0, SEEK_END); - len = ftello(f); - fseeko(f, pos, SEEK_SET); + { + "asm", + "XA65 compatible assembler", + { "s", "asm", NULL }, + ".byte", + + writeHeader_ASM, + writeDecl_ASM, + writeData_ASM, + writeFooter_ASM, + }, + + { + "c", + "ANSI C array", + { "c", "h", "cc", "cpp", "hpp", "c++", NULL }, + + "unsigned char", + + writeHeader_C, + writeDecl_C, + writeData_C, + writeFooter_C, + }, +}; + +static const int ndmFormatList = sizeof(dmFormatList) / sizeof(dmFormatList[0]); + + +off_t dmGetFileSize(FILE *fh) +{ + off_t len, pos = ftello(fh); + fseeko(fh, 0, SEEK_END); + len = ftello(fh); + fseeko(fh, pos, SEEK_SET); return len; } +const DMOutputFormat *dmGuessFormatFromName(const char *filename) +{ + const char *fext; + + if ((fext = strrchr(filename, '.')) == NULL) + return NULL; + + for (int i = 0; i < ndmFormatList; i++) + { + const DMOutputFormat *fmt = &dmFormatList[i]; + + for (int n = 0; n < SET_MAX_FEXTS && fmt->fexts[n] != NULL; n++) + { + if (strcasecmp(fext + 1, fmt->fexts[n]) == 0) + return fmt; + } + } + + return NULL; +} + + int main(int argc, char *argv[]) { - FILE *sfile = NULL, *dfile = NULL; - off_t inSize; - Uint8 inBuf[RA_LINEBUF]; - int tmpRes; + FILE *inFile = NULL, *outFile = NULL; + Uint8 *dataBuf = NULL; + size_t dataSize; + off_t totalSize; + int res; - /* Initialize */ - dmInitProg("data2inc", "Data to include converter", "0.6", NULL, NULL); + // Initialize + dmInitProg("data2inc", "Data to include converter", "0.7", NULL, NULL); dmVerbosity = 0; - /* Parse arguments */ + // Parse arguments if (!dmArgsProcess(argc, argv, optList, optListN, argHandleOpt, argHandleFile, OPTH_BAILOUT)) exit(1); - /* Determine output type, if not specified */ - if (optFormat == FMT_AUTO) + // Determine output type, if not specified + if (setFormat == NULL) { - char *dext; - if (optOutFilename == NULL) { dmErrorMsg("Output format not specified and no output filename given (try --help)\n"); - exit(1); + goto exit; } - /* Check filename extension */ - dext = strrchr(optOutFilename, '.'); - if (dext) + if ((setFormat = dmGuessFormatFromName(optOutFilename)) == NULL) { - dext++; - if (!strcasecmp(dext, "c") || !strcasecmp(dext, "h") || - !strcasecmp(dext, "cc") || !strcasecmp(dext, "cpp") || - !strcasecmp(dext, "hpp") || !strcasecmp(dext, "c++")) - optFormat = FMT_C; - else - optFormat = FMT_ASM; - } else - optFormat = FMT_ASM; + dmErrorMsg("Could not guess output format from filename '%s'.\n", + optOutFilename); + goto exit; + } + + dmMsg(0, "Guessed output format: %s (%s)\n", + setFormat->desc, setFormat->name); } - /* Set functions */ - switch (optFormat) - { - case FMT_ASM: - if (!optDataType) - optDataType = ".byte"; - - writeHeader = writeHeader_ASM; - writeDecl = writeDecl_ASM; - writeData = writeData_ASM; - writeFooter = writeFooter_ASM; - break; - - case FMT_C: - if (!optDataType) - optDataType = "unsigned char"; + // Set some option defaults + if (optDataType == NULL) + optDataType = setFormat->type; - writeHeader = writeHeader_C; - writeDecl = writeDecl_C; - writeData = writeData_C; - writeFooter = writeFooter_C; - break; - - case FMT_AUTO: - default: - dmErrorMsg("Internal error, FMT_AUTO at output function init.\n"); - exit(2); - } - - /* Open the files */ + // Open the files if (optInFilename == NULL) - sfile = stdin; + inFile = stdin; else - if ((sfile = fopen(optInFilename, "rb")) == NULL) + if ((inFile = fopen(optInFilename, "rb")) == NULL) { - tmpRes = dmGetErrno(); + res = dmGetErrno(); dmErrorMsg("Error opening input file '%s'. (%s)\n", - optInFilename, dmErrorStr(tmpRes)); - exit(3); + optInFilename, dmErrorStr(res)); + goto exit; } if (optOutFilename == NULL) - dfile = stdout; + outFile = stdout; else - if ((dfile = fopen(optOutFilename, "wa")) == NULL) + if ((outFile = fopen(optOutFilename, "wa")) == NULL) { - tmpRes = dmGetErrno(); + res = dmGetErrno(); dmErrorMsg("Error creating output file '%s'. (%s)\n", - optOutFilename, dmErrorStr(tmpRes)); - exit(4); + optOutFilename, dmErrorStr(res)); + goto exit; + } + + // Allocate linebuffer + dataSize = optLineLen * sizeof(Uint8); + if ((dataBuf = dmMalloc(dataSize)) == NULL) + { + dmErrorMsg("Could not allocate %" DM_PRIu_SIZE_T " byte buffer.\n", + dataSize); + goto exit; } - /* Get sourcefile size */ - inSize = dmGetFileSize(sfile); + // Get sourcefile size + totalSize = dmGetFileSize(inFile); - /* Output header */ + // Output header if (!optQuiet) - writeHeader(dfile, optOutFilename); + setFormat->writeHeader(outFile, optOutFilename); if (optAddLine) - fprintf(dfile, "%s\n", optAddLine); + fprintf(outFile, "%s\n", optAddLine); - /* Output declaration */ - writeDecl(dfile, inSize, optObjName); + // Output declaration + setFormat->writeDecl(outFile, totalSize, optObjName); - /* Output data */ - while (!feof(sfile)) + // Output data + while (!feof(inFile)) { - tmpRes = fread(inBuf, sizeof(Uint8), RA_LINEBUF, sfile); - if (tmpRes > 0) + res = fread(dataBuf, 1, dataSize, inFile); + if (res > 0) { if (optIndentation < 0) - fprintf(dfile, "\t"); + { + for (int i = 0; i < -optIndentation; i++) + fputs("\t", outFile); + } else if (optIndentation > 0) { - int i; - for (i = 0; i < optIndentation; i++) - fputs(" ", dfile); + for (int i = 0; i < optIndentation; i++) + fputs(" ", outFile); } - writeData(dfile, inBuf, tmpRes); + setFormat->writeData(outFile, dataBuf, res); - fprintf(dfile, "\n"); + fprintf(outFile, "\n"); } } - - /* Output footer */ - writeFooter(dfile, inSize, optObjName); + // Output footer + setFormat->writeFooter(outFile, totalSize, optObjName); - /* Exit */ - fclose(sfile); - fclose(dfile); +exit: + // Cleanup + if (inFile != NULL) + fclose(inFile); + + if (outFile != NULL) + fclose(outFile); + + dmFree(dataBuf); return 0; }