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