main.c - sbase - suckless unix tools
(HTM) git clone git://git.suckless.org/sbase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
main.c (5332B)
---
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 stop = signo;
94 }
95
96 static void
97 usage(void)
98 {
99 fputs("usage: make [-eiknprSstd] [-f file] [-j jobs] "
100 "[macro=value ...] [target ...]\n",
101 stderr);
102 exit(EXIT_FAILURE);
103 }
104
105 static char *
106 getarg(char **args, char ***argv)
107 {
108 char *s;
109
110 if ((*args)[1]) {
111 s = (*args) + 1;
112 *args += strlen(*args) - 1;
113 return s;
114 }
115
116 if (!argv)
117 usage();
118
119 if ((*argv)[1] == NULL)
120 usage();
121 (*argv)++;
122
123 return **argv;
124 }
125
126 static void
127 appendmakeflags(char *text)
128 {
129 int n;
130 char *s, *t, *fmt;
131
132 s = getmacro("MAKEFLAGS");
133 fmt = *s ? "%s %s" : "%s%s";
134 n = snprintf(NULL, 0, fmt, s, text);
135
136 t = emalloc(n+1);
137 snprintf(t, n+1, fmt, s, text);
138 setmacro("MAKEFLAGS", t, MAKEFLAGS, EXPORT);
139
140 free(t);
141 }
142
143 static int
144 hasargs(int c)
145 {
146 return c == 'f' || c == 'j';
147 }
148
149 static void
150 parseflag(int flag, char **args, char ***argv)
151 {
152 if (hasargs(flag))
153 getarg(args, argv);
154
155 switch (flag) {
156 case 'j':
157 case 'f':
158 break;
159 case 'e':
160 eflag = 1;
161 appendmakeflags("-e");
162 break;
163 case 'i':
164 iflag = 1;
165 appendmakeflags("-i");
166 break;
167 case 'k':
168 kflag = 1;
169 appendmakeflags("-k");
170 break;
171 case 'n':
172 nflag = 1;
173 appendmakeflags("-n");
174 break;
175 case 'p':
176 pflag = 1;
177 break;
178 case 'q':
179 qflag = 1;
180 appendmakeflags("-q");
181 break;
182 case 'r':
183 addtarget(".SUFFIXES", 0);
184 appendmakeflags("-r");
185 break;
186 case 'S':
187 kflag = 0;
188 appendmakeflags("-S");
189 break;
190 case 's':
191 sflag = 1;
192 appendmakeflags("-s");
193 break;
194 case 't':
195 tflag = 1;
196 appendmakeflags("-t");
197 break;
198 case 'd':
199 dflag = 1;
200 appendmakeflags("-d");
201 break;
202 default:
203 usage();
204 }
205 }
206
207 static int
208 assign(char *s, int where, int export)
209 {
210 int pos;
211 char *t;
212
213 if ((t = strchr(s, '=')) == NULL)
214 return 0;
215
216 pos = t - s;
217
218 appendmakeflags(s);
219 t = estrdup(s);
220 t[pos] = '\0';
221
222 setmacro(t, t+pos+1, where, export);
223 free(t);
224 return 1;
225 }
226
227 static void
228 parseargv(char **argv, char ***targets, int where, int export)
229 {
230 char *s;
231 char *hm = NULL;
232
233 for ( ; *argv; ++argv) {
234 s = *argv;
235 if (hm == NULL && strcmp(s, "--") == 0) {
236 hm = *argv;
237 } else if (hm && s[0] == '-') {
238 break;
239 } else if (s[0] != '-') {
240 if (!assign(s, where, export))
241 break;
242 continue;
243 }
244 while (hm == NULL && *++s)
245 parseflag(*s, &s, &argv);
246 }
247
248 if (targets)
249 *targets = argv;
250 }
251
252 static void
253 parsemakeflags(void)
254 {
255 int c, n;
256 char *s, *flags, **arr;
257
258 if ((flags = getenv("MAKEFLAGS")) == NULL)
259 return;
260
261 setmacro("MAKEFLAGS", "", MAKEFLAGS, EXPORT);
262
263 while (*flags == ' ' || *flags == '\t')
264 flags++;
265
266 if (flags[0] != '-' && !strchr(flags, '=')) {
267 while (*flags) {
268 parseflag(*flags, &flags, NULL);
269 flags++;
270 }
271 } else {
272 n = 0;
273 arr = NULL;
274 for (s = strtok(flags, " \t"); s; s = strtok(NULL, " \t")) {
275 n++;
276 arr = erealloc(arr, sizeof(char *) * (n+1));
277 arr[n-1] = s;
278 arr[n] = NULL;
279 }
280
281 if (arr)
282 parseargv(arr, NULL, MAKEFLAGS, NOEXPORT);
283 free(arr);
284 }
285 }
286
287 static void
288 parsemakefiles(char **argv)
289 {
290 char *s, *arg;
291 int c, hasmake;
292
293 hasmake = 0;
294 for ( ; *argv && **argv == '-'; ++argv) {
295 for (s = *argv; c = *s; ++s) {
296 if (hasargs(c))
297 arg = getarg(&s, &argv);
298
299 if (c == 'f') {
300 if (strcmp(arg, "-") == 0)
301 arg = NULL;
302 parse(arg);
303 hasmake = 1;
304 }
305 }
306 }
307
308 if (hasmake)
309 return;
310
311 if (parse("makefile"))
312 return;
313 if (parse("Makefile"))
314 return;
315 }
316
317 /*
318 * We want to enable debug as earlier as possible,
319 * if we wait until we read the Makefiles then
320 * we are going to lose to much debug information.
321 */
322 static void
323 enadebug(char *argv[])
324 {
325 int c;
326 char *p;
327
328 for ( ; *argv && **argv == '-'; ++argv) {
329 p = *argv;
330 for (++p; c = *p; ++p) {
331 if (hasargs(c))
332 getarg(&p, &argv);
333 if (c == 'd')
334 dflag = 1;
335 }
336 }
337 }
338
339 int
340 main(int argc, char *argv[])
341 {
342 char *arg0, **targets;
343
344 signal(SIGINT, sighandler);
345 signal(SIGHUP, sighandler);
346 signal(SIGTERM, sighandler);
347 signal(SIGQUIT, sighandler);
348
349 targets = NULL;
350 arg0 = *argv++;
351
352 enadebug(argv);
353 inject(defaults);
354 setmacro("MAKE", arg0, MAKEFILE, NOEXPORT);
355
356 parsemakeflags();
357 parseargv(argv, &targets, CMDLINE, EXPORT);
358 parsemakefiles(argv);
359
360 if (pflag) {
361 dumpmacros();
362 dumprules();
363 exit(EXIT_SUCCESS);
364 }
365
366 if (!*targets) {
367 build(NULL);
368 } else {
369 while (*targets)
370 build(*targets++);
371 }
372
373 exit(exitstatus);
374
375 return 0;
376 }