#include        "mk.h"

#define         MKFILE          "mkfile"

static char *version = "@(#)mk general release 4 (plan 9)";
int debug;
Rule *rules, *metarules;
int nflag = 0;
int tflag = 0;
int iflag = 0;
int kflag = 0;
int aflag = 0;
int uflag = 0;
char *explain = 0;
Word *target1;
int nreps = 1;
Job *jobs;
Biobuf bout;
Rule *patrule;
void badusage(void);
#ifdef  PROF
short buf[10000];
#endif

void
main(int argc, char **argv)
{
       Word *w;
       char *s, *temp;
       char *files[256], **f = files, **ff;
       int sflag = 0;
       int i;
       int tfd = -1;
       Biobuf tb;
       Bufblock *buf;
       Bufblock *whatif;

       /*
        *  start with a copy of the current environment variables
        *  instead of sharing them
        */

       Binit(&bout, 1, OWRITE);
       buf = newbuf();
       whatif = 0;
       USED(argc);
       for(argv++; *argv && (**argv == '-'); argv++)
       {
               bufcpy(buf, argv[0], strlen(argv[0]));
               insert(buf, ' ');
               switch(argv[0][1])
               {
               case 'a':
                       aflag = 1;
                       break;
               case 'd':
                       if(*(s = &argv[0][2]))
                               while(*s) switch(*s++)
                               {
                               case 'p':       debug |= D_PARSE; break;
                               case 'g':       debug |= D_GRAPH; break;
                               case 'e':       debug |= D_EXEC; break;
                               }
                       else
                               debug = 0xFFFF;
                       break;
               case 'e':
                       explain = &argv[0][2];
                       break;
               case 'f':
                       if(*++argv == 0)
                               badusage();
                       *f++ = *argv;
                       bufcpy(buf, argv[0], strlen(argv[0]));
                       insert(buf, ' ');
                       break;
               case 'i':
                       iflag = 1;
                       break;
               case 'k':
                       kflag = 1;
                       break;
               case 'n':
                       nflag = 1;
                       break;
               case 's':
                       sflag = 1;
                       break;
               case 't':
                       tflag = 1;
                       break;
               case 'u':
                       uflag = 1;
                       break;
               case 'w':
                       if(whatif == 0)
                               whatif = newbuf();
                       else
                               insert(whatif, ' ');
                       if(argv[0][2])
                               bufcpy(whatif, &argv[0][2], strlen(&argv[0][2]));
                       else {
                               if(*++argv == 0)
                                       badusage();
                               bufcpy(whatif, &argv[0][0], strlen(&argv[0][0]));
                       }
                       break;
               default:
                       badusage();
               }
       }
#ifdef  PROF
       {
               extern etext();
               monitor(main, etext, buf, sizeof buf, 300);
       }
#endif

       if(aflag)
               iflag = 1;
       usage();
       initenv();
       usage();

       /*
               assignment args become null strings
       */
       temp = 0;
       for(i = 0; argv[i]; i++) if(utfrune(argv[i], '=')){
               bufcpy(buf, argv[i], strlen(argv[i]));
               insert(buf, ' ');
               if(tfd < 0){
                       temp = maketmp();
                       if(temp == 0) {
                               perror("temp file");
                               Exit();
                       }
                       if((tfd = create(temp, ORDWR, 0600)) < 0){
                               perror(temp);
                               Exit();
                       }
                       Binit(&tb, tfd, OWRITE);
               }
               Bprint(&tb, "%s\n", argv[i]);
               *argv[i] = 0;
       }
       if(tfd >= 0){
               Bflush(&tb);
               LSEEK(tfd, 0L, 0);
               parse("command line args", tfd, 1);
               remove(temp);
       }

       if (buf->current != buf->start) {
               buf->current--;
               insert(buf, 0);
       }
       symlook("MKFLAGS", S_VAR, (void *) stow(buf->start));
       buf->current = buf->start;
       for(i = 0; argv[i]; i++){
               if(*argv[i] == 0) continue;
               if(i)
                       insert(buf, ' ');
               bufcpy(buf, argv[i], strlen(argv[i]));
       }
       insert(buf, 0);
       symlook("MKARGS", S_VAR, (void *) stow(buf->start));
       freebuf(buf);

       if(f == files){
               if(access(MKFILE, 4) == 0)
                       parse(MKFILE, open(MKFILE, 0), 0);
       } else
               for(ff = files; ff < f; ff++)
                       parse(*ff, open(*ff, 0), 0);
       if(DEBUG(D_PARSE)){
               dumpw("default targets", target1);
               dumpr("rules", rules);
               dumpr("metarules", metarules);
               dumpv("variables");
       }
       if(whatif){
               insert(whatif, 0);
               timeinit(whatif->start);
               freebuf(whatif);
       }
       execinit();
       /* skip assignment args */
       while(*argv && (**argv == 0))
               argv++;

       catchnotes();
       if(*argv == 0){
               if(target1)
                       for(w = target1; w; w = w->next)
                               mk(w->s);
               else {
                       fprint(2, "mk: nothing to mk\n");
                       Exit();
               }
       } else {
               if(sflag){
                       for(; *argv; argv++)
                               if(**argv)
                                       mk(*argv);
               } else {
                       Word *head, *tail, *t;

                       /* fake a new rule with all the args as prereqs */
                       tail = 0;
                       t = 0;
                       for(; *argv; argv++)
                               if(**argv){
                                       if(tail == 0)
                                               tail = t = newword(*argv);
                                       else {
                                               t->next = newword(*argv);
                                               t = t->next;
                                       }
                               }
                       if(tail->next == 0)
                               mk(tail->s);
                       else {
                               head = newword("command line arguments");
                               addrules(head, tail, strdup(""), VIR, mkinline, 0);
                               mk(head->s);
                       }
               }
       }
       if(uflag)
               prusage();
       exits(0);
}

void
badusage(void)
{

       fprint(2, "usage: mk [-f file] [-n] [-a] [-e] [-t] [-k] [-i] [-d[egp]] [targets ...]\n");
       Exit();
}

void *
Malloc(int n)
{
       register void *s;

       s = malloc(n);
       if(!s) {
               fprint(2, "mk: cannot alloc %d bytes\n", n);
               Exit();
       }
       return(s);
}

void *
Realloc(void *s, int n)
{
       if(s)
               s = realloc(s, n);
       else
               s = malloc(n);
       if(!s) {
               fprint(2, "mk: cannot alloc %d bytes\n", n);
               Exit();
       }
       return(s);
}

void
regerror(char *s)
{
       if(patrule)
               fprint(2, "mk: %s:%d: regular expression error; %s\n",
                       patrule->file, patrule->line, s);
       else
               fprint(2, "mk: %s:%d: regular expression error; %s\n",
                       infile, mkinline, s);
       Exit();
}