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"

/*
WARNING - broken versions of printf may fail on large OIF objects
the manual page for printf and fprintf says (on some machines - SunOs3.5
specifically) that fields longer than 128 get truncated. this would totally
screw everything up, but the code has been tested with fields longer than
BUFSIZ with no trouble at all. if you find yourself on a machine that has
trouble with this, you'll need to unroll the fprintf()s into fputc()s.
*/

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


#ifdef COMPRESS_OIF
/* Compression routines - lifted from TinyMUD and modified for use in Unter */
#include        "comp.h"

static int compress_on = 1;
static char ctab[128][128];

/*
the way in which compression is handled for toggling is gross, but this is
necessary to make loaddb work.
*/

void comp_on (int onoff)
{
  compress_on = onoff;
}


void comp_init ()
{
  int i;
  int j;

  for (i = 0; i < 128; i++)
    for (j = 0; j < 128; j++)
      ctab[i][j] = 0;

  for (i = 0; i < 128; i++)
    ctab[ctok[i][0]][ctok[i][1]] = i | 0x80;
}



/* VARARGS1 */
static int comp_len (...)
{
  va_list ap;
  char c;
  char *p;
  char *nxp;
  int nomor = 0;
  int skipone = 0;
  char nxt;
  int size = 0;

  va_start (ap);
  while (1) {
    nxp = (char *) 0;
    if (nomor)
      break;
    p = va_arg (ap, char *);
    if (p == (char *) 0)
      break;
  looked_ahead:
    while (*p != '\0') {

      /* out of string? lookahead */
      if ((nxt = p[1]) == '\0') {
        nxp = va_arg (ap, char *);
        if (nxp != (char *) 0)
          nxt = *nxp;
        else
          nomor++;
      }

      if ((c = ctab[p[0]][nxt]) != '\0') {
        size++;
        /* looked ahead? */
        if (nxp == (char *) 0)
          p += 2;
        else {
          p++;
          skipone++;
        }
      } else {
        size++;
        p++;
      }
    }

    if (nxp != (char *) 0) {
      p = nxp;
      nxp = (char *) 0;
      if (skipone) {
        p++;
        skipone = 0;
      }
      goto looked_ahead;
    }
  }
  va_end (ap);
  return (size);
}



/* VARARGS1 */
int comp_toFILE (FILE * fp, ...)
{
  va_list ap;
  char c;
  char *p;
  char *nxp;
  int nomor = 0;
  int skipone = 0;
  char nxt;

  va_start (ap);
  while (1) {
    nxp = (char *) 0;
    if (nomor)
      break;
    p = va_arg (ap, char *);
    if (p == (char *) 0)
      break;
  looked_ahead:
    while (*p != '\0') {

      /* out of string? lookahead */
      if ((nxt = p[1]) == '\0') {
        nxp = va_arg (ap, char *);
        if (nxp != (char *) 0)
          nxt = *nxp;
        else
          nomor++;
      }

      if ((c = ctab[p[0]][nxt]) != '\0') {
        if (fputc (c, fp) == EOF)
          return (1);

        /* looked ahead? */
        if (nxp == (char *) 0)
          p += 2;
        else {
          p++;
          skipone++;
        }
      } else {
        if (fputc (*p, fp) == EOF)
          return (1);
        p++;
      }
    }

    if (nxp != (char *) 0) {
      p = nxp;
      nxp = (char *) 0;
      if (skipone) {
        p++;
        skipone = 0;
      }
      goto looked_ahead;
    }
  }
  va_end (ap);
  return (0);
}



static char *sbuf_fdecomp (Sbuf * s, FILE * f)
{
  char c;

  if (f == (FILE *) 0 || s == (Sbuf *) 0 || ferror (f))
    return ((char *) 0);

  sbuf_reset (s);

  while (1) {
    c = getc (f);
    if (feof (f) || ferror (f)) {
      if (s->bp == s->buf)
        return ((char *) 0);
      sbuf_put ('\0', s);
      return (sbuf_buf (s));
    }

    if (c == '\n') {
      sbuf_put ('\0', s);
      return (sbuf_buf (s));
    }

    if (c & 0x80) {
      sbuf_put (ctok[c & 0x7f][0], s);
      sbuf_put (ctok[c & 0x7f][1], s);
    } else
      sbuf_put (c, s);
  }
}
#endif


/*
Return the object size of the given object when in OIF format
*/
int oif_objsiz (Obj * o, char *n)
{
  int ret = 0;
  int a;

#ifdef  COMPRESS_OIF
  if (compress_on) {
    ret = comp_len ("object ", n, "\n", (char *) 0);
    for (a = 0; a < o->ocnt; a++)
      ret += comp_len (o->oap[a], "\n", (char *) 0);
    ret += comp_len ("endobj\n", (char *) 0);
    return (ret);
  }
#endif
  /* otherwise "object " "endobj" + name length + 2 newlines */
  ret = 15 + strlen (n);

  for (a = 0; a < (int) o->ocnt; a++)
    ret += (strlen (o->oap[a]) + 1);
  return (ret);
}



