aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/cli.c
blob: b89037582e719da171d2a80b60b15a7f3af92be1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "cli.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "version.h"

static void print_version() {
    printf("ducc v%s\n", DUCC_VERSION);
}

CliArgs* parse_cli_args(int argc, char** argv) {
    const char* output_filename = NULL;
    int positional_arguments_start = -1;
    bool opt_c = false;
    bool opt_E = false;
    bool opt_wasm = false;
    bool opt_MD = false;
    bool opt_MMD = false;
    bool opt_g = false;
    StrArray include_dirs;
    strings_init(&include_dirs);
    StrArray defines;
    strings_init(&defines);

    for (int i = 1; i < argc; ++i) {
        if (argv[i][0] != '-') {
            positional_arguments_start = i;
            break;
        }
        char c = argv[i][1];
        if (c == 'f') {
            // ignore
        } else if (c == 'g') {
            // ignore
        } else if (c == 'm') {
            // ignore
        } else if (c == 'O') {
            // ignore
        } else if (c == 'W') {
            // ignore
        } else if (c == 'M' && argv[i][2] == '\0') {
            // ignore -M
        } else if (c == 'I') {
            const char* dir = NULL;
            if (argv[i][2] != '\0') {
                // -Ipath format
                dir = argv[i] + 2;
            } else if (argc > i + 1) {
                // -I path format
                dir = argv[i + 1];
                ++i;
            } else {
                fatal_error("-I requires directory");
            }
            strings_push(&include_dirs, dir);
        } else if (c == 'D') {
            const char* def = NULL;
            if (argv[i][2] != '\0') {
                // -DFOO or -DFOO=value format
                def = argv[i] + 2;
            } else if (argc > i + 1) {
                // -D FOO or -D FOO=value format
                def = argv[i + 1];
                ++i;
            } else {
                fatal_error("-D requires macro definition");
            }
            strings_push(&defines, def);
        } else if (c == 'o') {
            if (argc <= i + 1) {
                fatal_error("-o requires filename");
            }
            output_filename = argv[i + 1];
            ++i;
        } else if (c == 'c') {
            opt_c = true;
        } else if (c == 'E') {
            opt_E = true;
        } else if (c == 'g') {
            opt_g = true;
        } else if (strcmp(argv[i], "-MD") == 0) {
            opt_MD = true;
        } else if (strcmp(argv[i], "-MMD") == 0) {
            opt_MMD = true;
        } else if (strcmp(argv[i], "--version") == 0) {
            print_version();
            exit(0);
        } else if (str_starts_with(argv[i], "-std=")) {
            // ignore -std=*
        } else if (strcmp(argv[i], "--wasm") == 0) {
            opt_wasm = true;
        } else {
            fatal_error("unknown option: %s", argv[i]);
        }
    }
    if (positional_arguments_start == -1) {
        fatal_error("usage: ducc <file>");
    }

    CliArgs* a = calloc(1, sizeof(CliArgs));
    a->input_filename = argv[positional_arguments_start];
    a->output_filename = output_filename;
    a->output_assembly = !output_filename || str_ends_with(output_filename, ".s") || opt_wasm;
    a->only_compile = opt_c;
    a->preprocess_only = opt_E;
    a->totally_deligate_to_gcc = false;
    a->wasm = opt_wasm;
    a->gcc_command = NULL;
    a->generate_system_deps = opt_MD;
    a->generate_user_deps = opt_MD || opt_MMD;
    a->generate_debug_info = opt_g;
    a->include_dirs = include_dirs;
    a->defines = defines;

    if (!a->only_compile && str_ends_with(a->input_filename, ".o")) {
        a->totally_deligate_to_gcc = true;
        StrBuilder builder;
        strbuilder_init(&builder);
        strbuilder_append_string(&builder, "gcc ");
        for (int i = 1; i < argc; ++i) {
            strbuilder_append_char(&builder, '\'');
            strbuilder_append_string(&builder, argv[i]);
            strbuilder_append_char(&builder, '\'');
            if (i != argc - 1) {
                strbuilder_append_char(&builder, ' ');
            }
        }
        a->gcc_command = builder.buf;
    }

    return a;
}