#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>

/* since we're emitting C source, the comments containing the
	ASCII dump better not contain C comment markers! */
void fixasc(char *asc, int len) {
	int j;

	for(j=0; j<(len-1); j++) {
		/* slash-star or slash-slash become slash-dot */
		if(asc[j] == '/' && (asc[j+1] == '*' || asc[j+1] == '/'))
			asc[j+1] = '.';
		/* star-slash becomes dot-slash */
		else if(asc[j] == '*' && asc[j+1] == '/')
			asc[j] = '.';
	}
}

int main(int argc, char **argv) {
	int i, j, count = 0;
	char *p, asc[9];
	FILE *in;

	if(argc != 2) {
		fprintf(stderr,
				"#error usage: %s blobfile >blobfile.c 2>blobfile.h\n", argv[0]);
		exit(1);
	}

	if( !(in = fopen(argv[1], "rb")) ) {
		fprintf(stderr, "/* %s: %s */\n", argv[1], strerror(errno));
		exit(1);
	}

	printf("/* C source created by blob2c from input file %s */\n\n", argv[1]);
	fprintf(stderr,
			"/* C header created by blob2c from input file %s */\n\n", argv[1]);

	for(p = argv[1]; *p; p++)
		if(!isalnum(*p)) *p = '_';

	fprintf(stderr,
			"#ifndef %s_H\n"
			"#define %s_H\n\n",
			argv[1], argv[1]);

	/* start array definition */
	printf("unsigned char %s[] = {", argv[1]);

	asc[8] = '\0';

	/* read/process each input byte in loop, until EOF */
	while( (i = getc(in)) != EOF ) {
		if(count) putchar(',');

		if(count % 8 == 0) {
			if(count) {
				/* fix & print ASCII dump */
				fixasc(asc, 8);
				printf(" /* %s */", asc);
			}

			/* start next line */
			printf("\n\t/* %6d */  ", count);
		}

		/* store this byte of ASCII dump */
		asc[count % 8] = isprint(i) ? i : '.';

		/* print this byte of hex data */
		printf("0x%02x", i);

		count++;
	}

	/* fix ASCII dump for last line */
	i = count % 8;
	if(!i) i = 8;
	fixasc(asc, i);
	asc[i] = '\0';

	/* line it up with the previous lines */
	j = (8 - i) * 5;
	for(i=0; i<j; i++)
		putchar(' ');

	/* print it */
	printf("  /* %s */", asc);

	/* end of array definition */
	printf("\n}; /* %s */\n\n", argv[1]);

	/* array_len definition */
	printf("int %s_len = %d;\n", argv[1], count);

	/* check for read errors */
	i = 0;
	if(ferror(in)) {
		fprintf(stderr, "#error %s: %s\n", argv[1], strerror(errno));
		i = 1;
	}

	fclose(in);

	/* extern declarations to stderr */
	fprintf(stderr,
			"extern unsigned char %s[];\nextern int %s_len;\n",
			argv[1], argv[1]);

	fprintf(stderr, "\n#endif  /* %s_H */\n", argv[1]);

	return i;
}
