/*
 *				b u i l d 2 . c
 *
 * Process programs and libraries
 */

#include	<stdio.h>
#include	"build.h"

doprog(argc, argv, library)
int		argc;
char		*argv[];
int		library;	/* True if library building		*/
/*
 * Process program and library builds
 */
{
	register int	i;
	register char	*ap;
	register FILE	*fd;
	int		nfiles;		/* Wildcard files found		*/
	int		tfiles;		/* Total wildcard files found	*/
	int		bfiles;		/* Files built			*/
	int		missed;		/* Files not built		*/
	int		tbuilt;		/* Total files built		*/
	int		args;		/* Non-NULL arguments		*/
	char		*libfiles;

	tfiles = tbuilt = missed = args = 0;
	expout("$(INITIALIZE)$(FIRST)");
	if (library)
		libfiles = savest("");
retry:					/* Hack for "build foo"		*/
	for (i = 1; i < argc; i++) {
		if ((ap = argv[i]) == NULL)
			continue;
		args++;			/* We have a non-null argument	*/
		if (verbose)
			fprintf(stderr, "processing \"%s\":\n", ap);
		if ((fd = fwild(ap, "r")) == NULL) {
			fprintf(stderr, "can't open wild card file \"%s\"\n",
					ap);
			continue;
		}
		for (nfiles = bfiles = 0; fnext(fd) != NULL; nfiles++) {
			syclean();
			/*
			 * Comment out copy if COPYINCLUDE and SRC are both
			 * at their default values.
			 */
			if (src_name == NULL
					&& isdefault("SRC")
					&& isdefault("COPYINCLUDE"))
				sysave("COPYCOMMENT", "$(COMMENT)");
			if (!getmodel(fd, (library)
					? "/*)LIBRARY" : "/*)BUILD")) {
				missed++;
				continue;
			}
			bfiles++;
			if (opsys != UNIX) {
				if (!isdefault("DTOA")) {
					sysave("DTOA", "$(DTOA.OBJ)");
				}
				if (!isdefault("ATOF")) {
					sysave("ATOF", "$(ATOF.OBJ)");
				}
			}
			expout("$(PREFIX)");
			if (opsys != UNIX) {
				doeach("INCLUDE", "COPYINCLUDE", NULL);
				if (!isdefault("MP")) {
					if (!mpinstall) {
						expout("$(MPINSTALL)");
						mpinstall = TRUE;
					}
					doeach("FILES", "CCMP", ".C");
				}
				else {
					doeach("FILES", "CC", ".C");
				}
			}
			else {
				dounix("FILES");
			}
			if (zflag) {
				/*
				 * No cleanup, no postfix
				 */
			}
			else if (library) {
				libfiles = csavest(libfiles, " ");
				libfiles = csavest(libfiles, syvalue("FILES"));
			}
			else if (opsys != UNIX) {
				dolink();
				doeach("FILES", "CLEANUP", NULL);
				expout("$(POSTFIX)");
			}
		}
		tfiles += nfiles;
		tbuilt += bfiles;
		if (nfiles == 0) {
			fprintf(stderr, "warning, no files match \"%s\"\n",
					ap);
		}
		if (bfiles == 0) {
			fprintf(stderr, "warning, no builds for \"%s\"\n", ap);
		}
		/*
		 * I have a bad habit of typing "BUILD FOO" when I mean
		 * "BUILD FOO.C", so I'll just fix it up a bit...
		 * This loop will be entered ONLY if there is exactly
		 * one file argument, and it doesn't have a '.' anywhere.
		 *
		 * Note: args will equal 2 the next time around, so we
		 * can't loop indefinitly.
		 */
		if (bfiles == 0 && tfiles == 0 && args == 1) {
			for (i = 1; i < argc; i++) {
				if ((ap = argv[i]) == NULL)
					continue;
				while(*ap != EOS && *ap != '.')
					ap++;
				if (*ap == '.')
					break;	/* It had a dot		*/
				/*
				 * try for FOO.C
				 */
				setfile(argv[i], ".C");
				ap = syvalue("?");
				fprintf(stderr, "Changing \"%s\" to \"%s\"\n",
					argv[i], ap);
				argv[i] = savest(ap);
				goto retry;
			}
		}
	}
	if (library && !zflag) {
		dolibr(libfiles);
		doevery(libfiles, "CLEANUP", NULL);
	}
	expout("$(LAST)$(TERMINATE)");
	if (verbose) {
		fprintf(stderr,
		  "%d files found, %d files built, %d not built\n",
				tfiles, bfiles, missed);
	}
}

int
getmodel(fd, signal)
register FILE	*fd;
char		*signal;
/*
 * Look for a model string in the file, do model arguments,
 * returning TRUE if there was one.
 */
{
	register char	*model;
	register char	*text;
	int		siglen;
	
	setfile(fgetname(fd, work), NULL);
	if (verbose)
		fprintf(stderr, "  \"%s\"\n", syvalue("?"));
	siglen = strlen(signal);
	while (getline(fd) != NULL) {
		if (mmatch(inline, signal, siglen))
			break;
	}
	if (feof(fd)) {
		if (verbose)
			fprintf(stderr, "No %s in \"%s\"\n",
				signal, syvalue("?"));
		if (build == 0)
			return (FALSE);
	}
	/*
	 * Set PROGRAM name and initialize file name list to this program name.
	 * The file name list may be overwritten by model processing.
	 */
	text = syvalue("*");
	sysave("FILES", text, 0);
	sysave("PROGRAM", text, 0);
	if (!feof(fd)) {
		/*
		 * )BUILD was found
		 */
		model = savest(skipwhite(inline + siglen));
		while (getline(fd) != NULL) {
			text = skipwhite(inline);
			if (streq(text, "*/\n"))
				break;
			model = csavest(model, text);
		}
		if (feof(fd)) {
			fprintf(stderr, "?No trailing */ in \"%s\"\n", work);
			return (FALSE);
		}
		define(model);
		myfree(model);
	}
	/*
	 * Now, force $(PROGRAM) to uppercase (not on unix!)
	 */
	if (opsys != UNIX) {
		for (text = syvalue("PROGRAM"); *text != EOS; text++)
			*text = toupper(*text);
	}
	return (TRUE);
}

doeach(fmodel, command, filetype)
char		*fmodel;
char		*command;
char		*filetype;
/*
 * Expand command once for each file in syvalue(fmodel)
 */
{
	doevery(syvalue(fmodel), command, filetype);
}

doevery(arg, command, filetype)
char		*arg;
char		*command;
char		*filetype;		/* Default filetype if non-null	*/
/*
 * Expand command once for each file in flist.
 */
{
	register int		c;
	register char		*tp;
	register char		*ap;
	char			*macro;

	if (arg == NULL)
		return;			/* if no INCLUDE, for example	*/
	if ((macro = syvalue(command)) == NULL) {
		fprintf(stderr, "?No definition of %s\n", command);
		return;
	}
	for (ap = arg;;) {
		while (iswhite((c = *ap++)))
			;
		if (c == EOS)
			break;
		tp = work;
		do {
			*tp++ = c;
		} while ((c = *ap++) != EOS && !iswhite(c));
		*tp = EOS;
		setfile(work, filetype);
		expout(macro);
		if (c == EOS)
			break;
	}
}