/*
oif an object to the given stream.
*/
int oiftoFILE (Obj * o, FILE * f, char *nam)
{
  int a;

#ifdef  COMPRESS_OIF
  if (compress_on) {
    if (comp_toFILE (f, "object ", nam, "\n", (char *) 0) == EOF)
      return (1);
    for (a = 0; a < o->ocnt; a++)
      if (comp_toFILE (f, o->oap[a], "\n", (char *) 0) == EOF)
        return (1);
    if (comp_toFILE (f, "endobj\n", (char *) 0) == EOF)
      return (1);
    return (0);
  }
#endif
  if (fprintf (f, "object %s\n", nam) == EOF)
    return (1);
  for (a = 0; a < (int) o->ocnt; a++)
    if (fprintf (f, "%s\n", o->oap[a]) == EOF)
      return (1);
  if (fputs ("endobj\n", f) == EOF)
    return (1);
  if (ferror (f))
    return (1);
  return (0);
}




/*
read an oif object from the given stream.
*/
Obj *oiffromFILE (FILE * f, char *nbuf)
{
  Obj *ret = (Obj *) 0;
  Sbuf suf;
  char *cp;

  sbuf_initstatic (&suf);

  /* read an "object..."  line */
#ifdef  COMPRESS_OIF
  if (compress_on)
    cp = sbuf_fdecomp (&suf, f);
  else
#endif
    cp = sbuf_fgets (&suf, f);
  if (cp == (char *) 0 || strncmp (cp, "object", 6)) {
#ifdef  OIF_DEBUG
    if (cp != (char *) 0)
      fprintf (stderr, "expected object header, got %s\n", cp);
#endif
    sbuf_freestatic (&suf);
    return ((Obj *) 0);
  }

  /* if a name is given, take it */
  if (cp[6] == ' ' && nbuf != (char *) 0 && cp[7] != '\0')
    strncpy (nbuf, &cp[7], MAXOID);

  if ((ret = objnew ()) == (Obj *) 0) {
    sbuf_freestatic (&suf);
    return ((Obj *) 0);
  }

  while (1) {
    sbuf_reset (&suf);

#ifdef  COMPRESS_OIF
    if (compress_on)
      cp = sbuf_fdecomp (&suf, f);
    else
#endif
      cp = sbuf_fgets (&suf, f);

    if (cp == (char *) 0) {
#ifdef  OIF_DEBUG
      if (cp != (char *) 0)
        fprintf (stderr, "expected attr, got %s\n", cp);
#endif
      objfree (ret);
      sbuf_freestatic (&suf);
      return ((Obj *) 0);
    }

    if (!strcmp (cp, "endobj")) {
      sbuf_freestatic (&suf);
      return (ret);
    }

    /* not the end of an object, and not too big, so stuff it */
    if (objstuffattr (ret, cp, sbuf_len (&suf)))
      goto reject;
  }

reject:
  objfree (ret);
  sbuf_freestatic (&suf);
  return ((Obj *) 0);
}




/*
oif an object to the given string (with the given length)
*/
int oiftoSTRING (Obj * o, char *buf, char *nam, int len)
{
  int a;

  if (len < oif_objsiz (o, nam))
    return 1;

  strcpy (buf, "object ");
  strcat (buf, nam);
  strcat (buf, "\n");

  for (a = 0; a < (int) o->ocnt; a++) {
    strcat (buf, o->oap[a]);
    strcat (buf, "\n");
  }

  strcat (buf, "endobj\n");

  return (0);
}




/*
read an oif object from the given string.
*/
Obj *oiffromSTRING (char *string, char *nbuf)
{
  Obj *ret = (Obj *) 0;
  char *cp, *np;
  int len;

  if (!string)
    return ((Obj *) 0);

  if (strncmp (string, "object", 6))
    return ((Obj *) 0);

  /* if a name is given, take it */
  if (string[6] == ' ' && nbuf != (char *) 0 && string[7] != '\0') {
    for (cp = &string[7], len = 0; *cp && len < MAXOID && *cp != '\n'; len++)
      *nbuf++ = *cp++;
    if (len < MAXOID)
      *nbuf = '\0';
  } else
    cp = &string[6];

  cp = index (cp, '\n');
  if (!cp)
    /* error!  No newline */
    return ((Obj *) 0);

  if ((ret = objnew ()) == (Obj *) 0)
    return ((Obj *) 0);

  cp++;
  while (1) {
    /*
     * cp points to the beginning of the next "line"
     */
    if (!strcmp (cp, "endobj\n"))
      return (ret);

    /* find out where the end of the line is */
    np = index (cp, '\n');
    np = index (cp, '\n');
    if (!np)
      /* no newline! */
      goto reject;

    /* not the end of an object, and not too big, so stuff it */
    if (objstuffattr (ret, cp, np - cp))
      goto reject;
    cp = np + 1;
  }

reject:
  objfree (ret);
  return ((Obj *) 0);
}