14 struct item *suffix_of;
18 static void free_items(struct item *first) {
21 struct item *n = first->next;
31 static void find_suffixes(struct item *first) {
34 for (i = first; i; i = i->next) {
37 for (j = first; j; j = j->next) {
44 if (i->size > j->size)
47 if (i->size == j->size && !right)
50 if (memcmp(i->text, j->text+j->size-i->size, i->size) != 0)
59 static void fill_idx(struct item *first) {
63 for (i = first; i; i = i->next) {
71 for (i = first; i; i = i->next) {
77 for (p = i->suffix_of; p->suffix_of; p = p->suffix_of)
80 assert(i->size <= p->size);
81 assert(memcmp(i->text, p->text + p->size - i->size, i->size) == 0);
83 i->idx = p->idx + p->size - i->size;
87 static void dump_string(FILE *out, struct item *i) {
92 for (t = i->text; t < i->text+i->size; t++) {
104 fputs("\\n\"\n\t\"", out);
125 if (*t >= 32 && *t < 127)
128 fprintf(out, "\\x%02x", *t);
136 static void dump_text(FILE *out, struct item *first) {
139 for (i = first; i; i = i->next) {
142 fwrite(i->cnt, 1, i->cntl, out);
144 fprintf(out, "((const char*) %u)", i->idx);
148 static void dump_pool(FILE *out, struct item *first) {
150 int saved_rel=-1, saved_bytes=0, saved_strings=0;
152 for (i = first; i; i = i->next) {
157 saved_bytes += i->size;
161 fprintf(out, "/* Saved %i relocations, saved %i strings (%i b) due to suffix compression. */\n", saved_rel, saved_strings, saved_bytes);
163 fputs("static const char _strpool_[] =", out);
165 for (i = first; i; i = i->next) {
168 fputs("\n\t/*** Suppressed due to suffix: ", out);
180 static char *append(char *r, size_t *rl, char **c, size_t n) {
182 r = realloc(r, *rl + n);
187 memcpy(r + *rl, *c, n);
195 static int parse_hex_digit(char c) {
197 if (c >= '0' && c <= '9')
198 return c - '0' + 0x0;
200 if (c >= 'a' && c <= 'f')
201 return c - 'a' + 0xA;
203 if (c >= 'A' && c <= 'F')
204 return c - 'A' + 0xA;
209 static int parse_hex(const char *t, char *r) {
213 if ((a = parse_hex_digit(t[0])) < 0)
217 if ((b = parse_hex_digit(t[1])) < 0)
227 static int parse_oct_digit(char c) {
229 if (c >= '0' && c <= '7')
235 static int parse_oct(const char *t, char *r) {
236 int a, b = 0, c = 0, m;
239 if ((a = parse_oct_digit(t[0])) < 0)
244 if ((b = parse_oct_digit(t[1])) < 0)
251 if ((c = parse_oct_digit(t[2])) < 0)
259 m = (a << 6) | (b << 3) | c;
269 static int parse(FILE *in, const char *fname, struct item **rfirst, char **remain, size_t *remain_size) {
278 } state = STATE_TEXT;
284 struct item *first = NULL, *last = NULL;
286 unsigned pool_started_line = 0;
296 if (!(fgets(t, sizeof(t), in))) {
301 fprintf(stderr, "Failed to read: %s\n", strerror(errno));
311 /* fprintf(stderr, "enabled %i, state %i, cnt %i, remaining string is: %s", enabled, state, !!cnt, c); */
317 if (!strncmp(c, "/*", 2)) {
318 state = STATE_COMMENT_C;
319 r = append(r, &rl, &c, 2);
320 } else if (!strncmp(c, "//", 2)) {
321 state = STATE_COMMENT_CPP;
322 r = append(r, &rl, &c, 2);
323 } else if (*c == '"') {
324 state = STATE_STRING;
335 r = append(r, &rl, &c, 1);
336 } else if (*c == '\'') {
338 r = append(r, &rl, &c, 1);
342 r = append(r, &rl, &c, 1);
346 case STATE_COMMENT_C:
348 if (!strncmp(c, "*/", 2)) {
350 r = append(r, &rl, &c, 2);
351 } else if (!strncmp(c, "%STRINGPOOLSTART%", 17)) {
353 pool_started_line = nline;
354 r = append(r, &rl, &c, 17);
355 } else if (!strncmp(c, "%STRINGPOOLSTOP%", 16)) {
357 r = append(r, &rl, &c, 16);
361 r = append(r, &rl, &c, 1);
365 case STATE_COMMENT_CPP:
367 if (*c == '\n' || *c == '\r') {
369 r = append(r, &rl, &c, 1);
370 } else if (!strncmp(c, "%STRINGPOOLSTART%", 17)) {
372 pool_started_line = nline;
373 r = append(r, &rl, &c, 17);
374 } else if (!strncmp(c, "%STRINGPOOLSTOP%", 16)) {
376 r = append(r, &rl, &c, 16);
377 } else if (*c == 0) {
381 r = append(r, &rl, &c, 1);
388 if ((*c == '\'' && state == STATE_CHAR) || (*c == '"' && state == STATE_STRING)) {
390 if (state == STATE_STRING && enabled) {
392 i = malloc(sizeof(struct item));
421 r = append(r, &rl, &c, 1);
425 } else if (*c == '\\') {
461 if ((k = parse_hex(c+2, &d)) < 0) {
462 fprintf(stderr, "%s:%u: Parse failure: invalid hexadecimal escape sequence.\n", fname, nline);
477 if ((k = parse_oct(c+1, &d)) < 0) {
478 fprintf(stderr, "%s:%u: Parse failure: invalid octal escape sequence.\n", fname, nline);
485 fprintf(stderr, "%s:%u: Parse failure: invalid escape sequence.\n", fname, nline);
489 if (state == STATE_STRING && enabled) {
491 r = append(r, &rl, &x, 1);
494 r = append(r, &rl, &c, l);
495 } else if (*c == 0) {
496 fprintf(stderr, "%s:%u: Parse failure: multiline strings suck.\n", fname, nline);
499 r = append(r, &rl, &c, 1);
507 fprintf(stderr, "%s:%u: Parse failure: missing %%STRINGPOOLSTOP%%\n", fname, pool_started_line);
511 if (state != STATE_TEXT) {
512 fprintf(stderr, "%s:%u: Parse failure: unexpected EOF.\n", fname, nline);
534 static int process(FILE *in, FILE *out, const char*ifname) {
536 struct item *first = NULL;
538 size_t remain_size = 0;
540 if (parse(in, ifname, &first, &remain, &remain_size) < 0)
544 fwrite(remain, 1, remain_size, out);
546 find_suffixes(first);
549 dump_pool(out, first);
556 "#define _P(x) (_strpool_ + ((x) - (const char*) 0))\n"
559 dump_text(out, first);
560 fwrite(remain, 1, remain_size, out);
570 int main(int argc, char *argv[]) {
572 FILE *in = NULL, *out = NULL;
575 if (!(in = fopen(argv[1], "r"))) {
576 fprintf(stderr, "Failed to open '%s': %s\n", argv[1], strerror(errno));
584 if (!(out = fopen(argv[2], "2"))) {
585 fprintf(stderr, "Failed to open '%s': %s\n", argv[2], strerror(errno));
591 if (process(in, out, argc > 1 ? argv[1] : NULL) < 0)