From: greim@sbsvax.cs.uni-sb.de (Michael Greim) Newsgroups: alt.sources Subject: KEF - a library to store and identify function key presses, Part 03/06 Message-ID: <4365@sbsvax.cs.uni-sb.de> Date: 15 May 90 15:14:34 GMT #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'COPYING' <<'END_OF_FILE' X X KEF - a library to catch and identify function key strokes X X X (C) Copyright by Michael Greim, may 1990 X X XThe author, Michael Greim, allows you to do anything you want with X"KEF", provided the following conditions are met: X X1) When you distribute, or make available, a copy or a derivation of the X source code of this software, then X a) you must also distribute, or make available, this notice X b) changes from the original must be identifyable X2) When you distribute, or make available, this software in binary form, then X a) you must also distribute, or make available, this notice X b) you must tell the recipient, or make available a notice, that the X original software is available in both source and binary form, and, X if s/he so desires, must furnish it to him/her or tell him/her X where to get it. X3) When distributing, or making available, this software in any form for X a fee, this fee must not be for the writing of the original software X and it must be made clear to the customer that you don't charge him X with a fee for the original software. X4) When you distribute or make available only a part of this software X you must also distribute or make available a notice telling X the recipient that the software is incomplete and where s/he can X get the complete software. X XThere is no warranty of merchantability nor any warranty of fitness for a Xparticular purpose nor any other warranty, either express or implied, as Xto the accuracy of the herewith published program, or as to its Xsuitability for any particular purpose. XAccordingly, I, Michael Greim, assume no responsibility Xfor its use by the recipient. Further, I, Michael Greim, assume no Xobligation to furnish any assistance of any kind whatsoever, Xor to furnish any additional information or documentation. X X--------------------------------------------------------------- X XI will only accept patches sent to me that don't include an explicit Xcopyright. Such patches will, at my discretion, be included Xin future releases of the software and will fall under this copyright notice. XIf you don't like to share your patches with me and other users, then Xdon't bother. X XThe author asks anybody : X- to port this library and programs to as much computer systems as possible X and send him complaints, results, bug fixes, praise, beer, scottish X malt whisky ... X- to incorporate this library and programs in any package of programs for X free distribution X XExplanation: X1.b : This means you can e.g. distribute the original in a tar file and X your changes in form of context diffs in other tar files. Or you X can distribute your RCS archive with the original version as X base version. X3 : You can charge fees for distributing, for storage media, transmission X costs, changes, bugfixes, time spent on preparation of a distribution but X you must not charge a fee for the writing of the original software. X If you tell someone that s/he can get the software for free X (well, cost for packageing) by simply writing to me or sending mail to an X archive server, and then charge him/her e.g. $ 1000 for the distribution, X and s/he pays it, then this person deserves it. X (Send me the name and address, though. You know, I have this land to X sell, "'tween the salt water and the sea strand" ... :-) X If you have made an extension to the library, you may also charge a fee X for this work done by you. X This simply is to prevent people from saying they wrote the software X and making money from it. Their customers would have been able to X save money, if they had known that the software can be had quite X cheaply. X4 : You can sell or give away parts of the software, e.g. a set X of patches. But you must mention somewhere that it is not complete X and where to get the rest. X For instance, if you like the routines in "set_io.c" to switch X a line driver to "character-at-once" mode then you can do it, X but you must write, e.g. in a READ-ME file that you got it from KEF, X and where to get the rest. X XI am not obliged to furnish any assistance, but if you ask me nice, I Xmight consider to think about starting to contemplate speculating about Xdoing something ... X X XMichael Greim X Xgreim@cs.uni-sb.de Xuunet!unido!sbsvax!greim END_OF_FILE if test 4180 -ne `wc -c <'COPYING'`; then echo shar: \"'COPYING'\" unpacked with wrong size! fi # end of 'COPYING' fi if test -f 'demos/Makefile.SH' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'demos/Makefile.SH'\" else echo shar: Extracting \"'demos/Makefile.SH'\" \(2905 characters\) sed "s/^X//" >'demos/Makefile.SH' <<'END_OF_FILE' Xrmconfig='no' Xcase $CONFIG in X'') X if test ! -f config.sh; then X ln ../config.sh . || \ X ln ../../config.sh . || \ X ln ../../../config.sh . || \ X (echo "Can't find config.sh."; exit 1) X rmconfig='yes' X fi X . config.sh X ;; Xesac X: This forces SH files to create target in same directory as SH file. X: This is so that make depend always knows where to find SH derivatives. Xcase "$0" in X*/*) cd `expr X$0 : 'X\(.*\)/'` ;; Xesac Xecho "Extracting demos/Makefile (with variable substitutions)" X: Some headers, do no variable substitution X$spitshell >Makefile <<'!NO!SUBS!' X# X# Makefile fuer KEF demos X# X# sccsid = @(#) Makefile (v1.7 5/3/90) X# X X# X# Some general stuff X# XSHELL = /bin/sh XSCCSPATH= X!NO!SUBS! X: This section of the file will have variable substitutions done on it. X: Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!. X: Protect any dollar signs and backticks that you do not want interpreted X: by putting a backslash in front. You may delete these comments. X$spitshell >>Makefile <>Makefile <<'!NO!SUBS!' X X# X# We must know how to switch the terminal driver to a mode where a X# character becomes immediately available when a key has been pressed. X# Known interfaces (in set_io.c): X# TERMIO : on System III, SINIX X# STTY : on BSD, SUN OS, ... X# X# define USE_{INTERFACE} X# X# Machines/OS | TERMIO | STTY | preferred X# --------------------------------+--------+------+---------- X# SIEMENS PC-MX2 SINIX V2.1 | y | y | TERMIO X# VAX 11/780 4.3BSD | n | y | STTY X# VAX 8700 ULTRIX 2.1 | y | y | STTY X# SUN 3/260 | n | y | STTY X# X!NO!SUBS! X X: special treatment for the next line of Makefile X Xif $test "X$d_termio" = "Xdefine" ; then X echo "INTERF=-DUSE_TERMIO" >> Makefile Xelse X echo "INTERF=-DUSE_STTY" >> Makefile Xfi X X: In the following dollars and backticks do not need the extra backslash. X$spitshell >>Makefile <<'!NO!SUBS!' X# X# INCL should be pointing at the directory kef.h etc. are in. X# XINCL = -I.. X X# X# Compile flags. X# XCFLAGS = ${STDCFLAGS} ${INCL} X XKEF_LIBS= ../libkef.a ../libDkef.a X X X# X# Dependencies X# ============ X# X XDEMOS= demo11 demo13 demo15 X Xall: ${DEMOS} X Xdemo11: demo11.o set_io.o X ${CC} -o demo11 ${LDFLAGS} demo11.o set_io.o X Xdemo13: demo13.o set_io.o X ${CC} -o demo13 ${LDFLAGS} demo13.o set_io.o ${KEF_LIBS} X Xdemo15: demo15.o set_io.o X ${CC} -o demo15 ${LDFLAGS} demo15.o set_io.o ${KEF_LIBS} X Xset_io.o : set_io.c X ${CC} -c ${CFLAGS} ${INTERF} set_io.c X!NO!SUBS! Xchmod 755 Makefile X$eunicefix Makefile Xif test "$rmconfig" = "yes" ; then X rm -f config.sh Xfi END_OF_FILE if test 2905 -ne `wc -c <'demos/Makefile.SH'`; then echo shar: \"'demos/Makefile.SH'\" unpacked with wrong size! fi # end of 'demos/Makefile.SH' fi if test -f 'demos/set_io.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'demos/set_io.c'\" else echo shar: Extracting \"'demos/set_io.c'\" \(2620 characters\) sed "s/^X//" >'demos/set_io.c' <<'END_OF_FILE' Xstatic char * sccsid = "@(#) set_io.c (v1.5 5/2/90)"; X/* X * Routines to set a terminal line into a special mode. X * X * Call with "-D" where is one of X * USE_TERMIO or USE_STTY X * X * If the machines uses TERMIO and TCGETA and TCSETA are missing from X * "sys/termio.h" then define the values. This is the case on SIEMENS X * MX2 running SINIX v2.1 (SYSIII derived). X * X * Bugs: X * As we use a variable local to this module, it is only possible X * to use one terminal line. X * We assume that the terminal line is open on filedescriptor 0. X * X */ X X#include "config.h" X X#if !defined(USE_TERMIO) && !defined(USE_STTY) X# include "ERROR : neither USE_TERMIO nor USE_TTY defined" X#endif X X#ifdef USE_TERMIO X Xstatic char * tell = "set_io.c :: use TERMIO"; X X#ifdef SYSTERMIO X# include X#else X# include X#endif X X#ifndef TCGETA X# define TIOC ('T'<<8) X# define TCGETA (TIOC|1) X# define TCSETA (TIOC|2) X# define TCSETAW (TIOC|3) X# define TCSETAF (TIOC|4) X# define TCSBRK (TIOC|5) X# define TCXONC (TIOC|6) X# define TCFLSH (TIOC|7) X# define TCDSET (TIOC|32) X#endif X X/* X * old_tty hold the original settings of the terminal line, X * tty the most recently changed settings. X */ X Xstatic struct termio tty, old_tty; X Xtty_cbreak (ind) X int ind; X{ X if (ind == 1) { X tty.c_lflag &= ~ICANON; X tty.c_lflag |= ISIG; X tty.c_cchar[VMIN]=1; X tty.c_cchar[VTIME]=0; X } else { X tty.c_lflag |= ICANON; X } X} X Xtty_echo(ind) X int ind; X{ X if (ind == 1) X tty.c_lflag |= ECHO; X else X tty.c_lflag &= ~ECHO; X} X Xtty_nl(ind) X int ind; X{ X if (ind == 1) X tty.c_oflag |= ONLRET; X else X tty.c_oflag &= ~ONLRET; X} X Xtty_save () X{ X (void) ioctl (0, TCGETA, &tty); X (void) ioctl (0, TCGETA, &old_tty); X} X Xtty_set () X{ X (void) ioctl (0, TCSETAF, &tty); X} X Xtty_reset () X{ X (void) ioctl (0, TCSETAF, &old_tty); X} X X# endif /* USE_TERMIO */ X X# ifdef USE_STTY X Xstatic char * tell = "set_io.c :: use STTY"; X X/* X * old_tty hold the original settings of the terminal line, X * tty the most recently changed settings. X */ X X# include Xstatic struct sgttyb tty, old_tty; X Xmy_stty (fd, s) Xint fd; Xstruct sgttyb * s; X{ X (void) ioctl (fd, TIOCSETN, s); X} X Xtty_cbreak (ind) X int ind; X{ X if (ind == 1) X tty.sg_flags |= CBREAK; X else X tty.sg_flags &= ~CBREAK; X} X Xtty_echo (ind) X int ind; X{ X if (ind == 1) X tty.sg_flags |= ECHO; X else X tty.sg_flags &= ~ ECHO; X} X Xtty_nl (ind) X int ind; X{ X if (ind == 1) X tty.sg_flags |= CRMOD; X else X tty.sg_flags &= ~CRMOD; X} X Xtty_save () X{ X (void) gtty (0, &tty); X (void) gtty (0, &old_tty); X} X Xtty_set () X{ X my_stty (0, &tty); X} X Xtty_reset () X{ X my_stty (0, &old_tty); X} X X# endif /* USE_STTY */ END_OF_FILE if test 2620 -ne `wc -c <'demos/set_io.c'`; then echo shar: \"'demos/set_io.c'\" unpacked with wrong size! fi # end of 'demos/set_io.c' fi if test -f 'kdb-high/cleanup.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kdb-high/cleanup.c'\" else echo shar: Extracting \"'kdb-high/cleanup.c'\" \(2827 characters\) sed "s/^X//" >'kdb-high/cleanup.c' <<'END_OF_FILE' Xstatic char * sccsid = "@(#) cleanup.c (v1.9 4/26/90)"; X X/* X * Cleanup an array. X * X * First allocate an array in the same size as the old one, then X * copy the nodes in the correct sequence. X */ X X# include X# include "kef.h" X X#ifdef DEBUG_CLEANUP X# define L_DEBUG X#else X# ifdef L_DEBUG X# undef L_DEBUG X# endif X#endif X# include "local.h" X X#include "setup.h" X X/* X * Some global variables, so I don't have to pass them into the routines X * for each recursion. X */ Xstatic struct kef_db * kdb; Xstatic int num; Xstatic struct kef_node * nd; X X static void Xrun_tree (n) X kef_index n; X/* X * Run through the tree from node n. X */ X{ X register kef_index i; X register int count, where; X X /* X * First count elements in horizontal list ("next") X */ X count = 0; X for (i = n; i != KEF_NIL; i = kdb->node[i].next) X count ++; X X /* X * Give number in the horizontal list starting at current num, X * remembered in "where". Reserve future indices "where" to X * "where" + "count" - 1 X */ X where = num; X num += count; X X /* X * Run along the horizontal list again. Tweak the "pointers" to X * point at the future locations of their targets rather than their X * current ones. X */ X for (i = n; i != KEF_NIL; i = kdb->node[i].next) { X /* X * Node i goes to number "where". X */ X FASTCOPY ((char *)(&(kdb->node[i])), X (char *)(&(nd[where])), sizeof (struct kef_node)); X /* X * Go into the subtree if there is any. X * Change "sub" "pointer" to future location of first node X * in subtree. X */ X if (kdb->node[i].sub != KEF_NIL) { X nd[where].sub = num; /* Yes, we know that this is it */ X run_tree (kdb->node[i].sub); X SET_CLEAN(nd[where]); X } X /* X * Advance. Don't forget to change "next" too. X */ X if (kdb->node[i].next != KEF_NIL) X nd[where].next = where+1; /* This is it */ X where++; X } X} X X int Xkef_cleanup (my_kdb) X struct kef_db * my_kdb; X/* X * Cleanup the array of nodes. X * The reason behind this is that it is faster to search an array X * using binary search when the array is ordered. X */ X{ X DI("kef_cleanup ::") X X if ((long)(my_kdb->malloc) == 0L) X return KEF_E_NO_MALLOC; X if ((long)(my_kdb->free) == 0L) X return KEF_E_NO_FREE; X X kdb = my_kdb; X /* X * Allocate the new array. X */ X nd = (struct kef_node *) X (* kdb->malloc) (kdb->num_nodes * sizeof (struct kef_node)); X /* X * Note : root points at a dummy node, which will never be deleted, so X * it does not change place. It is always at index 0. X * New stuff is added below root, so root has no neighbour. X */ X FASTCOPY ((char *)(&(kdb->node[kdb->root])), X (char *)(&(nd[kdb->root])), sizeof (struct kef_node)); X SET_CLEAN(nd[kdb->root]); X X num = 1; X X run_tree (kdb->node[kdb->root].sub); X X (void) (* my_kdb->free) (kdb->node); X kdb->node = nd; X X kdb->high_nodes = kdb->used_nodes; X kdb->free_list = KEF_NIL; X X return KEF_E_OK; X} END_OF_FILE if test 2827 -ne `wc -c <'kdb-high/cleanup.c'`; then echo shar: \"'kdb-high/cleanup.c'\" unpacked with wrong size! fi # end of 'kdb-high/cleanup.c' fi if test -f 'kdb-high/str.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kdb-high/str.c'\" else echo shar: Extracting \"'kdb-high/str.c'\" \(4179 characters\) sed "s/^X//" >'kdb-high/str.c' <<'END_OF_FILE' Xstatic char * sccsid = "@(#) str.c (v1.8 3/21/90)"; X X/* X * High-level Routines to map value --> set of strings which are X * associated with value. X */ X X# include X# include "kef.h" X X#ifdef DEBUG_STR X# define L_DEBUG X#else X# ifdef L_DEBUG X# undef L_DEBUG X# endif X#endif X# include "local.h" X X int Xkef_build_str (kdb, inx, p) X struct kef_db * kdb; X kef_index inx; X char ** p; X/* X * Start at cell inx, run along "tag" links (returned by kef_walk or X * kef__next_inst) and build string. X * 0 : ok. X * KEF_E_INV_INX : invalid index while traversing list X * KEF_E_TAG_LOOP: endless loop in 'tag' list X */ X{ X DI("kef__build_str ::") X int n; X register struct kef_node * nd; X kef_index at; X X /* X * First count the links. X * Possible errors: X * - index outside of array (KEF_E_INV_INX) X * - endless loop (KEF_E_TAG_LOOP) X */ X X DEB2("%s started for %1d\n", inx); X FLUSH; X nd = kdb->node; X /* X * Note that the last element in the list is the root of X * the character tree and will not be printed. It is counted, though. X */ X for (at = inx, n = 0; n < kdb->num_nodes && at != KEF_NIL; n++) { X DEB2("%s count slot %1d\n", at); X FLUSH; X if (at >= kdb->num_nodes) X return KEF_E_INV_INX; X at = nd[at].tag; X } X if (n >= kdb->num_nodes) X return KEF_E_TAG_LOOP; X /* X * String will be n-1 characters long plus NUL. X */ X DEB2("%s there are %1d elements in 'tag' list\n", n-1); X if (kdb->malloc == NULL) X return KEF_E_NO_MALLOC; X *p = (* kdb->malloc) (n); X if (*p == NULL) X return KEF_E_ALLOC_FAILED; X n -= 2; /* pos of last character in buf */ X (*p)[n+1] = '\0'; X for (at = inx; n >= 0; n--) { X (*p)[n] = nd[at].what; X at = nd[at].tag; X } X DEB2("%s built string '%s'\n", *p); X return KEF_E_OK; X} X X int Xkef_get_strings (kdb, val, p) X struct kef_db * kdb; X kef_value val; X char **** p; X/* X * Get list of all strings that produce val. X * p is address of a pointer to an internal variable, that points at X * list of strings. List is terminated by NULL pointer. X * If *p == NULL then there was no string available. X * X * To minimize number of allocs we allocate GRAIN elements more X * each time. There are "size" slots in kefp array. X * Occupied are at most "size"-1 and actually only n. X * The last element must stay free. It will receive a NULL pointer. X * X * Watch out. If not handled carefully there may be a memory leak, i.e. X * memory may be allocated but not freed anymore. X */ X{ X#define GRAIN 10 X DI("kef_get_strings ::") X static char ** kefp = NULL; X char ** tmp; X int size, n; X int ret; X kef_index inx; X X DEB2("%s called for value %1d\n", val); X FLUSH; X if ((long)(kdb->malloc) == 0L) X return KEF_E_NO_MALLOC; X if ((long)(kdb->realloc) == 0L) X return KEF_E_NO_REALLOC; X if ((long)(kdb->free) == 0L) X return KEF_E_NO_FREE; X if (kefp != NULL) { X /* X * Count how much space (at least) is available from previous X * call. Delete all strings pointed at. X * We don't know (but realloc does) how much slots are really in kefp, X * but we know that there is a NULL pointer and all slots before it X * point to allocated strings and can be reused. X */ X DEB1("%s delete space left over from previous call\n"); X for (n = 0; kefp[n] != NULL; n++) X (void) (* kdb->free) (kefp[n]); X size = n; X } else { X if ((kefp = (char **) (* kdb->malloc) (2 * sizeof (char *))) == NULL) X return KEF_E_ALLOC_FAILED; X size = 2; X } X kefp[0] = NULL; X DEB2("%s currently we have at least %1d slots at our disposal\n", size); X X inx = KEF_NIL; X for (n = 0; kef__next_inst (kdb, val, &inx) == 1; n++) { X DEB2("%s loop for string end at %1d\n", inx); X FLUSH; X /* X * A new string. Is there a slot left in kefp or X * do we need more space ? X */ X if (n + 1 >= size) { X if ((tmp = (char **) (* kdb->realloc) (kefp, (size + GRAIN) X * sizeof (char *))) == NULL) { X (void) (* kdb->free) (kefp); X kefp = NULL; X return KEF_E_ALLOC_FAILED; X } X kefp = tmp; X size += GRAIN; X } X if ((ret = kef_build_str (kdb, inx, & (kefp[n]))) != KEF_E_OK) { X kefp[n] = NULL; /* this forces free in next call */ X return ret; X } X DEB3("%s new string in slot %1d '%s'\n", n, kefp[n]); X FLUSH; X } X kefp[n] = NULL; X *p = (n == 0) ? NULL : &kefp; X return KEF_E_OK; X} END_OF_FILE if test 4179 -ne `wc -c <'kdb-high/str.c'`; then echo shar: \"'kdb-high/str.c'\" unpacked with wrong size! fi # end of 'kdb-high/str.c' fi if test -f 'kdb-low/Makefile.SH' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kdb-low/Makefile.SH'\" else echo shar: Extracting \"'kdb-low/Makefile.SH'\" \(2402 characters\) sed "s/^X//" >'kdb-low/Makefile.SH' <<'END_OF_FILE' Xrmconfig='no' Xcase $CONFIG in X'') X if test ! -f config.sh; then X ln ../config.sh . || \ X ln ../../config.sh . || \ X ln ../../../config.sh . || \ X (echo "Can't find config.sh."; exit 1) X rmconfig='yes' X fi X . config.sh X ;; Xesac X: This forces SH files to create target in same directory as SH file. X: This is so that make depend always knows where to find SH derivatives. Xcase "$0" in X*/*) cd `expr X$0 : 'X\(.*\)/'` ;; Xesac Xecho "Extracting kdb-low/Makefile (with variable substitutions)" X: Some headers, do no variable substitution X$spitshell >Makefile <<'!NO!SUBS!' X# X# Makefile fuer KEF kdb-low X# X# sccsid = @(#) Makefile (v2.3 5/2/90) X# X X# X# Some general stuff X# XSHELL = /bin/sh XSCCSPATH= X!NO!SUBS! X: This section of the file will have variable substitutions done on it. X: Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!. X: Protect any dollar signs and backticks that you do not want interpreted X: by putting a backslash in front. You may delete these comments. X$spitshell >>Makefile <>Makefile <<'!NO!SUBS!' X X# Debug flags go into DEB. Delete the object and recompile. X# Debug info is written to "FILE * prot" X# X# flag | file X# ----------------+------------------ X# DEBUG_ADD : _add.c X# DEBUG_CLEANUP : _cleanup.c X# DEBUG_LOCATE : _locate.c, _locate2.c X# DEBUG_IO : _read.c _rtools.c write.c X# DEBUG_MATCH : match.c X# DEBUG_REMOVE : remove.c X# DEBUG_WALK : walk.c advance.c X# DEBUG_STR : _str XDEB = X X# X# INCL should be pointing at the directory kef.h etc. are in. X# XINCL = -I.. X X# X# Compile flags. X# XCFLAGS = ${STDCFLAGS} ${DEB} ${INCL} X X# X# Object files. X# XOBJS = _add.o _cleanup.o error.o _init_db.o _locate.o _locate2.o match.o \ X _read.o remove.o _rtools.o _str.o walk.o write.o advance.o X XDOBJS = _dump.o check.o X XKEF_LIB = ../libkef.a XKEF_DLIB= ../libDkef.a X X X# X# Dependencies X# ============ X# X Xall: ${KEF_LIB} ${KEF_DLIB} X X${KEF_LIB}: ${OBJS} X ar rv ${KEF_LIB} $? X ranlib ${KEF_LIB} X X${KEF_DLIB}: ${DOBJS} X ar rv ${KEF_DLIB} $? X ranlib ${KEF_DLIB} X!NO!SUBS! Xchmod 755 Makefile X$eunicefix Makefile Xif test "$rmconfig" = "yes" ; then X rm -f config.sh Xfi END_OF_FILE if test 2402 -ne `wc -c <'kdb-low/Makefile.SH'`; then echo shar: \"'kdb-low/Makefile.SH'\" unpacked with wrong size! fi # end of 'kdb-low/Makefile.SH' fi if test -f 'kdb-low/_cleanup.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kdb-low/_cleanup.c'\" else echo shar: Extracting \"'kdb-low/_cleanup.c'\" \(2882 characters\) sed "s/^X//" >'kdb-low/_cleanup.c' <<'END_OF_FILE' Xstatic char * sccsid = "@(#) _cleanup.c (v2.5 3/15/90)"; X X/* X */ X X# include X# include "kef.h" X X#ifdef DEBUG_CLEANUP X# define L_DEBUG X#else X# ifdef L_DEBUG X# undef L_DEBUG X# endif X#endif X# include "local.h" X Xstatic int num; Xstatic struct kef_node * nd; X Xextern void qsort (); X X static void Xrun_tree (n) X kef_index n; X/* X * Run through the tree from node n. X */ X{ X register kef_index i, j; X register int count, where; X X /* X * First count elements in horizontal list ("next") X */ X count = 0; X for (i = n; i != KEF_NIL; i = nd[i].next) X count ++; X X /* X * Give number in the horizontal list starting at current num, X * remembered in "where". Reserve future indices "where" to X * "where" + "count" - 1 X */ X where = num; X num += count; X X /* X * Run along the horizontal list again. Tweak the "pointers" to X * point at the future locations of their targets rather than their X * current ones. X */ X for (i = n; i != KEF_NIL; i = j) { X /* X * Node i will be at number "where". X */ X nd[i].tag = where++; X /* X * Go into the subtree if there is any. X * Change "sub" "pointer" to future location of first node X * in subtree. X */ X if (nd[i].sub != KEF_NIL) { X j = num; X run_tree (nd[i].sub); X nd[i].sub = j; /* Yes, we know that this is it */ X SET_CLEAN(nd[i]); X } X /* X * Advance. Don't forget to change "next" too. X */ X j = nd[i].next; X if (j != KEF_NIL) X nd[i].next = where; /* This is it */ X } X} X X static int Xcmp_node (p1, p2) X struct kef_node * p1, * p2; X{ X if (p1->tag < p2->tag) X return -1; X return p1->tag > p2->tag; X} X X int Xkef__cleanup (kdb) X struct kef_db * kdb; X/* X * Cleanup the array of nodes. X * The reason behind this is that it is faster to search an array X * using binary search when the array is ordered. X */ X{ X DI("kef__cleanup ::") X X /* X * Run through the tree of characters and change the 'pointers'. X * X * Imagine the order we want to put things in: subsequent nodes X * (linked by "next") are at subsequent indices. X * Give every node a tag which is the index it will occupy in X * the ordered array. Sort the array according to tag. X * X * Note : root points at a dummy node, which will never be deleted. X * New stuff is added below root, so root has no neighbour. X * The index of this root node will not change, thus we don't have X * to recompute kdb->root. X * X */ X num = 0; X nd = kdb->node; X X run_tree (kdb->root); X X /* X * Sort the array according to number stored in tag. X * Free nodes have a high value in tag, there is no KEF_NIL X * in any tag. Thus the free nodes are sorted to the end of X * the array. X */ X qsort (nd, kdb->high_nodes, sizeof(struct kef_node), cmp_node); X X /* , X * Voila. X * X * Shrink the array of nodes by simply setting high_nodes, thereby X * throwing away all empty nodes. X */ X kdb->high_nodes = kdb->used_nodes; X kdb->free_list = KEF_NIL; X X return KEF_E_OK; X} END_OF_FILE if test 2882 -ne `wc -c <'kdb-low/_cleanup.c'`; then echo shar: \"'kdb-low/_cleanup.c'\" unpacked with wrong size! fi # end of 'kdb-low/_cleanup.c' fi if test -f 'kdb-low/_dump.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kdb-low/_dump.c'\" else echo shar: Extracting \"'kdb-low/_dump.c'\" \(4099 characters\) sed "s/^X//" >'kdb-low/_dump.c' <<'END_OF_FILE' Xstatic char * sccsid = "@(#) _dump.c (v1.9 10/29/89)"; X/* X * Dump various parts of the structures X */ X X# include X# include "kef.h" X# include X Xextern char * malloc (); Xextern char * realloc (); Xextern FREE_TYPE free (); X X static char * Xcnv (n, m) X kef_index n; X int m; X{ X static char buf [10][7]; X if (n == KEF_NIL) X return "NIL"; X if (n == HIGH_TAG) X return "H-T"; X (void) sprintf (buf[m], "%3d", (int)n); X buf[m][3] = '\0'; X return buf[m]; X} X Xdump__node (f, kdb, n) X FILE * f; X struct kef_db * kdb; X int n; X{ X fprintf (f, "%3d : ", n); X if (isascii(kdb->node[n].what) && isprint(kdb->node[n].what)) X fprintf (f, "'%c'", kdb->node[n].what); X else X fprintf (f, " "); X fprintf (f, " 0x%2x ", kdb->node[n].what); X X fprintf (f, "sub=%3s next=%3s tag=%3s num=%2d", X cnv(kdb->node[n].sub, 0), cnv(kdb->node[n].next, 1), X cnv(kdb->node[n].tag, 2), kdb->node[n].num); X X fprintf (f, " flags= %cVALUE %cCLEAN %cFREE", X HAS_VALUE(kdb->node[n]) ? ' ' : '!', X IS_CLEAN(kdb->node[n]) ? ' ' : '!', X IS_FREE(kdb->node[n]) ? ' ' : '!'); X if (HAS_VALUE(kdb->node[n])) X fprintf (f, "(%1d)", kdb->node[n].value); X fprintf (f, "\n"); X} X Xdump_kef_db (f, kdb) X FILE * f; X struct kef_db * kdb; X/* X * Dump all structures of the kef_db structure. X */ X{ X register int i; X X fprintf (f, "Contents of kef_db structure at %1d\n", (int)kdb); X fprintf (f, "===============================\n"); X fprintf (f, "num_nodes = %3d (size of array of character nodes)\n",kdb->num_nodes); X fprintf (f, "used_nodes = %3d (number of used nodes)\n", kdb->used_nodes); X fprintf (f, "high_nodes = %3d (number of free+used nodes)\n",kdb->high_nodes); X fprintf (f, "root = %3s (index of first char link)\n", cnv(kdb->root, 0)); X fprintf (f, "free_list = %3s (start index of free list)\n", cnv(kdb->free_list, 0)); X fprintf (f, "longest = %3d (length of longest string)\n", kdb->longest); X fprintf (f, "must_clean = %3s (must CLEAN flag be recomputed after change)\n", X kdb->must_clean ? "yes" : " no"); X fprintf (f, "was_allocated = %s (was node array allocated ?)\n", X kdb->was_allocated ? "yes" : "no"); X fprintf (f, "malloc = %s\n", kdb->malloc == NULL ? "NULL" : X (kdb->malloc == malloc) ? "malloc" : "some proc"); X fprintf (f, "realloc = %s\n", kdb->realloc == NULL ? "NULL" : X (kdb->realloc == realloc) ? "realloc" : "some proc"); X fprintf (f, "free = %s\n", kdb->free == NULL ? "NULL" : X (kdb->free == free) ? "free" : "some proc"); X fprintf (f, "address of node array = %d\n", kdb->node); X X if (kdb->node != NULL) { X fprintf (f, "allocated nodes:\n"); X for (i = 0; i < kdb->high_nodes; i++) X dump__node (f, kdb, i); X } X fprintf (f, "====================\n"); X fprintf (f, "End of kdb structure\n\n"); X} X Xshow__strings (f, kdb) X FILE * f; X struct kef_db * kdb; X{ X char buf [80]; X buf [0] = 0; X /* start with stuff after topmost node */ X show__string (f, kdb, buf, 0, kdb->node[kdb->root].sub); X} X Xshow__string (f, kdb, buf, l, n) X FILE * f; X struct kef_db * kdb; X char buf []; X int l; X kef_index n; X{ X register int i, j; X X for (i = n; i != KEF_NIL; i = kdb->node[i].next) { X buf [l] = kdb->node[i].what; X if (HAS_VALUE(kdb->node[i])) { X fprintf (f, "key '"); X for (j = 0; j <= l; j++) X fputc (buf[j], f); X fprintf (f, "' value %1d\n", kdb->node[i].value); X fflush (f); X } else X if (kdb->node[i].sub == KEF_NIL) { X fprintf (f, "ERROR no sublist and no value at node %1d\n", i); X fflush (f); X } X if (kdb->node[i].sub != KEF_NIL) X show__string(f, kdb, buf, l+1, kdb->node[i].sub); X } X} X Xdump_fheader (f, kfh) X FILE * f; X struct kef_fheader * kfh; X{ X fprintf (f, "Header from file for kef_db structure\n"); X fprintf (f, "=====================================\n"); X fprintf (f, "magic = 0x%02x%02x%02x%02x\n", kfh->magic[0], X kfh->magic[1], kfh->magic[2], kfh->magic[3]); X fprintf (f, "swap = 0x%0x\n", kfh->swap); X fprintf (f, "num_nodes = %1d\n", kfh->num_nodes); X fprintf (f, "size_kdb = %1d\n", kfh->size_kdb); X fprintf (f, "size_node = %1d\n", kfh->size_node); X fprintf (f, "======================\n"); X} END_OF_FILE if test 4099 -ne `wc -c <'kdb-low/_dump.c'`; then echo shar: \"'kdb-low/_dump.c'\" unpacked with wrong size! fi # end of 'kdb-low/_dump.c' fi if test -f 'kdb-low/_rtools.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kdb-low/_rtools.c'\" else echo shar: Extracting \"'kdb-low/_rtools.c'\" \(3648 characters\) sed "s/^X//" >'kdb-low/_rtools.c' <<'END_OF_FILE' Xstatic char * sccsid = "@(#) _rtools.c (v1.7 3/21/90)"; X X/* X * Tools to read from a file. X * X * Don't use fwrite/fread : they may introduce malloc calls by including X * _flsbuf (the routine used by stdin to fill its buffers). X */ X X# include X# include "kef.h" X X#ifdef DEBUG_IO X# define L_DEBUG X#else X# ifdef L_DEBUG X# undef L_DEBUG X# endif X#endif X# include "local.h" X X/* X * Note: SWAP is defined as a macro, tmp is a temporary variable. X * Don't call it with arguments with sideeffects. X * "n" and "tmp" must be defined unsigned, else 1's may be shifted into n. X */ X# define SWAP(n) tmp = (n); (n) = (tmp << 8) | (tmp >> 8) X X int Xkef_read_header (fd, kfh) X int fd; X struct kef_fheader * kfh; X/* X * Read a kef header from file fd. X */ X{ X DI("kef_read_header ::") X int n; X unsigned short tmp; X X DEB1("%s called; read the kef_db header\n"); X /* X * Now read the header. X */ X n = sizeof (struct kef_fheader); X if (read (fd, (char *)kfh, n) != n) X return KEF_E_READ_ERROR; X X DEB2("%s have read header with %1d characters.\n", n); X X /* X * Check magic number. X */ X if (kfh->magic[0] != KEF_MAGIC0 || kfh->magic[1] != KEF_MAGIC1 || X kfh->magic[2] != KEF_MAGIC2 || kfh->magic[3] != KEF_MAGIC3) X return KEF_E_WRONG_MAGIC; X /* X * Check for swap. X */ X if (kfh->swap != 0x0201) { X /* X * Swap remaining fields in header. X */ X SWAP(kfh->num_nodes); X SWAP(kfh->size_kdb); X SWAP(kfh->size_node); X } X X /* X * Check for possible size errors. X */ X if (kfh->size_kdb > sizeof (struct kef_db) - sizeof (struct kef_node *)) { X DEB3("%s KEF_E_SIZE_KDB on file %1d, expected more than %1d\n", X kfh->size_kdb, sizeof(struct kef_db) - sizeof(struct kef_node *)); X return KEF_E_SIZE_KDB; X } X if (kfh->size_node != sizeof (struct kef_node)) X return KEF_E_SIZE_NODE; X X DEB1("%s success.\n"); X X return KEF_E_OK; X} X X int Xkef_read_file (fd, kdb, part, nd, num_nodes, ind_swap) X int fd; X struct kef_db * kdb; X short part; /* number of bytes in kdb, which are read in */ X struct kef_node * nd; X int num_nodes; /* number of nodes on file */ X int ind_swap; /* 0 : don't swap, else : swap */ X/* X * The caller must have tested that num_nd (number of nodes in array) X * >= num_nodes. X */ X{ X DI("kef_read_file") X int n, i; X unsigned short tmp; X char buf [4]; X X DEB4("%s called part=%1d num_nodes=%1d ind_swap=%1d\n", part, X num_nodes, ind_swap); X if (read (fd, (char *)kdb, part) != part) X return KEF_E_READ_ERROR; X DEB2("%s have read kef_db structure part with %1d characters\n", part); X DEB2("%s%sswap elements in kdb struct\n", ind_swap?" ":" don't "); X if (ind_swap) { X /* X * Swap the elements in the kdb structure. X */ X SWAP(kdb->num_nodes); X SWAP(kdb->used_nodes); X SWAP(kdb->high_nodes); X SWAP(kdb->root); X SWAP(kdb->free_list); X SWAP(kdb->longest); X } X kdb->node = NULL; X X# ifdef L_DEBUG X dump_kef_db (prot, kdb); X# endif X /* X * There maybe some (<4) padding bytes behind kef_db structure. X * Read them in. X */ X if (part & 0x03) { X n = 4 - part & 0x03; X DEB2("%s have read %1d padding characters\n", n); X if (read (fd, buf, n) != n) X return KEF_E_READ_ERROR; X } X X /* X * Read the nodes. X */ X n = sizeof (struct kef_node) * num_nodes; X DEB2("%s read %1d bytes for nodes array\n", n); X if (read (fd, (char *)nd, n) != n) X return KEF_E_READ_ERROR; X DEB2("%s have read nodes with a total of %1d character\n", n); X FLUSH; X X DEB2("%s%sswap contents of nodes\n", ind_swap?" ":" don't "); X if (ind_swap) { X /* X * Swap the fields in the nodes. X */ X for (i = 0; i < num_nodes; i++) { X SWAP(nd[i].sub); X SWAP(nd[i].next); X SWAP(nd[i].value); X SWAP(nd[i].num); X SWAP(nd[i].tag); X } X } X X return KEF_E_OK; X}; END_OF_FILE if test 3648 -ne `wc -c <'kdb-low/_rtools.c'`; then echo shar: \"'kdb-low/_rtools.c'\" unpacked with wrong size! fi # end of 'kdb-low/_rtools.c' fi if test -f 'kdb-low/_str.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kdb-low/_str.c'\" else echo shar: Extracting \"'kdb-low/_str.c'\" \(2642 characters\) sed "s/^X//" >'kdb-low/_str.c' <<'END_OF_FILE' Xstatic char * sccsid = "@(#) _str.c (v1.8 3/21/90)"; X X/* X * Routines to map value --> set of strings which are associated with X * value. X */ X X# include X# include "kef.h" X X#ifdef DEBUG_STR X# define L_DEBUG X#else X# ifdef L_DEBUG X# undef L_DEBUG X# endif X#endif X# include "local.h" X X int Xkef__next_inst (kdb, val, inx) X struct kef_db * kdb; X kef_value val; X kef_index * inx; X/* X * Run depth-first through tree of character cells searching for cells X * with value val. When found return index. X * Use kef_walk to traverse the tree. kef_walk manipulates the contents X * of the nodes to build a stack that can be used by kef__build_str. X * It uses the "tag" field to keep pointers to parent. "tag" is unused X * except by these routines and cleanup. X * String can be built backwards by running up chain of "tag" links. X * The "tag" stuff also serves as a stack X * so we don't have to hold a stack to retrace our steps on the tree. X * X * Returns : X * 0 : not found (== end of tree) X * 1 : found X * "inx" is used to get startpoint for tree traversal. If "inx" == KEF_NIL X * then we are at start of tree. X */ X{ X DI("kef__next_inst ::") X kef_index at; X register struct kef_node * nd; X int ret; X X DEB3("%s started for val %1d at node %1d\n", val, *inx); X X nd = kdb->node; X at = *inx; X while ((ret = kef_walk (kdb, &at)) == KEF_E_OK && at != KEF_NIL) X if (HAS_VALUE(nd[at]) && nd[at].value == val) { X *inx = at; X return 1; X } X return ret == KEF_E_OK ? 0 : ret; X} X X int Xkef__build_str (kdb, inx, buf, size_buf) X struct kef_db * kdb; X kef_index inx; X char * buf; X int size_buf; X/* X * Start at cell inx, run along "tag" links (returned by kef__next_inst) X * and build string. X * 0 : ok. X * -1 : buffer too small X * KEF_E_INV_INX : invalid index while traversing list X */ X{ X DI("kef__build_str ::") X int n; X register struct kef_node * nd; X kef_index at; X X /* X * First count the links. X * Possible errors: X * - too many links (more than size_buf - 1) X * - index outside of array (KEF_E_INV_INX) X */ X X DEB2("%s started for %1d\n", inx); X nd = kdb->node; X /* X * Note that the last element in the list is the root of X * the character tree and will not be printed. It is counted, though. X */ X for (at = inx, n = 0; n <= size_buf && at != KEF_NIL; n++) { X if (at >= kdb->num_nodes) X return KEF_E_INV_INX; X at = nd[at].tag; X } X /* X * String will be n-1 characters long plus NUL. X */ X DEB2("%s there are %1d elements in 'tag' list\n", n-1); X if (n > size_buf) X return -1; X n -= 2; /* pos of last character in buf */ X buf [n+1] = '\0'; X for (at = inx; n >= 0; n--) { X buf[n] = nd[at].what; X at = nd[at].tag; X } X return KEF_E_OK; X} END_OF_FILE if test 2642 -ne `wc -c <'kdb-low/_str.c'`; then echo shar: \"'kdb-low/_str.c'\" unpacked with wrong size! fi # end of 'kdb-low/_str.c' fi if test -f 'kdb-low/remove.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kdb-low/remove.c'\" else echo shar: Extracting \"'kdb-low/remove.c'\" \(3567 characters\) sed "s/^X//" >'kdb-low/remove.c' <<'END_OF_FILE' Xstatic char * sccsid = "@(#) remove.c (v1.8 3/15/90)"; X X/* X * Routines to remove a string from the kef_db structure. X */ X X# include X# include "kef.h" X# include X X#ifdef DEBUG_REMOVE X# define L_DEBUG X#else X# ifdef L_DEBUG X# undef L_DEBUG X# endif X#endif X# include "local.h" X Xstatic struct kef_node * nd; Xstatic struct kef_db * my_kdb; X Xextern int kef__is_clean (); X Xkef_remove (kdb, s) X struct kef_db * kdb; X char * s; X{ X int i; X X nd = kdb->node; X my_kdb = kdb; X i = kef__rm_node (kdb->root, s); X if (i == 0 || i == 1) X i = KEF_E_OK; X return i; X} X X static int Xkef__rm_node (l, s) X kef_index l; X char * s; X/* X * Delete node corresponding to s[0] from list of characters below l. X * X * return 0 : ok X * 1 : try to delete further up X * else : some error X */ X{ X DI("kef__rm_node ::") X int i; X kef_index here, before; X X DEB2("%s called for string '%s'\n", s); X X /* X * Is the character we are examining in the set of possible X * next characters ? X * Distinguish between "clean" arrays and "unclean" ones. X * "Clean" arrays can be searched by locate_node, others are X * searched sequentially. We need the node before the one we want to X * delete X */ X i = kef__locate_node (nd, s[0], l, &before); X DEB5("%s locate '%c' at link %1d returned %1d, before=%1d\n", X s[0], l, i, before); X if (i == 0) /* character not found */ X return KEF_E_NOT_FOUND; X here = before == KEF_NIL ? nd[l].sub : nd[before].next; X DEB2("%s here set to %1d\n", here); X /* X * Yes, it is. X * here : node associated with character X * before : points at node before "here" or is KEF_NIL if "here" X * is first in sublist X * If it is the last character of the string, then X * we start deleting here and return. X */ X if (s[1] == '\0') { X DEB1("%s this is the last character\n"); X if (!HAS_VALUE(nd[here])) X return KEF_E_NOT_FOUND; X /* X * Delete the entry at here only if there is no suffix. X */ X if (nd[here].sub != KEF_NIL) { X /* X * There is a suffix. Just clear the value flag and return. X */ X DEB1("%s there is a suffix. Clear value flag only\n"); X CLEAR_VALUE(nd[here]); X return 0; X } X /* X * Must delete the node. X */ X } else { X DEB1("%s this is NOT the last character. Recurse.\n"); X i = kef__rm_node (here, s+1); X DEB2("%s returned %1d\n", i); X if (i != 1) X return i; X /* X * If kef__rm_node did not return 1 we must continue to try X * to delete. Delete "here" if it does not have a value X * and no subsequent nodes attached. X */ X if (HAS_VALUE(nd[here]) || nd[here].sub != KEF_NIL) X return 0; X } X /* X * DELETE NODE X */ X DEB4("%s must delete the node %1d, before %1d, char = %c\n", X here, before, nd[here].what); X /* X * If the node in question is the only node, then we have X * to remove the link pointing here and we have to tell X * our caller that it must continue to try to remove nodes. X * If it is not the only node, the removing stops after we removed X * the node. X * Don't rely on "num" having the correct value. Rather decide X * on your own. "num" is updated though. X */ X X /* X * Remove the node. X */ X if (before == KEF_NIL) { X nd[l].sub = nd[here].next; X } else { X nd[before].next = nd[here].next; X } X nd[l].num --; X /* X * Give node back to free list. X */ X nd[here].next = my_kdb->free_list; X nd[here].tag = HIGH_TAG; X my_kdb->free_list = here; X my_kdb->used_nodes --; X SET_FREE(nd[here]); X /* X * Recompute value of CLEAN flag at l X */ X if (my_kdb->must_clean && nd[l].sub != KEF_NIL && kef__is_clean(my_kdb, l)) X SET_CLEAN(nd[l]); X else X CLEAR_CLEAN(nd[l]); X X return 1; X} END_OF_FILE if test 3567 -ne `wc -c <'kdb-low/remove.c'`; then echo shar: \"'kdb-low/remove.c'\" unpacked with wrong size! fi # end of 'kdb-low/remove.c' fi if test -f 'kef/fill.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kef/fill.c'\" else echo shar: Extracting \"'kef/fill.c'\" \(3868 characters\) sed "s/^X//" >'kef/fill.c' <<'END_OF_FILE' Xstatic char * sccsid = "@(#) fill.c (v1.11 4/27/90)"; X/* X * Read some characters from terminal and put them in X * the internal buffer. X */ X X# include X# include X# include X X# include "config.h" X# include "kef.h" X X#ifdef DEBUG_FILL X# define L_DEBUG X#else X# ifdef L_DEBUG X# undef L_DEBUG X# endif X#endif X# include "local.h" X X# include Xextern int errno; Xextern int kef_errno; X X int Xkef_fillbuf (k, ind, t) X struct kef * k; X int ind; X int t; X/* X * Fill buffer. X * If ind == 0 : see whether there is a character X * if ind != 0 : spend at most t milliseconds waiting for a character, or X * if t == 0 : wait until a character is available X * -> if some characters are available : read them and return X * If the read (or any other system call) gets interrupted by signal SIGINT, X * but no characters have been transferred yet, tell our caller about it. X * X * To do the last request all system calls in this routine and its X * dependants must return immediately when a SIGINT is received. X * If ind != 0 and t == 0 the routine can wait infinitely until a X * character is available. The easy way to do it is to use a "blocking read", X * that is, a call to read, which blocks until a character is available. X * Unfortunately on BSD systems, read is restarted when a SIGINT is X * received, thus the routine can not notice the interrupt. X * On BSD systems or systems that behave likewise, set the preprocessor X * variable REREAD. The routine will call kef_wait_c to wait X * for a character (which uses select, which is interruptible on BSD systems), X * and only call read when it is sure that there are some characters to be X * read and the read won't block. X * X * The routine returns one of the following codes: X * CHAR : character was available and has been read X * NO_CHAR : timed-out and no character available X * INTERRUTPED : system call got interrupted X * EOF : EOF X * SOME_ERROR : some error, kef_errno contains its error number X */ X{ X DI("kef_fillbuf ::") X register byte * from, * to; X int i, n; X X if (ind == 0) X i = kef_look_c (k->fd); X else X# ifdef REREAD X i = kef_wait_c (k->fd, t); X# else X { X if (t != 0) X i = kef_wait_c (k->fd, t); X else /* avoid unecessary system call */ X i = KEF_CHAR; X } X# endif /* REREAD */ X X if (i != KEF_CHAR) X return i; X X /* X * There is something available. X */ X /* X * First check whether it is necessary to move the lookahead X * characters to a save place. X * Note : buffer may only be written up to buf[size_buf-2] X */ X if (k->to - k->from > 0) { X /* X * There is lookahead in the buffer. X */ X if (k->from - k->buf >= k->size_buf - k->db->longest) { X DEB1("%s move lookahead to save place\n"); X /* X * move lookahead before buf_start. X * This is non-overlapping if longest is much smaller than X * size_buf X */ X DEB2 ("%s I am pushing back %1d characters into buffer : '", X k->to - k->from); X# ifdef L_DEBUG X for (from = k->from; from < k->to; from++) X fprintf (prot, "%c", *from); X fprintf (prot, "'\n"); X# endif X FLUSH; X to = k->buf; X for (from = k->from; from < k->to;) X *to++ = *from++; X k->cur = k->to = to; X k->from = k->buf; X } X } else X /* X * There is no lookahead in the buffer. Reset from and to X * to the start of the buffer. X */ X k->from = k->to = k->buf; X X n = k->size_buf - (k->to - k->buf) - 1; X DEB2("%s calling read for %1d characters\n", n); X i = read (k->fd, (char *)(k->to), n); X DEB2("%s read returned %1d\n", i); X if (i > 0) { X# ifdef L_DEBUG X fprintf (prot,"%s got %1d characters :", I, i); X for (n = 0; n < i; n++) X fputc (k->to[n], prot); X fputc ('\n', prot); X fflush (prot); X# endif X k->cur = k->to; X k->to += i; X return KEF_CHAR; X } X if (i == 0) X return KEF_EOF; X if (errno == EINTR) X return KEF_INTERRUPTED; X else { X kef_errno = errno; X return KEF_SOME_ERROR; X } X} END_OF_FILE if test 3868 -ne `wc -c <'kef/fill.c'`; then echo shar: \"'kef/fill.c'\" unpacked with wrong size! fi # end of 'kef/fill.c' fi if test -f 'kef/look_wait.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'kef/look_wait.c'\" else echo shar: Extracting \"'kef/look_wait.c'\" \(4182 characters\) sed "s/^X//" >'kef/look_wait.c' <<'END_OF_FILE' Xstatic char * sccsid = "@(#) look_wait.c (v4.2 4/24/90)"; X X/* X * This file contains two routines for a machine. X * X * int kef_look_c (fd) X * int fd; X * returns: X * CHAR : character available X * NO_CHAR : no character available X * INTERRUPT : system call got interrupted (errno == EINTR) X * SOME_ERROR : some error (kef_errno is set to the value of errno) X * X * int kef_wait_c (fd, t) X * int fd, t; X * T specifies a time in milliseconds (!), which the routine waits at most X * for a character. If t is 0, the routine will look forever. X * kef_wait_c will return : X * CHAR : character available X * NO_CHAR : no character available, due to timeout X * INTERRUPT : system call got interrupted (errno == EINTR) X * SOME_ERROR : some error (kef_errno is set to the value of errno) X */ X# include X# include X# include X# include "kef.h" X# include "setup.h" X X#ifdef DEBUG_GET X# define L_DEBUG X#else X# ifdef L_DEBUG X# undef L_DEBUG X# endif X#endif X# include "local.h" X Xextern int kef_errno; X X/* X * 1.) kef_look_c X */ X X# if LOOK4CHAR == USE_SELECT X X# include X# include Xextern int errno; X# define L_TIME_INCLUDED X# define L_ERRNO X X int Xkef_look_c (fd) X int fd; X{ X int n, readfds; X struct timeval tval; X X tval.tv_sec = tval.tv_usec = 0; X readfds = 1 << fd; X n = select (fd+1, &readfds, (int *)0, (int *)0, &tval); X if (n == -1) { X if (errno == EINTR) X return KEF_INTERRUPTED; X else { X kef_errno = errno; X return KEF_SOME_ERROR; X } X } X return n == 0 ? KEF_NO_CHAR : KEF_CHAR; X} X X# endif /* LOOK4CHAR == USE_SELECT */ X X# if LOOK4CHAR == USE_FIONREAD X X int Xkef_look_c (fd) X int fd; X{ X register int i; X int n; X X i = ioctl (fd, FIONREAD, &n); X if (i == -1) { X if (errno == EINTR) X return KEF_INTERRUPTED; X else { X kef_errno = errno; X return KEF_SOME_ERROR; X } X } X return n == 0 ? KEF_NO_CHAR : KEF_CHAR; X} X X# endif /* LOOK4CHAR == USE_FIONREAD */ X X X# if LOOK4CHAR == USE_RDCHK X X# include Xextern int errno; X# define L_ERRNO X X int Xkef_look_c (fd) X int fd; X{ X int i; X if ((i = rdchk (fd)) == -1) { X if (errno == EINTR) X return KEF_INTERRUPTED; X else { X kef_errno = errno; X return KEF_SOME_ERROR; X } X } X return i == 0 ? KEF_NO_CHAR : KEF_CHAR; X} X X# endif /* LOOK4CHAR == USE_RDCHK */ X X X/* X * 2.) kef_wait_c X */ X X# if WAIT4CHAR == USE_SELECT X X# ifndef L_TIME_INCLUDED X# include X# define L_TIME_INCLUDED X# endif X X# ifndef L_ERRNO X# include Xextern int errno; X# endif X X int Xkef_wait_c (fd, t) X int fd, t; X{ X int n, readfds; X struct timeval tval; X struct timeval * ptv; X X if (t == 0) X ptv = NULL; X else { X tval.tv_sec = t / 1000; X tval.tv_usec = (t % 1000) * 1000; X ptv = &tval; X } X readfds = 1 << fd; X n = select (fd+1, &readfds, (int *)0, (int *)0, ptv); X if (n == -1) { X if (errno == EINTR) X return KEF_INTERRUPTED; X else { X kef_errno = errno; X return KEF_SOME_ERROR; X } X } X return n == 0 ? KEF_NO_CHAR : KEF_CHAR; X} X X# endif /* WAIT4CHAR == USE_SELECT */ X X# if WAIT4CHAR == USE_RDCHK X X# ifndef L_ERRNO X# include Xextern int errno; X# endif X X int Xkef_wait_c (fd, t) X int fd, t; X{ X DI("kef_wait_c ::") X register int count_timeout, i; X struct timeb t0, t1; X# ifdef L_DEBUG X struct timeb t2; X# endif X X DEB2("%s called with t = %1d\n", t); X FLUSH; X ftime (&t0); X count_timeout = 0; X while ((i = kef_look_c (fd)) == KEF_NO_CHAR) { X count_timeout++; X ftime (&t1); X DEB4("%s kef_look_c returned %1d, count = %1d, delta-t = %1d millisecs\n", X i, count_timeout, X (t1.time - t0.time) * 1000 + t1.millitm - t0.millitm); X FLUSH; X if ((t1.time - t0.time) * 1000 + t1.millitm - t0.millitm >= t) X break; X } X# ifdef L_DEBUG X ftime (&t2); X switch (i) { X case KEF_CHAR: X fprintf (prot, "%s char is avialable", I); X break; X case KEF_NO_CHAR: X fprintf (prot, "%s char not available; timeout", I); X break; X case KEF_INTERRUPTED: X fprintf (prot, "%s got interrupt", I); X break; X default: X fprintf (prot, "%s some error, errno = %1d", I, kef_errno); X break; X } X fprintf (prot, " real time elapsed = %1d millisecs\n", X (t2.time - t0.time) * 1000 + t2.millitm - t0.millitm); X# endif X return i; X} X# endif /* LOOK4CHAR == USE_RDCHK */ END_OF_FILE if test 4182 -ne `wc -c <'kef/look_wait.c'`; then echo shar: \"'kef/look_wait.c'\" unpacked with wrong size! fi # end of 'kef/look_wait.c' fi if test -f 'setup.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'setup.h'\" else echo shar: Extracting \"'setup.h'\" \(3105 characters\) sed "s/^X//" >'setup.h' <<'END_OF_FILE' X/* X * Setup the variables for the kef subroutines. X * This header file includes config.h which has X * been generated from config.h.SH by the Configure script, X * which in turn was generated by metaconfig. X * X * config.h includes only simple definitions for variables. X * If you want to have complex ones we have to do it yourself. X * This comes from the way metaconfig is working. Maybe a future version X * has this problem fixed. X * X * sccsid = @(#) setup.h (v1.3 4/24/90) X * X */ X X# include "config.h" X X/* X * Several ways are possible to determine whether input is available. X * there is at least one character available. X * X * - USE_SELECT : select(2) is available and works. This is usually the case X * on 4BSD derived systems like 43BSD, SunOS 3.5. X * returns: X * 0 : no characters available, timeout X * -1: some error, like intr, error number in errno. X * else : (1 << fd) : filedescriptor for which stuff is available X * - USE_RDCHK : rdchk is available. Call as X * ret = rdchk(fd) X * it returns : -1 : error, 0 : no char available, 1 : char available X * This is usually the case on SYS III derived systems X * - USE_FIONREAD: there is an ioctl which returns the number of characters X * available. X * Call it as: X * ret = ioctl (fd, FIONREAD, &num) X * int num; X * where the number of characters is returned in num. X * This is usually the case on 4BSD systems. On some systems both X * rdchk and FIONREAD are available (Sinix 2.1), on some both X * select and FIONREAD are possible (BSD), use select then. X */ X X/* X * What method should the "wait" routine use to wait for input X * to become available? X * One of the flags X * WAITSELECT X * SEERDCHK X * must be set. X * Define symbol KEF_SEE_C with one of the symbols USE_SELECT or USE_RDCHK. X * If you specify WAITSELECT the "wait" routine calls "select". The operating X * system (UNIX) stops the process and wakens it if either a specified X * timeout expired or some character(s) are available. Thus your process X * does not spend time. X * If you specify WAITRDCHK the "wait" routine will execute a loop when X * it is waiting for characters checking with the "see" routine in each X * pass through the loop for input. This is only done when the prefix of X * a string in the database is found, and typically does not spend much X * processor time. For example, if you push a key that sends "\E[A" the X * three characters are made available rather quickly to the program. X * If you are lucky it takes only one read to get them, most often it takes X * 2 reads : "[" and "A" are made available while the "\E" is being processed X * by the program. X */ X X/* X * Some parts of the program uses a routine to copy memory from X * one place to another. The destination does never overlap the target. X * BSD systems have bcopy, SYS 5 systems have memcpy. If your system X * has both, bcopy is preferred, if your system has none, I supply my own. X * Define FASTCOPY(source,target,length) X */ X#ifdef BCOPY X# define FASTCOPY(s,t,l) (void)bcopy(s,t,l) X#endif X#if defined(MEMCPY) && ! defined(BCOPY) X# define FASTCOPY(s,t,l) (void)memcpy(t,s,l) X#endif END_OF_FILE if test 3105 -ne `wc -c <'setup.h'`; then echo shar: \"'setup.h'\" unpacked with wrong size! fi # end of 'setup.h' fi echo shar: End of archive 2 \(of 5\). cp /dev/null ark2isdone MISSING="" for I in 1 2 3 4 5 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 5 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- .-. .-. .-. Michael Greim ( X )( __) e-mail : greim@cs.uni-sb.de \ / \ / \ / or : ...!uunet!unido!sbsvax!greim ~ ~ ~