#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include struct entries { struct entry { char *in, *out; } *list; size_t n; }; static char *read_line(FILE *const f) { size_t n = 1; char *line = malloc(n); if (!line) { fprintf(stderr, "%s: malloc(3): %s\n", __func__, strerror(errno)); goto failure; } while (!feof(f)) { const int c = fgetc(f); if (c == EOF) { if (ferror(f)) { fprintf(stderr, "%s: fgetc(3): %s\n", __func__, strerror(errno)); goto failure; } break; } else if (c == '\n') break; char *const l = realloc(line, n + 1); if (!l) { fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno)); goto failure; } line = l; line[n++ - 1] = c; } line[n - 1] = '\0'; return line; failure: free(line); return NULL; } static int append_char(const char c, char **const str, size_t *const n) { char *const s = realloc(*str, *n + 1); if (!s) { fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno)); return -1; } *str = s; s[(*n)++] = c; return 0; } static int get_token(const char **const line, char **const out) { char *token = NULL; size_t n = 0; bool startquote = false, endquote = false, spaces = false; const char *l = *line; for (; *l; l++) { if (isspace(*l)) { if (endquote) continue; else if (!startquote) { if (token) spaces = true; continue; } else if (append_char(*l, &token, &n)) { fprintf(stderr, "%s: append_char failed\n", __func__); goto failure; } } else if (endquote) break; else if (*l == '\"') { if (!startquote) startquote = true; else endquote = true; } else if (spaces) break; else if (append_char(*l, &token, &n)) { fprintf(stderr, "%s: append_char failed\n", __func__); goto failure; } } if (token && append_char('\0', &token, &n)) { fprintf(stderr, "%s: append_char failed\n", __func__); goto failure; } *line = l; *out = token; return 0; failure: free(token); return -1; } static int append_entry(char *const in, char *const out, struct entries *const entries) { char *outdup = out; struct entry *const list = realloc(entries->list, (entries->n + 1) * sizeof *entries->list); if (!list) { fprintf(stderr, "%s: realloc(3): %s\n", __func__, strerror(errno)); return -1; } entries->list = list; if (!out && !(outdup = strdup(in))) { fprintf(stderr, "%s: strdup(3): %s\n", __func__, strerror(errno)); return -1; } entries->list[entries->n++] = (const struct entry) { .in = in, .out = outdup }; return 0; } static int process_line(struct entries *const entries, FILE *const f, bool *const done) { int ret = -1; char *const line = read_line(f); char *in = NULL, *out = NULL; if (!line) { fprintf(stderr, "%s: read_line failed\n", __func__); goto end; } else if (!*line) { *done = true; ret = 0; goto end; } const char *line_c = line; if (get_token(&line_c, &in)) { fprintf(stderr, "%s: get_token in failed\n", __func__); goto end; } else if (get_token(&line_c, &out)) { fprintf(stderr, "%s: get_token out failed\n", __func__); goto end; } else if (*line_c) { fprintf(stderr, "%s: unexpected extra %zu characters: %s\n", __func__, strlen(line_c), line_c); goto end; } else if (append_entry(in, out, entries)) { fprintf(stderr, "%s: append_entry failed\n", __func__); goto end; } ret = 0; end: if (ret) { free(in); free(out); } free(line); return ret; } static int process(struct entries *const entries, FILE *const f) { bool done = false; while (!done) if (process_line(entries, f, &done)) { fprintf(stderr, "%s: process_line failed\n", __func__); return -1; } return 0; } static int hexdump(FILE *const f) { if (fseek(f, 0, SEEK_SET)) { fprintf(stderr, "%s: fseek(3): %s\n", __func__, strerror(errno)); return -1; } puts("\t\t.buf = (const uint8_t[])\n" "\t\t{"); while (!feof(f)) { printf("\t\t\t"); for (size_t i = 0; i < 8; i++) { const int c = fgetc(f); if (c == EOF) break; printf("%#hhx", c); if (i + 1 < 8) printf(", "); } putchar('\n'); } puts("\t\t},"); return 0; } static int dump_entry(const struct entry *const e) { int ret = -1; FILE *const f = fopen(e->in, "rb"); if (!f) { fprintf(stderr, "%s: fopen(3) %s: %s\n", __func__, e->in, strerror(errno)); goto end; } puts("\t{"); printf("\t\t.pathname = \"%s\",\n", e->out); if (fseek(f, 0, SEEK_END)) { fprintf(stderr, "%s: fseek(3) %s: %s\n", __func__, e->in, strerror(errno)); goto end; } const long sz = ftell(f); if (sz < 0) { fprintf(stderr, "%s: ftell(3) %s: %s\n", __func__, e->in, strerror(errno)); goto end; } else if (!sz) puts("\t\t.buf = NULL,"); else if (hexdump(f)) { fprintf(stderr, "%s: hexdump %s failed\n", __func__, e->in); goto end; } printf("\t\t.sz = %ld\n", sz); puts("\t},"); ret = 0; end: if (f && fclose(f)) { fprintf(stderr, "%s: fclose(3) %s: %s\n", __func__, e->in, strerror(errno)); ret = -1; } return ret ; } static int dump(const struct entries *const entries) { puts("#include \n" "#include \n" "#include \n" "\n" "static const struct fswrap_entry entries[] = \n" "{"); for (size_t i = 0; i < entries->n; i++) { const struct entry *const e = &entries->list[i]; if (dump_entry(e)) { fprintf(stderr, "%s: dump_entry failed\n", __func__); return -1; } } puts("};\n" "\n" "static const struct fswrap fswrap = \n" "{\n" "\t.entries = entries,\n" "\t.n = sizeof entries / sizeof *entries\n" "};\n" "\n" "const struct fswrap *const fswrap_entries = &fswrap;"); return 0; } static void free_entries(struct entries *const entries) { for (size_t i = 0; i < entries->n; i++) { struct entry *const e = &entries->list[i]; free(e->in); free(e->out); } free(entries->list); } int main(int argc, char *argv[]) { struct entries e = {0}; int ret = EXIT_FAILURE; FILE *f = NULL; if (argc != 2) { fprintf(stderr, "%s FILE\n", *argv); goto end; } const char *const path = argv[1]; if (!(f = fopen(path, "rb"))) { fprintf(stderr, "%s: fopen(3) %s: %s\n", __func__, path, strerror(errno)); goto end; } else if (process(&e, f)) { fprintf(stderr, "%s: process failed\n", __func__); goto end; } else if (dump(&e)) { fprintf(stderr, "%s: dump failed\n", __func__); goto end; } ret = EXIT_SUCCESS; end: free_entries(&e); if (f && fclose(f)) { fprintf(stderr, "%s: fclose(3): %s\n", __func__, strerror(errno)); ret = EXIT_FAILURE; } return ret; }