fswrap/main.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;
}