main.c - scc - simple c99 compiler
(HTM) git clone git://git.simple-cc.org/scc
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Submodules
(DIR) README
(DIR) LICENSE
---
main.c (5346B)
---
1 #include <errno.h>
2 #include <signal.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "make.h"
9
10 #ifndef SIGINT
11 #define SIGINT -1
12 #endif
13
14 #ifndef SIGTERM
15 #define SIGTERM -1
16 #endif
17
18 #ifndef SIGQUIT
19 #define SIGQUIT -1
20 #endif
21
22 #ifndef SIGHUP
23 #define SIGHUP -1
24 #endif
25
26 int kflag, dflag, nflag, iflag, sflag;
27 int eflag, pflag, tflag, qflag;
28 int exitstatus;
29 volatile sig_atomic_t stop;
30
31 void
32 debug(char *fmt, ...)
33 {
34 va_list va;
35
36 if (!dflag)
37 return;
38
39 va_start(va, fmt);
40 vfprintf(stdout, fmt, va);
41 fputc('\n', stdout);
42 va_end(va);
43 }
44
45 int
46 hash(char *name)
47 {
48 int c;
49 unsigned h = 5381;
50
51 while (c = *name++)
52 h = h*33 ^ c;
53
54 return h;
55 }
56
57 void *
58 emalloc(size_t siz)
59 {
60 void *p;
61
62 if ((p = malloc(siz)) == NULL) {
63 perror("make");
64 exit(EXIT_FAILURE);
65 }
66
67 return p;
68 }
69
70 void *
71 erealloc(void *p, size_t siz)
72 {
73 if ((p = realloc(p, siz)) == NULL) {
74 perror("make");
75 exit(EXIT_FAILURE);
76 }
77
78 return p;
79 }
80
81 char *
82 estrdup(char *s)
83 {
84 size_t len;
85
86 len = strlen(s) + 1;
87 return memcpy(emalloc(len), s, len);
88 }
89
90 void
91 sighandler(int signo)
92 {
93 killchild();
94 stop = signo;
95 }
96
97 static void
98 usage(void)
99 {
100 fputs("usage: make [-eiknprSstd] [-f file] [-j jobs] "
101 "[macro=value ...] [target ...]\n",
102 stderr);
103 exit(EXIT_FAILURE);
104 }
105
106 static char *
107 getarg(char **args, char ***argv)
108 {
109 char *s;
110
111 if ((*args)[1]) {
112 s = (*args) + 1;
113 *args += strlen(*args) - 1;
114 return s;
115 }
116
117 if (!argv)
118 usage();
119
120 if ((*argv)[1] == NULL)
121 usage();
122 (*argv)++;
123
124 return **argv;
125 }
126
127 static void
128 appendmakeflags(char *text)
129 {
130 int n;
131 char *s, *t, *fmt;
132
133 s = getmacro("MAKEFLAGS");
134 fmt = *s ? "%s %s" : "%s%s";
135 n = snprintf(NULL, 0, fmt, s, text);
136
137 t = emalloc(n+1);
138 snprintf(t, n+1, fmt, s, text);
139 setmacro("MAKEFLAGS", t, MAKEFLAGS, EXPORT);
140
141 free(t);
142 }
143
144 static int
145 hasargs(int c)
146 {
147 return c == 'f' || c == 'j';
148 }
149
150 static void
151 parseflag(int flag, char **args, char ***argv)
152 {
153 if (hasargs(flag))
154 getarg(args, argv);
155
156 switch (flag) {
157 case 'j':
158 case 'f':
159 break;
160 case 'e':
161 eflag = 1;
162 appendmakeflags("-e");
163 break;
164 case 'i':
165 iflag = 1;
166 appendmakeflags("-i");
167 break;
168 case 'k':
169 kflag = 1;
170 appendmakeflags("-k");
171 break;
172 case 'n':
173 nflag = 1;
174 appendmakeflags("-n");
175 break;
176 case 'p':
177 pflag = 1;
178 break;
179 case 'q':
180 qflag = 1;
181 appendmakeflags("-q");
182 break;
183 case 'r':
184 addtarget(".SUFFIXES", 0);
185 appendmakeflags("-r");
186 break;
187 case 'S':
188 kflag = 0;
189 appendmakeflags("-S");
190 break;
191 case 's':
192 sflag = 1;
193 appendmakeflags("-s");
194 break;
195 case 't':
196 tflag = 1;
197 appendmakeflags("-t");
198 break;
199 case 'd':
200 dflag = 1;
201 appendmakeflags("-d");
202 break;
203 default:
204 usage();
205 }
206 }
207
208 static int
209 assign(char *s, int where, int export)
210 {
211 int pos;
212 char *t;
213
214 if ((t = strchr(s, '=')) == NULL)
215 return 0;
216
217 pos = t - s;
218
219 appendmakeflags(s);
220 t = estrdup(s);
221 t[pos] = '\0';
222
223 setmacro(t, t+pos+1, where, export);
224 free(t);
225 return 1;
226 }
227
228 static void
229 parseargv(char **argv, char ***targets, int where, int export)
230 {
231 char *s;
232 char *hm = NULL;
233
234 for ( ; *argv; ++argv) {
235 s = *argv;
236 if (hm == NULL && strcmp(s, "--") == 0) {
237 hm = *argv;
238 } else if (hm && s[0] == '-') {
239 break;
240 } else if (s[0] != '-') {
241 if (!assign(s, where, export))
242 break;
243 continue;
244 }
245 while (hm == NULL && *++s)
246 parseflag(*s, &s, &argv);
247 }
248
249 if (targets)
250 *targets = argv;
251 }
252
253 static void
254 parsemakeflags(void)
255 {
256 int c, n;
257 char *s, *flags, **arr;
258
259 if ((flags = getenv("MAKEFLAGS")) == NULL)
260 return;
261
262 setmacro("MAKEFLAGS", "", MAKEFLAGS, EXPORT);
263
264 while (*flags == ' ' || *flags == '\t')
265 flags++;
266
267 if (flags[0] != '-' && !strchr(flags, '=')) {
268 while (*flags) {
269 parseflag(*flags, &flags, NULL);
270 flags++;
271 }
272 } else {
273 n = 0;
274 arr = NULL;
275 for (s = strtok(flags, " \t"); s; s = strtok(NULL, " \t")) {
276 n++;
277 arr = erealloc(arr, sizeof(char *) * (n+1));
278 arr[n-1] = s;
279 arr[n] = NULL;
280 }
281
282 if (arr)
283 parseargv(arr, NULL, MAKEFLAGS, NOEXPORT);
284 free(arr);
285 }
286 }
287
288 static void
289 parsemakefiles(char **argv)
290 {
291 char *s, *arg;
292 int c, hasmake;
293
294 hasmake = 0;
295 for ( ; *argv && **argv == '-'; ++argv) {
296 for (s = *argv; c = *s; ++s) {
297 if (hasargs(c))
298 arg = getarg(&s, &argv);
299
300 if (c == 'f') {
301 if (strcmp(arg, "-") == 0)
302 arg = NULL;
303 parse(arg);
304 hasmake = 1;
305 }
306 }
307 }
308
309 if (hasmake)
310 return;
311
312 if (parse("makefile"))
313 return;
314 if (parse("Makefile"))
315 return;
316 }
317
318 /*
319 * We want to enable debug as earlier as possible,
320 * if we wait until we read the Makefiles then
321 * we are going to lose to much debug information.
322 */
323 static void
324 enadebug(char *argv[])
325 {
326 int c;
327 char *p;
328
329 for ( ; *argv && **argv == '-'; ++argv) {
330 p = *argv;
331 for (++p; c = *p; ++p) {
332 if (hasargs(c))
333 getarg(&p, &argv);
334 if (c == 'd')
335 dflag = 1;
336 }
337 }
338 }
339
340 int
341 main(int argc, char *argv[])
342 {
343 char *arg0, **targets;
344
345 signal(SIGINT, sighandler);
346 signal(SIGHUP, sighandler);
347 signal(SIGTERM, sighandler);
348 signal(SIGQUIT, sighandler);
349
350 targets = NULL;
351 arg0 = *argv++;
352
353 enadebug(argv);
354 inject(defaults);
355 setmacro("MAKE", arg0, MAKEFILE, NOEXPORT);
356
357 parsemakeflags();
358 parseargv(argv, &targets, CMDLINE, EXPORT);
359 parsemakefiles(argv);
360
361 if (pflag) {
362 dumpmacros();
363 dumprules();
364 exit(EXIT_SUCCESS);
365 }
366
367 if (!*targets) {
368 build(NULL);
369 } else {
370 while (*targets)
371 build(*targets++);
372 }
373
374 exit(exitstatus);
375
376 return 0;
377 }