scc

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

main.c (5346B)


      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 	killchild();
     94 	stop = signo;
     95 }
     96 
     97 static void
     98 usage(void)
     99 {
    100 	fputs("usage: make [-eiknprSstd] [-f file] [-j jobs] "
    101 	      "[macro=value ...] [target ...]\n",
    102 	      stderr);
    103 	exit(EXIT_FAILURE);
    104 }
    105 
    106 static char *
    107 getarg(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 
    127 static void
    128 appendmakeflags(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 
    144 static int
    145 hasargs(int c)
    146 {
    147 	return c == 'f' || c == 'j';
    148 }
    149 
    150 static void
    151 parseflag(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 
    208 static int
    209 assign(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 
    228 static void
    229 parseargv(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 
    253 static void
    254 parsemakeflags(void)
    255 {
    256 	int c, 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 
    288 static void
    289 parsemakefiles(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  */
    323 static void
    324 enadebug(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 
    340 int
    341 main(int argc, char *argv[])
    342 {
    343 	char *arg0, **targets;
    344 
    345 	signal(SIGINT, sighandler);
    346 	signal(SIGHUP, sighandler);
    347 	signal(SIGTERM, sighandler);
    348 	signal(SIGQUIT, sighandler);
    349 
    350 	targets = NULL;
    351 	arg0 = *argv++;
    352 
    353 	enadebug(argv);
    354 	inject(defaults);
    355 	setmacro("MAKE", arg0, MAKEFILE, NOEXPORT);
    356 
    357 	parsemakeflags();
    358 	parseargv(argv, &targets, CMDLINE, EXPORT);
    359 	parsemakefiles(argv);
    360 
    361 	if (pflag) {
    362 		dumpmacros();
    363 		dumprules();
    364 		exit(EXIT_SUCCESS);
    365 	}
    366 
    367 	if (!*targets) {
    368 		build(NULL);
    369 	} else {
    370 		while (*targets)
    371 			build(*targets++);
    372 	}
    373 
    374 	exit(exitstatus);
    375 
    376 	return 0;
    377 }