/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ident	"$Header: main.c 1.31 90/04/13 $"

#include <stdio.h>
#include <ctype.h>
#include "config.h"
#include <sys/stat.h>
#include "allocate.h"
#include "y.tab.h"

extern	FILE	*yyin;

long	Debug_mask = 0;	/* diagnostic messages */
int	Lflag = 1;	/* produce file list (on by default) */
int	Visibility = 0;	/* parameter visibility level */
boolean	Dflag = FALSE;	/* produce dependency information */
boolean	Config = TRUE;	/* make configuration (on by default) */
boolean	Vflag = FALSE;	/* display config command version# (off by default) */
boolean	Trouble = FALSE;/* so far, so errors */
boolean	Warning = FALSE;/* so far, no warnings */

FILE	*yyin0;
int	yylineno0;

char	*machine_type;		/* machine architecture (e.g. "symmetry") */
char	*configuration_name;	/* configuration (e.g. "std") */

int	Anchor_len;		/* strlen(Anchor_dir) */
char	Anchor_dir[MAXPATH];	/* anchor directory (see SRC_ANCHOR) */
char	Mach_dir[MAXPATH];	/* the machine architecture directory */
char	Build_dir[MAXPATH];	/* build dir: <machine>.<configuration> */
char	Module_dir[MAXPATH];	/* current module dir being parsed */
char	T_dirl[MAXPATH];	/* current module dir (local form) */
char	T_ddirl[MAXPATH];	/* current destination (local form) */
char	Smk_file[MAXPATH];	/* source system makefile.skel */
char	Mk_file[MAXPATH];	/* destination system makefile */
char	Files_file[MAXPATH];
char	Bfiles_file[MAXPATH];

char	rcs_id[] = "$Revision: 1.31 $";
struct	pmodule	*Pmodp;		/* current module information */
struct	cmodule	*Lcmodp;	/* current library module information */

struct	device	*dtab;
struct	connect *ctab;
struct	macro	*Subo;		/* system sub option list */

boolean	device_spec;
int	Max_bdev;
int	Max_cdev;
int	Max_cstr;
int	Max_bus=1;
int	Max_fs=1;
int	Max_syscall;
struct vers	Vers;

/*
 * Config builds a set of files for building a UNIX
 * system given a description of the desired system.
 *
 * Process command line options.
 * Set up names used by rest of program.
 * parse the module and system file.
 * parse the config file for each module.
 * generate the Makefile.
 * generate the interface files.
 *
 */
