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>89#include "make.h"1011#ifndef SIGINT12#define SIGINT -113#endif1415#ifndef SIGTERM16#define SIGTERM -117#endif1819#ifndef SIGQUIT20#define SIGQUIT -121#endif2223#ifndef SIGHUP24#define SIGHUP -125#endif2627int kflag, dflag, nflag, iflag, sflag;28int eflag, pflag, tflag, qflag;29int exitstatus;30volatile sig_atomic_t stop;3132void33debug(char *fmt, ...)34{35 va_list va;3637 if (!dflag)38 return;3940 va_start(va, fmt);41 vfprintf(stdout, fmt, va);42 fputc('\n', stdout);43 va_end(va);44}4546int47hash(char *name)48{49 int c;50 unsigned h = 5381;5152 while (c = *name++)53 h = h*33 ^ c;5455 return h;56}5758void *59emalloc(size_t siz)60{61 void *p;6263 if ((p = malloc(siz)) == NULL) {64 perror("make");65 exit(EXIT_FAILURE);66 }6768 return p;69}7071void *72erealloc(void *p, size_t siz)73{74 if ((p = realloc(p, siz)) == NULL) {75 perror("make");76 exit(EXIT_FAILURE);77 }7879 return p;80}8182char *83estrdup(char *s)84{85 size_t len;8687 len = strlen(s) + 1;88 return memcpy(emalloc(len), s, len);89}9091void92sighandler(int signo)93{94 killchild();95 stop = signo;96}9798static void99usage(void)100{101 fputs("usage: make [-eiknprSstd] [-f file] [-j jobs] "102 "[macro=value ...] [target ...]\n",103 stderr);104 exit(EXIT_FAILURE);105}106107static char *108getarg(char **args, char ***argv)109{110 char *s;111112 if ((*args)[1]) {113 s = (*args) + 1;114 *args += strlen(*args) - 1;115 return s;116 }117118 if (!argv)119 usage();120121 if ((*argv)[1] == NULL)122 usage();123 (*argv)++;124125 return **argv;126}127128static void129appendmakeflags(char *text)130{131 int n;132 char *s, *t, *fmt;133134 s = getmacro("MAKEFLAGS");135 fmt = *s ? "%s %s" : "%s%s";136 n = snprintf(NULL, 0, fmt, s, text);137138 t = emalloc(n+1);139 snprintf(t, n+1, fmt, s, text);140 setmacro("MAKEFLAGS", t, MAKEFLAGS, EXPORT);141142 free(t);143}144145static void146appendmacro(char *text)147{148 int n, idlen;149 char *p, *t, *s;150151 n = strlen(text) + 2;152 for (p = text; p = strchr(p, '\''); ++p)153 n++;154 s = emalloc(n + 1);155156 p = strchr(text, '=');157 idlen = p - text;158159 memcpy(s, text, idlen);160 s[idlen] = '\0';161162 if (strpbrk(s, " \t\v\n'\"")) {163 fprintf(stderr, "make: invalid macro name '%s'\n", text);164 exit(EXIT_FAILURE);165 }166167 p = s + idlen;168 *p++ = '=';169170 *p++ = '\'';171 for (t = text + idlen + 1; *t; ++t) {172 if (*t == '\'')173 *p++ = '\\';174 *p++ = *t;175 }176 *p++ = '\'';177178 *p = '\0';179 appendmakeflags(s);180 free(s);181}182183static int184hasargs(int c)185{186 return c == 'f' || c == 'j';187}188189static void190parseflag(int flag, char **args, char ***argv)191{192 if (hasargs(flag))193 getarg(args, argv);194195 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}246247static int248assign(char *s, int where, int export)249{250 int pos;251 char *t;252253 if ((t = strchr(s, '=')) == NULL)254 return 0;255256 pos = t - s;257258 appendmacro(s);259 t = estrdup(s);260 t[pos] = '\0';261262 setmacro(t, t+pos+1, where, export);263 free(t);264 return 1;265}266267static void268parseargv(char **argv, char ***targets, int where, int export)269{270 char *s;271 char *hm = NULL;272273 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 }287288 if (targets)289 *targets = argv;290}291292static void293parsemakeflags(void)294{295 int esc, c, n;296 char *t, *s, *buf, *flags, **arr;297298 if ((flags = getenv("MAKEFLAGS")) == NULL)299 return;300301 setmacro("MAKEFLAGS", "", MAKEFLAGS, EXPORT);302303 while (*flags == ' ' || *flags == '\t')304 flags++;305306 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);315316 for (s = flags; *s; ) {317 while (isspace(*s))318 ++s;319320 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';347348 n++;349 arr = erealloc(arr, sizeof(char *) * (n+1));350 arr[n-1] = estrdup(buf);351 arr[n] = NULL;352 }353 free(buf);354355 if (arr) {356 parseargv(arr, NULL, MAKEFLAGS, NOEXPORT);357 while (n-- > 0)358 free(arr[n]);359 free(arr);360 }361 }362}363364static void365parsemakefiles(char **argv)366{367 char *s, *arg;368 int c, hasmake;369370 hasmake = 0;371 for ( ; *argv && **argv == '-'; ++argv) {372 for (s = *argv; c = *s; ++s) {373 if (hasargs(c))374 arg = getarg(&s, &argv);375376 if (c == 'f') {377 if (strcmp(arg, "-") == 0)378 arg = NULL;379 parse(arg);380 hasmake = 1;381 }382 }383 }384385 if (hasmake)386 return;387388 if (parse("makefile"))389 return;390 if (parse("Makefile"))391 return;392}393394/*395 * We want to enable debug as earlier as possible,396 * if we wait until we read the Makefiles then397 * we are going to lose to much debug information.398 */399static void400enadebug(char *argv[])401{402 int c;403 char *p;404405 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}415416int417main(int argc, char *argv[])418{419 char *arg0, **targets;420421 signal(SIGINT, sighandler);422 signal(SIGHUP, sighandler);423 signal(SIGTERM, sighandler);424 signal(SIGQUIT, sighandler);425426 targets = NULL;427 arg0 = *argv++;428429 enadebug(argv);430 inject(defaults);431 setmacro("MAKE", arg0, MAKEFILE, NOEXPORT);432433 parsemakeflags();434 parseargv(argv, &targets, CMDLINE, EXPORT);435 parsemakefiles(argv);436437 if (pflag) {438 dumpmacros();439 dumprules();440 exit(EXIT_SUCCESS);441 }442443 if (!*targets) {444 build(NULL);445 } else {446 while (*targets)447 build(*targets++);448 }449450 exit(exitstatus);451452 return 0;453}