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));
449 r = append(r, &rl, &c, 1);
453 } else if (*c == '\\') {
489 if ((k = parse_hex(c+2, &d)) < 0) {
490 fprintf(stderr, "%s:%u: Parse failure: invalid hexadecimal escape sequence.\n", fname, nline);
505 if ((k = parse_oct(c+1, &d)) < 0) {
506 fprintf(stderr, "%s:%u: Parse failure: invalid octal escape sequence.\n", fname, nline);
513 fprintf(stderr, "%s:%u: Parse failure: invalid escape sequence.\n", fname, nline);
517 if (state == STATE_STRING && enabled) {
519 r = append(r, &rl, &x, 1);
522 r = append(r, &rl, &c, l);
523 } else if (*c == 0) {
524 fprintf(stderr, "%s:%u: Parse failure: multiline strings suck.\n", fname, nline);
527 r = append(r, &rl, &c, 1);
535 fprintf(stderr, "%s:%u: Parse failure: missing %%STRINGPOOLSTOP%%\n", fname, pool_started_line);
539 if (state != STATE_TEXT) {
540 fprintf(stderr, "%s:%u: Parse failure: unexpected EOF.\n", fname, nline);
562 static int process(FILE *in, FILE *out, const char*ifname) {
564 struct item *first = NULL;
566 size_t remain_size = 0;
568 if (parse(in, ifname, &first, &remain, &remain_size) < 0)
572 fwrite(remain, 1, remain_size, out);
574 find_suffixes(first);
577 dump_pool(out, first);
584 "#define _P(x) (_strpool_ + ((x) - (const char*) 1))\n"
589 fprintf(out, "#line 1 \"%s\"\n", ifname);
591 dump_text(out, first);
592 fwrite(remain, 1, remain_size, out);
602 int main(int argc, char *argv[]) {
604 FILE *in = NULL, *out = NULL;
607 if (!(in = fopen(argv[1], "r"))) {
608 fprintf(stderr, "Failed to open '%s': %s\n", argv[1], strerror(errno));
615 if (!(out = fopen(argv[2], "w"))) {
616 fprintf(stderr, "Failed to open '%s': %s\n", argv[2], strerror(errno));
622 if (process(in, out, argc > 1 ? argv[1] : NULL) < 0)