static char *RcsId = 
    "$Header: /src/bin/make/m/misc.c,v 4.8 84/04/24 21:17:32 crl Exp $";

/* static char *sccsid = "@(#)misc.c	4.1 (Berkeley) 81/02/28"; */

/*
 * $Log:	/src/bin/make/m/misc.c,v $
 * Revision 4.8  84/04/24  21:17:32  crl
 * Cleaned up error mesgs and added some portability casts.
 * 
 * Revision 4.7  84/04/13  00:40:25  crl
 * Turn off touchflag in quit() so we don't try to touch anything while
 * 	performing the cleanup.
 * 
 * Revision 4.6  83/10/31  01:34:23  crl
 * Added ncat() to do daisy-chained appends
 * 
 * Revision 4.5  83/10/22  20:03:09  crl
 * Fixed a possible bug in the original code.  mkqlist had both a return;
 * 	and a return();
 * 
 * Revision 4.4  83/07/23  15:34:55  crl
 * Added call of rm() in quit() if rmflag is true.
 * 
 * Revision 4.3  83/07/23  14:51:31  crl
 * Added quit() for later use in conjunction with removing auto-co'd 
 * 	files.
 * 
 * Revision 4.2  83/07/22  14:14:59  crl
 * Made to work transparently with RCS.
 * 
 * Revision 4.1  83/03/01  00:44:17  crl
 * Vanilla 4.1 version
 */

#include "defs.h"

FSTATIC struct nameblock *hashtab[HASHSIZE];
FSTATIC int nhashed	= 0;

/* simple linear hash.  hash function is sum of
 * characters mod hash table size.
 */
int
hashloc(s)
char *s;
{
	register int i;
	register int hashval;
	register char *t;

	hashval = 0;

	for(t=s; *t!='\0' ; ++t)
		hashval += *t;

	hashval %= HASHSIZE;

	for(i=hashval; hashtab[i]!=0 && unequal(s,hashtab[i]->namep);
						i = (i+1)%HASHSIZE)
		;

	return(i);
}

struct nameblock *
srchname(s)
char *s;
{
	return( hashtab[hashloc(s)] );
}

/*
 * make a fresh copy of the string s
 */
struct nameblock *
makename(s)
char *s;
{
	register struct nameblock *p;

	if(nhashed++ > HASHSIZE-3)
		fatal("Hash table overflow");

	p = ALLOC(nameblock);
	p->nxtnameblock = firstname;
	p->namep = copys(s);
	p->linep = 0;
	p->done = 0;
	p->septype = 0;
	p->modtime = 0;

	firstname = p;
	if(mainname == NULL)
		if(s[0]!='.' || hasslash(s) )
			mainname = p;

	hashtab[hashloc(s)] = p;

	return(p);
}

int
hasslash(s)
register char *s;
{
	while(*s)
		if(*s++ == '/')
			return(YES);
	return(NO);
}

char *
copys(s)
register char *s;
{
	register char *t, *t0;

	if( (t = t0 = calloc((unsigned) strlen(s)+1 , sizeof(char)) ) == NULL)
		fatal("out of memory");
	while(*t++ = *s++)
		;
	return(t0);
}

/*
 * c = concatenation of a and b 
 */
char *
concat(a,b,c)
register char *a,*b;
char *c;
{
	register char *t;
	t = c;

	while(*t = *a++)
		t++;
	while(*t++ = *b++)
		;
	return(c);
}

/*
 * is b the suffix of a?  if so, set p = prefix 
 */
int
suffix(a,b,p)
register char *a,*b,*p;
{
	char *a0,*b0;
	a0 = a;
	b0 = b;

	while(*a++)
		;
	while(*b++)
		;

	if( (a-a0) < (b-b0) )
		return(0);

	while(b>b0)
		if(*--a != *--b)
			return(0);

	while(a0<a)
		*p++ = *a0++;
	*p = '\0';

	return(1);
}

int *
ckalloc(n)
register int n;
{
	register int *p;

	if (p = (int *) calloc((unsigned) 1, (unsigned) n))
		return(p);

	fatal("out of memory");
	/* NOTREACHED */
}

/*
 * copy string a into b, substituting for arguments 
 * returns ptr to null at end of string b
 */
