/*************************************************************************
 *
 *  m a k e :   m a i n . c
 *
 *========================================================================
 * Edition history
 *
 *  #    Date                         Comments                       By
 * --- -------- ---------------------------------------------------- ---
 *   1    ??                                                         ??
 *   2 01.07.89 strcmp(makefile,..) only if makefile a valid ptr.    RAL
 *   3 23.08.89 initname() added                                     RAL
 *   4 30.08.89 argument parsing impr., indention ch., macro fl. add.PSH,RAL
 *   5 03.09.89 k-option added, initname -> init changed             RAL
 *   6 06.09.89 environment, MAKEFLAGS, e,d,a options added,         RAL
 *   7 09.09.89 tos support added, fatal args added, fopen makefile  PHH,RAL
 *   8 17.09.89 setoptions fixed for __STDC__                        RAL
 * ------------ Version 2.0 released ------------------------------- RAL
 *
 *************************************************************************/

/*
 *	make:
 *
 *	-a try to guess undefined ambiguous macros (*,<)
 *	-d print debugging info
 *	-e environment macro def. overwrite makefile def.
 *	-f makefile name
 *	-i ignore exit status
 *	-k continue on errors
 *	-n pretend to make
 *	-p print all macros & targets
 *	-q question up-to-dateness of target.  Return exit status 1 if not
 *	-r don't not use inbuilt rules
 *	-s make silently
 *	-t touch files instead of making them
 *	-m Change memory requirements (EON only)
 */

#define EXTERN
#define INIT(x) = x
#define INITARRAY
#include "h.h"

static char version[]= "2.0";

static char *makefile;      /*  The make file  */
static FILE *ifd;           /*  Input file desciptor  */
static char *ptrmakeflags;

/* There must be enough 'space' for all possible flags ! */
static char  makeflags[] = "MAKEFLAGS=                    ";

void main(argc, argv)
int    argc;
char **argv;
{
  register char        *p;		/*  For argument processing  */
  int                   estat = 0;	/*  For question  */
  register struct name *np;
  struct macro         *mp;
  int                   targc;		/* temporary for multiple scans */
  char                **targv;
  char                **nargv;		/* for removing items from argv */
  char                **envp;      /* enivironment ptr */


  ptrmakeflags = &makeflags[10];
  myname = (argc-- < 1) ? "make" : *argv++;
#ifdef tos
  myname = "Make";
#endif

  targc = argc;
  targv = nargv = argv;
  while (targc--) {
	if((p = strchr(*targv, '=')) != (char *)NULL) {
		*p = '\0';
		mp = setmacro(*targv, p + 1);
		mp->m_flag |= M_OVERRIDE;
		--argc;
	} else
		*nargv++ = *targv;

	++targv;
  }

  targc = argc;
  targv = nargv = argv;
  while (targc--) {
	if (**targv == '-') {
		--argc;
		p = *targv++;
		while (*++p != '\0') {
			switch(mylower(*p)) {
			case 'f':	/*  Alternate file name  */
				if (*++p == '\0') {
					--argc;
					if (targc-- == 0)
						usage();
					p = *targv++;
				}
				makefile = p;
				goto end_of_args;
#ifdef eon
			case 'm':	/*  Change space requirements  */
				if (*++p == '\0') {
					--argc;
					if (targc-- <= 0)
						usage();
					p = *targv++;
				}
				memspace = atoi(p);
				goto end_of_args;
#endif
			default :
				setoption(*p);
				break;
			}
		}
	end_of_args:;
	} else
		*nargv++ = *targv++;
  }

  /* evaluate and update environment MAKEFLAGS */
  if((p =getenv("MAKEFLAGS")) != (char *)0)
	while(*p) setoption(*p++);
  for( p = ptrmakeflags; !isspace((int)*p); p++) ;
  *p = '\0';
  putenv(makeflags);


#ifdef eon
  if (initalloc(memspace) == 0xffff)  /*  Must get memory for alloc  */
	fatal("Cannot initalloc memory",(char *)0,0);
#endif

  if (makefile && strcmp(makefile, "-") == 0)  /*   use stdin as makefile  */
	ifd = stdin;
  else if (!makefile) {    /*  If no file, then use default */
	if ((ifd = fopen(DEFN1, "r")) == (FILE *)0) {
		if (errno != MNOENT || !DEFN2)
			fatal("Can't open %s; error %02x", DEFN1, errno);
		else if ((ifd = fopen(DEFN2, "r")) == (FILE *)0)
			fatal("Can't open %s; error %02x", DEFN2, errno);
	}
  }
  else if ((ifd = fopen(makefile, "r")) == (FILE *)0)
	fatal("Can't open %s; error %2x", makefile, errno);

  init();

  makerules();

  mp = setmacro("MAKE", myname);
  mp->m_flag |= M_MAKE;
  setmacro("$", "$");

  /* set environment macros */
  envp = environ; /* get actual environment ptr. */
  while (*envp) {
	if((p = strchr(*envp, '=')) != (char *)NULL) {
		*p = '\0';
		mp = setmacro(*envp, p + 1);
		*p = '=';
		if (useenv) mp->m_flag |= M_OVERRIDE;
	} else
		fatal("invalid environment: %s",*envp,0);

	++envp;
  }

  input(ifd);	/*  Input all the gunga  */
  fclose(ifd);	/*  Finished with makefile  */
  lineno = 0;	/*  Any calls to error now print no line number */

  if (print)
	prt();	/*  Print out structures  */

  np = newname(".SILENT");
  if (np->n_flag & N_TARG)  silent = TRUE;

  np = newname(".IGNORE");
  if (np->n_flag & N_TARG)  ignore = TRUE;

  precious();

  if (!firstname)
	fatal("No targets defined",(char *)0,0);

  circh();	/*  Check circles in target definitions  */

  if (!argc)
	estat = make(firstname, 0);
  else
	while (argc--) {
		estat |= make(newname(*argv++), 0);
	}

  if (quest)
	exit(estat);
  else
		exit(0);
}

