422 lines
8.1 KiB
C
422 lines
8.1 KiB
C
#define _POSIX_C_SOURCE 200809L
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
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 <fswrap.h>\n"
|
|
"#include <stddef.h>\n"
|
|
"#include <stdint.h>\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;
|
|
}
|