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