scc

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

main.c (5175B)


      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 static 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 
    232 	for ( ; *argv; ++argv) {
    233 		s = *argv;
    234 		if (s[0] != '-') {
    235 			if (!assign(s, where, export))
    236 				break;
    237 			continue;
    238 		}
    239 		while (*++s)
    240 			parseflag(*s, &s, &argv);
    241 	}
    242 
    243 	if (targets)
    244 		*targets = argv;
    245 }
    246 
    247 static void
    248 parsemakeflags(void)
    249 {
    250 	int c, n;
    251 	char *s, *flags, **arr;
    252 
    253 	if ((flags = getenv("MAKEFLAGS")) == NULL)
    254 		return;
    255 
    256 	setmacro("MAKEFLAGS", "", MAKEFLAGS, EXPORT);
    257 
    258 	while (*flags == ' ' || *flags == '\t')
    259 		flags++;
    260 
    261 	if (flags[0] != '-' && !strchr(flags, '=')) {
    262 		while (*flags) {
    263 			parseflag(*flags, &flags, NULL);
    264 			flags++;
    265 		}
    266 	} else {
    267 		n = 0;
    268 		arr = NULL;
    269 		for (s = strtok(flags, " \t"); s; s = strtok(NULL, " \t")) {
    270 			n++;
    271 			arr = erealloc(arr, sizeof(char *) * (n+1));
    272 			arr[n-1] = s;
    273 			arr[n] = NULL;
    274 		}
    275 
    276 		if (arr)
    277 			parseargv(arr, NULL, MAKEFLAGS, NOEXPORT);
    278 		free(arr);
    279 	}
    280 }
    281 
    282 static void
    283 parsemakefiles(char **argv)
    284 {
    285 	char *s, *arg;
    286 	int c, hasmake;
    287 
    288 	hasmake = 0;
    289 	for ( ; *argv && **argv == '-'; ++argv) {
    290 		for (s = *argv; c = *s; ++s) {
    291 			if (hasargs(c))
    292 				arg = getarg(&s, &argv);
    293 
    294 			if (c == 'f') {
    295 				if (strcmp(arg, "-") == 0)
    296 					arg = NULL;
    297 				parse(arg);
    298 				hasmake = 1;
    299 			}
    300 		}
    301 	}
    302 
    303 	if (hasmake)
    304 		return;
    305 
    306 	if (parse("makefile"))
    307 		return;
    308 	if (parse("Makefile"))
    309 		return;
    310 }
    311 
    312 /*
    313  * We want to enable debug as earlier as possible,
    314  * if we wait until we read the Makefiles then
    315  * we are going to lose to much debug information.
    316  */
    317 static void
    318 enadebug(char *argv[])
    319 {
    320 	int c;
    321 	char *p;
    322 
    323 	for ( ; *argv && **argv == '-'; ++argv) {
    324 		p = *argv;
    325 		for (++p; c = *p; ++p) {
    326 			if (hasargs(c))
    327 				getarg(&p, &argv);
    328 			if (c == 'd')
    329 				dflag = 1;
    330 		}
    331 	}
    332 }
    333 
    334 int
    335 main(int argc, char *argv[])
    336 {
    337 	char *arg0, **targets;
    338 
    339 	signal(SIGINT, sighandler);
    340 	signal(SIGHUP, sighandler);
    341 	signal(SIGTERM, sighandler);
    342 	signal(SIGQUIT, sighandler);
    343 
    344 	targets = NULL;
    345 	arg0 = *argv++;
    346 
    347 	enadebug(argv);
    348 	inject(defaults);
    349 	setmacro("MAKE", arg0, MAKEFILE, NOEXPORT);
    350 
    351 	parsemakeflags();
    352 	parseargv(argv, &targets, CMDLINE, EXPORT);
    353 	parsemakefiles(argv);
    354 
    355 	if (pflag) {
    356 		dumpmacros();
    357 		dumprules();
    358 	}
    359 
    360 	if (!*targets) {
    361 		build(NULL);
    362 	} else {
    363 		while (*targets)
    364 			build(*targets++);
    365 	}
    366 
    367 	exit(exitstatus);
    368 
    369 	return 0;
    370 }