home *** CD-ROM | disk | FTP | other *** search
- Path: xanth!mcnc!rutgers!cmcl2!husc6!necntc!ncoast!allbery
- From: mjr@welchsun2.UUCP (Marcus J. Ranum)
- Newsgroups: comp.sources.misc
- Subject: v03i047: key mapping library for curses type applications
- Message-ID: <8806112005.AA08362@welchsun2>
- Date: 11 Jun 88 20:05:42 GMT
- Sender: allbery@ncoast.UUCP
- Reply-To: mjr@welchsun2.UUCP (Marcus J. Ranum)
- Lines: 1271
- Approved: allbery@ncoast.UUCP
-
- comp.sources.misc: Volume 3, Issue 47
- Submitted-By: "Marcus J. Ranum" <mjr@welchsun2.UUCP>
- Archive-Name: kiface
-
- Key Interface Library
-
- This library provides some fairly useful tools for mapping keys to
- return values that can be checked by a user interface, and acted
- upon. The idea is essentially to allow a program to assign a return
- value to a key, or a string of keys, so that a single returned value
- can be checked after a set of keys is input. IE: suppose we want to be
- able to support a 'generic UP key' that could be either '^P' for
- you EMACS fans, or '^[[A' for you with arrow keys that happen to return
- that.
-
- ---chop---slice---dice---shred---chop---slice---dice---shred---chop---slice--
- #!/bin/sh
- # This is a shell archive.
- # run the file through sh.
- # shar: Shell Archiver
- # Run the following text with /bin/sh to create:
- # README
- # Makefile
- # iface.h
- # iface.3
- # iface.c
- # tester.c
- # This archive created: Sat Jun 11 16:02:20 1988
- echo shar: extracting README '(3032 characters)'
- sed 's/^XX//' << \SHAR_EOF > README
- XXKey Interface Library
- XX
- XXThis library provides some fairly useful tools for mapping keys to
- XX"return values" that can be checked by a user interface, and acted
- XXupon. The idea is essentially to allow a program to assign a return
- XXvalue to a key, or a string of keys, so that a single returned value
- XXcan be checked after a set of keys is input. IE: suppose we want to be
- XXable to support a 'generic UP key' that could be either '^P' for
- XXyou EMACS fans, or '^[[A' for you with arrow keys that happen to return
- XXthat.
- XX
- XXThere are some basic keys that must be supported for some of the
- XXroutines to work. The interface must be configured with at least
- XXa key that is defined to mean 'delete', as well as 'return', 'abort',
- XXand a few others. A function (that could be improved upon) is
- XXprovided to establish this minimal set from termcap. Those of you
- XXwith bitmapped displays and windows systems will find this all to
- XXbe useless.
- XX
- XXThe main disadvantage with this package - (and it is a severe one!)
- XXis that I was not patient to do forward-looking in the mapping. If
- XXboth "foo" and "foobar" are defined, "foobar" will never be reached,
- XXsince "foo" will always return first. In practice, this may require
- XXsome juggling. Right now, the code performs no checks against having
- XXoverlapped mappings, so you have the option to really screw yourself.
- XXI suppose something could be done with a timeout, and stuff like that,
- XXbut this is simpler and more likely to be portable. If anyone adds
- XXthis, please let me know :-)
- XX
- XXAn additional routine is provided to support input and line-editing of
- XXa buffer. This could be considerably enhanced depending on your display
- XXand if you're running curses, or whatever, but the demo program is
- XXas simple as possible. The intent of the ifgetstr() function is to
- XXallow something like:
- XX
- XX bufs[5][xx];
- XX thisbuf = 0;
- XX
- XX while(1) {
- XX /* curses call to move cursor to beginning of bufs[thisbuf] */
- XX /* wherever it lies on the screen */
- XX ret = ifgetstr(&keymap,bufs[thisbuf],xx);
- XX switch(ret) {
- XX case IF_UPWRMOVE:
- XX if(--thisbuf) < 0
- XX thisbuf = xx-1;
- XX break;
- XX
- XX case IF_DWNWMOVE:
- XX case IF_CRETURN:
- XX if(++thisbuf) > xx-1
- XX thisbuf = 0;
- XX break;
- XX
- XX case IF_ABORTKEY:
- XX return(something);
- XX }
- XX }
- XX
- XXWhich would allow editing multiple buffers until an escape key was pressed.
- XX(note "esc" preceeds a lot of the arrow keys, see defect above)
- XXThere are loads of hooks in the code, including a pointer to where we
- XXleft off in the buffer, but use of such things should depend on the
- XXapplication. The ifgetstr() function is designed to be useful, but also
- XXto provide a basic starting point for more elaborate input management
- XXroutines.
- XX
- XXThis code is not public domain, though it is freely modifiable
- XXand distributable as long as the copyright notices are retained. If
- XXyou make any nifty improvements, please let me know, (E-mail, I am not
- XXon usenet) bugfixes, etc, are welcome.
- XX
- XX
- XX Marcus J. Ranum, William Welch Medical Library, 1988
- XX mjr@jhuigf.BITNET || uunet!mimsy!aplcen!osiris!welchvax!mjr
- SHAR_EOF
- if test 3032 -ne "`wc -c README`"
- then
- echo shar: error transmitting README '(should have been 3032 characters)'
- fi
- echo shar: extracting Makefile '(1094 characters)'
- sed 's/^XX//' << \SHAR_EOF > Makefile
- XX# Makefile for keyboard input library
- XX# Copyright(C) 1988, Marcus J. Ranum, William Welch Medical Library
- XX#
- XX# $Header: Makefile,v 1.2 88/06/10 22:44:14 mjr rel $: Makefile
- XX#
- XX# $Log: Makefile,v $
- XX# Revision 1.2 88/06/10 22:44:14 mjr
- XX# cleaned up some, added install option, other junk.
- XX#
- XX# Revision 1.1 88/06/10 17:02:10 mjr
- XX# Initial revision
- XX#
- XX#
- XX
- XXLIBS= -ltermcap
- XXCFLAGS=-O
- XXLFLAGS=-s
- XXLINTFLAGS=-h -x -u
- XX
- XXLIB= libiface.a
- XX
- XX# installation stuff
- XXLIBDIR= /usr/local/lib
- XXHDR= iface.h
- XXHDRDIR= /usr/local/include
- XXMAN= iface.3
- XXMANDIR= /usr/man/manl
- XX
- XXall: tester
- XX
- XXtester: tester.o $(LIB)
- XX cc $(LFLAGS) -o tester tester.o $(LIB) $(LIBS)
- XX
- XXclean:
- XX rm -f *.o tester iface.shar $(LIB)
- XX
- XXlint:
- XX lint $(LINTFLAGS) iface.c
- XX
- XXshar:
- XX shar -a README Makefile iface.h iface.3 iface.c tester.c > iface.shar
- XX
- XXinstall: $(LIB)
- XX cp $(LIB) $(LIBDIR)/$(LIB)
- XX chmod 644 $(LIBDIR)/$(LIB)
- XX ranlib $(LIBDIR)/$(LIB)
- XX cp $(HDR) $(HDRDIR)/$(HDR)
- XX chmod 644 $(HDRDIR)/$(HDR)
- XX cp $(MAN) $(MANDIR)/$(MAN)
- XX chmod 644 $(MANDIR)/$(MAN)
- XX
- XXlibiface.a: iface.o
- XX ar rcv libiface.a iface.o
- XX ranlib $@
- XX
- XXiface.o: iface.c Makefile
- SHAR_EOF
- if test 1094 -ne "`wc -c Makefile`"
- then
- echo shar: error transmitting Makefile '(should have been 1094 characters)'
- fi
- echo shar: extracting iface.h '(2594 characters)'
- sed 's/^XX//' << \SHAR_EOF > iface.h
- XX/*
- XX * Copyright (C) 1988, Marcus J. Ranum, William Welch Medical Library
- XX * $Author: mjr $
- XX */
- XX
- XX/*
- XX * $Header: iface.h,v 1.3 88/06/11 15:58:53 mjr rel $: iface.h
- XX *
- XX * $Log: iface.h,v $
- XX * Revision 1.3 88/06/11 15:58:53 mjr
- XX * added possibly useful macros. moved input buffer into map structure
- XX *
- XX * Revision 1.2 88/06/10 22:45:43 mjr
- XX * improved readability of some comments.
- XX *
- XX * Revision 1.1 88/06/10 17:02:00 mjr
- XX * Initial revision
- XX *
- XX */
- XX
- XX#ifndef _INCL_IFACE_H
- XX
- XX/* size to hash key mappings into - a key mapping is stored in lexical */
- XX/* order, hashed based on the first character (hell of a hash, eh ?) */
- XX/* this really does not have to be a very big number */
- XX#define IF_HSIZE 10
- XX
- XX/* size of input buffer */
- XX#define IF_INBUFSIZ 300
- XX
- XX/* a key mapping element */
- XXstruct ifkey {
- XX char *lhs;
- XX int rhs;
- XX struct ifkey *next;
- XX};
- XX
- XX/* a command/key map */
- XXstruct ifmap {
- XX struct ifkey *htab[IF_HSIZE]; /* key mapping entries */
- XX int hold; /* holdover key */
- XX /* usually the key that */
- XX /* caused an error, or 0 */
- XX int lastret; /* last recognized key */
- XX /* reset during getkey() */
- XX /* each time called */
- XX int lastbuf; /* usable in ifgetstr() */
- XX /* - last position of curs */
- XX /* use at own risk */
- XX char inbuf[IF_INBUFSIZ]; /* input buffer - whatever */
- XX /* we currently have read */
- XX /* cleared in each call to */
- XX /* ifgetkey - may be long */
- XX};
- XX
- XX/* can be used to flush a pending character */
- XX#define ifclearhold(map) ((map).hold = '\0')
- XX#define iflastch(map) ((map).hold)
- XX#define iflastret(map) ((map).lastret)
- XX
- XX/* these are expected to be builtins - if you intend to use ifgetstr */
- XX/* these must be defined, at a minimum. (more can be). - to set up a */
- XX/* more or less "standard" set, you can use ifdfltmap() - which uses */
- XX/* some reasonable assumptions from termcap */
- XX#define IF_NOTFOUND -1 /* this one does not need to be bound ! */
- XX /* since it is what we return when we are */
- XX /* unable to find something interesting */
- XX#define IF_DELCHAR -2 /* we want to delete a character */
- XX#define IF_BACKMOVE -3 /* go backwards a char (nondestructive) */
- XX#define IF_FORWMOVE -4 /* go forward a char (nondestructive) */
- XX#define IF_UPWRMOVE -5 /* go up a char - sometimes can mean EOL */
- XX#define IF_DWNWMOVE -6 /* go down a char - sometimes can mean EOL */
- XX#define IF_CRETURN -7 /* return from input normally */
- XX#define IF_ABORTKEY -8 /* return from input with cancel */
- XX
- XX
- XXextern void ifinitmap();
- XXextern void ifdfltmap();
- XXextern void iffreemap();
- XXextern struct ifkey *iflookup();
- XX
- XX#define _INCL_IFACE_H
- XX#endif
- SHAR_EOF
- if test 2594 -ne "`wc -c iface.h`"
- then
- echo shar: error transmitting iface.h '(should have been 2594 characters)'
- fi
- echo shar: extracting iface.3 '(8748 characters)'
- sed 's/^XX//' << \SHAR_EOF > iface.3
- XX.\" iface.3l (C)1988 Marcus J. Ranum, Welch Medical Library
- XX.\" $Header: iface.3,v 1.1 88/06/11 15:58:24 mjr rel $
- XX.TH IFACE 3l
- XX.SH NAME
- XXifinstall, ifdelete, ifgetkey, ifgetstr, ifdfltmap, iffreemap, ifinitmap,
- XXiflookup, ifclearhold, iflastch, iflastret
- XX.br
- XX\- mappable key interface library
- XX.SH SYNTAX
- XX.B #include <local/iface.h>
- XX.PP
- XX.B int ifinstall(keymap,string,retval)
- XX.br
- XX.SM
- XX.B struct ifmap *keymap;
- XX.br
- XX.B char *string;
- XX.br
- XX.B int retval;
- XX.PP
- XX.B int ifdelete(keymap,string)
- XX.br
- XX.SM
- XX.B struct ifmap *keymap;
- XX.br
- XX.B char *string;
- XX.PP
- XX.B int ifgetkey(keymap)
- XX.br
- XX.SM
- XX.B struct ifmap *keymap;
- XX.PP
- XX.B int ifgetstr(keymap,buf,max,boffset)
- XX.br
- XX.SM
- XX.B struct ifmap *keymap;
- XX.br
- XX.B char *buf;
- XX.br
- XX.B int max, boffset;
- XX.PP
- XX.B void ifdfltmap(keymap)
- XX.br
- XX.SM
- XX.B struct ifmap *keymap;
- XX.PP
- XX.B void iffreemap(keymap)
- XX.br
- XX.SM
- XX.B struct ifmap *keymap;
- XX.PP
- XX.B void ifinitmap(keymap)
- XX.br
- XX.SM
- XX.B struct ifmap *keymap;
- XX.PP
- XX.B struct ifkey *iflookup(keymap,string)
- XX.br
- XX.SM
- XX.B struct ifmap *keymap;
- XX.br
- XX.B char *string;
- XX.PP
- XX.B (macro) ifclearhold(keymap)
- XX.br
- XX.SM
- XX.B struct ifmap *keymap;
- XX.PP
- XX.B (macro) iflastch(keymap)
- XX.br
- XX.SM
- XX.B struct ifmap *keymap;
- XX.PP
- XX.B (macro) iflastret(keymap)
- XX.br
- XX.SM
- XX.B struct ifmap *keymap;
- XX.PP
- XX.SH DESCRIPTION
- XX.PP
- XXThe mappable key interface library is designed to allow basic keymapping in
- XXapplications that rely on arrow keys, escape codes, etc. It is designed to
- XXgather keyboard input, looking for specific strings, and to return numerical
- XXcodes to indicate matches. Multiple mappings are supported, to allow many
- XXstrings to map to one return value. Every effort is made to minimize code
- XXsize and to maximize efficiency in string matching. The library includes
- XXtools to allow basic key initialization, as well as deleting mappings,
- XXsearching mappings, and simple visual string editing. The primary shortcoming
- XXof the library is that a value is returned \fIas soon as a match is made\fP.
- XXThere is no effort to scan ahead, or timeout on input to try to figure
- XXwhat keys will be pressed next. This means that strings that are unique
- XXand short will always be matched before longer strings containing them.
- XXFor example, if "foo" is mapped to a value, "foobar" will never be matched,
- XXsince input will return at "foo". This becomes a problem when mapping
- XXsomething like the \fIesc\fP key, since the \fIesc\fP key preceeds many
- XXdesirable sequences such as arrow keys. This means that juggling on the
- XXpart of the user is necessary to prevent mapping useful keys to where
- XXthey are inaccessible.
- XX.PP
- XXThe key mappings are all stored in a hashed linked list, in alphabetic
- XXorder. Dynamic memory allocation is used to maintain the list. Initially
- XXa mapping table has no keys mapped at all, and must be "prepped" with a
- XXcall to
- XX.B ifinitmap
- XXto make sure everything is initialized properly. The library requires
- XXthat certain basic tokens be mapped (see \fIiface.h\fP) and provides a
- XXminimal function to set up some reasonable defaults from termcap values.
- XXUsers who do not like these values can assemble their own quite easily.
- XX.B Ifgetkey
- XXis the workhorse routine that performs matching of the mappings, and
- XXreturns values accordingly. Several additional values in the
- XX.B ifmap
- XXstructure are used to hold information, including the last keypress
- XXin the event of a failure to match. This information can be accessed
- XXby the user to handle errors, or to perform default actions (see the
- XXcode in \fIiface.c\fP line \fI420\fP for an example). There are
- XXmacros in \fIiface.h\fP that allow manipulation of these values,
- XXthough values and effects are not documented except in the source code.
- XX.PP
- XXThe
- XX.B ifinstall
- XXfunction installs
- XX.B string
- XXas a string in
- XX.B keymap
- XXwith a return code of
- XX.B retval.
- XXThere can be more than one string installed that returns
- XX.B retval.
- XX.B Ifinstall
- XXreturns 0 on success; -1 in the event of error. If the string already
- XXexists, the return value is modified to be
- XX.B retval.
- XX.PP
- XXThe
- XX.B ifdelete
- XXfunction removes the mapping string
- XX.B string
- XXfrom
- XX.B keymap,
- XXreturning 0 if it found and deleted something, -1 if it failed to
- XXfind the string.
- XX.PP
- XXThe
- XX.B ifgetkey
- XXroutine is the main entry point to the library, performing the actual
- XXgathering of user input, and returning mapped values.
- XX.B Ifgetkey
- XXassumes that input is being done in cbreak mode, presumably with
- XXnoecho set. Setting the terminal modes is the user's problem, and
- XXshould be handled elsewhere.
- XX.B Ifgetkey
- XXreads characters, trying to match them against the mapped strings
- XXin
- XX.B keymap,
- XXreturning the installed integer value of found strings. If there is no
- XXmatch found,
- XX.B ifgetkey
- XXreturns the default value
- XX.B IF_NOTFOUND
- XXwhich is defined in \fIiface.h\fP to be -1. Additional information
- XXabout what was found by
- XX.B ifgetkey
- XXcan be extracted from
- XX.B keymap.
- XXThere is an integer value
- XX.B keymap.hold
- XXwhich contains the last character read, and a character buffer
- XX.B keymap.inbuf
- XXwhich contains the current input string, in the even of a match that
- XXfailed after several characters. (IE - if we were trying to match "frobnitz"
- XXand only got "frobb",
- XX.B keymap.ibuf
- XXwould have "frobb" stored in it, marking the point at which our input
- XXceased to match.)
- XXThe
- XX.B ifclearhold
- XXand
- XX.B iflastch
- XXmacros allow access to these structures.
- XX.PP
- XXThe
- XX.B ifgetstr
- XXfunction is a building-block for a buffer editor. It uses the default
- XXkey mappings for upkey, downkey, etc, to handle editing of a character
- XXarray. Input is allowed until a return, abort, or up or down arrow
- XXis entered. The input is assembled into
- XX.B buf
- XXwith input being prohibited past
- XX.B max
- XXcharacters.
- XXThe argument
- XX.B boffset
- XXcan be given as a point within the buffer at which to begin the edit.
- XXIt is the \fIuser's\fP responsibility to initially "paint" the contents
- XXof
- XX.B buf
- XXon the terminal in a desired location, before calling
- XX.B ifgetstr.
- XX.B Ifgetstr
- XXwill maintain its location on the screen by using backspaces, etc, to the
- XXbest of its ability, but if the user's application requires moving the
- XXcursor around, the results will be less than pretty. The intent of
- XXproviding
- XX.B ifgetstr
- XXis to demonstrate how these routines can be linked into something that
- XXis actually useful, rather than to provide a solution to string input
- XXproblems.
- XX.PP
- XXThe
- XX.B ifdfltmap
- XXfunction builds a minimal "default" key mapping set into
- XX.B keymap,
- XXusing termcap/termlib and whatever seems reasonable. This is also an
- XXexample routine, and far from definitive, but provides a minimal set of
- XXoperations. EMACS fans would probably prefer to map up, down, etc, to
- XXdifferent keys. Before calling
- XX.B ifdfltmap,
- XXthe keymap should be initialized using
- XX.B ifinitmap.
- XX.PP
- XXThe
- XXiffreemap
- XXfunction frees all (even the minimal) mappings in
- XX.B keymap.
- XXThis actually frees the dynamically allocated memory, and is completely
- XXdifferent in purpose from
- XX.B ifinitmap
- XXwhich only initializes the mapping hash table.
- XX.PP
- XXThe
- XX.B ifinitmap
- XXfunction makes sure that the hash table, etc, pointers in
- XX.B keymap
- XXare all properly blanked out. It should be called before the keymap
- XXis used, unless you are sure that everything is already set up properly.
- XXCalling
- XX.B ifinitmap
- XXon a keymap with entries added will not free any memory that has been
- XXallocated.
- XX.PP
- XXThe
- XX.B iflookup
- XXfunction returns a pointer to a structure of type
- XX.B ifmap,
- XXor to NULL, depending on whether there is a match for
- XX.B string
- XXin
- XX.B keymap
- XXor not. This routine is provided for completeness, not because I can
- XXthink of much use for it. (otherwise, it can be inlined into
- XX.B ifinstall
- XXif you like)
- XX.PP
- XXThe
- XX.B ifclearhold,
- XX.B iflastch,
- XXand
- XX.B iflastret
- XXmacros allow easy access to the various bits of information retained
- XXin
- XX.B keymap.
- XX.B Ifclearhold
- XXsets the held character to 0, which prevents
- XX.B ifgetkey
- XXfrom trying to use it to complete the next match. For example, if the
- XXprogram is trying to match "foo" and gets "fg", the 'g' is retained
- XXin
- XX.B keymap.hold
- XXto use as the first input character for the next call to
- XX.B ifgetkey.
- XXThis is sometimes not desirable. The
- XX.B iflastch
- XXmacro allows access to this last character, if desired, but does not
- XXclear it. The
- XX.B iflastret
- XXmacro allows access to whatever
- XX.B ifgetkey
- XXlast \fIreturned\fP. This is included for logical completeness. It is
- XXreset during every call to
- XX.B ifgetkey.
- XX.PP
- XX.SH RESTRICTIONS
- XX.PP
- XXIf two mappings completely overlap, the longer will never be returned
- XXsince the shorter one will always match first. Thus, "foo" and "foobar"
- XXwill cause "foo" to always match first, even if "foobar" is typed. Mappings
- XXsuch as "foop" and "foobar" will not conflict.
- XX.PP
- XXThis library is useless to anyone with a higher-level window management
- XXsystem.
- XX.SH DIAGNOSTICS
- XX.PP
- XX.SH AUTHOR
- XX.PP
- XXMarcus J. Ranum, Welch Medical Library.
- XX.br
- XX.ti 1i
- XXuunet!aplcen!osiris!welchvax!mjr
- XX.br
- XX.ti 1i
- XXmjr@jhuigf.BITNET
- XX.SH SEE ALSO
- SHAR_EOF
- if test 8748 -ne "`wc -c iface.3`"
- then
- echo shar: error transmitting iface.3 '(should have been 8748 characters)'
- fi
- echo shar: extracting iface.c '(8279 characters)'
- sed 's/^XX//' << \SHAR_EOF > iface.c
- XX/*
- XX * Copyright (C) 1988, Marcus J. Ranum, William Welch Medical Library
- XX * $Author: mjr $
- XX */
- XX
- XX#ifndef lint
- XXstatic char *RCSid="$Header: iface.c,v 1.3 88/06/11 15:58:32 mjr rel $: iface.c";
- XX#endif
- XX
- XX/*
- XX * $Log: iface.c,v $
- XX * Revision 1.3 88/06/11 15:58:32 mjr
- XX * added better initializations to ifinitmap
- XX *
- XX * Revision 1.2 88/06/10 22:45:14 mjr
- XX * added option to edit a buffer from an arbitrary point in the buffer.
- XX *
- XX * Revision 1.1 88/06/10 17:01:40 mjr
- XX * Initial revision
- XX *
- XX */
- XX
- XX#include <stdio.h>
- XX#include "iface.h"
- XX
- XX
- XX
- XX/* free a key map table - this zaps all mappings totally */
- XXvoid
- XXiffreemap(kmap)
- XXstruct ifmap *kmap;
- XX{
- XX int x;
- XX struct ifkey *kp;
- XX struct ifkey *xp;
- XX
- XX for(x = 0; x < IF_HSIZE; x++) {
- XX kp = kmap->htab[x];
- XX while(kp != NULL) {
- XX xp = kp->next;
- XX (void)free(kp->lhs);
- XX (void)free((char *)kp);
- XX kp = xp;
- XX }
- XX kmap->htab[x] = NULL;
- XX }
- XX}
- XX
- XX
- XX
- XX/* clear a key map table - this prepares the table for adding mappings */
- XXvoid
- XXifinitmap(kmap)
- XXstruct ifmap *kmap;
- XX{
- XX int x;
- XX
- XX /* all we do here is set the hash entries to NULL */
- XX /* THIS IS NOT THE SAME AS FREEING ALL THE MAP ENTRIES */
- XX /* call this when a map table is first created, call iffreemap() */
- XX /* if you want to deallocate a mapping table */
- XX for(x = 0; x < IF_HSIZE; x++)
- XX kmap->htab[x] = NULL;
- XX
- XX /* set these, too */
- XX kmap->hold = '\0';
- XX kmap->lastret = -1;
- XX kmap->lastbuf = 0;
- XX kmap->inbuf[0] = '\0';
- XX}
- XX
- XX
- XX/* install a default key map table - or most of one */
- XXvoid
- XXifdfltmap(kmap)
- XXstruct ifmap *kmap;
- XX{
- XX char tbuf[1024];
- XX char fill[1024];
- XX char *fptr = fill;
- XX char *forch;
- XX char *uprch;
- XX char *bwrch;
- XX char *dnrch;
- XX char *crch;
- XX static char hbuf[2];
- XX static char *dforch = "\33[C";
- XX static char *duprch = "\33[A";
- XX static char *dbwrch = "\33[D";
- XX static char *ddnrch = "\33[B";
- XX static char *dcrch = "\n";
- XX extern char *getenv();
- XX extern char *tgetstr();
- XX
- XX if(((forch = getenv("TERM")) != NULL) && (tgetent(tbuf,forch) == 1)) {
- XX if((forch = tgetstr("kr",&fptr)) == 0)
- XX forch = dforch;
- XX if((uprch = tgetstr("ku",&fptr)) == 0)
- XX uprch = duprch;
- XX if((bwrch = tgetstr("kl",&fptr)) == 0)
- XX bwrch = dbwrch;
- XX if((dnrch = tgetstr("kd",&fptr)) == 0)
- XX dnrch = ddnrch;
- XX if((crch = tgetstr("cr",&fptr)) == 0)
- XX crch = dcrch;
- XX } else {
- XX /* could get terminal entry - use whatever */
- XX forch = dforch;
- XX uprch = duprch;
- XX bwrch = dbwrch;
- XX dnrch = ddnrch;
- XX crch = dcrch;
- XX }
- XX
- XX /* install the foogers */
- XX hbuf[0] = 127;
- XX hbuf[1] = '\0';
- XX (void)ifinstall(kmap,hbuf,IF_DELCHAR);
- XX (void)ifinstall(kmap,"\b",IF_DELCHAR);
- XX (void)ifinstall(kmap,bwrch,IF_BACKMOVE);
- XX (void)ifinstall(kmap,forch,IF_FORWMOVE);
- XX (void)ifinstall(kmap,uprch,IF_UPWRMOVE);
- XX (void)ifinstall(kmap,dnrch,IF_DWNWMOVE);
- XX (void)ifinstall(kmap,crch,IF_CRETURN);
- XX return;
- XX}
- XX
- XX
- XX
- XX/* look the bad boy up */
- XXstruct ifkey *
- XXiflookup(kmap,s)
- XXstruct ifmap *kmap;
- XXchar *s;
- XX{
- XX struct ifkey *kp;
- XX for(kp = kmap->htab[*s % IF_HSIZE]; kp != NULL; kp = kp->next)
- XX if(strcmp(s,kp->lhs) == 0)
- XX return(kp);
- XX return(NULL);
- XX}
- XX
- XX
- XX
- XX/* install a key mapping, hashed, and in lexical order */
- XXifinstall(kmap,lh,rh)
- XXstruct ifmap *kmap;
- XXchar *lh;
- XXint rh;
- XX{
- XX struct ifkey *kp;
- XX struct ifkey *after;
- XX extern char *malloc();
- XX extern char *strcpy();
- XX
- XX /* not found - install anew */
- XX if((kp = iflookup(kmap,lh)) == NULL) {
- XX
- XX /* figure out where to put it */
- XX kp = kmap->htab[*lh % IF_HSIZE];
- XX after = NULL;
- XX while(kp != NULL) {
- XX if(strcmp(lh,kp->lhs) < 0)
- XX break;
- XX after = kp;
- XX kp = kp->next;
- XX }
- XX
- XX/* avoid the possible pointer alignment problem message */
- XX#ifndef lint
- XX /* allocate it */
- XX kp = (struct ifkey *)malloc(sizeof(struct ifkey));
- XX#else
- XX kp = NULL;
- XX#endif
- XX if(kp == NULL)
- XX return(-1);
- XX kp->lhs = malloc((unsigned)strlen(lh));
- XX if(kp->lhs == NULL)
- XX return(-1);
- XX kp->rhs = rh;
- XX (void)strcpy(kp->lhs,lh);
- XX
- XX /* fixup sibling pointers */
- XX if(after != NULL) {
- XX kp->next = after->next;
- XX after->next = kp;
- XX } else {
- XX if(kmap->htab[*lh % IF_HSIZE] != NULL) {
- XX kp->next = kmap->htab[*lh % IF_HSIZE];
- XX kmap->htab[*lh % IF_HSIZE] = kp;
- XX } else {
- XX kmap->htab[*lh % IF_HSIZE] = kp;
- XX kp->next = NULL;
- XX }
- XX }
- XX } else {
- XX /* just change the return value */
- XX kp->rhs = rh;
- XX }
- XX
- XX return(0);
- XX}
- XX
- XX
- XX
- XX/* de-install a key mapping (by key string) */
- XXifdelete(kmap,s)
- XXstruct ifmap *kmap;
- XXchar *s;
- XX{
- XX struct ifkey *kp;
- XX struct ifkey *lptr = NULL;
- XX extern char *strcpy();
- XX
- XX for(kp = kmap->htab[*s % IF_HSIZE]; kp != NULL; kp = kp->next) {
- XX if(strcmp(s,kp->lhs) == 0) {
- XX if(lptr != NULL) {
- XX /* last node next points to the next one */
- XX lptr->next = kp->next;
- XX } else {
- XX /* root node next points to the next one */
- XX kmap->htab[*s % IF_HSIZE] = kp->next;
- XX }
- XX (void)free(kp->lhs);
- XX (void)free((char *)kp);
- XX return(0);
- XX }
- XX lptr = kp;
- XX }
- XX return(-1);
- XX}
- XX
- XX
- XX
- XXifgetkey(kmap)
- XXstruct ifmap *kmap;
- XX{
- XX int c =0;
- XX int nfound;
- XX int nclose;
- XX char *i;
- XX char *o;
- XX int cnt =0;
- XX int xcnt;
- XX struct ifkey *kp; /* current key pointer */
- XX struct ifkey *bp = NULL; /* bottom closest match pointer */
- XX struct ifkey *ret = NULL; /* our match */
- XX
- XX
- XX while(1) {
- XX if((c = getchar()) == EOF) {
- XX kmap->lastret = IF_NOTFOUND;
- XX kmap->hold = c;
- XX return(IF_NOTFOUND);
- XX }
- XX
- XX /* should happen once and only once per call */
- XX /* we set the bottom pointer to point to just before */
- XX /* the first char of our input stream */
- XX if(bp == NULL) {
- XX bp = kmap->htab[c % IF_HSIZE];
- XX
- XX /* nothing in this hash chain to find */
- XX if(bp == NULL) {
- XX kmap->lastret = IF_NOTFOUND;
- XX kmap->hold = c;
- XX return(IF_NOTFOUND);
- XX }
- XX
- XX /* otherwise skate or die */
- XX while(bp->next != NULL && c > *bp->lhs)
- XX bp = bp->next;
- XX }
- XX
- XX
- XX nfound = 0;
- XX nclose = 0;
- XX kp = bp;
- XX
- XX if(cnt + 1 > IF_INBUFSIZ)
- XX return(-1);
- XX
- XX kmap->inbuf[cnt++] = c;
- XX kmap->inbuf[cnt] = '\0';
- XX
- XX while(kp != NULL) {
- XX
- XX xcnt = 0;
- XX o = kp->lhs;
- XX i = kmap->inbuf;
- XX
- XX if(*o != *i)
- XX break;
- XX
- XX /* a mix of strcmp and strncmp */
- XX for(; *o == *i; o++, i++, xcnt++) {
- XX if(*o == '\0') {
- XX nfound++;
- XX ret = kp;
- XX break;
- XX }
- XX }
- XX if(xcnt == cnt)
- XX nclose++;
- XX kp = kp->next;
- XX }
- XX
- XX /* didn't find any !! - unmapped key */
- XX if(nfound == 0 && nclose == 0) {
- XX kmap->hold = c;
- XX kmap->lastret = IF_NOTFOUND;
- XX return(IF_NOTFOUND);
- XX }
- XX
- XX /* only found one - great! */
- XX if(nfound) {
- XX kmap->hold = '\0';
- XX kmap->lastret = ret->rhs;
- XX return(ret->rhs);
- XX }
- XX }
- XX}
- XX
- XX
- XX
- XXifgetstr(kmap,buf,max,bpos)
- XXstruct ifmap *kmap;
- XXchar buf[];
- XXint max;
- XXint bpos;
- XX{
- XX int c =0; /* input returned char */
- XX int high =0; /* line high water mark */
- XX int cnt =0; /* current position/count */
- XX
- XX high = strlen(buf);
- XX if(bpos > high)
- XX cnt = high;
- XX else
- XX cnt = bpos;
- XX
- XX while(1) {
- XX
- XX /* get a key from the map */
- XX switch(c = ifgetkey(kmap)) {
- XX
- XX /* delete a character */
- XX case IF_DELCHAR:
- XX /* if at current high water mark */
- XX
- XX /* if at beginning of line */
- XX if(cnt - 1 < 0) {
- XX (void)fputc(07,stderr);
- XX } else {
- XX if(cnt == high) {
- XX high = --cnt;
- XX buf[cnt] = 0;
- XX } else {
- XX buf[--cnt] = ' ';
- XX }
- XX (void)fprintf(stderr,"\b \b");
- XX }
- XX break;
- XX
- XX
- XX /* NON-DESTRUCTIVE backwards move */
- XX case IF_BACKMOVE:
- XX if(cnt - 1 < 0) {
- XX (void)fputc(07,stderr);
- XX } else {
- XX cnt--;
- XX (void)fprintf(stderr,"\b");
- XX }
- XX break;
- XX
- XX
- XX /* NON-DESTRUCTIVE forward move */
- XX case IF_FORWMOVE:
- XX if(cnt + 1 > max) {
- XX (void)fputc(07,stderr);
- XX } else {
- XX if(high == cnt) {
- XX buf[cnt] = ' ';
- XX high = ++cnt;
- XX } else {
- XX ++cnt;
- XX }
- XX (void)fputc(buf[cnt - 1],stderr);
- XX }
- XX break;
- XX
- XX
- XX /* FINISHED */
- XX case IF_CRETURN:
- XX buf[high] = '\0';
- XX kmap->lastbuf = cnt;
- XX return(IF_CRETURN);
- XX
- XX
- XX /* DOWN */
- XX case IF_DWNWMOVE:
- XX buf[high] = '\0';
- XX kmap->lastbuf = cnt;
- XX return(IF_DWNWMOVE);
- XX
- XX
- XX /* UP */
- XX case IF_UPWRMOVE:
- XX buf[high] = '\0';
- XX kmap->lastbuf = cnt;
- XX return(IF_UPWRMOVE);
- XX
- XX
- XX /* abort */
- XX case IF_ABORTKEY:
- XX buf[0] = '\0';
- XX kmap->lastbuf = cnt;
- XX return(IF_ABORTKEY);
- XX
- XX
- XX /* must be a character insert */
- XX case IF_NOTFOUND:
- XX c = kmap->hold;
- XX kmap->hold = '\0';
- XX if(cnt + 1 > max) {
- XX (void)fputc(07,stderr);
- XX buf[cnt] = '\0';
- XX } else {
- XX buf[cnt] = c;
- XX (void)fputc(c,stderr);
- XX if(high == cnt)
- XX high = ++cnt;
- XX else
- XX ++cnt;
- XX }
- XX break;
- XX }
- XX }
- XX}
- SHAR_EOF
- if test 8279 -ne "`wc -c iface.c`"
- then
- echo shar: error transmitting iface.c '(should have been 8279 characters)'
- fi
- echo shar: extracting tester.c '(4851 characters)'
- sed 's/^XX//' << \SHAR_EOF > tester.c
- XX/*
- XX * Copyright (C) 1988, Marcus J. Ranum, William Welch Medical Library
- XX * $Author: mjr $
- XX */
- XX
- XX#ifndef lint
- XXstatic char *RCSid="$Header: tester.c,v 1.2 88/06/10 22:46:12 mjr rel $: tester.c";
- XX#endif
- XX
- XX/*
- XX * $Log: tester.c,v $
- XX * Revision 1.2 88/06/10 22:46:12 mjr
- XX * added example of function calling, buffer edit.
- XX *
- XX * Revision 1.1 88/06/10 17:01:51 mjr
- XX * Initial revision
- XX *
- XX */
- XX
- XX#include <stdio.h>
- XX#include <sys/ioctl.h>
- XX#include "iface.h"
- XX
- XX#define EDBUFSIZ 100
- XX
- XX/* for the sake of example - a decent way to use this library */
- XX/* obviously, you really should build a structure with pointers to */
- XX/* functions and everything - then call the iface. exercise for the */
- XX/* reader */
- XX#define TEST_DOTHIS 1
- XXextern void dothis();
- XX#define TEST_DOTHAT 2
- XXextern void dothat();
- XX#define TEST_DONADA 3
- XXextern void donada();
- XX
- XXmain()
- XX{
- XX char instr[BUFSIZ];
- XX int c;
- XX char buf[BUFSIZ];
- XX char edbuf[EDBUFSIZ];
- XX int ret;
- XX struct ifmap keymap;
- XX struct ifkey *keyp;
- XX struct sgttyb ttybuf;
- XX extern void igets();
- XX extern char *strcpy();
- XX
- XX ifinitmap(&keymap);
- XX ifdfltmap(&keymap);
- XX
- XX /* for edit demo */
- XX (void)strcpy(edbuf,"Edit This !:");
- XX
- XX
- XX /* install dothis, dothat, donada - to "1", "2" and "3" */
- XX if(ifinstall(&keymap,"1",TEST_DOTHIS) != 0)
- XX (void)printf("error!\n");
- XX if(ifinstall(&keymap,"2",TEST_DOTHAT) != 0)
- XX (void)printf("error!\n");
- XX if(ifinstall(&keymap,"3",TEST_DONADA) != 0)
- XX (void)printf("error!\n");
- XX
- XX /* you have to handle putting the terminal is noecho cbreak */
- XX if(ioctl(0,TIOCGETP,(char *)&ttybuf) < 0)
- XX perror("ioctl - GETP");
- XX ttybuf.sg_flags |= CBREAK;
- XX ttybuf.sg_flags &= ~ECHO;
- XX if(ioctl(0,TIOCSETP,(char *)&ttybuf) <0)
- XX perror("ioctl - SETP");
- XX
- XX
- XX /* main demo loop */
- XX while (1) {
- XX (void)printf("\nEdit Run Install Search Delete GetKey Line Quit:");
- XX if((c = getchar()) == NULL) {
- XX (void)printf("\n");
- XX exit(0);
- XX }
- XX
- XX switch (c) {
- XX
- XX /* quit */
- XX case 'q':
- XX case 'Q':
- XX ttybuf.sg_flags &= ~CBREAK;
- XX ttybuf.sg_flags |= ECHO;
- XX if(ioctl(0,TIOCSETP,(char *)&ttybuf) <0)
- XX perror("ioctl - SETP");
- XX (void)printf("\n");
- XX exit(0);
- XX
- XX
- XX /* edit a string */
- XX case 'e':
- XX case 'E':
- XX (void)printf("\n%s",edbuf);
- XX ret = ifgetstr(&keymap,edbuf,EDBUFSIZ,EDBUFSIZ);
- XX switch(ret) {
- XX case IF_UPWRMOVE:
- XX (void)printf("\n(up)got:\"%s\"\n",edbuf);
- XX break;
- XX
- XX case IF_DWNWMOVE:
- XX (void)printf("\n(down)got:\"%s\"\n",edbuf);
- XX break;
- XX
- XX case IF_CRETURN:
- XX (void)printf("\n(return)got:\"%s\"\n",edbuf);
- XX break;
- XX
- XX case IF_ABORTKEY:
- XX (void)printf("\n(abort)got:\"%s\"\n",edbuf);
- XX break;
- XX
- XX default:
- XX (void)printf("\n(err)got:\"%s\"\n",edbuf);
- XX break;
- XX }
- XX break;
- XX
- XX
- XX case 'r':
- XX case 'R':
- XX (void)printf("\ncommand ? (press 1, 2, or 3):");
- XX ret = ifgetkey(&keymap);
- XX switch(ret) {
- XX case TEST_DOTHIS:
- XX dothis();
- XX break;
- XX case TEST_DOTHAT:
- XX dothat();
- XX break;
- XX case TEST_DONADA:
- XX donada();
- XX break;
- XX case IF_NOTFOUND:
- XX (void)printf("\nI said, 1, 2, or 3\n");
- XX break;
- XX default:
- XX (void)printf("\nwhassat ?\n");
- XX }
- XX break;
- XX
- XX
- XX /* search for a mapping entry */
- XX case 's':
- XX case 'S':
- XX (void)printf("\nSearch for:");
- XX (void)igets(buf,&ttybuf);
- XX keyp = iflookup(&keymap,buf);
- XX if(keyp == NULL)
- XX (void)printf("\nnot found\n");
- XX else
- XX (void)printf("\nKval:%d\n",keyp->rhs);
- XX break;
- XX
- XX
- XX /* install a mapping entry */
- XX case 'i':
- XX case 'I':
- XX (void)printf("\nNumber:");
- XX (void)igets(buf,&ttybuf);
- XX ret = atoi(buf);
- XX (void)printf("Install string:");
- XX (void)igets(buf,&ttybuf);
- XX if(ifinstall(&keymap,buf,ret) != 0)
- XX (void)printf("error!\n");
- XX break;
- XX
- XX
- XX /* enter a line of junk */
- XX case 'L':
- XX case 'l':
- XX (void)printf("\nEnter Stuff:");
- XX ret = ifgetstr(&keymap,instr,BUFSIZ,0);
- XX if(ret != 0)
- XX (void)printf("\nabort..\n");
- XX else
- XX (void)printf("\ngot:\"%s\"\n",instr);
- XX break;
- XX
- XX /* get a key in "raw" mode */
- XX case 'g':
- XX case 'G':
- XX ifclearhold(keymap);
- XX (void)printf("\ngo:\n",ret);
- XX while((ret = ifgetkey(&keymap)) != IF_NOTFOUND)
- XX (void)printf("\n%d",ret);
- XX (void)printf("\n(done)\n",ret);
- XX break;
- XX
- XX
- XX /* delete a map entry */
- XX case 'd':
- XX case 'D':
- XX (void)printf("\nDelete string:");
- XX (void)igets(buf,&ttybuf);
- XX if(ifdelete(&keymap,buf) != 0)
- XX (void)printf("error!\n");
- XX break;
- XX
- XX default:
- XX (void)printf("\nhuh?\n");
- XX }
- XX }
- XX}
- XX
- XXvoid
- XXigets(buf,ttybuf)
- XXchar buf[];
- XXstruct sgttyb *ttybuf;
- XX{
- XX ttybuf->sg_flags &= ~CBREAK;
- XX ttybuf->sg_flags |= ECHO;
- XX if(ioctl(0,TIOCSETP,(char *)ttybuf) <0)
- XX perror("ioctl - SETP");
- XX (void)gets(buf);
- XX ttybuf->sg_flags |= CBREAK;
- XX ttybuf->sg_flags &= ~ECHO;
- XX if(ioctl(0,TIOCSETP,(char *)ttybuf) <0)
- XX perror("ioctl - SETP");
- XX}
- XX
- XXvoid
- XXdothis()
- XX{
- XX (void)printf("\ndothis called");
- XX}
- XX
- XXvoid
- XXdothat()
- XX{
- XX (void)printf("\ndothat called");
- XX}
- XX
- XXvoid
- XXdonada()
- XX{
- XX (void)printf("\ndonada called");
- XX}
- SHAR_EOF
- if test 4851 -ne "`wc -c tester.c`"
- then
- echo shar: error transmitting tester.c '(should have been 4851 characters)'
- fi
- # End of shell archive
- exit 0
-