/*
 *     Control of the implicit suffix rules
 */

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

/* function to added by DJ */

/* concat() - concatenate two strings into a third, null terminate,
	with max length limit and status return.
*/

char *concat(dest,source1,source2,maxlen)
	char		*source1,
				*source2,
				*dest;
	long		maxlen;
{	char		*result = dest;

	for (;;)
	{	if (maxlen-- < 0) return NULL;
		if (*source1) *dest++ = *source1++;
		else if (*source2) *dest++ = *source2++;
		else { *dest= 0; return result; }
	}
}

/*
 *     Return a pointer to the suffix of a name
 */
char *suffix(name)
	char *name;
{	return rindex(name, '.');
}

/*
 *     Dynamic dependency.  This routine applies the suffix rules
 *     to try and find a source and a set of rules for a missing
 *     target.	If found, np is made into a target with the implicit
 *     source name, and rules.	Returns TRUE if np was made into
 *     a target.
 */

#define FNAME_LENGTH		32

bool dyndep(np) struct name *np;
{	register char		*p;
	register char		*q;
	register char		*suff;			/*  Old suffix  */
	register char		*basename;		/*  Name without suffix	*/
	struct name			*op;			/*  New dependent  */
	struct name			*sp;			/*  pointer to Suffix name record */
	struct line			*lp;
	struct depend		*dp;			/* dependancy pointer */
	char				*newsuff;		/* pointer to new suffix string */
	char				new_name[FNAME_LENGTH];	/* temp string buffer */

	p = new_name;
	q = np->n_name;

	if (!(suff = suffix(q))) return FALSE;		/* No suffix */

	while (q < suff) *p++ = *q++;				/* copy base name to new_name */
	*p = '\0';									/* and null terminate */

	basename = setmacro("*",new_name)->m_val;	/* set the macro '*' := basename */

	/* look for the '.SUFFIXES' entry. If no targets specified, then dynamic
		dependancies are diabled.
	*/

	if (!((sp = newname(".SUFFIXES"))->n_flag & N_TARG))
		return FALSE;

	/* else, look through the list of valid suffixes to find which one applies
		to this file.
		NOTE: Manx make does not need this, as it infers the valid suffxes from
		the rules list.
	*/

	for (lp = sp->n_line; lp; lp = lp->l_next)		/* for each line of 'suffix' */
		for (dp = lp->l_dep; dp; dp = dp->d_next)	/* for each dependancy spec'd */
		{
			newsuff = dp->d_name->n_name;			/* pointer to a new suffix */

				/* new_name = newsuff + suff */
			if (!concat(new_name,newsuff,suff,FNAME_LENGTH))
				fatal("Suffix rule too long");

			sp = newname(new_name);					/* get that rule, if exists */
			if (sp->n_flag & N_TARG)				/* if has targets */
			{
				/* now append the new suffix to the name, result in new_name */

				if (!concat(new_name,basename,newsuff,FNAME_LENGTH))
					fatal("Suffix rule too long");

				/* special rule for PAMAKE, allows partial match... */
				/* (I'm not sure how good of an idea this is, but we'll see...
					I think I'd rather use things like FileOnly()
				*/

/* deleted until we can get a strstr() */
/*
				if (strstr(q=np->n_line->l_dep->d_name->n_name,str1))
					op=newname(q);
				else
*/
					op = newname(new_name);		/* make that a name */

				if (null_time(&op->n_time))			/* if file note yet looked at */
					modtime(op);					/* look for it */
				if (!null_time(&op->n_time))		/* if found */
				{	dp = newdep(op, 0);				/* make a new dependancy */
					newline(np, dp, sp->n_line->l_cmd, 0);	/* a new line entry */
					setmacro("<", op->n_name);		/* set the macro '<' to name */
					return TRUE;					/* yup, we did it */
				}
			}
		}
	return FALSE;
}


/*
 *     Make the default rules
 */
void makerules()
{	struct cmd			*cp;
	struct name			*np;
	struct depend		*dp;

/*
 *     Some of the UNIX implicit rules
 */

#ifdef unix
	setmacro("CC", "cc");
	setmacro("CFLAGS", "-O");
	cp = newcmd("$(CC) $(CFLAGS) -c $<", 0);
	np = newname(".c.o");
	newline(np, 0, cp, 0);

	setmacro("AS", "as");
	cp = newcmd("$(AS) -o $@ $<", 0);
	np = newname(".s.o");
	newline(np, 0, cp, 0);

	setmacro("YACC", "yacc");
	/*      setmacro("YFLAGS", ""); */
	cp = newcmd("$(YACC) $(YFLAGS) $<", 0);
	cp = newcmd("mv y.tab.c $@", cp);
	np = newname(".y.c");
	newline(np, 0, cp, 0);

	cp = newcmd("$(YACC) $(YFLAGS) $<", 0);
	cp = newcmd("$(CC) $(CFLAGS) -c y.tab.c", cp);
	cp = newcmd("rm y.tab.c", cp);
	cp = newcmd("mv y.tab.o $@", cp);
	np = newname(".y.o");
	newline(np, 0, cp, 0);

	np = newname(".s");
	dp = newdep(np, 0);
	np = newname(".o");
	dp = newdep(np, dp);
	np = newname(".c");
	dp = newdep(np, dp);
	np = newname(".y");
	dp = newdep(np, dp);
	np = newname(".SUFFIXES");
	newline(np, dp, 0, 0);
#endif
#ifdef MCH_AMIGA

	/* default rule for .c files */

	setmacro("CC", "cc");
	setmacro("CFLAGS", "-O");
	cp = newcmd("$(CC) $(CFLAGS) $<", 0);
	np = newname(".c.o");
	newline(np, 0, cp, 0);

	/* default rule for .asm files */

	setmacro("AS", "as");
	cp = newcmd("$(AS) -o $@ $<", 0);
	np = newname(".asm.o");
	newline(np, 0, cp, 0);

	/* default rule for .y files to .c and .o */

	setmacro("YACC", "yacc");
	/*      setmacro("YFLAGS", ""); */
	cp = newcmd("$(YACC) $(YFLAGS) $<", 0);
	cp = newcmd("mv y.tab.c $@", cp);
	np = newname(".y.c");
	newline(np, 0, cp, 0);

	cp = newcmd("$(YACC) $(YFLAGS) $<", 0);
	cp = newcmd("$(CC) $(CFLAGS) -c y.tab.c", cp);
	cp = newcmd("rm y.tab.c", cp);
	cp = newcmd("mv y.tab.o $@", cp);
	np = newname(".y.o");
	newline(np, 0, cp, 0);

	/* define valid suffixes: .asm .o .c .y */

	np = newname(".asm");		dp = newdep(np, 0);
	np = newname(".o");			dp = newdep(np, dp);
	np = newname(".c");			dp = newdep(np, dp);
	np = newname(".y");			dp = newdep(np, dp);
	np = newname(".SUFFIXES");	newline(np, dp, 0, 0);

	/* add lattice C, C++, whatever else, etc. */

#endif
}
