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
58sighandler(int signo)
59{
60 killchild();
61 stop = signo;
62}
63
64static void
65usage(void)
66{
67 fputs(
68 "usage: make [-eiknprSstd] [-f file] [-j jobs] "
69 "[macro=value ...] [target ...]\n",
70 stderr
71 );
72 exit(EXIT_FAILURE);
73}
74
75static char *
76getarg(char **args, char ***argv)
77{
78 char *s;
79
80 if ((*args)[1]) {
81 s = (*args) + 1;
82 *args += strlen(*args) - 1;
83 return s;
84 }
85
86 if (!argv)
87 usage();
88
89 if ((*argv)[1] == NULL)
90 usage();
91 (*argv)++;
92
93 return **argv;
94}
95
96static void
97appendmakeflags(char *text)
98{
99 int n;
100 char *s, *t, *fmt;
101
102 s = getmacro("MAKEFLAGS");
103 fmt = *s ? "%s %s" : "%s%s";
104 n = snprintf(NULL, 0, fmt, s, text);
105
106 t = emalloc(n + 1);
107 snprintf(t, n + 1, fmt, s, text);
108 setmacro("MAKEFLAGS", t, MAKEFLAGS, EXPORT);
109
110 free(t);
111}
112
113static int
114hasargs(int c)
115{
116 return c == 'f' || c == 'j';
117}
118
119static void
120parseflag(int flag, char **args, char ***argv)
121{
122 if (hasargs(flag))
123 getarg(args, argv);
124
125 switch (flag) {
126 case 'j':
127 /* ?man -j:jobs: number of parallel jobs (accepted, runs
128 * serially) */
129 case 'f':
130 /* ?man -f:file: read rules from file instead of makefile or
131 * Makefile */
132 break;
133 case 'e':
134 /* ?man -e: environment variables override makefile assignments
135 */
136 eflag = 1;
137 appendmakeflags("-e");
138 break;
139 case 'i':
140 /* ?man -i: ignore errors from executed commands */
141 iflag = 1;
142 appendmakeflags("-i");
143 break;
144 case 'k':
145 /* ?man -k: continue building other targets after an error */
146 kflag = 1;
147 appendmakeflags("-k");
148 break;
149 case 'n':
150 /* ?man -n: print commands without executing them */
151 nflag = 1;
152 appendmakeflags("-n");
153 break;
154 case 'p':
155 /* ?man -p: print the rule and macro database then exit */
156 pflag = 1;
157 break;
158 case 'q':
159 /* ?man -q: question mode, return zero if up to date, one
160 * otherwise */
161 qflag = 1;
162 appendmakeflags("-q");
163 break;
164 case 'r':
165 /* ?man -r: clear the built-in suffix rules and variables */
166 addtarget(".SUFFIXES", 0);
167 appendmakeflags("-r");
168 break;
169 case 'S':
170 /* ?man -S: cancel a previous -k, stop on first error */
171 kflag = 0;
172 appendmakeflags("-S");
173 break;
174 case 's':
175 /* ?man -s: silent, do not echo commands before running them */
176 sflag = 1;
177 appendmakeflags("-s");
178 break;
179 case 't':
180 /* ?man -t: touch targets instead of rebuilding them */
181 tflag = 1;
182 appendmakeflags("-t");
183 break;
184 case 'd':
185 /* ?man -d: enable debug output */
186 dflag = 1;
187 appendmakeflags("-d");
188 break;
189 default:
190 usage();
191 }
192}
193
194static int
195assign(char *s, int where, int export)
196{
197 int pos;
198 char *t;
199
200 if ((t = strchr(s, '=')) == NULL)
201 return 0;
202
203 pos = t - s;
204
205 appendmakeflags(s);
206 t = estrdup(s);
207 t[pos] = '\0';
208
209 setmacro(t, t + pos + 1, where, export);
210 free(t);
211 return 1;
212}
213
214static void
215parseargv(char **argv, char ***targets, int where, int export)
216{
217 char *s;
218 char *hm = NULL;
219
220 for (; *argv; ++argv) {
221 s = *argv;
222 if (hm == NULL && strcmp(s, "--") == 0) {
223 hm = *argv;
224 } else if (hm && s[0] == '-') {
225 break;
226 } else if (s[0] != '-') {
227 if (!assign(s, where, export))
228 break;
229 continue;
230 }
231 while (hm == NULL && *++s)
232 parseflag(*s, &s, &argv);
233 }
234
235 if (targets)
236 *targets = argv;
237}
238
239static void
240parsemakeflags(void)
241{
242 int n;
243 char *s, *flags, **arr;
244
245 if ((flags = getenv("MAKEFLAGS")) == NULL)
246 return;
247
248 setmacro("MAKEFLAGS", "", MAKEFLAGS, EXPORT);
249
250 while (*flags == ' ' || *flags == '\t')
251 flags++;
252
253 if (flags[0] != '-' && !strchr(flags, '=')) {
254 while (*flags) {
255 parseflag(*flags, &flags, NULL);
256 flags++;
257 }
258 } else {
259 n = 0;
260 arr = NULL;
261 for (s = strtok(flags, " \t"); s; s = strtok(NULL, " \t")) {
262 n++;
263 arr = erealloc(arr, sizeof(char *) * (n + 1));
264 arr[n - 1] = s;
265 arr[n] = NULL;
266 }
267
268 if (arr)
269 parseargv(arr, NULL, MAKEFLAGS, NOEXPORT);
270 free(arr);
271 }
272}
273
274static void
275parsemakefiles(char **argv)
276{
277 char *s, *arg;
278 int c, hasmake;
279
280 hasmake = 0;
281 for (; *argv && **argv == '-'; ++argv) {
282 for (s = *argv; (c = *s); ++s) {
283 if (hasargs(c))
284 arg = getarg(&s, &argv);
285
286 if (c == 'f') {
287 if (strcmp(arg, "-") == 0)
288 arg = NULL;
289 parse(arg);
290 hasmake = 1;
291 }
292 }
293 }
294
295 if (hasmake)
296 return;
297
298 if (parse("makefile"))
299 return;
300 if (parse("Makefile"))
301 return;
302}
303
304/*
305 * We want to enable debug as earlier as possible,
306 * if we wait until we read the Makefiles then
307 * we are going to lose to much debug information.
308 */
309static void
310enadebug(char *argv[])
311{
312 int c;
313 char *p;
314
315 for (; *argv && **argv == '-'; ++argv) {
316 p = *argv;
317 for (++p; (c = *p); ++p) {
318 if (hasargs(c))
319 getarg(&p, &argv);
320 if (c == 'd')
321 dflag = 1;
322 }
323 }
324}
325
326// ?man make: maintain program dependencies
327// ?man arguments: [name=value ...] [target ...]
328// ?man update files based on dependency rules in a makefile.
329// ?man if no -f is given, make tries makefile then Makefile.
330// ?man if no target is given the first non-dot target in the makefile is built.
331int
332main(int argc, char *argv[])
333{
334 char *arg0, **targets;
335
336 (void)argc;
337
338 signal(SIGINT, sighandler);
339 signal(SIGHUP, sighandler);
340 signal(SIGTERM, sighandler);
341 signal(SIGQUIT, sighandler);
342
343 targets = NULL;
344 arg0 = *argv++;
345
346 enadebug(argv);
347 inject(defaults);
348 setmacro("MAKE", arg0, MAKEFILE, NOEXPORT);
349
350 parsemakeflags();
351 parseargv(argv, &targets, CMDLINE, EXPORT);
352 parsemakefiles(argv);
353
354 if (pflag) {
355 dumpmacros();
356 dumprules();
357 exit(EXIT_SUCCESS);
358 }
359
360 if (!*targets) {
361 build(NULL);
362 } else {
363 while (*targets)
364 build(*targets++);
365 }
366
367 exit(exitstatus);
368
369 return 0;
370}