main(argc, argv)
	int argc;
	char **argv;
{
	extern boolean next_sysconfig();/* get next system configuration file */
	extern void write_params();	/* write configurable parameter defns */
	extern void eval_params();	/* evaluate configurable parameters */
	extern void select_sysconfig();	/* select sys_config file parameters */
	static void usage();		/* usage diagnostics */

	extern	char	*optarg;
	extern	int	optind;
	extern	int	Fflags;
	extern	int	yylineno;

	FILE		*modfp;		/* module configuration file */
	char		*param_file;	/* pointer to file for "-p" option */
	char		*expr_file;	/* pointer to file for "-x" option */
	int		select;		/* select file flag "-f" seen */
	int		ch;
	boolean		otheropts;

	/*
	 * initialise fatal strings.
	 */
	yylineno = 0;
	Fflags = FTLMSG;

	param_file = (char *)NULL;
	expr_file = (char *)NULL;
	machine_type = (char *)NULL;
	configuration_name = (char *)NULL;
	select = 0;

	/*
	 * Parse command arguments.
	 */
	otheropts = FALSE;
	while ((ch=getopt(argc, argv, "c:dD:f:lLm:p:vx:z:")) != EOF) {
		switch(ch) {

		/*
		 * define configuration type.
		 */
		case 'c':
			if (configuration_name != (char *)NULL) {
				usage(argv[0]);
			}
			configuration_name = optarg;
			otheropts = TRUE;
			break;
		/*
		 * produce dependencies -not useful.
		 */
		case 'd':
			otheropts = TRUE;
			Dflag = TRUE;
			break;
		/*
		 * Debug mode: 0 -- phase information
		 *	       1 -- header file directory info
		 *	       4 -- basic interconnect info
		 *	       6 -- make rules info
		 *	       8 -- more interconnect info
		 *	      12 -- detailed interconnect info
		 *	      16 -- parameter directives
		 *	      20 -- symbol table debugging
		 *	      24 -- detailed parameter directive info
		 *	      31 -- memory management statistics
		 *
		 *  By default, it is all cumulative.  That is, saying
		 *  "-D 4" will get you basic interconnect information AND
		 *  phase and header directory information.
		 *
		 *  If you want specific information, you need to use a
		 *  bit mask specified by a leading '0x' prefix.  For
		 *  example, you could say:  "-D 0x80010011."  This would
		 *  select:
		 *
		 *	   31: memory management statistics;
		 *	   16: parameter directives;
		 *	    4: basic interconnect info;
		 *	    0: phase information.
		 */
		case 'D':
			Debug_mask = strtol(optarg, (char **)NULL, 0);
			if (optarg[0] != '0' || optarg[1] != 'x') {
				/*
				 *  Not given as mask.
				 */
				if (Debug_mask > 31)
					Debug_mask = 31;
				Debug_mask = (1L << Debug_mask);
				Debug_mask += (Debug_mask - 1);
			}
			break;
		/*
		 * select parameters from the named system configuration
		 * file and all of its module configuration files.
		 */
		case 'f':
			select_sysconfig(optarg);
			select = 1;
			otheropts = TRUE;
			break;
		/*
		 * produce "list" file. - on by default.
		 */
		case 'l':
			otheropts = TRUE;
			Lflag = 1;
			break;
		case 'L':
			otheropts = TRUE;
			Lflag = 2;
			break;
		/*
		 * define machine type.
		 */
		case 'm':
			if (machine_type != (char *)NULL) {
				usage(argv[0]);
			}
			machine_type = optarg;
			otheropts = TRUE;
			break;
		/*
		 * generate list of configurable parameters in the
		 * designated file.
		 */
		case 'p':
			if (param_file != (char *)NULL) {
				usage(argv[0]);
			}
			param_file = optarg;
			otheropts = TRUE;
			Config = FALSE;		/* suppress configuration */
			break;
		/*
		 * display the config(1) command version#. - off by default
		 */
		case 'v':
			Vflag = TRUE;
			break;
		/*
		 * generate list of all expressions for the configurable
		 * parameters in the designated file.
		 */
		case 'x':
			if (expr_file != (char *)NULL) {
				usage(argv[0]);
			}
			expr_file = optarg;
			otheropts = TRUE;
			Config = FALSE;		/* suppress configuration */
			break;
		/*
		 * Select all parameters at or higher than the given
		 * visibility level.
		 */
		case 'z':
			Visibility = strtol(optarg, (char **)NULL, 0);
			otheropts = TRUE;
			break;
		/*
		 * error cases.
		 */
		default:
			usage(argv[0]);
		}
	}
	if (Debug_mask) {
		long mask;
		int i, start;
		
		printf("Debug levels [");
		i = 0;
		mask = 0x1;
		while (i <= 31) {
			if (Debug_mask & mask) {
				start = i++;
				mask <<= 1;
				while (i <= 31 && (Debug_mask & mask)) {
					i++;
					mask <<= 1;
				}
				if (i - 1 == start) {
					printf (" %d", start);
				} else {
					printf (" %d..%d", start, i-1);
				}
			}
			i++;
			mask <<= 1;
		}
		printf("]\n");
	}
	if ((Vflag && otheropts) || (select && Config))
		usage(argv[0]);
	if (Vflag) {
		printf("Supported configuration levels are %d.%d to %d.%d.\n",
			SUPPORT_V, SUPPORT_SVL, SUPPORT_V, SUPPORT_SVH);
		exit(0);
	}
	/*
	 * establish default machine (architecture) type and configuration.
	 */
	if (machine_type == (char *)NULL)
		machine_type = DEF_MACH;
	if (configuration_name == (char *)NULL)
		configuration_name = DEF_CONF;

	/*
	 *  Create names for global files and FILE descriptors.
	 */
	set_mach();			

	/*
	 *  Process the system files (and their corresponding
	 *  module configurations).
	 */
	while (next_sysconfig())
		;

	/*
	 * check and complete the connection trees.
	 */
	if (Config)
		check_connect();

	if (!Trouble) {			/* no trouble so far... */
		eval_params();		/* evaluate parameters */
		if (!Trouble) {		/* no errors.... */
			if (Config) {
				scan_skel();	/* generate Makefile */
				/*
				 * generate the I/O tables in conf.c
				 * and config.h
				 */
				do_conf();	/* generate interface modules */
				if (!Trouble)
					mk_hdrdirs();	/* make header dirs */
			} else
				write_params(param_file, expr_file);
		}
	}

	if (DEBUG_LEVEL(31)) {
		show_liststats();
		show_exprstats();
		show_exprliststats();
	}

	if (Trouble)
		exit(1);
	/*
	 *  If we're generating a parameters or expressions file (i.e. we
	 *  are being invoked via the menu system), AND we have warnings,
	 *  then exit(2).
	 */
	if (Warning && !Config) {
		exit(2);
	}
	exit(0);
	return(0);			/* for lint */
}

/*
 * Usage message.
 */
usage(pgm_name)
register char *pgm_name;		/* program invocation name */
{
	fprintf(stderr, "usage: %s [-c configuration_name] [-m machine_type]\n",
			pgm_name);
	fprintf(stderr, "   or: %s -v\n", pgm_name);
	exit(1);
}
