/
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/DB/RCS/oif.c,v 1.3 91/08/19 16:21:51 mjr Exp $";
#endif

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


#include	<stdio.h>
#include	<varargs.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(onoff)
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_alist)
va_dcl
{
	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 */
comp_toFILE(fp,va_alist)
FILE	*fp;
va_dcl
{
	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(s,f)
FILE	*f;
Sbuf	*s;
{
	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(o,n)
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 < o->ocnt; a++)
		ret += (strlen(o->oap[a]) + 1);
	return(ret);
}



/*
oif an object to the given stream.
*/
oiftoFILE(o,f,nam)
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 < 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(f,nbuf)
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)
*/
oiftoSTRING(o,buf,nam,len)
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 < 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(string,nbuf)
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);
}