Edit

kc3-lang/kc3/kc3txt

Branch :

  • kc3txt.c
  • #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    
    
    #include "../libkc3/types.h"
    #include "../libkc3/fact.h"
    #include "../libkc3/tag.h"
    #include "../libkc3/buf_inspect.h"
    #include "../libkc3/buf.h"
    #include "../libkc3/buf_file.h"
    #include "../libkc3/str.h"
    #include "../libkc3/marshall_read.h"
    #include "../libkc3/env.h"
    #include "../libkc3/facts.h"
    
    static void render(s_buf *out, uw id, u8 action, s_fact *fact) {
    
        buf_inspect_uw(out, id);
        buf_write_1(out, action == FACT_ACTION_ADD ? " ADD " :
                         action == FACT_ACTION_REMOVE ? " REMOVE " : " REPLACE ");
        buf_inspect_fact(out, fact);
        buf_write_1(out, "\n");
    }
    
    int main (int argc, char **argv)
    {
        char b[BUF_SIZE];
        char real_argv0[4096];
        char *resolved_argv0 = argv[0];
        uw id;
        u8 action;
        s_fact fact;
        s_str path;
        s_buf out;
        s_env env;
        int e_argc = 1;
        if (argc != 2) {
            fprintf(stderr, "Usage: %s <path>\n", argv[0]);
            return 1;
        }
        if (realpath(argv[0], real_argv0))
            resolved_argv0 = real_argv0;
        char *e_argv_data[] = { resolved_argv0, NULL };
        char **e_argv = e_argv_data;
        {
            const char *fp = argv[1];
            size_t flen = strlen(fp);
            if (flen >= 5 && ! strcmp(fp + flen - 5, ".dump")) {
                const char *slash = strrchr(fp, '/');
                char dump_dir[1024] = ".";
                const char *dump_name = fp;
                if (slash) {
                    size_t len = slash - fp;
                    if (len >= sizeof(dump_dir)) len = sizeof(dump_dir) - 1;
                    memcpy(dump_dir, fp, len);
                    dump_dir[len] = '\0';
                    dump_name = slash + 1;
                }
                const char *restore_path = fp;
                {
                    char db_path[1100];
                    snprintf(db_path, sizeof(db_path), "%s/db", dump_dir);
                    if (access(db_path, F_OK) == 0) {
                        char log_path[2200];
                        snprintf(log_path, sizeof(log_path), "%s/app.facts.bin.facts", db_path);
                        if (access(log_path, F_OK) != 0) {
                            fprintf(stderr, "%s: dump references %s which does not exist\n",
                                    argv[0], log_path);
                            fprintf(stderr, "  the restore would create it (write side-effect).\n");
                            fprintf(stderr, "  kc3cat refuses to write. either prepare the log\n");
                            fprintf(stderr, "  manually, or use a tool that accepts writes.\n");
                            return 1;
                        }
                        if (slash && chdir(dump_dir) != 0) {
                            fprintf(stderr, "%s: cannot chdir to %s\n", argv[0], dump_dir);
                            return 1;
                        }
                        restore_path = dump_name;
                    }
                }
                char  *d_argv_data[] = { resolved_argv0, "--restore", (char *)restore_path, NULL };
                int    d_argc = 3;
                char **d_argv = d_argv_data;
                if (! env_init(&env, &d_argc, &d_argv)) {
                    fprintf(stderr, "%s: cannot restore env dump: %s\n", argv[0], argv[1]);
                    return 1;
                }
                buf_init(&out, false, sizeof(b), b);
                buf_file_open_w(&out, stdout);
                facts_dump(env.facts, &out);
                buf_flush(&out);
                buf_file_close(&out);
                buf_clean(&out);
                env_clean(&env);
                return 0;
            }
            if (flen >= 5 && ! strcmp(fp + flen - 5, ".kc3c")) {
                s_marshall_read kmr = {0};
                uw n;
                uw i;
                if (! env_init(&env, &e_argc, &e_argv)) {
                    fprintf(stderr, "%s: env_init failed\n", argv[0]);
                    return 1;
                }
                str_init_1(&path, NULL, argv[1]);
                if (! marshall_read_init_file(&kmr, &path)) {
                    fprintf(stderr, "%s: cannot open %s\n", argv[0], argv[1]);
                    str_clean(&path);
                    env_clean(&env);
                    return 1;
                }
                marshall_read_size(&kmr);
                buf_init(&out, false, sizeof(b), b);
                buf_file_open_w(&out, stdout);
                if (! marshall_read_uw(&kmr, false, &n)) goto kc3c_done;
                i = 0;
                while (i < n) {
                    s_str s = {0};
                    if (! marshall_read_str(&kmr, false, &s)) goto kc3c_done;
                    buf_write_1(&out, "dlopen ");
                    buf_inspect_str(&out, &s);
                    buf_write_1(&out, "\n");
                    str_clean(&s);
                    i++;
                }
                if (! marshall_read_uw(&kmr, false, &n)) goto kc3c_done;
                i = 0;
                while (i < n) {
                    s_tag t = {0};
                    if (! marshall_read_tag(&kmr, false, &t)) goto kc3c_done;
                    buf_inspect_tag(&out, &t);
                    buf_write_1(&out, "\n");
                    tag_clean(&t);
                    i++;
                }
            kc3c_done:
                buf_flush(&out);
                buf_file_close(&out);
                buf_clean(&out);
                marshall_read_clean(&kmr);
                str_clean(&path);
                env_clean(&env);
                return 0;
            }
        }
        {
            FILE *peek = fopen(argv[1], "rb");
            if (peek) {
                int first = fgetc(peek);
                fclose(peek);
                if (first == '%') {
                    FILE *fp = fopen(argv[1], "rb");
                    if (! fp) {
                        fprintf(stderr, "%s: cannot open %s\n", argv[0], argv[1]);
                        return 1;
                    }
                    char tbuf[BUF_SIZE];
                    size_t n;
                    while ((n = fread(tbuf, 1, sizeof(tbuf), fp)) > 0)
                        fwrite(tbuf, 1, n, stdout);
                    fclose(fp);
                    return 0;
                }
            }
        }
        if (! env_init(&env, &e_argc, &e_argv)) {
            fprintf(stderr, "%s: env_init failed\n", argv[0]);
            return 1;
        }
        str_init_1(&path, NULL, argv[1]);
        s_marshall_read mr = {0};
        sw r;
        if ( ! marshall_read_init_file(&mr, &path)) {
            fprintf(stderr, "Failed to open file: %s\n", argv[1]);
            str_clean(&path);
            return 1;
        };
        buf_init(&out, false, sizeof(b), b);
        buf_file_open_w(&out, stdout);
        while (1) {
            while ((r = buf_peek_1(mr.buf, "KC3MARSH")) == 0) {
                if (buf_peek_1(mr.buf, "_KC3UW_") <= 0) goto done;
                if (! marshall_read_uw(&mr, false, &id) ||
                ! marshall_read_u8(&mr, false, &action) ||
                ! marshall_read_fact(&mr, false, &fact))
                    goto done;
                render(&out, id, action, &fact);
                fact_clean_all(&fact);
            }
            if (r > 0) { marshall_read_chunk_file(&mr); continue;}
            break;
        }
        done:
        buf_flush(&out);
        buf_file_close(&out);
        marshall_read_clean(&mr);
        str_clean(&path);
        env_clean(&env);
        return 0;
    }