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

/* 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 (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 (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 (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 (char *l, char *buf, int bs)
{
  char *op = buf;

  if (l == (char *) 0 || *l == '\0')
    return ((char *) 0);

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

      /* if there is nothing in the buffer, keep going. */
      if (op != buf)
        break;
      else
        continue;
    }

    /* objid too big */
    if (--bs <= 0) {
      log_printf ("object-id too big\n", (char *) 0);
      while (*l != ';' && *l != '\0')
        l++;
      op = buf;
      continue;
    }
    *op++ = *l++;
  }
  *op = '\0';
  return (l);
}




/*
return a copy of the next element in list 'l', or null pointer at list end.
items are copied out into a stretchy-buf.
*/
char *lstnextsbuf (char *l, Sbuf * sb)
{
  if (l == (char *) 0 || *l == '\0')
    return ((char *) 0);
  sbuf_reset (sb);

  while (*l != '\0') {
    if (*l == ';') {
      l++;
      /* >= 'cuz we haven't added the null yet */
      if (sbuf_len (sb) >= 0)
        break;
      else {
        sbuf_reset (sb);
        continue;
      }
    }

    sbuf_put (*l, sb), l++;
  }
  sbuf_put ('\0', sb);
  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 (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 (char *l)
{
  int ret = 0;

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

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