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