/*
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);
}