From 59e18aee0e509a3ca75dbe6f909e18c1d17893d1 Mon Sep 17 00:00:00 2001 From: mingodad Date: Fri, 11 Jan 2013 00:04:38 +0000 Subject: Added what I call virtual io to tinycc this way we can make a monolitic executable or library that contains all needed to compile programs, truly tinycc portable. Tested under linux exec the "mk-it" shell script and you'll end up with a portable tinycc executable that doesn't depend on anything else. --- bin2c.c | 615 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 615 insertions(+) create mode 100644 bin2c.c (limited to 'bin2c.c') diff --git a/bin2c.c b/bin2c.c new file mode 100644 index 0000000..e8d2795 --- /dev/null +++ b/bin2c.c @@ -0,0 +1,615 @@ + +#include +#include +#include +#include +#include +#include +#include + +/* Version information */ +const char *versionInfo = + "bin2c version 1.0 by Fatih Aygun\n" + "\n" + "Visit sourceforge.net/projects/bin2c to for new versions.\n" + "This program is public domain, do whatever you want with it.\n" +; + +/* Command line help */ +const char *commandLineHelp = + "Usage: bin2c [OPTION...] FILE [FILE...]\n" + "bin2c creates a C soures and headers from binary files.\n" + "\n" + "Examples:\n" + " bin2c -o foo.h bar.bin # Create 'foo.h' from the contents of\n" + " 'bar.bin'\n" + " bin2c -o foo.h file1 file2 # Create 'foo.h' from the contents of 'file1'\n" + " and 'file2'\n" + " bin2c -d foo.h -o foo.c bar.bin # Create 'foo.c' and 'foo.h' from the\n" + " contents of 'bar.bin'\n" + "\n" + "Options:\n" + " -d, --header Name a header file (A header file will not be\n" + " created unless explicitly named)\n" + " -h, --help Print this command line help and exit immediately\n" + " -o, --output Name an output file\n" + " -m, --macro Create the size definition as a macro instead of\n" + " a const\n" + " -n, --name Name the symbol to be defined\n" + " -v, --version Print version information and exit immediately\n" + "\n" + "Visit sourceforge.net/projects/bin2c to for new versions.\n" + "This program is public domain, do whatever you want with it.\n" + ; + +/* Output formatting macros */ +#define bytesPerLine 16 +#define indentString " " +#define outputFormatBase "0x%.2X" +#define outputFormat outputFormatBase", " +#define outputFormatEOL outputFormatBase",\n" +#define outputFormatEOF outputFormatBase"\n" +#define sizeDefinition "const long int bin2c_%s_size = %d;\n" +#define sizeMacroDefinition "#define bin2c_%s_size %d\n" +#define typeName "const unsigned char" + +/* Define bool */ +#define bool int +#define false 0 +#define true 1 + +/* Global variables */ +FILE *outputFile=0; /* Current output file stream */ +const char *outputFileName=0; /* Current output file name */ +FILE *headerFile=0; /* Current header file */ +const char *headerFileName=0; /* Current header file name */ +FILE *tmpFuncFile=0; /* File to write final function that search for files */ +const char *tmpFuncFileName=0; /* Current tmpFunc file name */ +char *symbolName=0; /* Current symbol name */ +char *headerSymbol=0; /* Symbol for multiple inclusion protection */ +bool createMacro = false; /* Should we create a define instead of a const? */ + +/* Error messages */ +const char* cantOpen = "Can't open file '%s'"; +const char* cantClose = "Can't close file '%s'"; +const char* cantRemove = "Can't remove file '%s'"; +const char* cantWrite = "Can't write to file '%s'"; +const char* noOutputFilesAreNamed = "No output files are named"; +const char* noHeaderFilesAreNamed = "No header files are named"; +const char* cantMalloc = "Can't allocate memory for '%s'"; +const char* cantSeek = "Can't seek in the file '%s'"; +const char* cantDetermine = "Can't determine the file size of '%s'"; +const char* cantRead = "Can't read from file %s"; +const char* unknownOption = "Unknown option '%s'"; +const char* tryHelp = "Try 'bin2c --help' for more information.\n"; +const char* noSymbolName = "No symbol name is given"; +const char* notValidId = "'%s' is not a valid identifier"; +const char* symbolNameGiven = "Symbol name is given twice"; + +/* Print a formatted error message */ +static void vprintfError(const char *format, va_list args) +{ + fprintf(stderr, "bin2c: "); + vfprintf(stderr, format, args); + if (errno) { + fprintf(stderr, ": "); + perror(""); + errno = 0; + } else { + fprintf(stderr, "\n"); + } +} + +static void printfError(const char *format, ...) +{ + va_list args; + + va_start(args, format); + vprintfError(format, args); + va_end(args); +} + +/* Panic */ +static void panic() +{ + /* Close and remove the output file if it's open */ + if (outputFile) { + if (fclose(outputFile)) { + printfError(cantClose, outputFileName); + } + + if (remove(outputFileName)) { + printfError(cantRemove, outputFileName); + } + } + + /* Close and remove the header file if it's open */ + if (headerFile) { + if (fclose(headerFile)) { + printfError(cantClose, headerFileName); + } + + if (remove(headerFileName)) { + printfError(cantRemove, headerFileName); + } + } + + /* Close and remove the header file if it's open */ + if (tmpFuncFile) { + if (fclose(tmpFuncFile)) { + printfError(cantClose, tmpFuncFileName); + } + + if (remove(tmpFuncFileName)) { + printfError(cantRemove, tmpFuncFileName); + } + } + + /* Exit with an error code */ + exit(EXIT_FAILURE); +} + +/* Check a contidion and panic if it's false */ +static void check(bool condition, const char *format, ...) +{ + va_list args; + + if (!condition) { + va_start(args, format); + vprintfError(format, args); + va_end(args); + panic(); + } +} + +/* Write a formatted string to the output file and check for errors */ +static void output(const char *format, ...) +{ + va_list args; + + /* Try to write to the file */ + va_start(args, format); + vfprintf(outputFile, format, args); + va_end(args); + + /* Check for errors */ + check(!ferror(outputFile), cantWrite, outputFileName); +} + +/* Write a formatted string to the header file and check for errors */ +static void header(const char *format, ...) +{ + va_list args; + + /* Try to write to the file */ + va_start(args, format); + vfprintf(headerFile, format, args); + va_end(args); + + /* Check for errors */ + check(!ferror(headerFile), cantWrite, headerFileName); +} + +/* Write a formatted string to the tmp file and check for errors */ +static void tmpFunc(const char *format, ...) +{ + va_list args; + + /* Try to write to the file */ + va_start(args, format); + vfprintf(tmpFuncFile, format, args); + va_end(args); + + /* Check for errors */ + check(!ferror(tmpFuncFile), cantWrite, tmpFuncFileName); +} + +/* Allocate a valid C identifier from a file name */ +static char *fileNameToSymbol(const char *fileName) +{ + char *name; + int i; + + name = malloc(strlen(fileName) + 1); + check(name != 0, cantMalloc, "the symbol name"); + + /* Copy the file name to symbolName */ + strcpy(name, fileName); + + /* Replace every non alphanumerical character with '_' */ + for (i = 0; name[i]; ++i) { + if (!((name[i] >= 'a' && name[i] <= 'z') || + (name[i] >= 'A' && name[i] <= 'Z') || + (name[i] >= '0' && name[i] <= '9'))) { + name[i] = '_'; + } + } + + /* Replace the first character with '_' if it's a digit */ + if (name[0] >= '0' && name[0] <= '9') { + name[0] = '_'; + } + + return name; +} + + int isdir(const char * path) +{ + int bOK = 0; + #ifndef _MSC_VER + struct stat buf; + if (path == NULL) return 0; + if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) bOK=1; + #else + wchar_t *wcpath = to_wide_string((char*)path); + if (wcpath == NULL) return FALSE; + bOK = isdirW(wcpath); + FREE(wcpath); + #endif + return bOK; + } + +/* Process an input file */ +static int processFile(const char *fileName, long int from, long int to) +{ + bool symbolNameAllocated = false; /* Did we allocate the symbolName? */ + long int i, j; /* Indexes for various purposes */ + FILE *inputFile; /* Input file stream */ + int byte; /* Byte read from the input */ + long int fsize=0; + + if(isdir(fileName)) return 0; + + /* Be sure that the output file is open */ + check(outputFile != 0, noOutputFilesAreNamed); + + /* Write the comment */ + output("\n/* Contents of file %s */\n", fileName); + if (headerFile) { + header("\n/* Contents of file %s */\n", fileName); + } + + /* Make up a suitable symbolName if we don't have one */ + if (!symbolName) { + symbolName = fileNameToSymbol(fileName); + symbolNameAllocated = true; + } + + /* Open the input file */ + inputFile = fopen(fileName, "rb"); + check(inputFile != 0, cantOpen, fileName); + + /* If to == -1, set it to the last byte of the file */ + if (to == -1) { + check(!fseek(inputFile, 0, SEEK_END), cantSeek, fileName); + to = ftell(inputFile); + check(to >= 0, cantDetermine, fileName); + --to; + } + + assert(from <= to - 1); + + /* Position the file to "from" */ + check(!fseek(inputFile, from, SEEK_SET), cantSeek, fileName); + + fsize = to - from + 1; + + /* Output the size definition */ + if (headerFile) { + if (createMacro) { + header(sizeMacroDefinition, symbolName, fsize); + } else { + header("extern "sizeDefinition, symbolName, fsize); + output(sizeDefinition, symbolName, fsize); + } + } else { + if (createMacro) { + output(sizeMacroDefinition, symbolName, fsize); + } else { + output(sizeDefinition, symbolName, fsize); + } + } + + if (tmpFuncFile) { + tmpFunc("\t{\"/_attach_/%s\", bin2c_%s, %d},\n", fileName, symbolName, fsize); + } + /* Output the definition */ + output("%s bin2c_%s[%d] = {\n", typeName, symbolName, fsize); + if (headerFile) { + header("extern %s *bin2c_%s;\n", typeName, symbolName, fsize); + } + + /* Output the contents */ + j = 1; + for (i = from; i <= to; ++i) { + /* Read a byte from the input file */ + byte = fgetc(inputFile); + check(byte != EOF, cantRead, fileName); + + /* Output the indentation if it's the first byte of a line */ + if (j == 1) { + output(indentString); + } + + /* Output the actual byte */ + if (i == to) { + /* Output the last byte */ + output(outputFormatEOF, byte); + } else if (j == bytesPerLine) { + /* Output the last byte of a line */ + output(outputFormatEOL, byte); + } else { + /* Output a normal byte */ + output(outputFormat, byte); + } + + /* Next byte */ + ++j; + if (j > bytesPerLine) { + j = 1; + } + } + + /* Output the end of definition */ + output("};\n"); + + /* Free the symbol name if it was allocated by us */ + if (symbolNameAllocated) { + free(symbolName); + } + + /* Clear the symbol name */ + symbolName = 0; + return 1; +} + +/* Unknown option error */ +static void handleUnknownOption(const char *s) +{ + printfError(unknownOption, s); + fprintf(stderr, tryHelp); + panic(); +} + +/* Open an output file */ +static void openOutputFile(const char *fileName) +{ + /* Be sure that a file name is given */ + if (!fileName) { + printfError(noOutputFilesAreNamed); + fprintf(stderr, tryHelp); + panic(); + } + + /* Close previous output file if any */ + if (outputFile) { + check(!fclose(outputFile), cantClose, outputFileName); + } + + /* Open the new output file */ + outputFile = fopen(fileName, "w"); + check(outputFile != 0, cantOpen, outputFileName); + outputFileName = fileName; + + output("/* Generated by bin2c, do not edit manually */\n"); +} + +/* Open a header file */ +static void openHeaderFile(const char *fileName) +{ + /* Be sure that a file name is given */ + if (!fileName) { + printfError(noHeaderFilesAreNamed); + fprintf(stderr, tryHelp); + panic(); + } + + /* Close previous header file if any */ + if (headerFile) { + header("\n#endif /* __%s_included */\n", headerSymbol); + free(headerSymbol); + headerSymbol = 0; + check(!fclose(headerFile), cantClose, headerFileName); + } + + /* Open the new header file */ + headerFile = fopen(fileName, "w"); + check(headerFile != 0, cantOpen, headerFileName); + headerFileName = fileName; + headerSymbol = fileNameToSymbol(fileName); + + header("/* Generated by bin2c, do not edit manually */\n"); + header("#ifndef __%s_included\n", headerSymbol); + header("#define __%s_included\n", headerSymbol); +} + + typedef void writeFileFunc(const char *format, ...); + + void writeAttchmentStruct(writeFileFunc *writeFunc){ + (*writeFunc)("\ntypedef struct {\n"); + (*writeFunc)("\tconst char *file_name;\n"); + (*writeFunc)("\tconst unsigned char *sym_name;\n"); + (*writeFunc)("\tlong size;\n"); + (*writeFunc)("} bin2c_filesAttached_st;\n"); +} + +/* Open a header file */ +static void openFuncFile(const char *fileName) +{ + static char fnBuf[1024]; + /* Be sure that a file name is given */ + if (!fileName) { + printfError(noHeaderFilesAreNamed); + fprintf(stderr, tryHelp); + panic(); + } + + /* Close previous header file if any */ + if (tmpFuncFile) { + tmpFunc("\n};\n"); + check(!fclose(tmpFuncFile), cantClose, tmpFuncFileName); + } + + snprintf(fnBuf, sizeof(fnBuf), "%s.tmp", fileName); + + /* Open the new header file */ + tmpFuncFile = fopen(fnBuf, "w"); + check(tmpFuncFile != 0, cantOpen, fnBuf); + tmpFuncFileName = fnBuf; + + tmpFunc("\n/* Generated by bin2c, do not edit manually */\n"); + writeAttchmentStruct(&tmpFunc); + tmpFunc("const bin2c_filesAttached_st bin2c_filesAttached[] = {\n"); +} + +/* Set the symbol name for next file */ +static void setSymbolName(char *name) +{ + int i; + + if (symbolName) { + printfError(symbolNameGiven); + fprintf(stderr, tryHelp); + panic(); + } + + /* Be sure that a symbol name is given */ + if (!name) { + printfError(noSymbolName); + fprintf(stderr, tryHelp); + panic(); + } + + /* Check if the symbol is a valid C identifier */ + check((name[0] >= 'a' && name[0] <='z') || + (name[0] >= 'A' && name[0] <='Z') || + (name[0] == '_'), notValidId, name); + + for (i = 1; name[i]; ++i) { + check((name[i] >= 'a' && name[i] <='z') || + (name[i] >= 'A' && name[i] <='Z') || + (name[i] >= '0' && name[i] <='9') || + (name[i] == '_'), notValidId, name); + } + + /* Set the symbol name */ + symbolName = name; + } + + void concatenate(const char *dest, const char *src){ + int i,ch; + FILE *fpdest=fopen(dest,"a"); + FILE *fpsrc=fopen(src,"r"); + while((ch=getc(fpsrc))!=EOF) putc(ch,fpdest); + } + +/* Main function */ +int main(int argc, char **argv) +{ + int i; /* Index to process commandline arguments */ + int ipf = 0; /*total files processed*/ + + /* Scan for a -h or --help option */ + for (i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { + /* Print command line arguments help and exit immediately */ + printf("%s", commandLineHelp); + return EXIT_SUCCESS; + } + } + + /* Scan for a -v or --version option */ + for (i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { + /* Print version information and exit immediately */ + printf("%s", versionInfo); + return EXIT_SUCCESS; + } + } + + /* Process command line arguments */ + for (i = 1; i < argc; ++i) { + /* Check if it's an option or file name */ + if (argv[i][0] == '-') { + /* Process the option */ + switch (argv[i][1]) { + case '-': + /* Long options */ + if (!strcmp(argv[i], "--output")) { + /* Name an output file */ + openOutputFile(argv[i+1]); + openFuncFile(argv[i+1]); + ++i; + } else if (!strcmp(argv[i], "--header")) { + /* Name a header file */ + openHeaderFile(argv[i+1]); + ++i; + } else if (!strcmp(argv[i], "--macro")) { + /* Create a macro for the size definition */ + createMacro = true; + } else if (!strcmp(argv[i], "--name")) { + /* Name the symbol */ + setSymbolName(argv[i+1]); + ++i; + } else { + /* Unknown option */ + handleUnknownOption(argv[i]); + } + break; + case 'o': + /* Name an output file */ + openOutputFile(argv[i+1]); + openFuncFile(argv[i+1]); + ++i; + break; + case 'd': + /* Name a header file */ + openHeaderFile(argv[i+1]); + ++i; + break; + case 'm': + /* Create a macro for the size definition */ + createMacro = true; + break; + case 'n': + /* Name the symbol */ + setSymbolName(argv[i+1]); + ++i; + break; + default: + /* Unknown option */ + handleUnknownOption(argv[i]); + } + } else { + /* Process the file */ + if(processFile(argv[i], 0, -1)) ipf++; + } + } + + /* Close any remaining output files */ + if (headerFile) { + writeAttchmentStruct(&header); + header("extern const bin2c_filesAttached_st bin2c_filesAttached[%d];\n", ipf); + + header("\n#endif /* __%s_included */\n", headerSymbol); + free(headerSymbol); + headerSymbol = 0; + check(!fclose(headerFile), cantClose, headerFileName); + } + + if (tmpFuncFile) { + tmpFunc("};\n"); + check(!fclose(tmpFuncFile), cantClose, tmpFuncFileName); + } + + if (outputFile) { + check(!fclose(outputFile), cantClose, outputFileName); + } + + if (tmpFuncFile && outputFile) { + concatenate(outputFileName, tmpFuncFileName); + remove(tmpFuncFileName); + } + + return EXIT_SUCCESS; +} -- cgit v1.3.1