/*
* Ficl softcore generator.
* Generates both uncompressed and Lempel-Ziv compressed versions.
* Strips blank lines, strips full-line comments, collapses whitespace.
* Chops, blends, dices, makes julienne fries.
*
* Contributed by Larry Hastings, larry@hastings.org
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "ficl.h"
#ifndef SOFTCORE_OUT
#define SOFTCORE_OUT "softcore.c"
#endif
extern size_t
lz4_compress(void *s_start, void *d_start, size_t s_len, size_t d_len, int n);
void
fprintDataAsHex(FILE *f, unsigned char *data, int length)
{
int i;
while (length) {
fprintf(f, "\t");
for (i = 0; (i < 8) && length; i++) {
char buf[16];
/*
* if you don't do this little stuff, you get ugly
* sign-extended 0xFFFFFF6b crap.
*/
sprintf(buf, "%08x", (unsigned int)*data++);
fprintf(f, "0x%s, ", buf + 6);
length--;
}
fprintf(f, "\n");
}
}
void
fprintDataAsQuotedString(FILE *f, char *data)
{
int lineIsBlank = 1; /* true */
while (*data) {
if (*data == '\n') {
if (!lineIsBlank)
fprintf(f, "\\n\"\n");
lineIsBlank = 1; /* true */
} else {
if (lineIsBlank) {
fputc('\t', f);
fputc('"', f);
lineIsBlank = 0; /* false */
}
if (*data == '"')
fprintf(f, "\\\"");
else if (*data == '\\')
fprintf(f, "\\\\");
else
fputc(*data, f);
}
data++;
}
if (!lineIsBlank)
fprintf(f, "\"");
}
int
main(int argc, char *argv[])
{
char *uncompressed = (char *)malloc(128 * 1024);
unsigned char *compressed = malloc(128 * 1024);
char *trace = uncompressed;
int i;
size_t compressedSize = 128 * 1024;
size_t uncompressedSize;
char *src, *dst;
FILE *f;
time_t currentTimeT;
struct tm *currentTime;
char cleverTime[32];
time(&currentTimeT);
currentTime = localtime(&currentTimeT);
strftime(cleverTime, sizeof (cleverTime),
"%Y/%m/%d %H:%M:%S", currentTime);
*trace++ = ' ';
for (i = 1; i < argc; i++) {
int size;
/*
* This ensures there's always whitespace space between files.
* It *also* ensures that src[-1] is always safe in comment
* detection code below. (Any leading whitespace will be
* thrown away in a later pass.)
* --lch
*/
*trace++ = ' ';
f = fopen(argv[i], "rb");
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
fread(trace, 1, size, f);
fclose(f);
trace += size;
}
*trace = 0;
#define IS_EOL(x) ((*x == '\n') || (*x == '\r'))
#define IS_EOL_COMMENT(x) \
(((x[0] == '\\') && isspace(x[1])) || \
((x[0] == '/') && (x[1] == '/') && isspace(x[2])))
#define IS_BLOCK_COMMENT(x) \
((x[0] == '(') && isspace(x[1]) && isspace(x[-1]))
src = dst = uncompressed;
while (*src) {
/* ignore leading whitespace, or entirely blank lines */
while (isspace(*src))
src++;
/* if the line is commented out */
if (IS_EOL_COMMENT(src)) {
/* throw away this entire line */
while (*src && !IS_EOL(src))
src++;
continue;
}
/*
* This is where we'd throw away mid-line comments, but
* that's simply unsafe. Things like
* start-prefixes
* : \ postpone \ ;
* : ( postpone ( ;
* get broken that way.
* --lch
*/
while (*src && !IS_EOL(src)) {
*dst++ = *src++;
}
/* strip trailing whitespace */
dst--;
while (isspace(*dst))
dst--;
dst++;
/* and end the line */
*dst++ = '\n';
}
*dst = 0;
/*
* now make a second pass to collapse all contiguous whitespace
* to a single space.
*/
src = dst = uncompressed;
while (*src) {
*dst++ = *src;
if (!isspace(*src))
src++;
else {
while (isspace(*src))
src++;
}
}
*dst = 0;
f = fopen(SOFTCORE_OUT, "wt");
if (f == NULL) {
printf("couldn't open " SOFTCORE_OUT
" for writing! giving up.\n");
exit(-1);
}
fprintf(f,
"/*\n"
"** Ficl softcore\n"
"** both uncompressed and LZ4 compressed versions.\n"
"**\n"
"** Generated %s\n"
"**/\n"
"\n"
"#include \"ficl.h\"\n"
"\n"
"\n", cleverTime);
uncompressedSize = dst - uncompressed;
compressedSize = lz4_compress(uncompressed, compressed,
uncompressedSize, compressedSize, 0);
fprintf(f, "static size_t ficlSoftcoreUncompressedSize = %d; "
"/* not including trailing null */\n", uncompressedSize);
fprintf(f, "\n");
fprintf(f, "#if !FICL_WANT_LZ4_SOFTCORE\n");
fprintf(f, "\n");
fprintf(f, "static char ficlSoftcoreUncompressed[] =\n");
fprintDataAsQuotedString(f, uncompressed);
fprintf(f, ";\n");
fprintf(f, "\n");
fprintf(f, "#else /* !FICL_WANT_LZ4_SOFTCORE */\n");
fprintf(f, "\n");
fprintf(f, "extern int lz4_decompress(void *, void *, size_t, "
"size_t, int);\n\n");
fprintf(f, "static unsigned char ficlSoftcoreCompressed[%d] = "
"{\n", compressedSize);
fprintDataAsHex(f, compressed, compressedSize);
fprintf(f, "\t};\n");
fprintf(f, "\n");
fprintf(f, "#endif /* !FICL_WANT_LZ4_SOFTCORE */\n");
fprintf(f,
"\n"
"\n"
"void ficlSystemCompileSoftCore(ficlSystem *system)\n"
"{\n"
" ficlVm *vm = system->vmList;\n"
" int returnValue;\n"
" ficlCell oldSourceID = vm->sourceId;\n"
" ficlString s;\n"
"#if FICL_WANT_LZ4_SOFTCORE\n"
" char *ficlSoftcoreUncompressed = malloc(ficlSoftcoreUncompressedSize+1);\n"
" returnValue = lz4_decompress(ficlSoftcoreCompressed, "
"ficlSoftcoreUncompressed, sizeof(ficlSoftcoreCompressed), "
"ficlSoftcoreUncompressedSize+1, 0);\n"
" FICL_VM_ASSERT(vm, returnValue == 0);\n"
"#endif /* FICL_WANT_LZ4_SOFTCORE */\n"
" vm->sourceId.i = -1;\n"
" FICL_STRING_SET_POINTER(s, (char *)(ficlSoftcoreUncompressed));\n"
" FICL_STRING_SET_LENGTH(s, ficlSoftcoreUncompressedSize);\n"
" returnValue = ficlVmExecuteString(vm, s);\n"
" vm->sourceId = oldSourceID;\n"
"#if FICL_WANT_LZ4_SOFTCORE\n"
" free(ficlSoftcoreUncompressed);\n"
"#endif /* FICL_WANT_LZ4_SOFTCORE */\n"
" FICL_VM_ASSERT(vm, returnValue != FICL_VM_STATUS_ERROR_EXIT);\n"
" return;\n"
"}\n\n"
"/* end-of-file */\n");
free(uncompressed);
free(compressed);
return (0);
}