char *
subst(a,b)
register char *a,*b;
{
	static depth	= 0;
	register char *s;
	char vname[MAXPATH];
	struct varblock *vbp;
	char closer;

	if(++depth > 100)
		fatal("infinitely recursive macro?");
	if(a!=0)
		while(*a) {
			if(*a != '$')
				*b++ = *a++;
			else if(*++a=='\0' || *a=='$')
				*b++ = *a++;
			else {
				s = vname;
				if( *a=='(' || *a=='{' ) {
					closer = ( *a=='(' ? ')' : '}');
					++a;
					while(*a == ' ')
						++a;
					while(*a!=' ' && *a!=closer && *a!='\0')
						*s++ = *a++;
					while(*a!=closer && *a!='\0')
						++a;
					if(*a == closer)
						++a;
				} else
					*s++ = *a++;
	
				*s = '\0';
				if( (vbp = varptr(vname)) ->varval != 0) {
					b = subst(vbp->varval, b);
					vbp->used = YES;
				}
			}
	}

	*b = '\0';
	--depth;
	return(b);
}

setvar(v,s)
char *v, *s;
{
	struct varblock *p;

	p = varptr(v);
	if(p->noreset == 0) {
		p->varval = s;
		p->noreset = inarglist;
		if(p->used && unequal(v,"@") && unequal(v,"*")
		    && unequal(v,"<") && unequal(v,"?") )
			fprintf(stderr, "%s: Warning--%s changed after being used\n", progname, v);
	}
}

/*
 * look for arguments with equal signs but not colons 
 */
int
eqsign(a)
char *a;
{
	register char *s, *t;

	while(*a == ' ')
		++a;
	for(s = a; *s != '\0' && *s != ':'; ++s)
		if(*s == '=') {
			for(t = a ; *t!='=' && *t!=' ' && *t!='\t' ;  ++t )
				;
			*t = '\0';

			for(++s; *s==' ' || *s=='\t' ; ++s)
				;
			setvar(a, copys(s));
			return(YES);
		}

	return(NO);
}

struct varblock *
varptr(v)
char *v;
{
	register struct varblock *vp;

	for(vp = firstvar; vp ; vp = vp->nxtvarblock)
		if(! unequal(v , vp->varname))
			return(vp);

	vp = ALLOC(varblock);
	vp->nxtvarblock = firstvar;
	firstvar = vp;
	vp->varname = copys(v);
	vp->varval = 0;
	return(vp);
}

fatal1(s, t)
char *s, *t;
{
	char buf[100];
	sprintf(buf, s, t);
	fatal(buf);
}

fatal(s)
char *s;
{
	if(s)
		fprintf(stderr, "%s: %s.  Stop.\n", progname, s);
	else
		fprintf(stderr, "%s: Stop.\n", progname);
#ifdef unix
	quit(1);
#endif
#ifdef gcos
	quit(0);
#endif
}

yyerror(s)
char *s;
{
	char buf[50];
	extern int yylineno;

	sprintf(buf, "line %d: %s", yylineno, s);
	fatal(buf);
}

struct chain *
appendq(head, tail)
struct chain *head;
char *tail;
{
	register struct chain *p, *q;

	p = ALLOC(chain);
	p->datap = tail;

	if(head) {
		for(q = head ; q->nextp ; q = q->nextp)
			;
		q->nextp = p;
		return(head);
	} else
		return(p);
}

char *
mkqlist(p)
struct chain *p;
{
	register char *qbufp, *s;
	static char qbuf[QBUFMAX];

	if(p == NULL) {
		qbuf[0] = '\0';
		return(qbuf);
	}

	qbufp = qbuf;

	for( ; p ; p = p->nextp) {
		s = p->datap;
		if(qbufp+strlen(s) > &qbuf[QBUFMAX-3]) {
			fprintf(stderr, "%s: $? list too long\n", progname);
			break;
		}
		while (*s)
			*qbufp++ = *s++;
		*qbufp++ = ' ';
	}
	*--qbufp = '\0';
	return(qbuf);
}

quit(val)
int val;
{
#ifdef RCS
	if (rmflag) {			/* clean up co'ed files */
		touchflag = 0;		/* don't try to touch anything */
		rm();
	}
#endif
	exit(val);
}

#ifdef RCS
/*
 * ncat copies n chars of string b at a, returning a pointer to the
 * null terminating a.  This way, it can be used to daisy-chain.
 * If n < 0, all chars of b will be copied
 */
char *
ncat(a, b, n)
register char *a, *b;
register int n;
{
	if (n < 0) {
		while(*a++ = *b++)
			;
		return(--a);
	} else {
		if (n != 0) 
			do {
				if ((*a++ = *b++) == '\0')
					return(--a);
			} while (--n);
		*a = '\0';
		return(a);
	}
}
#endif
