This repository has been archived by the owner on Oct 6, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.c
132 lines (111 loc) · 3.67 KB
/
main.c
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
/* Copyright (c) 2021, Evgeny Baskov. All rights reserved */
#include "callgraph.h"
#include "util.h"
#include "worker.h"
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SKIP_OPT ((void*)-1)
static _Noreturn void usage(const char *argv0, int code) {
if (config.log_level > 0 || code == EXIT_SUCCESS) {
size_t i = 0;
do fputs(argv0, stdout);
while((argv0 = usage_string(i++)));
}
exit(code);
}
static void parse_options(char **argv) {
size_t ind = 1;
char *arg;
const char *opt;
while (argv[ind] && argv[ind][0] == '-') {
size_t cind = 0;
if (!argv[ind][1]) usage(argv[0], EXIT_FAILURE);
if (argv[ind][1] == '-') {
if (!argv[ind][2]) {
ind++;
break;
}
//Long options
opt = argv[ind] + 2; /* skip '--' */
if ((arg = strchr(argv[ind], '='))) {
*arg++ = '\0';
if (!*arg) arg = argv[++ind];
if (strcmp(opt, "config") && !set_option(opt, arg))
usage(argv[0], EXIT_FAILURE);
} else {
if (!strcmp(opt, "help"))
usage(argv[0], EXIT_SUCCESS);
else {
const char *val = "true";
if (!strncmp(opt, "no-", 3)) opt += 3, val = "false";
if (!set_option(opt, val))
usage(argv[0], EXIT_FAILURE);
}
}
} else while (argv[ind] && argv[ind][++cind]) {
char letter = argv[ind][cind];
// One letter options
switch (letter) {
case 'Q':
config.log_level = 0;
break;
case 'h':
usage(argv[0], EXIT_SUCCESS);
default:;
opt = NULL;
switch (letter) {
case 'C': opt = SKIP_OPT; break;
case 'L': opt = "log-level"; break;
case 'T': opt = "threads"; break;
case 'o': opt = "out"; break;
case 'p': opt = "path"; break;
}
if (opt) {
// Has arguments
if (!argv[ind][++cind]) ind++, cind = 0;
if (!argv[ind]) usage(argv[0], EXIT_FAILURE);
arg = argv[ind] + cind;
if (opt != SKIP_OPT)
set_option(opt, arg);
goto next;
}
warn("Unknown option -%c", letter);
}
}
next:
if (argv[ind]) ind++;
}
}
int main(int argc, char **argv) {
(void) argc;
// Parse --config/-C argument before parsing config file
char *cpath = NULL;
for (int i = 1; i < argc; i++) {
if (!strncmp(argv[i], "--config=", sizeof "--config=" - 1) ||
!strncmp(argv[i], "-C", sizeof "-C" - 1)) {
char *arg = argv[i] + (argv[i][1] == '-' ? sizeof "--config=" : sizeof "-C") - 1;
if (!*arg) arg = argv[++i];
if (!arg) usage(argv[0], EXIT_FAILURE);
cpath = arg;
}
}
/* Parse config file */
init_config(cpath);
/* Parse command line options after config
* since argv have bigger priority than config file */
parse_options(argv);
/* Initiallize worker threads pool */
init_workers();
struct callgraph *cg = parse_directory(config.build_dir);
assert(cg);
filter_graph(cg);
dump_dot(cg, config.output_path);
free_callgraph(cg);
fini_workers(1);
fini_config();
return EXIT_SUCCESS;
}