URI:
       main.c - scc - simple c99 compiler
  HTML git clone git://git.simple-cc.org/scc
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR 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 }