Revert "pe: fix tcc not linking to user32 and gdi32"
[tinycc.git] / bin2c.c
blobe8d2795e9b9e4049fdccd695e1db382030027c57
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <stdarg.h>
5 #include <errno.h>
6 #include <string.h>
7 #include <sys/stat.h>
8 #include <assert.h>
10 /* Version information */
11 const char *versionInfo =
12 "bin2c version 1.0 by Fatih Aygun\n"
13 "\n"
14 "Visit sourceforge.net/projects/bin2c to for new versions.\n"
15 "This program is public domain, do whatever you want with it.\n"
18 /* Command line help */
19 const char *commandLineHelp =
20 "Usage: bin2c [OPTION...] FILE [FILE...]\n"
21 "bin2c creates a C soures and headers from binary files.\n"
22 "\n"
23 "Examples:\n"
24 " bin2c -o foo.h bar.bin # Create 'foo.h' from the contents of\n"
25 " 'bar.bin'\n"
26 " bin2c -o foo.h file1 file2 # Create 'foo.h' from the contents of 'file1'\n"
27 " and 'file2'\n"
28 " bin2c -d foo.h -o foo.c bar.bin # Create 'foo.c' and 'foo.h' from the\n"
29 " contents of 'bar.bin'\n"
30 "\n"
31 "Options:\n"
32 " -d, --header <file name> Name a header file (A header file will not be\n"
33 " created unless explicitly named)\n"
34 " -h, --help Print this command line help and exit immediately\n"
35 " -o, --output <file name> Name an output file\n"
36 " -m, --macro Create the size definition as a macro instead of\n"
37 " a const\n"
38 " -n, --name <symbol name> Name the symbol to be defined\n"
39 " -v, --version Print version information and exit immediately\n"
40 "\n"
41 "Visit sourceforge.net/projects/bin2c to for new versions.\n"
42 "This program is public domain, do whatever you want with it.\n"
45 /* Output formatting macros */
46 #define bytesPerLine 16
47 #define indentString " "
48 #define outputFormatBase "0x%.2X"
49 #define outputFormat outputFormatBase", "
50 #define outputFormatEOL outputFormatBase",\n"
51 #define outputFormatEOF outputFormatBase"\n"
52 #define sizeDefinition "const long int bin2c_%s_size = %d;\n"
53 #define sizeMacroDefinition "#define bin2c_%s_size %d\n"
54 #define typeName "const unsigned char"
56 /* Define bool */
57 #define bool int
58 #define false 0
59 #define true 1
61 /* Global variables */
62 FILE *outputFile=0; /* Current output file stream */
63 const char *outputFileName=0; /* Current output file name */
64 FILE *headerFile=0; /* Current header file */
65 const char *headerFileName=0; /* Current header file name */
66 FILE *tmpFuncFile=0; /* File to write final function that search for files */
67 const char *tmpFuncFileName=0; /* Current tmpFunc file name */
68 char *symbolName=0; /* Current symbol name */
69 char *headerSymbol=0; /* Symbol for multiple inclusion protection */
70 bool createMacro = false; /* Should we create a define instead of a const? */
72 /* Error messages */
73 const char* cantOpen = "Can't open file '%s'";
74 const char* cantClose = "Can't close file '%s'";
75 const char* cantRemove = "Can't remove file '%s'";
76 const char* cantWrite = "Can't write to file '%s'";
77 const char* noOutputFilesAreNamed = "No output files are named";
78 const char* noHeaderFilesAreNamed = "No header files are named";
79 const char* cantMalloc = "Can't allocate memory for '%s'";
80 const char* cantSeek = "Can't seek in the file '%s'";
81 const char* cantDetermine = "Can't determine the file size of '%s'";
82 const char* cantRead = "Can't read from file %s";
83 const char* unknownOption = "Unknown option '%s'";
84 const char* tryHelp = "Try 'bin2c --help' for more information.\n";
85 const char* noSymbolName = "No symbol name is given";
86 const char* notValidId = "'%s' is not a valid identifier";
87 const char* symbolNameGiven = "Symbol name is given twice";
89 /* Print a formatted error message */
90 static void vprintfError(const char *format, va_list args)
92 fprintf(stderr, "bin2c: ");
93 vfprintf(stderr, format, args);
94 if (errno) {
95 fprintf(stderr, ": ");
96 perror("");
97 errno = 0;
98 } else {
99 fprintf(stderr, "\n");
103 static void printfError(const char *format, ...)
105 va_list args;
107 va_start(args, format);
108 vprintfError(format, args);
109 va_end(args);
112 /* Panic */
113 static void panic()
115 /* Close and remove the output file if it's open */
116 if (outputFile) {
117 if (fclose(outputFile)) {
118 printfError(cantClose, outputFileName);
121 if (remove(outputFileName)) {
122 printfError(cantRemove, outputFileName);
126 /* Close and remove the header file if it's open */
127 if (headerFile) {
128 if (fclose(headerFile)) {
129 printfError(cantClose, headerFileName);
132 if (remove(headerFileName)) {
133 printfError(cantRemove, headerFileName);
137 /* Close and remove the header file if it's open */
138 if (tmpFuncFile) {
139 if (fclose(tmpFuncFile)) {
140 printfError(cantClose, tmpFuncFileName);
143 if (remove(tmpFuncFileName)) {
144 printfError(cantRemove, tmpFuncFileName);
148 /* Exit with an error code */
149 exit(EXIT_FAILURE);
152 /* Check a contidion and panic if it's false */
153 static void check(bool condition, const char *format, ...)
155 va_list args;
157 if (!condition) {
158 va_start(args, format);
159 vprintfError(format, args);
160 va_end(args);
161 panic();
165 /* Write a formatted string to the output file and check for errors */
166 static void output(const char *format, ...)
168 va_list args;
170 /* Try to write to the file */
171 va_start(args, format);
172 vfprintf(outputFile, format, args);
173 va_end(args);
175 /* Check for errors */
176 check(!ferror(outputFile), cantWrite, outputFileName);
179 /* Write a formatted string to the header file and check for errors */
180 static void header(const char *format, ...)
182 va_list args;
184 /* Try to write to the file */
185 va_start(args, format);
186 vfprintf(headerFile, format, args);
187 va_end(args);
189 /* Check for errors */
190 check(!ferror(headerFile), cantWrite, headerFileName);
193 /* Write a formatted string to the tmp file and check for errors */
194 static void tmpFunc(const char *format, ...)
196 va_list args;
198 /* Try to write to the file */
199 va_start(args, format);
200 vfprintf(tmpFuncFile, format, args);
201 va_end(args);
203 /* Check for errors */
204 check(!ferror(tmpFuncFile), cantWrite, tmpFuncFileName);
207 /* Allocate a valid C identifier from a file name */
208 static char *fileNameToSymbol(const char *fileName)
210 char *name;
211 int i;
213 name = malloc(strlen(fileName) + 1);
214 check(name != 0, cantMalloc, "the symbol name");
216 /* Copy the file name to symbolName */
217 strcpy(name, fileName);
219 /* Replace every non alphanumerical character with '_' */
220 for (i = 0; name[i]; ++i) {
221 if (!((name[i] >= 'a' && name[i] <= 'z') ||
222 (name[i] >= 'A' && name[i] <= 'Z') ||
223 (name[i] >= '0' && name[i] <= '9'))) {
224 name[i] = '_';
228 /* Replace the first character with '_' if it's a digit */
229 if (name[0] >= '0' && name[0] <= '9') {
230 name[0] = '_';
233 return name;
236 int isdir(const char * path)
238 int bOK = 0;
239 #ifndef _MSC_VER
240 struct stat buf;
241 if (path == NULL) return 0;
242 if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) bOK=1;
243 #else
244 wchar_t *wcpath = to_wide_string((char*)path);
245 if (wcpath == NULL) return FALSE;
246 bOK = isdirW(wcpath);
247 FREE(wcpath);
248 #endif
249 return bOK;
252 /* Process an input file */
253 static int processFile(const char *fileName, long int from, long int to)
255 bool symbolNameAllocated = false; /* Did we allocate the symbolName? */
256 long int i, j; /* Indexes for various purposes */
257 FILE *inputFile; /* Input file stream */
258 int byte; /* Byte read from the input */
259 long int fsize=0;
261 if(isdir(fileName)) return 0;
263 /* Be sure that the output file is open */
264 check(outputFile != 0, noOutputFilesAreNamed);
266 /* Write the comment */
267 output("\n/* Contents of file %s */\n", fileName);
268 if (headerFile) {
269 header("\n/* Contents of file %s */\n", fileName);
272 /* Make up a suitable symbolName if we don't have one */
273 if (!symbolName) {
274 symbolName = fileNameToSymbol(fileName);
275 symbolNameAllocated = true;
278 /* Open the input file */
279 inputFile = fopen(fileName, "rb");
280 check(inputFile != 0, cantOpen, fileName);
282 /* If to == -1, set it to the last byte of the file */
283 if (to == -1) {
284 check(!fseek(inputFile, 0, SEEK_END), cantSeek, fileName);
285 to = ftell(inputFile);
286 check(to >= 0, cantDetermine, fileName);
287 --to;
290 assert(from <= to - 1);
292 /* Position the file to "from" */
293 check(!fseek(inputFile, from, SEEK_SET), cantSeek, fileName);
295 fsize = to - from + 1;
297 /* Output the size definition */
298 if (headerFile) {
299 if (createMacro) {
300 header(sizeMacroDefinition, symbolName, fsize);
301 } else {
302 header("extern "sizeDefinition, symbolName, fsize);
303 output(sizeDefinition, symbolName, fsize);
305 } else {
306 if (createMacro) {
307 output(sizeMacroDefinition, symbolName, fsize);
308 } else {
309 output(sizeDefinition, symbolName, fsize);
313 if (tmpFuncFile) {
314 tmpFunc("\t{\"/_attach_/%s\", bin2c_%s, %d},\n", fileName, symbolName, fsize);
316 /* Output the definition */
317 output("%s bin2c_%s[%d] = {\n", typeName, symbolName, fsize);
318 if (headerFile) {
319 header("extern %s *bin2c_%s;\n", typeName, symbolName, fsize);
322 /* Output the contents */
323 j = 1;
324 for (i = from; i <= to; ++i) {
325 /* Read a byte from the input file */
326 byte = fgetc(inputFile);
327 check(byte != EOF, cantRead, fileName);
329 /* Output the indentation if it's the first byte of a line */
330 if (j == 1) {
331 output(indentString);
334 /* Output the actual byte */
335 if (i == to) {
336 /* Output the last byte */
337 output(outputFormatEOF, byte);
338 } else if (j == bytesPerLine) {
339 /* Output the last byte of a line */
340 output(outputFormatEOL, byte);
341 } else {
342 /* Output a normal byte */
343 output(outputFormat, byte);
346 /* Next byte */
347 ++j;
348 if (j > bytesPerLine) {
349 j = 1;
353 /* Output the end of definition */
354 output("};\n");
356 /* Free the symbol name if it was allocated by us */
357 if (symbolNameAllocated) {
358 free(symbolName);
361 /* Clear the symbol name */
362 symbolName = 0;
363 return 1;
366 /* Unknown option error */
367 static void handleUnknownOption(const char *s)
369 printfError(unknownOption, s);
370 fprintf(stderr, tryHelp);
371 panic();
374 /* Open an output file */
375 static void openOutputFile(const char *fileName)
377 /* Be sure that a file name is given */
378 if (!fileName) {
379 printfError(noOutputFilesAreNamed);
380 fprintf(stderr, tryHelp);
381 panic();
384 /* Close previous output file if any */
385 if (outputFile) {
386 check(!fclose(outputFile), cantClose, outputFileName);
389 /* Open the new output file */
390 outputFile = fopen(fileName, "w");
391 check(outputFile != 0, cantOpen, outputFileName);
392 outputFileName = fileName;
394 output("/* Generated by bin2c, do not edit manually */\n");
397 /* Open a header file */
398 static void openHeaderFile(const char *fileName)
400 /* Be sure that a file name is given */
401 if (!fileName) {
402 printfError(noHeaderFilesAreNamed);
403 fprintf(stderr, tryHelp);
404 panic();
407 /* Close previous header file if any */
408 if (headerFile) {
409 header("\n#endif /* __%s_included */\n", headerSymbol);
410 free(headerSymbol);
411 headerSymbol = 0;
412 check(!fclose(headerFile), cantClose, headerFileName);
415 /* Open the new header file */
416 headerFile = fopen(fileName, "w");
417 check(headerFile != 0, cantOpen, headerFileName);
418 headerFileName = fileName;
419 headerSymbol = fileNameToSymbol(fileName);
421 header("/* Generated by bin2c, do not edit manually */\n");
422 header("#ifndef __%s_included\n", headerSymbol);
423 header("#define __%s_included\n", headerSymbol);
426 typedef void writeFileFunc(const char *format, ...);
428 void writeAttchmentStruct(writeFileFunc *writeFunc){
429 (*writeFunc)("\ntypedef struct {\n");
430 (*writeFunc)("\tconst char *file_name;\n");
431 (*writeFunc)("\tconst unsigned char *sym_name;\n");
432 (*writeFunc)("\tlong size;\n");
433 (*writeFunc)("} bin2c_filesAttached_st;\n");
436 /* Open a header file */
437 static void openFuncFile(const char *fileName)
439 static char fnBuf[1024];
440 /* Be sure that a file name is given */
441 if (!fileName) {
442 printfError(noHeaderFilesAreNamed);
443 fprintf(stderr, tryHelp);
444 panic();
447 /* Close previous header file if any */
448 if (tmpFuncFile) {
449 tmpFunc("\n};\n");
450 check(!fclose(tmpFuncFile), cantClose, tmpFuncFileName);
453 snprintf(fnBuf, sizeof(fnBuf), "%s.tmp", fileName);
455 /* Open the new header file */
456 tmpFuncFile = fopen(fnBuf, "w");
457 check(tmpFuncFile != 0, cantOpen, fnBuf);
458 tmpFuncFileName = fnBuf;
460 tmpFunc("\n/* Generated by bin2c, do not edit manually */\n");
461 writeAttchmentStruct(&tmpFunc);
462 tmpFunc("const bin2c_filesAttached_st bin2c_filesAttached[] = {\n");
465 /* Set the symbol name for next file */
466 static void setSymbolName(char *name)
468 int i;
470 if (symbolName) {
471 printfError(symbolNameGiven);
472 fprintf(stderr, tryHelp);
473 panic();
476 /* Be sure that a symbol name is given */
477 if (!name) {
478 printfError(noSymbolName);
479 fprintf(stderr, tryHelp);
480 panic();
483 /* Check if the symbol is a valid C identifier */
484 check((name[0] >= 'a' && name[0] <='z') ||
485 (name[0] >= 'A' && name[0] <='Z') ||
486 (name[0] == '_'), notValidId, name);
488 for (i = 1; name[i]; ++i) {
489 check((name[i] >= 'a' && name[i] <='z') ||
490 (name[i] >= 'A' && name[i] <='Z') ||
491 (name[i] >= '0' && name[i] <='9') ||
492 (name[i] == '_'), notValidId, name);
495 /* Set the symbol name */
496 symbolName = name;
499 void concatenate(const char *dest, const char *src){
500 int i,ch;
501 FILE *fpdest=fopen(dest,"a");
502 FILE *fpsrc=fopen(src,"r");
503 while((ch=getc(fpsrc))!=EOF) putc(ch,fpdest);
506 /* Main function */
507 int main(int argc, char **argv)
509 int i; /* Index to process commandline arguments */
510 int ipf = 0; /*total files processed*/
512 /* Scan for a -h or --help option */
513 for (i = 1; i < argc; ++i) {
514 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
515 /* Print command line arguments help and exit immediately */
516 printf("%s", commandLineHelp);
517 return EXIT_SUCCESS;
521 /* Scan for a -v or --version option */
522 for (i = 1; i < argc; ++i) {
523 if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
524 /* Print version information and exit immediately */
525 printf("%s", versionInfo);
526 return EXIT_SUCCESS;
530 /* Process command line arguments */
531 for (i = 1; i < argc; ++i) {
532 /* Check if it's an option or file name */
533 if (argv[i][0] == '-') {
534 /* Process the option */
535 switch (argv[i][1]) {
536 case '-':
537 /* Long options */
538 if (!strcmp(argv[i], "--output")) {
539 /* Name an output file */
540 openOutputFile(argv[i+1]);
541 openFuncFile(argv[i+1]);
542 ++i;
543 } else if (!strcmp(argv[i], "--header")) {
544 /* Name a header file */
545 openHeaderFile(argv[i+1]);
546 ++i;
547 } else if (!strcmp(argv[i], "--macro")) {
548 /* Create a macro for the size definition */
549 createMacro = true;
550 } else if (!strcmp(argv[i], "--name")) {
551 /* Name the symbol */
552 setSymbolName(argv[i+1]);
553 ++i;
554 } else {
555 /* Unknown option */
556 handleUnknownOption(argv[i]);
558 break;
559 case 'o':
560 /* Name an output file */
561 openOutputFile(argv[i+1]);
562 openFuncFile(argv[i+1]);
563 ++i;
564 break;
565 case 'd':
566 /* Name a header file */
567 openHeaderFile(argv[i+1]);
568 ++i;
569 break;
570 case 'm':
571 /* Create a macro for the size definition */
572 createMacro = true;
573 break;
574 case 'n':
575 /* Name the symbol */
576 setSymbolName(argv[i+1]);
577 ++i;
578 break;
579 default:
580 /* Unknown option */
581 handleUnknownOption(argv[i]);
583 } else {
584 /* Process the file */
585 if(processFile(argv[i], 0, -1)) ipf++;
589 /* Close any remaining output files */
590 if (headerFile) {
591 writeAttchmentStruct(&header);
592 header("extern const bin2c_filesAttached_st bin2c_filesAttached[%d];\n", ipf);
594 header("\n#endif /* __%s_included */\n", headerSymbol);
595 free(headerSymbol);
596 headerSymbol = 0;
597 check(!fclose(headerFile), cantClose, headerFileName);
600 if (tmpFuncFile) {
601 tmpFunc("};\n");
602 check(!fclose(tmpFuncFile), cantClose, tmpFuncFileName);
605 if (outputFile) {
606 check(!fclose(outputFile), cantClose, outputFileName);
609 if (tmpFuncFile && outputFile) {
610 concatenate(outputFileName, tmpFuncFileName);
611 remove(tmpFuncFileName);
614 return EXIT_SUCCESS;