/
umud/DOC/
umud/DOC/examples/
umud/DOC/internals/
umud/DOC/wizard/
umud/MISC/
umud/MISC/dbchk/
umud/RWHO/rwhod/
/*
	Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
*/

#ifndef	lint
static	char	RCSid[] = "$Header: /usr/users/mjr/hacks/umud/RCS/list.c,v 1.1 91/07/04 17:32:27 mjr Rel $";
#endif

/* configure all options BEFORE including system stuff. */
#include	"config.h"


#include	"sbuf.h"
#include	"mud.h"

/*
WARNING - static stretchy buffers
several static stretchy buffers are allocated and kept here. this is the
only way to do this efficiently. if the allocations fail, there's really
jack-all we can do at this point, so we exit
*/


/* PRIVATE!! search for 'nam' in list 'l' and return a pointer to it */
static char	*
lstlookup(l,nam)
char	*l;
char	*nam;
{
	char	*np;
	char	*bp;

	if(l == (char *)0)
		return((char *)0);
	while(*l != '\0') {
		np = nam;
		bp = l;

		while(*np != '\0') {
			if(*l != *np)
				break;

			l++, np++;
		}

		/* have we found it ? */
		if(*np == '\0' && (*l == '\0' || *l == ';'))
			return(bp);

		/* no. skip to next semicolon */
		while(*l != '\0') {
			if(*l++ == ';')
				break;
		}
	}
	return((char *)0);
}





/* user-level access to listlookup() - denied because i want to keep
people from directly accessing pointers into the contents of a list */
int
lstlook(l,nam)
char	*l;
char	*nam;
{
	if(lstlookup(l,nam))
		return(1);
	return(0);
}




/*
add 'nam' to list 'l' and return a pointer to the result.
if 'lp' is not (int *)0, place the length of the result in 'lp.
*/
char	*
lstadd(l,nam,lp)
char	*l;
char	*nam;
int	*lp;
{
	static Sbuf	*sp = (Sbuf *)0;
	char		*xp;

	if(sp == (Sbuf *)0 && (sp = sbuf_new()) == (Sbuf *)0)
		fatal("cannot get list buffer: ",(char *)-1,"\n",(char *)0);

	sbuf_reset(sp);
	xp = l;

	while(xp != (char *)0 && *xp != '\0') {
		if(*xp != ';' || *(xp + 1) != ';')
			sbuf_put(*xp,sp);
		xp++;
	}


	/* only you can prevent dups */
	if(lstlookup(l,nam) == (char *)0) {

		/* special case - if the previous list SHOULD have a ; add */
		if(xp != (char *)0 && xp > l && *(xp - 1) != ';')
			sbuf_put(';',sp);

		/* copy in new and add a semicolon */
		while(*nam != '\0')
			sbuf_put(*nam,sp), nam++;
		sbuf_put(';',sp);
	}

	sbuf_put('\0',sp);

	if(lp != (int *)0)
		*lp = sbuf_len(sp);
	return(sbuf_buf(sp));
}




/*
return a copy of the next element in list 'l', or null pointer at list end.
buffer given is assumed to be large enough to fit an ID.
WARNING - do not fiddle with the logic of scanning list next elements.
NOTE!!!!! the match code assumes that this routine will "do the right thing"
if given a single object-id as well as a list. if you change that, all hell
will break loose in matching.
*/
char	*
lstnext(l,buf)
char		*l;
char		*buf;
{
	char	*op = buf;

	if(l == (char *)0)
		return(l);

	while(*l != '\0') {
		if(*l == ';') {
			l++;
			break;
		}
		*op++ = *l++;
	}
	*op = '\0';
	if(op == buf)
		return((char *)0);

	return(l);
}




/*
delete 'nam' from list 'l' and return a pointer to the result
if 'lp' is not (int *)0, place the length of the result in 'lp.
*/
char	*
lstdel(l,nam,lp)
char	*l;
char	*nam;
int	*lp;
{
	static Sbuf	*sp = (Sbuf *)0;
	char	*p1;
	char	*p2;

	if(sp == (Sbuf *)0 && (sp = sbuf_new()) == (Sbuf *)0)
		fatal("cannot get list buffer: ",(char *)-1,"\n",(char *)0);
	sbuf_reset(sp);

	/* heh. already not there, you goob */
	if((p1 = lstlookup(l,nam)) == (char *)0) {
		(void)sbuf_strcpy(l,sp);
		goto done;
	}

	p2 = l;
	while(p2 < p1)
		sbuf_put(*p2,sp), p2++;

	/* skip the infected part */
	while(*p2 != '\0') {

		/* skip the semicolon if one */
		if(*p2 == ';') {
			p2++;
			break;
		}
		p2++;
	}

	/* take the rest */
	while(*p2 != '\0')
		sbuf_put(*p2,sp), p2++;

	sbuf_put('\0',sp);

done:
	if(lp != (int *)0)
		*lp = sbuf_len(sp);
	return(sbuf_buf(sp));
}




/* return the number of elements in list 'l' */
int
lstcnt(l)
char	*l;
{
	char	*cp;
	int	ret = 0;

	if((cp = l) == (char *)0)
		return(0);

	while(*cp != '\0') {
		if(*cp == ';')
			ret++;
		l++;
	}
	return(ret);
}