1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
4 This file is part of libatasmart.
6 Copyright 2008 Lennart Poettering
8 libatasmart is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as
10 published by the Free Software Foundation, either version 2.1 of the
11 License, or (at your option) any later version.
13 libatasmart is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with libatasmart. If not, If not, see
20 <http://www.gnu.org/licenses/>.
30 #include <sys/types.h>
40 struct item *suffix_of;
44 static void free_items(struct item *first) {
47 struct item *n = first->next;
57 static void find_suffixes(struct item *first) {
60 for (i = first; i; i = i->next) {
63 for (j = first; j; j = j->next) {
70 if (i->size > j->size)
73 if (i->size == j->size && !right)
76 if (memcmp(i->text, j->text+j->size-i->size, i->size) != 0)
85 static void fill_idx(struct item *first) {
89 for (i = first; i; i = i->next) {
97 for (i = first; i; i = i->next) {
103 for (p = i->suffix_of; p->suffix_of; p = p->suffix_of)
106 assert(i->size <= p->size);
107 assert(memcmp(i->text, p->text + p->size - i->size, i->size) == 0);
109 i->idx = p->idx + p->size - i->size;
113 static void dump_string(FILE *out, struct item *i) {
116 fputs("\n\t\"", out);
118 for (t = i->text; t < i->text+i->size; t++) {
130 fputs("\\n\"\n\t\"", out);
151 if (*t >= 32 && *t < 127)
154 fprintf(out, "\\x%02x", *t);
162 static void dump_text(FILE *out, struct item *first) {
165 for (i = first; i; i = i->next) {
168 fwrite(i->cnt, 1, i->cntl, out);
170 /* We offset all indexes by one, to avoid clashes
171 * between index 0 and NULL */
172 fprintf(out, "((const char*) %u)", i->idx+1);
176 static void dump_pool(FILE *out, struct item *first) {
178 int saved_rel=-1, saved_bytes=0, saved_strings=0;
180 for (i = first; i; i = i->next) {
185 saved_bytes += i->size;
189 fprintf(out, "/* Saved %i relocations, saved %i strings (%i b) due to suffix compression. */\n", saved_rel, saved_strings, saved_bytes);
191 fputs("static const char _strpool_[] =", out);
193 for (i = first; i; i = i->next) {
196 fputs("\n\t/*** Suppressed due to suffix: ", out);
208 static char *append(char *r, size_t *rl, char **c, size_t n) {
210 r = realloc(r, *rl + n);
215 memcpy(r + *rl, *c, n);
223 static int parse_hex_digit(char c) {
225 if (c >= '0' && c <= '9')
226 return c - '0' + 0x0;
228 if (c >= 'a' && c <= 'f')
229 return c - 'a' + 0xA;
231 if (c >= 'A' && c <= 'F')
232 return c - 'A' + 0xA;
237 static int parse_hex(const char *t, char *r) {
241 if ((a = parse_hex_digit(t[0])) < 0)
245 if ((b = parse_hex_digit(t[1])) < 0)
255 static int parse_oct_digit(char c) {
257 if (c >= '0' && c <= '7')
263 static int parse_oct(const char *t, char *r) {
264 int a, b = 0, c = 0, m;
267 if ((a = parse_oct_digit(t[0])) < 0)
272 if ((b = parse_oct_digit(t[1])) < 0)
279 if ((c = parse_oct_digit(t[2])) < 0)
287 m = (a << 6) | (b << 3) | c;
297 static int parse(FILE *in, const char *fname, struct item **rfirst, char **remain, size_t *remain_size) {
306 } state = STATE_TEXT;
312 struct item *first = NULL, *last = NULL;
314 unsigned pool_started_line = 0;
324 if (!(fgets(t, sizeof(t), in))) {
329 fprintf(stderr, "Failed to read: %s\n", strerror(errno));
339 /* fprintf(stderr, "enabled %i, state %i, cnt %i, remaining string is: %s", enabled, state, !!cnt, c); */
345 if (!strncmp(c, "/*", 2)) {
346 state = STATE_COMMENT_C;
347 r = append(r, &rl, &c, 2);
348 } else if (!strncmp(c, "//", 2)) {
349 state = STATE_COMMENT_CPP;
350 r = append(r, &rl, &c, 2);
351 } else if (*c == '"') {
352 state = STATE_STRING;
363 r = append(r, &rl, &c, 1);
364 } else if (*c == '\'') {
366 r = append(r, &rl, &c, 1);
370 r = append(r, &rl, &c, 1);
374 case STATE_COMMENT_C:
376 if (!strncmp(c, "*/", 2)) {
378 r = append(r, &rl, &c, 2);
379 } else if (!strncmp(c, "%STRINGPOOLSTART%", 17)) {
381 pool_started_line = nline;
382 r = append(r, &rl, &c, 17);
383 } else if (!strncmp(c, "%STRINGPOOLSTOP%", 16)) {
385 r = append(r, &rl, &c, 16);
389 r = append(r, &rl, &c, 1);
393 case STATE_COMMENT_CPP:
395 if (*c == '\n' || *c == '\r') {
397 r = append(r, &rl, &c, 1);
398 } else if (!strncmp(c, "%STRINGPOOLSTART%", 17)) {
400 pool_started_line = nline;
401 r = append(r, &rl, &c, 17);
402 } else if (!strncmp(c, "%STRINGPOOLSTOP%", 16)) {
404 r = append(r, &rl, &c, 16);
405 } else if (*c == 0) {
409 r = append(r, &rl, &c, 1);
416 if ((*c == '\'' && state == STATE_CHAR) || (*c == '"' && state == STATE_STRING)) {
418 if (state == STATE_STRING && enabled) {
420 i = malloc(sizeof(struct item));
450 r = append(r, &rl, &c, 1);
454 } else if (*c == '\\') {
490 if ((k = parse_hex(c+2, &d)) < 0) {
491 fprintf(stderr, "%s:%u: Parse failure: invalid hexadecimal escape sequence.\n", fname, nline);
506 if ((k = parse_oct(c+1, &d)) < 0) {
507 fprintf(stderr, "%s:%u: Parse failure: invalid octal escape sequence.\n", fname, nline);
514 fprintf(stderr, "%s:%u: Parse failure: invalid escape sequence.\n", fname, nline);
518 if (state == STATE_STRING && enabled) {
520 r = append(r, &rl, &x, 1);
523 r = append(r, &rl, &c, l);
524 } else if (*c == 0) {
525 fprintf(stderr, "%s:%u: Parse failure: multiline strings suck.\n", fname, nline);
528 r = append(r, &rl, &c, 1);
536 fprintf(stderr, "%s:%u: Parse failure: missing %%STRINGPOOLSTOP%%\n", fname, pool_started_line);
540 if (state != STATE_TEXT) {
541 fprintf(stderr, "%s:%u: Parse failure: unexpected EOF.\n", fname, nline);
563 static int process(FILE *in, FILE *out, const char*ifname) {
565 struct item *first = NULL;
567 size_t remain_size = 0;
569 if (parse(in, ifname, &first, &remain, &remain_size) < 0)
573 fwrite(remain, 1, remain_size, out);
575 find_suffixes(first);
578 dump_pool(out, first);
585 "#define _P(x) (_strpool_ + ((x) - (const char*) 1))\n"
590 fprintf(out, "#line 1 \"%s\"\n", ifname);
592 dump_text(out, first);
593 fwrite(remain, 1, remain_size, out);
603 int main(int argc, char *argv[]) {
605 FILE *in = NULL, *out = NULL;
608 if (!(in = fopen(argv[1], "r"))) {
609 fprintf(stderr, "Failed to open '%s': %s\n", argv[1], strerror(errno));
616 if (!(out = fopen(argv[2], "w"))) {
617 fprintf(stderr, "Failed to open '%s': %s\n", argv[2], strerror(errno));
623 if (process(in, out, argc > 1 ? argv[1] : NULL) < 0)