scc

A fork of https://git.simple-cc.org/scc/ for Qute

git clone https://git.8pit.net/scc.git

  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
 27int kflag, dflag, nflag, iflag, sflag;
 28int eflag, pflag, tflag, qflag;
 29int exitstatus;
 30volatile sig_atomic_t  stop;
 31
 32void
 33debug(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
 46int
 47hash(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
 58void *
 59emalloc(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
 71void *
 72erealloc(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
 82char *
 83estrdup(char *s)
 84{
 85	size_t len;
 86
 87	len = strlen(s) + 1;
 88	return memcpy(emalloc(len), s, len);
 89}
 90
 91void
 92sighandler(int signo)
 93{
 94	killchild();
 95	stop = signo;
 96}
 97
 98static void
 99usage(void)
100{
101	fputs("usage: make [-eiknprSstd] [-f file] [-j jobs] "
102	      "[macro=value ...] [target ...]\n",
103	      stderr);
104	exit(EXIT_FAILURE);
105}
106
107static char *
108getarg(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
128static void
129appendmakeflags(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
145static void
146appendmacro(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
183static int
184hasargs(int c)
185{
186	return c == 'f' || c == 'j';
187}
188
189static void
190parseflag(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
247static int
248assign(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
267static void
268parseargv(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
292static void
293parsemakeflags(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
364static void
365parsemakefiles(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 */
399static void
400enadebug(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
416int
417main(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}