master xplshn/aruu / cmd / posix / make / main.c
  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}