/*
 *				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") || !isdefault("CPP")) {
			if (!mpinstall) {
			    expout("$(MPINSTALL)");
			    mpinstall = TRUE;
			}
			doeach("FILES", "CCMP", ".C");
		    }
		    else {
			doeach("FILES", "CC", ".C");
		    }
		}
		else {
		    dounix("FILES");
		}
		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", FALSE);
		    ap = syvalue("?");
		    fprintf(stderr, "Changing \"%s\" to \"%s\"\n", argv[i], ap);
		    argv[i] = savest(ap);
		    goto retry;
		}
	    }
	}
	if (library) {
	    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, TRUE);
	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, TRUE);
		expout(macro);
		if (c == EOS)
			break;
	}
}
