vextoly/cryn

/* tools/embed.c - turn runtime sources into C string headers for the compiler.
   Lines of the form '#include "..."' are dropped (their content is inlined
   around the string); system includes with <...> are kept. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void emit_escaped(const char* s, size_t n) {
    for (size_t i = 0; i < n; i++) {
        unsigned char c = (unsigned char)s[i];
        switch (c) {
        case '\\': printf("\\\\"); break;
        case '"': printf("\\\""); break;
        case '\t': printf("\\t"); break;
        case '\r': break;
        default:
            if (c < 32 || c > 126) printf("\\%03o", c);
            else putchar(c);
        }
    }
}

static void emit_string(const char* name, const char* path) {
    FILE* f = fopen(path, "rb");
    if (!f) {
        fprintf(stderr, "embed: cannot open %s\n", path);
        exit(1);
    }
    printf("static const char %s[] =\n", name);
    char line[1024];
    int first = 1;
    while (fgets(line, sizeof line, f)) {
        if (strncmp(line, "#include \"", 10) == 0) continue; /* local include: dropped */
        size_t n = strlen(line);
        /* strip trailing newline */
        while (n > 0 && (line[n - 1] == '\n' || line[n - 1] == '\r')) n--;
        if (!first) printf("\n");
        printf("\"");
        emit_escaped(line, n);
        printf("\\n\"");
        first = 0;
    }
    printf(";\n\n");
    fclose(f);
}

int main(int argc, char** argv) {
    if (argc < 3 || (argc - 1) % 2 != 0) {
        fprintf(stderr, "usage: embed <file> <symbol> [<file> <symbol> ...]\n");
        return 1;
    }
    printf("/* generated by tools/embed - do not edit */\n");
    printf("#ifndef CR_RT_SRC_H\n#define CR_RT_SRC_H\n\n");
    for (int i = 1; i + 1 < argc; i += 2)
        emit_string(argv[i + 1], argv[i]);
    printf("#endif\n");
    return 0;
}