1*afc2ba1dSToomas Soome /*
2*afc2ba1dSToomas Soome  * Ficl softcore generator.
3*afc2ba1dSToomas Soome  * Generates both uncompressed and Lempel-Ziv compressed versions.
4*afc2ba1dSToomas Soome  * Strips blank lines, strips full-line comments, collapses whitespace.
5*afc2ba1dSToomas Soome  * Chops, blends, dices, makes julienne fries.
6*afc2ba1dSToomas Soome  *
7*afc2ba1dSToomas Soome  * Contributed by Larry Hastings, larry@hastings.org
8*afc2ba1dSToomas Soome  */
9*afc2ba1dSToomas Soome #include <ctype.h>
10*afc2ba1dSToomas Soome #include <stdio.h>
11*afc2ba1dSToomas Soome #include <stdlib.h>
12*afc2ba1dSToomas Soome #include <time.h>
13*afc2ba1dSToomas Soome 
14*afc2ba1dSToomas Soome #include "ficl.h"
15*afc2ba1dSToomas Soome 
16*afc2ba1dSToomas Soome #ifndef SOFTCORE_OUT
17*afc2ba1dSToomas Soome #define	SOFTCORE_OUT	"softcore.c"
18*afc2ba1dSToomas Soome #endif
19*afc2ba1dSToomas Soome 
20*afc2ba1dSToomas Soome extern size_t
21*afc2ba1dSToomas Soome lz4_compress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n);
22*afc2ba1dSToomas Soome 
23*afc2ba1dSToomas Soome void
fprintDataAsHex(FILE * f,unsigned char * data,int length)24*afc2ba1dSToomas Soome fprintDataAsHex(FILE *f, unsigned char *data, int length)
25*afc2ba1dSToomas Soome {
26*afc2ba1dSToomas Soome 	int i;
27*afc2ba1dSToomas Soome 	while (length) {
28*afc2ba1dSToomas Soome 		fprintf(f, "\t");
29*afc2ba1dSToomas Soome 		for (i = 0; (i < 8) && length; i++) {
30*afc2ba1dSToomas Soome 			char buf[16];
31*afc2ba1dSToomas Soome 			/*
32*afc2ba1dSToomas Soome 			 * if you don't do this little stuff, you get ugly
33*afc2ba1dSToomas Soome 			 * sign-extended 0xFFFFFF6b crap.
34*afc2ba1dSToomas Soome 			 */
35*afc2ba1dSToomas Soome 			sprintf(buf, "%08x", (unsigned int)*data++);
36*afc2ba1dSToomas Soome 			fprintf(f, "0x%s, ", buf + 6);
37*afc2ba1dSToomas Soome 			length--;
38*afc2ba1dSToomas Soome 		}
39*afc2ba1dSToomas Soome 		fprintf(f, "\n");
40*afc2ba1dSToomas Soome 	}
41*afc2ba1dSToomas Soome }
42*afc2ba1dSToomas Soome 
43*afc2ba1dSToomas Soome void
fprintDataAsQuotedString(FILE * f,char * data)44*afc2ba1dSToomas Soome fprintDataAsQuotedString(FILE *f, char *data)
45*afc2ba1dSToomas Soome {
46*afc2ba1dSToomas Soome 	int lineIsBlank = 1; /* true */
47*afc2ba1dSToomas Soome 
48*afc2ba1dSToomas Soome 	while (*data) {
49*afc2ba1dSToomas Soome 		if (*data == '\n') {
50*afc2ba1dSToomas Soome 			if (!lineIsBlank)
51*afc2ba1dSToomas Soome 				fprintf(f, "\\n\"\n");
52*afc2ba1dSToomas Soome 			lineIsBlank = 1; /* true */
53*afc2ba1dSToomas Soome 		} else {
54*afc2ba1dSToomas Soome 			if (lineIsBlank) {
55*afc2ba1dSToomas Soome 				fputc('\t', f);
56*afc2ba1dSToomas Soome 				fputc('"', f);
57*afc2ba1dSToomas Soome 				lineIsBlank = 0; /* false */
58*afc2ba1dSToomas Soome 			}
59*afc2ba1dSToomas Soome 
60*afc2ba1dSToomas Soome 			if (*data == '"')
61*afc2ba1dSToomas Soome 				fprintf(f, "\\\"");
62*afc2ba1dSToomas Soome 			else if (*data == '\\')
63*afc2ba1dSToomas Soome 				fprintf(f, "\\\\");
64*afc2ba1dSToomas Soome 			else
65*afc2ba1dSToomas Soome 				fputc(*data, f);
66*afc2ba1dSToomas Soome 		}
67*afc2ba1dSToomas Soome 		data++;
68*afc2ba1dSToomas Soome 	}
69*afc2ba1dSToomas Soome 	if (!lineIsBlank)
70*afc2ba1dSToomas Soome 		fprintf(f, "\"");
71*afc2ba1dSToomas Soome }
72*afc2ba1dSToomas Soome 
73*afc2ba1dSToomas Soome int
main(int argc,char * argv[])74*afc2ba1dSToomas Soome main(int argc, char *argv[])
75*afc2ba1dSToomas Soome {
76*afc2ba1dSToomas Soome 	char *uncompressed = (char *)malloc(128 * 1024);
77*afc2ba1dSToomas Soome 	unsigned char *compressed = malloc(128 * 1024);
78*afc2ba1dSToomas Soome 	char *trace = uncompressed;
79*afc2ba1dSToomas Soome 	int i;
80*afc2ba1dSToomas Soome 	size_t compressedSize = 128 * 1024;
81*afc2ba1dSToomas Soome 	size_t uncompressedSize;
82*afc2ba1dSToomas Soome 	char *src, *dst;
83*afc2ba1dSToomas Soome 	FILE *f;
84*afc2ba1dSToomas Soome 	time_t currentTimeT;
85*afc2ba1dSToomas Soome 	struct tm *currentTime;
86*afc2ba1dSToomas Soome 	char cleverTime[32];
87*afc2ba1dSToomas Soome 
88*afc2ba1dSToomas Soome 	time(&currentTimeT);
89*afc2ba1dSToomas Soome 	currentTime = localtime(&currentTimeT);
90*afc2ba1dSToomas Soome 	strftime(cleverTime, sizeof (cleverTime),
91*afc2ba1dSToomas Soome 	    "%Y/%m/%d %H:%M:%S", currentTime);
92*afc2ba1dSToomas Soome 
93*afc2ba1dSToomas Soome 	*trace++ = ' ';
94*afc2ba1dSToomas Soome 
95*afc2ba1dSToomas Soome 	for (i = 1; i < argc; i++) {
96*afc2ba1dSToomas Soome 		int size;
97*afc2ba1dSToomas Soome 		/*
98*afc2ba1dSToomas Soome 		 * This ensures there's always whitespace space between files.
99*afc2ba1dSToomas Soome 		 * It *also* ensures that src[-1] is always safe in comment
100*afc2ba1dSToomas Soome 		 * detection code below.  (Any leading whitespace will be
101*afc2ba1dSToomas Soome 		 * thrown away in a later pass.)
102*afc2ba1dSToomas Soome 		 * --lch
103*afc2ba1dSToomas Soome 		 */
104*afc2ba1dSToomas Soome 		*trace++ = ' ';
105*afc2ba1dSToomas Soome 
106*afc2ba1dSToomas Soome 		f = fopen(argv[i], "rb");
107*afc2ba1dSToomas Soome 		fseek(f, 0, SEEK_END);
108*afc2ba1dSToomas Soome 		size = ftell(f);
109*afc2ba1dSToomas Soome 		fseek(f, 0, SEEK_SET);
110*afc2ba1dSToomas Soome 		fread(trace, 1, size, f);
111*afc2ba1dSToomas Soome 		fclose(f);
112*afc2ba1dSToomas Soome 		trace += size;
113*afc2ba1dSToomas Soome 	}
114*afc2ba1dSToomas Soome 	*trace = 0;
115*afc2ba1dSToomas Soome 
116*afc2ba1dSToomas Soome #define	IS_EOL(x)	((*x == '\n') || (*x == '\r'))
117*afc2ba1dSToomas Soome #define	IS_EOL_COMMENT(x)	\
118*afc2ba1dSToomas Soome 	(((x[0] == '\\') && isspace(x[1])) || \
119*afc2ba1dSToomas Soome 	((x[0] == '/') && (x[1] == '/') && isspace(x[2])))
120*afc2ba1dSToomas Soome #define	IS_BLOCK_COMMENT(x)	\
121*afc2ba1dSToomas Soome 	((x[0] == '(') && isspace(x[1]) && isspace(x[-1]))
122*afc2ba1dSToomas Soome 
123*afc2ba1dSToomas Soome 	src = dst = uncompressed;
124*afc2ba1dSToomas Soome 	while (*src) {
125*afc2ba1dSToomas Soome 		/* ignore leading whitespace, or entirely blank lines */
126*afc2ba1dSToomas Soome 		while (isspace(*src))
127*afc2ba1dSToomas Soome 			src++;
128*afc2ba1dSToomas Soome 		/* if the line is commented out */
129*afc2ba1dSToomas Soome 		if (IS_EOL_COMMENT(src)) {
130*afc2ba1dSToomas Soome 			/* throw away this entire line */
131*afc2ba1dSToomas Soome 			while (*src && !IS_EOL(src))
132*afc2ba1dSToomas Soome 				src++;
133*afc2ba1dSToomas Soome 			continue;
134*afc2ba1dSToomas Soome 		}
135*afc2ba1dSToomas Soome 		/*
136*afc2ba1dSToomas Soome 		 * This is where we'd throw away mid-line comments, but
137*afc2ba1dSToomas Soome 		 * that's simply unsafe.  Things like
138*afc2ba1dSToomas Soome 		 *	start-prefixes
139*afc2ba1dSToomas Soome 		 *	: \ postpone \ ;
140*afc2ba1dSToomas Soome 		 *	: ( postpone ( ;
141*afc2ba1dSToomas Soome 		 * get broken that way.
142*afc2ba1dSToomas Soome 		 * --lch
143*afc2ba1dSToomas Soome 		 */
144*afc2ba1dSToomas Soome 		while (*src && !IS_EOL(src)) {
145*afc2ba1dSToomas Soome 			*dst++ = *src++;
146*afc2ba1dSToomas Soome 		}
147*afc2ba1dSToomas Soome 
148*afc2ba1dSToomas Soome 		/* strip trailing whitespace */
149*afc2ba1dSToomas Soome 		dst--;
150*afc2ba1dSToomas Soome 		while (isspace(*dst))
151*afc2ba1dSToomas Soome 			dst--;
152*afc2ba1dSToomas Soome 		dst++;
153*afc2ba1dSToomas Soome 
154*afc2ba1dSToomas Soome 		/* and end the line */
155*afc2ba1dSToomas Soome 		*dst++ = '\n';
156*afc2ba1dSToomas Soome 	}
157*afc2ba1dSToomas Soome 
158*afc2ba1dSToomas Soome 	*dst = 0;
159*afc2ba1dSToomas Soome 
160*afc2ba1dSToomas Soome 	/*
161*afc2ba1dSToomas Soome 	 * now make a second pass to collapse all contiguous whitespace
162*afc2ba1dSToomas Soome 	 * to a single space.
163*afc2ba1dSToomas Soome 	 */
164*afc2ba1dSToomas Soome 	src = dst = uncompressed;
165*afc2ba1dSToomas Soome 	while (*src) {
166*afc2ba1dSToomas Soome 		*dst++ = *src;
167*afc2ba1dSToomas Soome 		if (!isspace(*src))
168*afc2ba1dSToomas Soome 			src++;
169*afc2ba1dSToomas Soome 		else {
170*afc2ba1dSToomas Soome 			while (isspace(*src))
171*afc2ba1dSToomas Soome 				src++;
172*afc2ba1dSToomas Soome 		}
173*afc2ba1dSToomas Soome 	}
174*afc2ba1dSToomas Soome 	*dst = 0;
175*afc2ba1dSToomas Soome 
176*afc2ba1dSToomas Soome 	f = fopen(SOFTCORE_OUT, "wt");
177*afc2ba1dSToomas Soome 	if (f == NULL) {
178*afc2ba1dSToomas Soome 		printf("couldn't open " SOFTCORE_OUT
179*afc2ba1dSToomas Soome 		    " for writing!  giving up.\n");
180*afc2ba1dSToomas Soome 		exit(-1);
181*afc2ba1dSToomas Soome 	}
182*afc2ba1dSToomas Soome 
183*afc2ba1dSToomas Soome 	fprintf(f,
184*afc2ba1dSToomas Soome "/*\n"
185*afc2ba1dSToomas Soome "** Ficl softcore\n"
186*afc2ba1dSToomas Soome "** both uncompressed and LZ4 compressed versions.\n"
187*afc2ba1dSToomas Soome "**\n"
188*afc2ba1dSToomas Soome "** Generated %s\n"
189*afc2ba1dSToomas Soome "**/\n"
190*afc2ba1dSToomas Soome "\n"
191*afc2ba1dSToomas Soome "#include \"ficl.h\"\n"
192*afc2ba1dSToomas Soome "\n"
193*afc2ba1dSToomas Soome "\n", cleverTime);
194*afc2ba1dSToomas Soome 
195*afc2ba1dSToomas Soome 	uncompressedSize = dst - uncompressed;
196*afc2ba1dSToomas Soome 	compressedSize = lz4_compress(uncompressed, compressed,
197*afc2ba1dSToomas Soome 	    uncompressedSize, compressedSize, 0);
198*afc2ba1dSToomas Soome 
199*afc2ba1dSToomas Soome 	fprintf(f, "static size_t ficlSoftcoreUncompressedSize = %d; "
200*afc2ba1dSToomas Soome 	    "/* not including trailing null */\n", uncompressedSize);
201*afc2ba1dSToomas Soome 	fprintf(f, "\n");
202*afc2ba1dSToomas Soome 	fprintf(f, "#if !FICL_WANT_LZ4_SOFTCORE\n");
203*afc2ba1dSToomas Soome 	fprintf(f, "\n");
204*afc2ba1dSToomas Soome 	fprintf(f, "static char ficlSoftcoreUncompressed[] =\n");
205*afc2ba1dSToomas Soome 	fprintDataAsQuotedString(f, uncompressed);
206*afc2ba1dSToomas Soome 	fprintf(f, ";\n");
207*afc2ba1dSToomas Soome 	fprintf(f, "\n");
208*afc2ba1dSToomas Soome 	fprintf(f, "#else /* !FICL_WANT_LZ4_SOFTCORE */\n");
209*afc2ba1dSToomas Soome 	fprintf(f, "\n");
210*afc2ba1dSToomas Soome 	fprintf(f, "extern int lz4_decompress(void *, void *, size_t, "
211*afc2ba1dSToomas Soome 	    "size_t, int);\n\n");
212*afc2ba1dSToomas Soome 	fprintf(f, "static unsigned char ficlSoftcoreCompressed[%d] = "
213*afc2ba1dSToomas Soome 	    "{\n", compressedSize);
214*afc2ba1dSToomas Soome 	fprintDataAsHex(f, compressed, compressedSize);
215*afc2ba1dSToomas Soome 	fprintf(f, "\t};\n");
216*afc2ba1dSToomas Soome 	fprintf(f, "\n");
217*afc2ba1dSToomas Soome 	fprintf(f, "#endif /* !FICL_WANT_LZ4_SOFTCORE */\n");
218*afc2ba1dSToomas Soome 	fprintf(f,
219*afc2ba1dSToomas Soome "\n"
220*afc2ba1dSToomas Soome "\n"
221*afc2ba1dSToomas Soome "void ficlSystemCompileSoftCore(ficlSystem *system)\n"
222*afc2ba1dSToomas Soome "{\n"
223*afc2ba1dSToomas Soome "    ficlVm *vm = system->vmList;\n"
224*afc2ba1dSToomas Soome "    int returnValue;\n"
225*afc2ba1dSToomas Soome "    ficlCell oldSourceID = vm->sourceId;\n"
226*afc2ba1dSToomas Soome "    ficlString s;\n"
227*afc2ba1dSToomas Soome "#if FICL_WANT_LZ4_SOFTCORE\n"
228*afc2ba1dSToomas Soome "    char *ficlSoftcoreUncompressed = malloc(ficlSoftcoreUncompressedSize+1);\n"
229*afc2ba1dSToomas Soome "    returnValue = lz4_decompress(ficlSoftcoreCompressed, "
230*afc2ba1dSToomas Soome "ficlSoftcoreUncompressed, sizeof(ficlSoftcoreCompressed), "
231*afc2ba1dSToomas Soome "ficlSoftcoreUncompressedSize+1, 0);\n"
232*afc2ba1dSToomas Soome "    FICL_VM_ASSERT(vm, returnValue == 0);\n"
233*afc2ba1dSToomas Soome "#endif /* FICL_WANT_LZ4_SOFTCORE */\n"
234*afc2ba1dSToomas Soome "    vm->sourceId.i = -1;\n"
235*afc2ba1dSToomas Soome "    FICL_STRING_SET_POINTER(s, (char *)(ficlSoftcoreUncompressed));\n"
236*afc2ba1dSToomas Soome "    FICL_STRING_SET_LENGTH(s, ficlSoftcoreUncompressedSize);\n"
237*afc2ba1dSToomas Soome "    returnValue = ficlVmExecuteString(vm, s);\n"
238*afc2ba1dSToomas Soome "    vm->sourceId = oldSourceID;\n"
239*afc2ba1dSToomas Soome "#if FICL_WANT_LZ4_SOFTCORE\n"
240*afc2ba1dSToomas Soome "    free(ficlSoftcoreUncompressed);\n"
241*afc2ba1dSToomas Soome "#endif /* FICL_WANT_LZ4_SOFTCORE */\n"
242*afc2ba1dSToomas Soome "    FICL_VM_ASSERT(vm, returnValue != FICL_VM_STATUS_ERROR_EXIT);\n"
243*afc2ba1dSToomas Soome "    return;\n"
244*afc2ba1dSToomas Soome "}\n\n"
245*afc2ba1dSToomas Soome "/* end-of-file */\n");
246*afc2ba1dSToomas Soome 	free(uncompressed);
247*afc2ba1dSToomas Soome 	free(compressed);
248*afc2ba1dSToomas Soome 	return (0);
249*afc2ba1dSToomas Soome }