[alt.sources] lq-text Full Text Retrieval Database Part 11/13

lee@sq.sq.com (Liam R. E. Quin) (03/04/91)

: cut here --- cut here --
: To unbundle, sh this file
#! /bin/sh
: part 11
echo x - lq-text/src/test/trywid.c 1>&2
sed 's/^X//' >lq-text/src/test/trywid.c <<'@@@End of lq-text/src/test/trywid.c'
X/* trywid.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
X * This code is NOT in the public domain.
X * See the file COPYRIGHT for full details.
X *
X * $Header: /usr/src/cmd/lq-text/src/test/RCS/trywid.c,v 1.1 90/08/09 19:17:51 lee Rel1-10 $
X *
X * $Log:	trywid.c,v $
X * Revision 1.1  90/08/09  19:17:51  lee
X * Initial revision
X * 
X *
X */
X
X#include "globals.h" /* defines and declarations for database filenames */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include "fileinfo.h"
X#include "wordinfo.h"
X
X/** Unix Library Functions: **/
Xextern long atol();
X/** liblqtext functions: **/
Xextern t_WID GetMaxWID();
Xextern t_WID GetNextWID();
X/** **/
X
Xint
Xmain(argc, argv)
X    int argc;
X    char *argv[];
X{
X    t_WID W, Max;
X
X    Max = atol(argv[1]);
X
X    for (W = GetMaxWID(); W <= Max; ) {
X	printf("%lu\n", W = GetNextWID());
X    }
X    return 0;
X}
@@@End of lq-text/src/test/trywid.c
echo x - lq-text/src/test/wordlengths 1>&2
sed 's/^X//' >lq-text/src/test/wordlengths <<'@@@End of lq-text/src/test/wordlengths'
XA
XBB
XCCC
XDDDD
XEEEEE
XFFFFFF
XGGGGGGG
XHHHHHHHH
XIIIIIIIII
XJJJJJJJJJJ
XKKKKKKKKKKK
XLLLLLLLLLLLL
XMMMMMMMMMMMMM
XNNNNNNNNNNNNNN
XOOOOOOOOOOOOOOO
XPPPPPPPPPPPPPPPP
XQQQQQQQQQQQQQQQQQ
XRRRRRRRRRRRRRRRRRR
XSSSSSSSSSSSSSSSSSSS
XTTTTTTTTTTTTTTTTTTTT
XUUUUUUUUUUUUUUUUUUUUU
XVVVVVVVVVVVVVVVVVVVVVV
XWWWWWWWWWWWWWWWWWWWWWWW
XXXXXXXXXXXXXXXXXXXXXXXXX
XYYYYYYYYYYYYYYYYYYYYYYYYY
XZZZZZZZZZZZZZZZZZZZZZZZZZZ
X
XA
XBB
XCCC
XDDDD
XEEEEE
XFFFFFF
XGGGGGGG
XHHHHHHHH
XIIIIIIIII
XJJJJJJJJJJ
XKKKKKKKKKKK
XLLLLLLLLLLLL
XMMMMMMMMMMMMM
XNNNNNNNNNNNNNN
XOOOOOOOOOOOOOOO
XPPPPPPPPPPPPPPPP
XQQQQQQQQQQQQQQQQQ
XRRRRRRRRRRRRRRRRRR
XSSSSSSSSSSSSSSSSSSS
XTTTTTTTTTTTTTTTTTTTT
XUUUUUUUUUUUUUUUUUUUUU
XVVVVVVVVVVVVVVVVVVVVVV
XWWWWWWWWWWWWWWWWWWWWWWW
XXXXXXXXXXXXXXXXXXXXXXXXX
XYYYYYYYYYYYYYYYYYYYYYYYYY
XZZZZZZZZZZZZZZZZZZZZZZZZZZ
X
@@@End of lq-text/src/test/wordlengths
echo x - lq-text/src/ozmahash/Makefile 1>&2
sed 's/^X//' >lq-text/src/ozmahash/Makefile <<'@@@End of lq-text/src/ozmahash/Makefile'
X# $Id: Makefile,v 1.2 91/03/02 19:10:36 lee Exp $
XDIR=	.
XSRC1=	dynahash.c log2.c page.c big.c buf.c hfunc.c
XSRC2=	mkstemp.c bcopy.c 
XSRCS=	$(SRC1) $(SRC2)
X#SRCS=	$(SRC1) 
XOBJ1=	dynahash.o log2.o page.o big.o buf.o hfunc.o
XOBJ2=	mkstemp.o bcopy.o 
XOBJS=	$(OBJ1) $(OBJ2)
X#OBJS=	$(OBJ1) 
XMAIN1=	tread2.c tverify.c tseq.c tdel.c thash4.c tcreat3.c 
XMAINS=	thash.c tcreat.c tread.c tread2.c tverify.c tseq.c tseq2.c tcreat2.c thash2.c tdel.c thash3.c thash4.c tcreat3.c 
XHDRS=	hash.h page.h db.h endian.h
XRANLIB=ranlib
X
XDEBUGFLAGS= -DHASH_STATISTICS -g -pg
XPROFFLAGS= -p -DHASH_STATISTICS
XTIMEFLAGS = -O2
XTESTFLAGS= $(DEBUGFLAGS) 
XLDFLAGS= 
X#CFLAGS=	-I.  $(DEBUGFLAGS)
X#CFLAGS=	-I.  $(PROFFLAGS)
XCFLAGS=	-I.  $(TIMEFLAGS)
X
Xall: install
X	$(MAKE) -$(MAKEFLAGS) tidy
X
X#all:	libhash.a tread2 tverify tseq thash4 tcreat3 tdel
X#all:	tcreat tread tread2 tverify thash tseq tseq2 tcreat2 thash2 thash3 thash4 tdel tcreat3
X
Xlib:	libhash.a
X
Xinstall: lib
X	cp libhash.a ../lib
X	$(RANLIB) ../lib/libhash.a
X
Xtidy:
X	/bin/rm -f *.o core *.out
X
Xclean: tidy
X	/bin/rm -f core *.a
X
Xtar:	
X	tar cf hash.tar README Makefile $(SRCS) $(MAIN1) $(HDRS) ndbm.c ndbm.h hsearch.c search.h byte_order.c db.3 hash.ps
X
Xshar:	
X	shar -f XFER $(SRC1) $(MAINS) $(HDRS) Makefile
X
Xlibhash.a:	$(OBJS) ndbm.o hsearch.o
X	ar ruv libhash.a $(OBJS) ndbm.o hsearch.o
X	$(RANLIB) libhash.a
X
Xtdel:	tdel.o $(OBJS)
X	cc tdel.o $(LDFLAGS) -o tdel $(OBJS)
X
Xtseq2:	tseq2.o $(OBJS)
X	cc tseq2.o $(LDFLAGS) -o tseq2 $(OBJS)
X
Xtseq:	tseq.o $(OBJS)
X	cc tseq.o $(LDFLAGS) -o tseq $(OBJS)
X
Xtverify:	tverify.o $(OBJS)
X	cc tverify.o $(LDFLAGS) -o tverify $(OBJS)
X
Xtcreat2:	tcreat2.o $(OBJS)
X	cc tcreat2.o $(LDFLAGS) -o tcreat2 $(OBJS)
X
Xtcreat3:	tcreat3.o $(OBJS)
X	cc tcreat3.o $(LDFLAGS) -o tcreat3 $(OBJS)
X
Xtcreat:	tcreat.o $(OBJS)
X	cc tcreat.o $(LDFLAGS) -o tcreat $(OBJS)
X
Xtread:	tread.o $(OBJS)
X	cc tread.o $(LDFLAGS) -o tread $(OBJS)
X
Xtread2:	tread2.o $(OBJS)
X	cc tread2.o $(LDFLAGS) -o tread2 $(OBJS)
X
Xthash:	thash.o $(OBJS)
X	cc thash.o $(LDFLAGS) -o thash $(OBJS)
X
Xthash2:	thash2.o $(OBJS)
X	cc thash2.o $(LDFLAGS) -o thash2 $(OBJS)
X
Xthash3:	thash3.o $(OBJS)
X	cc thash3.o $(LDFLAGS) -o thash3 $(OBJS)
X
Xthash4:	thash4.o $(OBJS)
X	cc thash4.o $(LDFLAGS) -o thash4 $(OBJS)
X
X
Xsrc:	
X	co $(SRCS) $(HDRS) $(MAINS)
X
Xdepend:
X	mkdep $(CFLAGS) $(SRCS)
X
X# DO NOT DELETE THIS LINE -- mkdep uses it.
X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
X
Xdynahash.o: dynahash.c db.h hash.h  endian.h
Xlog2.o: log2.c
Xpage.o: page.c db.h hash.h page.h  endian.h
Xbig.o: big.c db.h hash.h page.h 
Xbuf.o: buf.c hash.h 
Xhfunc.o: hfunc.c
Xmkstemp.o: mkstemp.c  
Xbcopy.o: bcopy.c  
X
X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
@@@End of lq-text/src/ozmahash/Makefile
echo x - lq-text/src/ozmahash/README 1>&2
sed 's/^X//' >lq-text/src/ozmahash/README <<'@@@End of lq-text/src/ozmahash/README'
XThis package implements a superset of the hsearch and dbm/ndbm libraries.
X
XContents:
X
XHashing Package:
X	dynahash.c
X	page.c
X	buf.c
X	big.c
X	hfunc.c
X	log2.c
X
X	hash.h
X	page.h
X	db.h
X
XBackward Compatibility Routines:
X	ndbm.c
X	ndbm.h
X	hsearch.c
X	search.h
X
XMisc
X	byte_order.c
X
XBSD Files:
X	endian.h
X	mkstemp.c
X	bcopy.c
X
XTest Programs:
X	All test programs which need key/data pairs expect them entered
X	with key and data on separate lines
X
X	tcreat3.c	
X		Takes 
X			bucketsize (bsize), 
X			fill factor (ffactor), and
X			initial number of elements (nelem).  
X		Creates a hash table named hashtest containing the 
X		keys/data pairs entered from standard in.
X	thash4.c
X		Takes
X			bucketsize (bsize), 
X			fill factor (ffactor), 
X			initial number of elements (nelem)
X			bytes of cache (ncached), and
X			file from which to read data  (fname)
X		Creates a table from the key/data pairs on standard in and
X		then does a read of each key/data in fname
X	tdel.c
X		Takes
X			bucketsize (bsize), and
X			fill factor (ffactor).
X			file from which to read data (fname)
X		Reads each key/data pair from fname and deletes the
X		key from the hash table hashtest
X	tseq.c
X		Reads the key/data pairs in the file hashtest and writes them
X		to standard out.
X	tread2.c
X		Takes
X			butes of cache (ncached).
X		Reads key/data pairs from standard in and looks them up
X		in the file hashtest.
X	tverify.c
X		Reads key/data pairs from standard in, looks them up
X		in the file hashtest, and verifies that the data is
X		correct.
X
XIf you are running on a BSD system, the BSD h files should be in 
X/usr/include and the BSD .c files should be in libc.  On a non-BSD 
Xsystem, you will need to compile the copies here into the package.  
XBe sure to set BYTE_ORDER in endian.h appropriately for your machine.  
XIf you don't know what "endian" your machine is, compile byte_order.c 
Xand run it.  It should tell you.
X
XThe file search.h is used only for using the hsearch compatible interface on
XBSD systems.  On System V derived systems, search.h should appear in 
X/usr/include.
X
XThe man page db.3 explains the interface to the hashing system.
XThe file hash.ps is a postscript copy of a paper explaining
Xthe history, implementation, and performance of the hash package.
X
X"bugs" or idiosyncracies
X
XIf you have a lot of overflows, it is possible to run out of overflow
Xpages.  Currently, this will cause a message to be printed on stderr.
XEventually, this will be indicated by a return error code.
X
XIf you have a lot of overflow pages and a small cache, you might run
Xout of buffers to hold a single hash chain.  You will get an error
Xexit.  If you have very long keys and/or small pages, try increasing
Xyour buffer pool space to make this go away (you can also compile
Xwith HASH_STATISTICS to see just how many expansions you really are
Xgetting).
@@@End of lq-text/src/ozmahash/README
echo x - lq-text/src/ozmahash/bcopy.c 1>&2
sed 's/^X//' >lq-text/src/ozmahash/bcopy.c <<'@@@End of lq-text/src/ozmahash/bcopy.c'
X/*-
X * Copyright (c) 1990 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Chris Torek.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that: (1) source distributions retain this entire copyright
X * notice and comment, and (2) distributions including binaries display
X * the following acknowledgement:  ``This product includes software
X * developed by the University of California, Berkeley and its contributors''
X * in the documentation or other materials provided with the distribution
X * and in all advertising materials mentioning features or use of this
X * software. Neither the name of the University nor the names of its
X * contributors may be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)bcopy.c	5.7 (Berkeley) 5/16/90";
X#endif /* LIBC_SCCS and not lint */
X
X#include <string.h>
X#include <sys/types.h>
X
X/*
X * sizeof(word) MUST BE A POWER OF TWO
X * SO THAT wmask BELOW IS ALL ONES
X */
Xtypedef	int word;		/* "word" used for optimal copy speed */
X
X#define	wsize	sizeof(word)
X#define	wmask	(wsize - 1)
X
X/*
X * Copy a block of memory, handling overlap.
X * This is the routine that actually implements
X * (the portable versions of) bcopy, memcpy, and memmove.
X */
Xvoid
Xbcopy(src0, dst0, length)
X	char *dst0;
X	char *src0;
X	register size_t length;
X{
X	register char *dst = dst0;
X	register char *src = src0;
X	register size_t t;
X
X	if (length == 0 || dst == src)		/* nothing to do */
X		return;
X
X	/*
X	 * Macros: loop-t-times; and loop-t-times, t>0
X	 */
X#define	TLOOP(s) if (t) TLOOP1(s)
X#define	TLOOP1(s) do { s; } while (--t)
X
X	if ((unsigned long)dst < (unsigned long)src) {
X		/*
X		 * Copy forward.
X		 */
X		t = (int)src;	/* only need low bits */
X		if ((t | (int)dst) & wmask) {
X			/*
X			 * Try to align operands.  This cannot be done
X			 * unless the low bits match.
X			 */
X			if ((t ^ (int)dst) & wmask || length < wsize)
X				t = length;
X			else
X				t = wsize - (t & wmask);
X			length -= t;
X			TLOOP1(*dst++ = *src++);
X		}
X		/*
X		 * Copy whole words, then mop up any trailing bytes.
X		 */
X		t = length / wsize;
X		TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
X		t = length & wmask;
X		TLOOP(*dst++ = *src++);
X	} else {
X		/*
X		 * Copy backwards.  Otherwise essentially the same.
X		 * Alignment works as before, except that it takes
X		 * (t&wmask) bytes to align, not wsize-(t&wmask).
X		 */
X		src += length;
X		dst += length;
X		t = (int)src;
X		if ((t | (int)dst) & wmask) {
X			if ((t ^ (int)dst) & wmask || length <= wsize)
X				t = length;
X			else
X				t &= wmask;
X			length -= t;
X			TLOOP1(*--dst = *--src);
X		}
X		t = length / wsize;
X		TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
X		t = length & wmask;
X		TLOOP(*--dst = *--src);
X	}
X	return;
X}
@@@End of lq-text/src/ozmahash/bcopy.c
echo x - lq-text/src/ozmahash/big.c 1>&2
sed 's/^X//' >lq-text/src/ozmahash/big.c <<'@@@End of lq-text/src/ozmahash/big.c'
X/*-
X * Copyright (c) 1990 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Margo Seltzer.
X *
X * %sccs.include.redist.c%
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "%W% (Berkeley) %G%";
X#endif /* LIBC_SCCS and not lint */
X
X/******************************************************************************
X
XPACKAGE: hash
X
XDESCRIPTION: 
X	Big key/data handling for the hashing package.
X
XROUTINES: 
X    External
X	big_keydata
X	big_split
X	big_insert
X	big_return
X	big_delete
X	find_last_page
X    Internal
X	collect_key
X	collect_data
X******************************************************************************/
X/* Includes */
X#include <sys/types.h>
X#include <sys/file.h>
X#include <assert.h>
X#include <errno.h>
X#include <db.h>
X#include <hash.h>
X#include <page.h>
X#include <stdio.h>
X
X/* Externals */
X/* buf.c */
Xextern BUFHEAD *get_buf();
X
X/* page.c */
Xextern BUFHEAD *add_ovflpage();
X
X/* My externals */
Xextern int big_keydata();
Xextern int big_split();
Xextern int big_insert();
Xextern int big_return();
Xextern int big_delete();
Xextern u_short find_last_page();
Xextern int find_bigpair();
X
X/* My internals */
Xstatic int collect_key();
Xstatic int collect_data();
X
X#ifdef HASH_STATISTICS
Xextern long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
X#endif
X/*
XBig_insert
X
XYou need to do an insert and the key/data pair is too big
X0 ==> OK
X-1 ==> ERROR
X*/
Xextern int
Xbig_insert ( bufp, key, val )
XBUFHEAD *bufp;
XDBT	*key, *val;
X{
X    char	*cp = bufp->page;	/* Character pointer of p */
X    register u_short	*p = (u_short *)cp;
X    char	*key_data, *val_data;
X    int		key_size, val_size;
X    int		n;
X    u_short	space, move_bytes, off;
X
X    key_data = key->data;
X    key_size = key->size;
X    val_data = val->data;
X    val_size = val->size;
X
X    /* First move the Key */
X    for ( space = FREESPACE(p) - BIGOVERHEAD; 
X	  key_size; 
X	  space = FREESPACE(p) - BIGOVERHEAD ) {
X	move_bytes = MIN(space, key_size);
X	off = OFFSET(p) - move_bytes;
X	bcopy (key_data, cp+off, move_bytes );
X	key_size -= move_bytes;
X	key_data += move_bytes;
X	n = p[0];
X	p[++n] = off;
X	p[0] = ++n;
X	FREESPACE(p) = off - PAGE_META(n);
X	OFFSET(p) = off;
X	p[n] = PARTIAL_KEY;
X	bufp = add_ovflpage(bufp);
X	if ( !bufp ) {
X	    return(-1);
X	}
X	n = p[0];
X	if ( !key_size ) {
X	    if ( FREESPACE(p) ) {
X		move_bytes = MIN (FREESPACE(p), val_size);
X		off = OFFSET(p) - move_bytes;
X		p[n] = off;
X		bcopy ( val_data, cp + off, move_bytes );
X		val_data += move_bytes;
X		val_size -= move_bytes;
X		p[n-2] = FULL_KEY_DATA;
X		FREESPACE(p) = FREESPACE(p) - move_bytes;
X		OFFSET(p) = off;
X	    }
X	    else p[n-2] = FULL_KEY;
X	}
X	p = (u_short *)bufp->page;
X	cp = bufp->page;
X	bufp->flags |= BUF_MOD;
X    }
X
X    /* Now move the data */
X    for ( space = FREESPACE(p) - BIGOVERHEAD; 
X	  val_size; 
X	  space = FREESPACE(p) - BIGOVERHEAD ) {
X	move_bytes = MIN(space, val_size);
X	/*
X	    Here's the hack to make sure that if the data ends
X	    on the same page as the key ends, FREESPACE is
X	    at least one
X	*/
X	if ( space == val_size && val_size == val->size ) {
X	    move_bytes--;
X	}
X	off = OFFSET(p) - move_bytes;
X	bcopy (val_data, cp+off, move_bytes );
X	val_size -= move_bytes;
X	val_data += move_bytes;
X	n = p[0];
X	p[++n] = off;
X	p[0] = ++n;
X	FREESPACE(p) = off - PAGE_META(n);
X	OFFSET(p) = off;
X	if ( val_size ) {
X	    p[n] = FULL_KEY;
X	    bufp = add_ovflpage (bufp);
X	    if ( !bufp ) {
X		return(-1);
X	    }
X	    cp = bufp->page;
X	    p = (u_short *)cp;
X	} else {
X	    p[n] = FULL_KEY_DATA;
X	}
X	bufp->flags |= BUF_MOD;
X    }
X    return(0);
X}
X
X/*
X    Called when bufp's page  contains a partial key (index should be 1)
X
X    All pages in the big key/data pair except bufp are freed.  We cannot
X    free bufp because the page pointing to it is lost and we can't
X    get rid of its pointer.
X
X    Returns 0 => OK
X	    -1 => ERROR
X*/
Xextern int
Xbig_delete (bufp, ndx)
XBUFHEAD	*bufp;
Xint	ndx;
X{
X	register	BUFHEAD		*rbufp = bufp;
X	register	BUFHEAD		*last_bfp = NULL;
X	char	*cp;
X	u_short	*bp = (u_short *)bufp->page;
X	u_short	*xbp;
X	u_short	pageno = 0;
X	u_short	off, free_sp;
X	int	key_done = 0;
X	int	n;
X
X	while (!key_done || (bp[2] != FULL_KEY_DATA)) {
X	    if ( bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA ) key_done = 1;
X
X	    /*
X		If there is freespace left on a FULL_KEY_DATA page,
X		then the data is short and fits entirely on this
X		page, and this is the last page.
X	    */
X	    if ( bp[2] == FULL_KEY_DATA && FREESPACE(bp) ) break;
X	    pageno = bp[bp[0]-1];
X	    rbufp->flags |= BUF_MOD;
X	    rbufp = get_buf ( pageno, rbufp, 0 );
X	    if ( last_bfp ) free_ovflpage(last_bfp);
X	    last_bfp = rbufp;
X	    if ( !rbufp ) return(-1);			/* Error */
X	    bp = (u_short *)rbufp->page;
X	}
X
X	/* 
X	    If we get here then rbufp points to the last page of
X	    the big key/data pair.  Bufp points to the first
X	    one -- it should now be empty pointing to the next
X	    page after this pair.  Can't free it because we don't
X	    have the page pointing to it.
X	*/
X
X	/* This is information from the last page of the pair */
X	n = bp[0];
X	pageno = bp[n-1];
X
X	/* Now, bp is the first page of the pair */
X	bp = (u_short *)bufp->page;
X	if ( n > 2 ) {
X	    /* There is an overflow page */
X	    bp[1] = pageno;
X	    bp[2] = OVFLPAGE;
X	    bufp->ovfl = rbufp->ovfl;
X	} else {
X	    /* This is the last page */
X	    bufp->ovfl = NULL;
X	}
X	n -= 2;
X	bp[0] = n;
X	FREESPACE(bp) = hashp->BSIZE - PAGE_META(n);
X	OFFSET(bp) = hashp->BSIZE - 1;
X
X	bufp->flags |= BUF_MOD;
X	if ( rbufp ) free_ovflpage(rbufp);
X	if ( last_bfp != rbufp ) free_ovflpage(last_bfp);
X
X	hashp->NKEYS--;
X	return(0);
X}
X
X/*
X    0 = key not found
X    -1 = get next overflow page
X    -2 means key not found and this is big key/data
X    -3 error
X*/
Xextern int
Xfind_bigpair(bufp, ndx, key, size )
XBUFHEAD	*bufp;
Xint	ndx;
Xchar	*key;
Xint	size;
X{
X    register	u_short	*bp = (u_short *)bufp->page;
X    register	char	*p = bufp->page;
X    int		ksize = size;
X    char	*kkey = key;
X    u_short	bytes;
X
X
X    for ( bytes = hashp->BSIZE - bp[ndx]; 
X	  bytes <= size && bp[ndx+1] == PARTIAL_KEY; 
X	  bytes = hashp->BSIZE - bp[ndx] ) {
X
X	if ( bcmp ( p+bp[ndx], kkey, bytes ))return(-2);
X	kkey += bytes;
X	ksize -= bytes;
X	bufp = get_buf ( bp[ndx+2], bufp, 0 );
X	if ( !bufp ) {
X	    return(-3);
X	}
X	p = bufp->page;
X	bp = (u_short *)p;
X	ndx = 1;
X    }
X
X    if ( (bytes != ksize) || bcmp ( p+bp[ndx], kkey, bytes )) {
X#ifdef HASH_STATISTICS
X	hash_collisions++;
X#endif
X	return(-2);
X    }
X    else return (ndx);
X}
X
X
X/*
X    Given the buffer pointer of the first overflow page of a big pair, 
X    find the end of the big pair
X
X    This will set bpp to the buffer header of the last page of the big pair.  
X    It will return the pageno of the overflow page following the last page of 
X    the pair; 0 if there isn't any (i.e. big pair is the last key in the 
X    bucket)
X*/
Xextern u_short
Xfind_last_page ( bpp )
XBUFHEAD	**bpp;
X{
X	int	n;
X	u_short	pageno;
X	BUFHEAD	*bufp = *bpp;
X	u_short	*bp = (u_short *)bufp->page;
X
X	while ( 1 ) {
X	    n = bp[0];
X
X	    /*
X		This is the last page if:
X			the tag is FULL_KEY_DATA and either
X				only 2 entries
X				OVFLPAGE marker is explicit
X				there is freespace on the page
X	    */
X	    if ( bp[2] == FULL_KEY_DATA &&
X		 ((n == 2) ||  (bp[n] == OVFLPAGE) || (FREESPACE(bp)) ) ) break;
X
X	    pageno = bp[n-1];
X	    bufp = get_buf ( pageno, bufp, 0 );
X	    if ( !bufp ) return (0);		/* Need to indicate an error! */
X	    bp = (u_short *)bufp->page;
X	}
X
X	*bpp = bufp;
X	if ( bp[0] > 2 ) return ( bp[3] );
X	else return(0);
X}
X
X
X/*
X    Return the data for the key/data pair
X    that begins on this page at this index
X    (index should always be 1)
X*/
Xextern int
Xbig_return ( bufp, ndx, val, set_current )
XBUFHEAD	*bufp;
Xint	ndx;
XDBT	*val;
Xint	set_current;
X{
X    BUFHEAD	*save_p;
X    u_short	save_addr;
X    u_short	*bp = (u_short *)bufp->page;
X    u_short	off, len;
X    char	*cp, *tp;
X
X    while ( bp[ndx+1] == PARTIAL_KEY ) {
X	bufp = get_buf ( bp[bp[0]-1], bufp, 0 );
X	if ( !bufp ) return(-1);
X	bp = (u_short *)bufp->page;
X	ndx = 1;
X    }
X
X    if ( bp[ndx+1] == FULL_KEY ) {
X	bufp = get_buf ( bp[bp[0]-1], bufp, 0 );
X	if ( !bufp ) return(-1);
X	bp = (u_short *)bufp->page;
X	save_p = bufp;
X	save_addr = save_p->addr;
X	off = bp[1];
X	len = 0;
X    } else if (!FREESPACE(bp)) {
X	/*
X	    This is a hack.  We can't distinguish between
X	    FULL_KEY_DATA that contains complete data or
X	    incomplete data, so we require that if the
X	    data  is complete, there is at least 1 byte
X	    of free space left.
X	*/
X	off = bp[bp[0]];
X	len = bp[1] - off;
X	save_p = bufp;
X	save_addr = bufp->addr;
X	bufp = get_buf ( bp[bp[0]-1], bufp, 0 );
X	if ( !bufp ) return(-1);
X	bp = (u_short *)bufp->page;
X    } else {
X	/* The data is all on one page */
X	tp = (char *)bp;
X	off = bp[bp[0]];
X	val->data = tp + off;
X	val->size = bp[1] - off;
X	if ( set_current ) {
X	    if ( bp[0] == 2 ) {		/* No more buckets in chain */
X		hashp->cpage = NULL;
X		hashp->cbucket++;
X		hashp->cndx=1;
X	    } else  {
X		hashp->cpage = get_buf ( bp[bp[0]-1], bufp, 0 );
X		if ( !hashp->cpage )return(-1);
X		hashp->cndx = 1;
X		if ( !((u_short *)hashp->cpage->page)[0] ) {
X		    hashp->cbucket++;
X		    hashp->cpage = NULL;
X		}
X	    }
X	}
X	return(0);
X    }
X    
X    val->size = collect_data ( bufp, len, set_current );
X    if ( val->size == -1 ) {
X	return(-1);
X    }
X    if ( save_p->addr != save_addr ) {
X	/* We are pretty short on buffers */
X	errno = EINVAL;		/* OUT OF BUFFERS */
X	return(-1);
X    }
X    bcopy ( (save_p->page)+off, hashp->tmp_buf, len );
X    val->data = hashp->tmp_buf;
X    return(0);
X}
X
X/*
X    Count how big the total datasize is by
X    recursing through the pages.  Then allocate
X    a buffer and copy the data as you recurse up.
X*/
Xstatic int
Xcollect_data ( bufp, len, set )
XBUFHEAD	*bufp;
Xint	len;
Xint	set;
X{
X    register	char	*p = bufp->page;
X    register	u_short	*bp = (u_short *)p;
X    u_short	save_addr;
X    int	mylen, totlen;
X    BUFHEAD	*xbp;
X
X    mylen = hashp->BSIZE - bp[1];
X    save_addr = bufp->addr;
X
X    if ( bp[2] == FULL_KEY_DATA ) {	/* End of Data */
X	totlen = len + mylen;
X	if ( hashp->tmp_buf ) free (hashp->tmp_buf);
X	hashp->tmp_buf = (char *)malloc ( totlen );
X	if ( !hashp->tmp_buf ) {
X	    return(-1);
X	}
X	if ( set ) {
X	    hashp->cndx = 1;
X	    if ( bp[0] == 2 ) {		/* No more buckets in chain */
X		hashp->cpage = NULL;
X		hashp->cbucket++;
X	    } else  {
X		hashp->cpage = get_buf ( bp[bp[0]-1], bufp, 0 );
X		if (!hashp->cpage) {
X		    return(-1);
X		} else if ( !((u_short *)hashp->cpage->page)[0] ) {
X		    hashp->cbucket++;
X		    hashp->cpage = NULL;
X		}
X	    }
X	}
X    } else {
X	xbp = get_buf ( bp[bp[0]-1], bufp, 0 );
X	if ( !xbp || ((totlen = collect_data ( xbp, len + mylen, set )) < 1) ) {
X	    return(-1);
X	}
X    }
X    if ( bufp->addr != save_addr ) {
X	errno = EINVAL;		/* Out of buffers */
X	return(-1);
X    }
X    bcopy ( (bufp->page) + bp[1], &hashp->tmp_buf[len], mylen );
X    return ( totlen );
X}
X
X/*
X	Fill in the key and data
X	for this big pair 
X*/
Xextern int
Xbig_keydata ( bufp, ndx, key, val, set )
XBUFHEAD	*bufp;
Xint	ndx;
XDBT	*key, *val;
Xint	set;
X{
X    key->size = collect_key ( bufp, 0, val, set );
X    if ( key->size == -1 ) {
X	return (-1);
X    }
X    key->data = hashp->tmp_key;
X    return(0);
X}
X
X/*
X    Count how big the total key size is by
X    recursing through the pages.  Then collect
X    the data, allocate a buffer and copy the key as
X    you recurse up.
X*/
Xstatic int
Xcollect_key ( bufp, len, val, set )
XBUFHEAD	*bufp;
Xint	len;
XDBT	*val;
Xint	set;
X{
X    char	*p = bufp->page;
X    u_short	*bp = (u_short *)p;
X    u_short	save_addr;
X    int	mylen, totlen;
X    BUFHEAD	*xbp;
X
X    mylen = hashp->BSIZE - bp[1];
X
X    save_addr = bufp->addr;
X    totlen = len + mylen;
X    if ( bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA ) {/* End of Key */
X	if ( hashp->tmp_key ) free (hashp->tmp_key);
X	hashp->tmp_key = (char *)malloc ( totlen );
X	if ( !hashp->tmp_key ) {
X	    return(-1);
X	}
X	big_return ( bufp, 1, val, set );
X    } else {
X	xbp = get_buf (bp[bp[0]-1], bufp, 0);
X	if ( !xbp || ((totlen = collect_key (xbp, totlen, val, set)) < 1 ) ) {
X	    return(-1);
X	}
X    }
X    if ( bufp->addr != save_addr ) {
X	errno = EINVAL;		/* MIS -- OUT OF BUFFERS */
X	return (-1);
X    }
X    bcopy ( (bufp->page) + bp[1], &hashp->tmp_key[len], mylen );
X    return ( totlen );
X}
X
X
X/*
X    return 0 => OK
X	   -1 => error
X*/
Xextern int
Xbig_split ( op, np, big_keyp, addr, obucket, ret )
XBUFHEAD	*op;		/* Pointer to where to put keys that go in old bucket */
XBUFHEAD	*np;		/* Pointer to new bucket page */
XBUFHEAD	*big_keyp;	/* Pointer to first page containing the big key/data */
Xu_short	addr;		/* Address of big_keyp */
Xint	obucket;	/* Old Bucket */
XSPLIT_RETURN	*ret;
X{
X    register	u_short	*prev_pagep;
X    register	BUFHEAD	*tmpp;
X    register	u_short 	*tp;
X    BUFHEAD	*bp = big_keyp;
X    u_short	off, free_space;
X    u_short	n;
X
X    DBT		key, val;
X
X    int		change;
X
X    /* Now figure out where the big key/data goes */
X    if (big_keydata ( big_keyp, 1, &key, &val, 0 )) {
X	return(-1);
X    }
X    change = (call_hash ( key.data, key.size ) != obucket );
X
X    if ( ret->next_addr = find_last_page ( &big_keyp ) ) {
X	if (!(ret->nextp = get_buf ( ret->next_addr, big_keyp, 0 ))) {
X	    return(-1);;
X	}
X    } else {
X	ret->nextp = NULL;
X    }
X
X    /* Now make one of np/op point to the big key/data pair */
X    assert(np->ovfl == NULL);
X    if ( change ) tmpp = np;
X    else tmpp = op;
X
X    tmpp->flags |= BUF_MOD;
X#ifdef DEBUG1
X    fprintf ( stderr, "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr,
X		(tmpp->ovfl?tmpp->ovfl->addr:0), 
X		(bp?bp->addr:0) );
X#endif
X    tmpp->ovfl = bp;		/* one of op/np point to big_keyp */
X    tp = (u_short *)tmpp->page;
X    assert ( FREESPACE(tp) >= OVFLSIZE);
X    n = tp[0];
X    off = OFFSET(tp);
X    free_space = FREESPACE(tp);
X    tp[++n] = addr;
X    tp[++n] = OVFLPAGE;
X    tp[0] = n;
X    OFFSET(tp) = off;
X    FREESPACE(tp) = free_space - OVFLSIZE;
X
X    /* 
X	Finally, set the new and old return values.
X	BIG_KEYP contains a pointer to the last page of the big key_data pair.
X	Make sure that big_keyp has no following page (2 elements) or create
X	an empty following page.
X    */
X
X    ret->newp = np;
X    ret->oldp = op;
X
X    tp = (u_short *)big_keyp->page;
X    big_keyp->flags |= BUF_MOD;
X    if ( tp[0] > 2 ) {
X	/* 
X	    There may be either one or two offsets on this page 
X	    If there is one, then the overflow page is linked on
X	    normally and tp[4] is OVFLPAGE.  If there are two, tp[4]
X	    contains the second offset and needs to get stuffed in
X	    after the next overflow page is added
X	*/
X	n = tp[4];		
X	free_space = FREESPACE(tp);
X	off = OFFSET(tp);
X	tp[0] -= 2;
X	FREESPACE(tp) = free_space + OVFLSIZE;
X	OFFSET(tp) = off;
X	tmpp = add_ovflpage ( big_keyp );
X	if ( !tmpp ) {
X	    return(-1);
X	}
X	tp[4] = n;
X    } else {
X	tmpp = big_keyp;
X    }
X
X    if ( change ) ret->newp = tmpp;
X    else ret->oldp = tmpp;
X
X    return(0);
X}
@@@End of lq-text/src/ozmahash/big.c
echo x - lq-text/src/ozmahash/buf.c 1>&2
sed 's/^X//' >lq-text/src/ozmahash/buf.c <<'@@@End of lq-text/src/ozmahash/buf.c'
X/*-
X * Copyright (c) 1990 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Margo Seltzer.
X *
X * %sccs.include.redist.c%
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "%W% (Berkeley) %G%";
X#endif /* LIBC_SCCS and not lint */
X/******************************************************************************
X
XPACKAGE: hash
X
XDESCRIPTION: 
X	Contains buffer management
X
XROUTINES: 
X    External
X	buf_init
X	get_buf
X	buf_free
X	reclaim_buf
X    Internal
X	newbuf
X
X******************************************************************************/
X#include <sys/types.h>
X#include <sys/file.h>
X#include <assert.h>
X#include <errno.h>
X#include <hash.h>
X#include <stdio.h>
X
X/* Externals */
Xextern HTAB	*hashp;
X
X/* My internals */
Xstatic BUFHEAD *newbuf();
X
X/* Unlink B from its place in the lru */
X#define BUF_REMOVE(B)			\
X{					\
X    B->prev->next = B->next;		\
X    B->next->prev = B->prev;		\
X}
X
X/* Insert B after P */
X#define BUF_INSERT(B,P)			\
X{					\
X    B->next = P->next;			\
X    B->prev = P;			\
X    P->next = B;			\
X    B->next->prev = B;			\
X}
X
X#define	MRU	hashp->bufhead.next
X#define	LRU	hashp->bufhead.prev
X
X#define MRU_INSERT(B)	BUF_INSERT(B,(&hashp->bufhead))
X#define LRU_INSERT(B)	BUF_INSERT(B,LRU)
X
X/*
X    We are looking for a buffer with address "addr".
X    If prev_bp is NULL, then address is a bucket index.
X    If prev_bp is not NULL, then it points to the page previous
X	to an overflow page that we are trying to find.
X
X    CAVEAT:  The buffer header accessed via prev_bp's ovfl field
X    may no longer be valid.  Therefore, you must always verify that
X    its address matches the address you are seeking.
X*/
Xextern BUFHEAD *
Xget_buf ( addr, prev_bp, newpage )
Xint	addr;
XBUFHEAD	*prev_bp;
Xint	newpage;		/* If prev_bp is set, indicates that this is
X					a new overflow page */
X{
X    register int	segment_ndx;
X    register	BUFHEAD	*bp;
X    register	unsigned	is_disk = 0;
X    SEGMENT	segp;
X
X    if ( prev_bp ) {
X	bp = prev_bp->ovfl;
X	if ( !bp || (bp->addr != addr) ) bp = NULL;
X	if ( !newpage ) is_disk = BUF_DISK;
X    }
X    else {
X	/* Grab buffer out of directory */
X	segment_ndx = addr & ( hashp->SGSIZE - 1 );
X
X	/*
X	 * valid segment ensured by call_hash()
X	 */
X	segp = hashp->dir[addr >> hashp->SSHIFT];
X#ifdef DEBUG
X	assert(segp != NULL);
X#endif
X	bp = PTROF(segp[segment_ndx]);
X	is_disk = ISDISK(segp[segment_ndx]);
X    } 
X
X    if ( !bp ) {
X	bp = newbuf ( addr, prev_bp );
X	if ( !bp || get_page ( bp->page, addr, !prev_bp, (int)is_disk, 0 )) {
X	    return(NULL);
X	}
X	if ( !prev_bp ) {
X	    segp[segment_ndx] = (BUFHEAD *)((unsigned)bp | is_disk);
X	}
X    } else {
X	BUF_REMOVE ( bp );
X	MRU_INSERT ( bp );
X    }
X    return(bp);
X}
X
X/*
X    We need a buffer for this page. Either allocate one, or
X    evict a resident one (if we have as many buffers as we're
X    allowed) and put this one in.
X
X    If newbuf finds an error (returning NULL), it also sets errno
X*/
Xstatic BUFHEAD *
Xnewbuf ( addr, prev_bp )
Xint	addr;
XBUFHEAD	*prev_bp;
X{
X    register	BUFHEAD	*bp;	/* The buffer we're going to use */
X    register	BUFHEAD	*xbp;	/* Temp pointer */
X    register	BUFHEAD *next_xbp;
X    int	segment_ndx;
X    u_short	*shortp;
X    u_short	oaddr;
X    SEGMENT	segp;
X
X    if ( hashp->nbufs ) {
X	/* Allocate a new one */
X	bp = (BUFHEAD *)malloc ( sizeof (struct _bufhead) );
X	if ( !bp || !(bp->page = (char *)malloc ( hashp->BSIZE )) ) {
X	    return (NULL);
X	}
X	hashp->nbufs--;
X    } else {
X	/* Kick someone out */
X	bp = LRU;
X	BUF_REMOVE( bp );
X	/* 
X	    Set oaddr before put_page so that you get it 
X	    before bytes are swapped
X	*/
X	shortp = (u_short *)bp->page;
X	oaddr = shortp[shortp[0]-1];
X	if ( (bp->flags & BUF_MOD) && 
X	     put_page(bp->page, bp->addr, (int)IS_BUCKET(bp->flags), 0) ) {
X	    return(NULL);
X	}
X	/* 
X	    Update the pointer to this page (i.e. invalidate it).
X
X	    If this is a new file (i.e. we created it at open time), 
X	    make sure that we mark pages which have been written to 
X	    disk so we retrieve them from disk later, rather than
X	    allocating new pages.
X	*/
X
X	if ( IS_BUCKET(bp->flags)) {
X	    segment_ndx = bp->addr & ( hashp->SGSIZE - 1 );
X
X	    segp = hashp->dir[bp->addr >> hashp->SSHIFT];
X
X	    assert(segp != NULL);
X
X	    if ( hashp->new_file && 
X		 ((bp->flags & BUF_MOD) || ISDISK(segp[segment_ndx])) ) {
X		segp[segment_ndx] = (BUFHEAD *)BUF_DISK;
X	    } else segp[segment_ndx] = NULL;
X	}
X
X	/*
X	    Since overflow pages can only be access by means of
X	    their bucket, free overflow pages associated with this
X	    bucket.
X	*/
X	for ( xbp = bp; xbp->ovfl; ) {
X
X	    next_xbp = xbp->ovfl;
X	    xbp->ovfl = 0;
X	    xbp = next_xbp;
X
X	    /* Check that ovfl pointer is up date */
X	    if ( IS_BUCKET(xbp->flags) || (oaddr != xbp->addr) ) break;
X
X	    shortp = (u_short *)xbp->page;
X	    oaddr = shortp[shortp[0]-1];	/* set before put_page */
X	    if ( (xbp->flags & BUF_MOD) &&
X		put_page ( xbp->page, xbp->addr, 0, 0 ) ) {
X		return(NULL);
X	    }
X	    xbp->addr = 0;
X	    xbp->flags = 0;
X	    BUF_REMOVE ( xbp );
X	    LRU_INSERT ( xbp );
X	}
X    }
X
X    /* Now assign this buffer */
X    bp->addr = addr;
X#ifdef DEBUG1
X    fprintf ( stderr, "NEWBUF1: %d->ovfl was %d is now %d\n", bp->addr,
X		(bp->ovfl?bp->ovfl->addr:0),  0);
X#endif
X    bp->ovfl = NULL;
X    if ( prev_bp ) {
X	/* 
X	    If prev_bp is set, this is an overflow page, hook it in to the
X	    buffer overflow links
X	*/
X#ifdef DEBUG1
X	fprintf ( stderr, "NEWBUF2: %d->ovfl was %d is now %d\n", prev_bp->addr,
X		    (prev_bp->ovfl?bp->ovfl->addr:0),  
X		    (bp?bp->addr: 0));
X#endif
X	prev_bp->ovfl = bp;
X	bp->flags = 0;
X    } else bp->flags = BUF_BUCKET;
X    MRU_INSERT ( bp );
X    return ( bp );
X}
X
Xextern void
Xbuf_init ( nbytes )
Xint	nbytes;
X{
X    int	npages;
X    BUFHEAD	*bfp = &(hashp->bufhead);
X
X    npages = (nbytes + hashp->BSIZE - 1) >> hashp->BSHIFT;
X    npages = MAX ( npages, MIN_BUFFERS );
X
X    hashp->nbufs = npages;
X    bfp->next = bfp;
X    bfp->prev = bfp;
X    /*
X	This space is calloc'd so these are already null
X
X	bfp->ovfl = NULL;
X	bfp->flags = 0;
X	bfp->page = NULL;
X	bfp->addr = 0;
X    */
X}
X
Xextern int
Xbuf_free ( do_free, to_disk )
Xint	do_free;
Xint	to_disk;
X{
X    BUFHEAD	*bp;
X
X    /* Need to make sure that buffer manager has been initialized */
X    if ( !LRU ) {
X	return(0);
X    }
X
X    for ( bp = LRU; bp != &hashp->bufhead; ) {
X	/* Check that the buffer is valid */
X	if ( bp->addr || IS_BUCKET(bp->flags) ) {
X	    if ( to_disk && (bp->flags & BUF_MOD) &&
X		 put_page (bp->page, bp->addr, IS_BUCKET(bp->flags)), 0 ) {
X		return (-1);
X	    }
X	}
X
X	/* Check if we are freeing stuff */
X	if ( do_free ) {
X	    if ( bp->page ) free ( bp->page );
X	    BUF_REMOVE(bp);
X	    (void)free ( bp );
X	    bp = LRU;
X	} else bp = bp->prev;
X    }
X
X    return(0);
X}
X
Xextern void
Xreclaim_buf ( bp )
XBUFHEAD	*bp;
X{
X    bp->ovfl = 0;
X    bp->addr = 0;
X    bp->flags = 0;
X    BUF_REMOVE ( bp );
X    LRU_INSERT ( bp );
X}
@@@End of lq-text/src/ozmahash/buf.c
echo x - lq-text/src/ozmahash/byte_order.c 1>&2
sed 's/^X//' >lq-text/src/ozmahash/byte_order.c <<'@@@End of lq-text/src/ozmahash/byte_order.c'
X/*-
X * Copyright (c) 1990 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Margo Seltzer.
X *
X * %sccs.include.redist.c%
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "%W% (Berkeley) %G%";
X#endif /* LIBC_SCCS and not lint */
X
X#include <stdio.h>
Xmain ( argc, argv )
Xint	argc;
Xchar	**argv;
X{
X    int		num = 0x41424344;
X    if ( ((((char *)&num)[0]) == 0x41) && ((((char *)&num)[1]) == 0x42) &&
X	 ((((char *)&num)[2]) == 0x43) && ((((char *)&num)[3]) == 0x44) ) {
X	    printf ( "BIG ENDIAN\n" );
X    } else if ( ((((char *)&num)[3]) == 0x41) && 
X		((((char *)&num)[2]) == 0x42) && 
X		((((char *)&num)[1]) == 0x43) && 
X		((((char *)&num)[0]) == 0x44) ) {
X	    printf ( "LITTLE ENDIAN\n" );
X    } else {
X	printf ( "Odd Endian -- are you running on a PDP-11?\n");
X    }
X
X}
@@@End of lq-text/src/ozmahash/byte_order.c
echo x - lq-text/src/menu/error.c 1>&2
sed 's/^X//' >lq-text/src/menu/error.c <<'@@@End of lq-text/src/menu/error.c'
X/* Error.c -- print an error message and exit.
X * If we're in curses mode, do an endwin() first.
X *
X * $Header: /usr/src/cmd/lq-text/src/menu/RCS/error.c,v 1.1 90/08/29 21:49:49 lee Rel1-10 $
X *
X * $Log:	error.c,v $
X * Revision 1.1  90/08/29  21:49:49  lee
X * Initial revision
X * 
X * Revision 2.1  89/08/07  13:49:36  lee
X * First fully working (V.3.2 only) release;
X * this is the baseline for future development.
X * 
X * Revision 1.2  89/08/04  17:59:14  lee
X * Fully working with Basic Functionality.
X * Scrolling menubar, scrolling menus, moveable Info windows.
X * 
X *
X */
X
X#include <stdio.h>
X#ifdef ultrix
X# include <cursesX.h>
X#else
X# include <curses.h>
X#endif
X#include <malloc.h>
X#include "internal.h"
X#include "error.h"
X
Xint InCurses = 0;
Xextern char *cmdname, *progname;
X
X/*PRINTFLIKE1*/
X/*VARARGS1*/
Xvoid
Xerror(Type, fmt, a1, a2, a3, a4)
X    int Type;
X    char *fmt;
X{
X    extern char *strchr();
X    char *p;
X    extern char *malloc();
X
X    if (InCurses) {
X	if (!(Type & (ERR_INTERNAL | ERR_MEMORY))) {
X	    if ((p = malloc(500)) == (char *) 0) {
X		Type |= ERR_MEMORY;
X	    } else {
X		(void) sprintf(p, fmt, a1, a2, a3, a4);
X		(void) ShowInfo(p, (WINDOW *) 0, COLS / 2 - 20, LINES / 2 - 4);
X		if (Type & ERR_FATAL) {
X		    endwin();
X		    exit(1);
X		} else {
X		    return;
X		}
X	    }
X	}
X	if (Type & ERR_FATAL) {
X	    endwin();
X	    exit(1);
X	}
X    }
X    if (InCurses) {
X	if (Type & ERR_FATAL) {
X	    endwin();
X	    InCurses = 0;
X	}
X    }
X    if (InCurses && !(Type & ERR_INTERNAL)) {
X	wmove(stdscr, 5, 0);
X	clrtoeol();
X	refresh();
X    }
X    if (cmdname) {
X	(void) fprintf(stderr, "%s: ", cmdname);
X    }
X    if (progname) {
X	(void) fprintf(stderr, "%s: ", progname);
X    }
X    (void) fprintf(stderr, fmt, a1, a2, a3, a4);
X    if (strchr(fmt, '\n') == (char *) 0) {
X	(void) fputc('\n', stderr);
X    }
X    if (InCurses) fputc('\r', stderr);
X    if (Type & ERR_FATAL) exit(-1);
X}
@@@End of lq-text/src/menu/error.c
echo x - lq-text/src/menu/error.h 1>&2
sed 's/^X//' >lq-text/src/menu/error.h <<'@@@End of lq-text/src/menu/error.h'
X/* Codes that can be passed to error()
X *
X * $Header: /usr/src/cmd/lq-text/src/menu/RCS/error.h,v 1.1 90/08/29 21:49:53 lee Rel1-10 $
X *
X * $Log:	error.h,v $
X * Revision 1.1  90/08/29  21:49:53  lee
X * Initial revision
X * 
X * Revision 2.1  89/08/07  13:48:38  lee
X * First fully working (V.3.2 only) release;
X * this is the baseline for future development.
X * 
X * Revision 1.1  89/07/28  19:11:06  lee
X * Initial revision
X * 
X *
X */
X
Xextern void error();
X
X#define ERR_INTERNAL	01
X#define ERR_MEMORY	02
X#define ERR_FATAL	04
@@@End of lq-text/src/menu/error.h
echo x - lq-text/src/menu/internal.h 1>&2
sed 's/^X//' >lq-text/src/menu/internal.h <<'@@@End of lq-text/src/menu/internal.h'
X/* internal.h -- header file for internal use.
X *
X * $Header: /usr/src/cmd/lq-text/src/menu/RCS/internal.h,v 1.1 90/08/29 21:50:36 lee Rel1-10 $
X *
X * $Log:	internal.h,v $
X * Revision 1.1  90/08/29  21:50:36  lee
X * Initial revision
X * 
X * Revision 2.1  89/08/07  13:49:27  lee
X * First fully working (V.3.2 only) release;
X * this is the baseline for future development.
X * 
X * Revision 1.1  89/07/27  11:39:40  lee
X * Initial revision
X * 
X *
X */
X
X/* Thanks to Henry Spencer (utzoo!henry) for this: */
X#define STREQ(boy,girl) ((*(boy)== *(girl))&&!strcmp((boy),(girl)))
X
X
X/* SAVEMENULINE is set if you want to the menus to hang down from
X * the bar when selected.  (this is default)
X * Otherwise, define MENUTEXTOVERBAR and recompile...
X * the top line of the menu goes on screen row MENUTOP.
X * If MENUTOP is >= 2, the top line of the menu is boxed.  Otherwise,
X * the first item in the menu goes on the menu line, overwriting it.
X * Only use this if you have (ROWS - 1) items on each menu...
X */
X
X#ifndef MENUTEXTOERBAR
X# define SAVEMENULINE
X#endif
X#define SAVEMENULINE
X#ifdef SAVEMENULINE
X  /* MENUTOP is the line on which pull-down menus start. */
X# ifndef MENUTOP
X#  define MENUTOP 2
X# endif /*!MENUTOP*/
X# if MENUTOP>1
X#  define MENUBOXONTOPLINE
X# endif
X#else
X# define MENUTOP 1
X#  undef MENUBOXONTOPLINE
X#endif
X
X#define new(type)	((type *) malloc(sizeof(type)))
@@@End of lq-text/src/menu/internal.h
echo x - lq-text/src/menu/menu.h 1>&2
sed 's/^X//' >lq-text/src/menu/menu.h <<'@@@End of lq-text/src/menu/menu.h'
X#ifdef ultrix
X# include "ultrixhack.h"
X#endif
X/* menu.h -- user programs should include this after curses.h 
X *
X * $Header: /usr/src/cmd/lq-text/src/menu/RCS/menu.h,v 1.1 90/08/29 21:50:50 lee Rel1-10 $
X *
X * $Log:	menu.h,v $
X * Revision 1.1  90/08/29  21:50:50  lee
X * Initial revision
X * 
X * Revision 2.1  89/08/07  13:49:31  lee
X * First fully working (V.3.2 only) release;
X * this is the baseline for future development.
X * 
X * Revision 1.2  89/08/04  17:59:07  lee
X * Fully working with Basic Functionality.
X * Scrolling menubar, scrolling menus, moveable Info windows.
X * 
X * Revision 1.1  89/07/27  11:39:20  lee
X * Initial revision
X * 
X *
X */
X
X/* for errors... -- set this whenever initscr() is in effect */
Xextern int InCurses;
X
X/* A menu bar from a data structures (how quaint!) viewpoint:
X *
X *   File  Edit  *Implement*  Duration
X * -------------+---------------+------------------------------------
X *		| Tongs		|
X *		| *Whip******** |
X *		| Branding Iron |
X *		| Thumbscrew	|
X *		| Dead Fish	|
X *		+---------------+
X *
X * MenuBar ---> +-----------------------------------------------------
X *		|HowManyMenus = 4
X *		|SelectedMenu = 2
X *		|MenuBarId [internal] = 34 (say)
X *		|ScrollOffset = 0 // horizontal scrolling of bar
X *		|Menus--->an array of 4 menu structures:
X *		|	 
X *
X * MenuBar->Menus[2] looks like this:
X *		+-----------------------------------------------------
X *		|Name = "Implement"
X *		|HowManyItems = 5
X *		|NeedToBox = 1
X *		|IsSelected = 1 // it's highlighted in the MenuBar
X *		|TopLineOnScreen = 0 // for vertical scrolling
X *		|PositionInBar = 13 // characters from the left
X *		|Width = 14 // length of widest item
X *		|SelectedLine = 1 // they're numbered from 0
X *		|MenuId [private] = 4097 (say)
X *		|Description = "Choose a torture implement..."
X *		|Items--->an array of 5 items:
X *		|
X *
X * MenuBar->Menus[2]->Items[1] looks like this:
X *		+-----------------------------------------------------
X *		|Function-->points to a function to be called when
X *		|Name = "Whip"
X *		|NameLength = 4 // strlen(Name), for speed
X *		|Description = "Cat O' Nine Tails"
X *		|LongText = "Ouch" // passed to Function().
X */
X
Xtypedef struct {
X    int (*Function)();
X    /* Function is called when the menu is selected.  If it is
X     * zero, you just get a beep(); this is intended for testing.
X     * The function is passed two arguments: a pointer to the menu
X     * which contained this item, and the item number.  In the
X     * "Whip" example above, it would be a pointer to the Implement
X     * menu, and the number "1".
X     * The LongText argumenht is intended for use by this function,
X     * although what it does with it is undefined.  For example,
X     * it could contain a shell command, or it could be a pointer
X     * into a table of statements to be interpreted, or....
X     */
X    char *Name;
X    /* Name is the string displayed in the menu itself.
X     */
X    unsigned short NameLength;
X    /* NameLength must either be 0 or strlen(Name).  In the former case,
X     * it will automatically be updated.  It is not clear that this is
X     * a big saving, so it may well go way soon.
X     */
X    char *Description;
X    /* pop-up box for help/explanation; when the item is highlighted,
X     * the user can press `?' or `x' and get this short explanation in
X     * a pop-up box.
X     */
X    char *LongText;
X    /* for use only by Function -- see the comment there.
X     */
X} t_MenuItem;
X
X/* For MenuStyle, see below */
X#ifndef MENUSTYLE_DEFAULT
X# define MENUSTYLE_DEFAULT 0
X#endif
X
X/* Each menu structure holds (a pointer to) a number of Items...*/
Xtypedef struct {
X    int HowManyItems;
X    /* This can of course be less than the real number, if you want to
X     * shorten a menu for some reason.  If there are more items than
X     * will fit on the screen, the menu can scroll vertically, so there
X     * is no limit imposed on this by the menu routines.  On the other
X     * hand, it would be so irritating to scroll through 1000 items that
X     * the list should preferably be under 20.
X     */
X    t_MenuItem *Items;
X    /* This is a pointer to a block of menus.
X     * A linked list might be better.
X     */
X    unsigned int MenuStyle;
X    /* currently always zero, as there is only one style.
X     * you can use MENUSTYLE_DEFAULT for this.
X     * A future style might have no box, just a line on the left.
X     */
X    unsigned int IsSelected : 1;
X    /* This is in case you are using interrupts to change menus.  You
X     * wouldn't want to delete or hide a selected menu!
X     * The software updates this, but otherwise ignores it.
X     */
X    int TopLineOnScreen;
X    /* This is for vertical scrolling;  if it's 13 (say), then the
X     * first 13 lines of the menu are not displayed -- If it was "1" in
X     * the example, "Whip" would be where "Tongs" are, and "Tongs"
X     * would not be displayed.
X     */
X    int PositionInBar;
X    /* Horizontal position of the left edge of the box.  This is set
X     * for each menu by ShowMenuBar() at each call.
X     */
X    int Width;
X    /* The same as the length of the longest item.
X     * If you change the items, set this to zero to force ShowMenuBar()
X     * or ShowMenu() to recalculate it from the Item->[*].Width entries,
X     * or using strlen() if necessary.
X     */
X    char *Name;
X    int NameLength;
X    /* This is the text displayed on the menu bar.
X     * NameLength is computed by ShowMenuBar(); the user should set it
X     * to zero to indicate that this is necessary, when the menu is
X     * created and whenever the name changes.
X     */
X    char *Description;
X    /* This should be a short (one line) description of the purpose
X     * of this menu.
X     */
X    int SelectedLine;
X    /* This is the currently highlighted line.  If you set it yourself,
X     * ShowMenu() will make this the highlighted item when it first
X     * displays the menu.  Subsequently, of course, the user will move
X     * it up or down at will...
X     * The default is zero, the first item.
X     */
X    /* private */ int MenuId;
X    /* Set this to zero. */
X} t_Menu;
X
X#define MENUMAXINBAR 30
X
X/* A Menu Bar... */
Xtypedef struct {
X    int HowManyMenus;
X    /* The number of menus in Menus[].  Only the first MENUMAXINBAR will
X     * be used, however.  Also, not all will be displayed on the screen...
X     * depending on how many fit.
X     */
X    int SelectedMenu;
X    /* This is the Menu whose name is highlighted.
X     * Default is zero; set it to something else if you want...
X     */
X    t_Menu *Menus[MENUMAXINBAR];
X    /* Pointers to the menu structures */
X    int ScrollOffset;
X    /* This is for horizontal scrolling.
X     * The default is zero, meaning that the first menu is as near to the
X     * left of the screen as it will go (there's a 2-char gap to make
X     * room for the left edge of the box).
X     */
X    /* private */ int MenuBarId;
X    /* Set this to zero. */
X} t_MenuBar;
X
X/* Some functions that you can arrange to have called by menu selection.
X * The functions in this table must all take two arguments, a t_Menu *
X * and an integer, which represents the (menu, item) combination that
X * was selected.
X * They should return either the integer or -1.
X * If they return -3 or -4, it's the same as if the user pressed the
X * left or right arrow keys instead of selecting.
X * If they return -5, it's as if they typed 'q' at the prompt.
X */
X
X/*PRINTFLIKE1*/
Xextern void error();
X
X/* A TextBox has the following structure:
X *
X * +------------------------------------------
X * | Name (optional, only displayed if != 0)
X * | Flags
X * | 	BoldName
X * |	BoldText
X * |	CanEdit
X * |	IfChanged (set if the text has been edited)
X * | Window (0 if not allocated)
X * | tlx, tly -- where it is
X * | Height, Width -- how big it is (including the surrounding box)
X * | char *Text -- the text itself
X * | HowManyLines
X * | short *LineLengths --> pointer to array of line lengths
X * | HScrollPos, VScrollPos
X */
Xtypedef struct s_TextBox {
X    char *Name;
X    unsigned long flags;
X    WINDOW *Window;
X    short tlx, tly;
X    short Height, Width;
X    int HScrollPos, VScrollPos;
X    char *String;
X    int HowManyLines;
X    short *LineLengths;
X    int StringWidth;
X} t_StringBox;
X
@@@End of lq-text/src/menu/menu.h
echo end of part 11
-- 
Liam R. E. Quin,  lee@sq.com, SoftQuad Inc., Toronto, +1 (416) 963-8337