#ifdef __STDC__
void setoption(char option)
#else
void setoption(option)
char option;
#endif
{
  register char *c;

  option = mylower(option);
  switch(option) {
	case 'n':	/*  Pretend mode  */
		domake = FALSE;
		break;
	case 'i':	/*  Ignore fault mode  */
		ignore = TRUE;
		break;
	case 'k':	/*  Continue on errror  */
		conterr = TRUE;
		break;
	case 's':	/*  Silent about commands  */
		silent = TRUE;
		break;
	case 'p':
		print = TRUE;
		break;
	case 'r':
		rules = FALSE;
		break;
	case 't':
		dotouch = TRUE;
		break;
	case 'q':
		quest = TRUE;
		break;
	case 'e':
		useenv = TRUE;
		break;
	case 'd':
		dbginfo = TRUE;
		break;
	case 'a':
		ambigmac = TRUE;
		break;
	default:	/*  Wrong option  */
		usage();
  }
  for( c = ptrmakeflags; !isspace((int)*c); c++)
	if ( *c == option) return;
  *c = option;
}

void usage()
{
  fprintf(stderr, "Syntax: %s [{options | macro=val | target}]\n", myname);
  fprintf(stderr, "Function: maintaining computer programs      V%s\n",version);
  fprintf(stderr, "Options : -a : try to guess undefined ambiguous macros (*,<)\n");
  fprintf(stderr, "          -d : print debugging information\n");
  fprintf(stderr, "          -e : environment macro def. overwrite makefile def.\n");
  fprintf(stderr, "          -f filename : makefile name (default: makefile, Makefile)\n");
  fprintf(stderr, "          -i : ignore exit status of executed commands\n");
  fprintf(stderr, "          -k : continue with unrelated branches on errors\n");
  fprintf(stderr, "          -n : pretend to make\n");
  fprintf(stderr, "          -p : print all macros & targets\n");
  fprintf(stderr, "          -q : question up-to-dateness of target\n");
  fprintf(stderr, "          -r : don't use inbuilt rules\n");
  fprintf(stderr, "          -s : make silently\n");
  fprintf(stderr, "          -t : touch files instead of making them\n");
  fprintf(stderr, "Environment: MAKEFLAGS\n");
  exit(1);
}


void fatal(msg, a1, a2)
char *msg;
char *a1;
int   a2;
{
  fprintf(stderr, "%s: ", myname);
  fprintf(stderr, msg, a1, a2);
  fputc('\n', stderr);
  exit(1);
}
