scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

main.c (6559B)


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