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
26int kflag, dflag, nflag, iflag, sflag;
27int eflag, pflag, tflag, qflag;
28int exitstatus;
29volatile sig_atomic_t stop;
30
31void
32debug(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
45int
46hash(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
57void *
58emalloc(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
70void *
71erealloc(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
81char *
82estrdup(char *s)
83{
84 size_t len;
85
86 len = strlen(s) + 1;
87 return memcpy(emalloc(len), s, len);
88}
89
90void
91sighandler(int signo)
92{
93 killchild();
94 stop = signo;
95}
96
97static void
98usage(void)
99{
100 fputs("usage: make [-eiknprSstd] [-f file] [-j jobs] "
101 "[macro=value ...] [target ...]\n",
102 stderr);
103 exit(EXIT_FAILURE);
104}
105
106static char *
107getarg(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
127static void
128appendmakeflags(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
144static int
145hasargs(int c)
146{
147 return c == 'f' || c == 'j';
148}
149
150static void
151parseflag(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
208static int
209assign(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
228static void
229parseargv(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
253static void
254parsemakeflags(void)
255{
256 int 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
288static void
289parsemakefiles(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 */
323static void
324enadebug(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
340int
341main(int argc, char *argv[])
342{
343 char *arg0, **targets;
344
345 (void)argc;
346
347 signal(SIGINT, sighandler);
348 signal(SIGHUP, sighandler);
349 signal(SIGTERM, sighandler);
350 signal(SIGQUIT, sighandler);
351
352 targets = NULL;
353 arg0 = *argv++;
354
355 enadebug(argv);
356 inject(defaults);
357 setmacro("MAKE", arg0, MAKEFILE, NOEXPORT);
358
359 parsemakeflags();
360 parseargv(argv, &targets, CMDLINE, EXPORT);
361 parsemakefiles(argv);
362
363 if (pflag) {
364 dumpmacros();
365 dumprules();
366 exit(EXIT_SUCCESS);
367 }
368
369 if (!*targets) {
370 build(NULL);
371 } else {
372 while (*targets)
373 build(*targets++);
374 }
375
376 exit(exitstatus);
377
378 return 0;
379}