Debian bug report logs - #1724
unexpected keypress translations

Package: ae; Reported by: Ian Jackson <ian@chiark.chu.cam.ac.uk>; 10 days old.

Message received at debian-bugs:


From sentex.net!achowe Sat Oct 28 08:26:46 1995
Return-Path: <achowe@sentex.net>
Received: from pixar.com by mongo.pixar.com with smtp
	(Smail3.1.28.1 #15) id m0t9D9i-000DPoC; Sat, 28 Oct 95 08:26 PDT
Received: from granite.sentex.net ([199.212.134.1]) by pixar.com with SMTP id AA13284
  (5.67b/IDA-1.5 for debian-bugs-pipe@mongo.pixar.com); Sat, 28 Oct 1995 08:26:11 -0700
Received: (from achowe@localhost) by granite.sentex.net (8.6.12/8.6.9) id LAA04989; Sat, 28 Oct 1995 11:25:47 -0400
Date: Sat, 28 Oct 1995 11:25:47 -0400
From: Anthony Howe <achowe@sentex.net>
Message-Id: <199510281525.LAA04989@granite.sentex.net>
To: achowe@sentex.net, mitchell@mdd.comm.mot.com
Subject: Re: Bug#1724: unexpected keypress translations (fwd)
Cc: debian-bugs@pixar.com


Sorry for the delay.  Here is a shar archive containing replacement
source modules to fix portability for TERMCAP and TERMINFO.  Check
ae.man in the configuration section about how to configure for either
database method.

NOTE these changes should be tested.  I've only been able to test using
BSDI Curses and Termcap, and noticed a problem with the help message
which I suspect is a bug in BSDI Curses addstr().  

	THIS CODE NEEDS TO BE TESTED FOR TERMINFO.  

To compile for a termcap system, ensure that -DTERMCAP is define, else 
undefined for terminfo.  Note the two new configuration files :

	modeless.ti		TERMINFO version
	modeless.tc		TERMCAP version

Install the desired version that corresponds with your system.

Anthony

----update95.shar----
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	ae.man
#	header.h
#	command.c
#	key.c
#	main.c
#	modeless.tc
#	modeless.ti
#
echo x - ae.man
sed 's/^X//' >ae.man << 'END-of-ae.man'
X0.  NAME
X
X	ae	Anthony's Editor October 95
X
X
X1.  SYNOPSIS
X
X	ae [-f config_file]  [filename]
X
X
X2.  OPERANDS
X
Xconfig_file     The pathname of an AE configuration file.  The
X		pathname may be absolute, relative the current
X		directory, or relative the user's home directory.
X
Xfilename	The name of a existing or new file to edit.
X
X
X3.  DESCRIPTION
X
XAE is a simple full screen text editor that can be configured for
Xeither a modual (VI-style interface) or a modeless (EMACS-style
Xinterface).
X
XText files consist of lines of printable text or tab characters.  
XA line can be of arbitary length and is delimited by either a 
Xnewline or the end of file.  Carriage return is mapped to newline 
Xon input and ignored on output.  Carriage returns already in the file
Xare preserved.  Tab stops are every eight columns.
X
X
X4.  COMMANDS
X
XTwo default configuration files are supplied.  One of them should be
Xrenamed to "ae.rc" and placed in the user's home directory.  The two
Xsupplied files are "mode.rc" and "modeless.rc" which configure the
Xeditor for either modual (VI-style) or modeless (EMACS-style)
Xoperation.
X
X
X4.1.  MODUAL CONFIGURATION 
X
X4.1.1.  SUPPORT
X
X?		Toggle help on/off.
XM		Macro add, change, delete, or view.
Xr		Refresh the screen.
XR W		Read and write file to and from the buffer.
Xq Q		Quit with and without query.
XV		Display version.
X
X4.1.2.  MOVEMENT
X
Xh j k l		Left, down, up, right cursor movement.
XH J K L		Word left, page down, page up, word right.
X[ ]		Beginning and end of line.
XT B		Top and bottom of file.
X
X4.1.3.  EDIT
X
Xi ESC ERASE	Enter insert mode, escape to leave, backspace.
X^V		Next character typed will be treated as a literal.
XX x		Delete character left or under the cursor.
XSPACE		Toggle block on/off.
XC		Cut block to scrap.
XP		Paste scrap into buffer.
Xu		Undo last cut, delete, paste, read, insert, or undo.
X~		Invert case of letters.
X
X4.1.4.  MACROS
X
Xa		Append after cursor.
XA		Append at teh end of a line.
Xcw		Change word.
XD		Delete from cursor to end of line.
Xdd		Delete line.
Xdw		Delete word.
Xo O		Open line below or above.
Xy		Yank current block.
X
X
X4.2.  MODELESS CONFIGURATION
X
X4.2.1.  SUPPORT
X
XF1		Toggle help on/off.
X^K^M		Macro add, change, delete, or view.
X^L		Refresh the screen.
X^R ^W		Read and write file to and from the buffer.
X^C ^K^C		Quit with and without query.  
X^K^V		Display version.
X
X
X4.2.2.  MOVEMENT
X
Xcursor keys	Left, down, up, right cursor movement (ansi defined).
X^A ^D		Word left,  word right.
X^F ^E		Front and end of line.
X^N ^P		Next and previous page.
X^T ^B		Top and bottom of file.
X
X
X4.2.3.  EDIT
X
Xunbound keys	Insert.
XBACKSPACE ^X	Delete character left or under the cursor.
X^V		Next character typed will be treated as a literal.
XF2		Toggle block on/off.
XF3		Cut block to scrap.
XF4		Paste scrap into buffer.
X^U		Undo last cut, paste, read, or undo.
X^^		Invert case of letters.
X
X4.2.4.  MACROS
X
XNo pre-defined macros.
X
X
X5.  CONFIGURATION
X
XIt is possible to redefine copies of the sample configuration files in 
Xorder to support key-bindings and text messages of the user's choice.  
XThe user can define an interface similar to either Vi or Emacs, and 
Xsupport multibyte key sequences.  The text messages can be rephrased or
Xtranslated into any 8-bit character set.  
X
XThe configuration file layout is fairly simple.  All keywords begin 
Xon a line starting with a period (.).  Messages begin with a message
Xnumber followed by a colon (:) and end with the first unescaped newline.
XInvalid keywords and messages are ignored.
X
XThe parameters <string> and <character> can be any text other than
Xwhitspace (blank, tab, carriage-return, and newline).  It is possible
Xto specify control keys by prefixing the following characters with a
Xcaret (^):
X
X	@ a b c d e f g h i j k l m n o 
X	p q r s t u v w x y z [ \ ] ^ _
X
XThe sequence ^? represents ASCII DEL (0x7f).  The following escape 
Xconstants are recognised:
X
X	backspace	\b
X	formfeed	\f
X	newline		\n
X	return		\r
X	space		\s
X	tab		\t
X	
XAlso numeric escapes are possible.  The value represented must be 
Xbetween 0 and 255 inclusive.
X
X	decimal		\ddd
X	octal		\0ooo
X	hex		\0xhh
X
XA literal escape begins with a backslash and is followed by any
Xcharacter that does not specify an escape constant or start a 
Xnumber, and will represent the character itself.
X
XAlso, there is support for termcap and terminfo by using $(id) or
X$(capname) strings in the <string>.  An id is a two letter termcap
Xid name used to identify a string capbility; capname is a two to five
Xletter terminfo capability name.  These strings can be used to specify
Xkey bindings in a portable manner.  Below are some common capabilities
X(see your system's man page for termcap or terminfo for a complete list).
XThe files modeless.tc and modeless.ti are examples using termcap and
Xterminfo.  An invalid id or capname or a missing capability will map to 
Xthe alert character (\a).
X
X		TERMCAP		TERMINFO
XLeft		kl		kcuf1
XRight		kr		kcub1
XUp		ku		kcuu1
XDown		kd		kcud1
XF1		k1		kf1
X...
XF10		k0		kf10
X
XSome examples of the paragraphs above :
X
X	.insert_enter	i		<-- single character string
X	.insert_exit	^[		<-- defines ASCII ESC
X	.delete_right	\0x7f		<-- defines ASCII DEL
X	.cursor_up	^[[A		<-- defines sequence ESC [ A
X	.cursor_down	$(kd)		<-- termcap arrow down
X	.cursor_down	$(kcud1)	<-- terminfo arrow down
X
X
X5.1.  KEYWORDS
X
X5.1.1.  SUPPORT
X
X.file_read <string>
X.file_write <string>
X	Read or write a file to or from a buffer.
X
X.help <string>
X	Toggle the help text and ruler line on and off.
X
X.help_off
X	Disable initial help message at startup.  
X
X.itself <character>
X	The following character represents itself.  This is really a
X	redundant keyword since any key not defined by a keyword,
X	automatically represents itself.
X
X.macro <string>
X	Define a macro during an edit session.  The user will be
X	prompted for an input line consisting of zero, one, or two 
X	<strings> separated by whitespace.  
X
X	Pressing <return> at the prompt, with no input strings, will
X	display the current set of macros definitions and how many
X	slots have been used versus the total number of slots available.
X
X	One string entered will remove the macro defined to have 
X	that string as the left-hand-side.  
X
X	Two input strings defines a macro, where the first string, 
X	when typed, pushes the second string onto an input stack.
X
X	Macros may be nested.  It is only possible to delete or change 
X	macros that appear in the listing of currently defined macros.
X	All other key-bindings cannot be redefined during an edit
X	session.
X
X.macro_define
X.macro_define <lhs string> <rhs string>
X	The first case reserves space for one macro definition that 
X	may be defined during the edit session.  The other case will 
X	actually define a macro, where the left-hand-side, when typed
X	will push onto an input stack the right-hand-side.  Either
X	case may be used as many times as desired (memory permiting).
X	Macros may be nested.
X
X.quit <string>
X.quit_ask <string>
X	Exit the editor.
X
X.redraw <string>
X	Force a screen redraw.
X
X.show_version <string>
X	Display the release information.
X
X
X5.1.2.  CURSOR MOTION
X
X.cursor_up <string>
X.cursor_down <string>
X.cursor_left <string>
X.cursor_right <string>
X	Cursor motion in four directions.  Typically the arrow keys.
X
X.file_top <string>
X.file_bottom <string>
X	Move to the top and bottom of the file buffer.
X
X.line_left <string>
X.line_right <string>
X	Move to the beginning or end of the line.
X
X.page_up <string>
X.page_down <string>
X        Previous or next screen full of text.
X
X.word_left <string>
X.word_right <string>
X        Move the cursor to start of the previous or next word.  
X	A word is defined as a sequence of alpha and/or numeric
X	characters.
X
X
X5.1.3.  EDIT
X
X.block <string>
X.cut <string>
X.paste <string>
X	Block on/off toggle, cut block, and paste before.
X
X.delete_left <string>
X.delete_right <string>
X	Delete character to the left or right of the cursor.
X
X.insert_enter <string>
X.insert_exit <string>
X	Enter and exit insert mode.  The use of .insert_enter denotes
X	a modual user interface.  Insert mode does not perform macro
X	expansion.
X
X.literal <string>
X	Next character entered is treated as a literal.
X
X.stty_erase
X.stty_kill
X	Declare that the terminal's values for the erase and kill
X	characters should be used in insert mode to backspace-erase,
X	or discard and restart input.
X
X.undo <string>
X	Undo last cut, delete, insert, paste, read, or undo.
X
X.flip_case <string>
X	Invert the case of letters from lower to upper and visa-versa.
X	When no region is selected, the cursor will advance right one 
X	character position.
X
X
X5.2.  MESSAGES
X
XEach message has the form:
X
X	number : text
X
XLong messages can be continued by escaping the newline with a backslash (\).
XThe first unescaped newline terminates the message text and is not included
Xas part of the text.
X
XThe following is a list of messages:
X
X1:
X	Help text. See the sample configuration files for an example.
X
X2:%s: Terminated successfully.\n
X	Exit succesfully.  %s is the program name.
X
X3:%s: Unspecified error.\n
X	Exit due to an unknown error.  %s is the program name.
X
X4:usage: %s [-f <config>] [file]\n
X	Exit with usage error.  %s is the program name.
X
X5:%s: Failed to initialize the screen.\n
X	Exit because Curses couldn't be initialized.  %s is the program name.
X
X6:%s: Problem with configuration file.\n
X	Exit due to a problem with the configuration file.  %s is the 
X	program name.  Possible causes are:
X
X	o   Configuration file not found.
X	o   Invalid control character, ^X, specified.
X	o   Numeric escape not in range 0 .. 255.
X	
X7:%s: Failed to allocate required memory.\n
X	Exit because required memory is not available.  %s is the program
X	name.
X
X8:Ok.
X	No error.
X	
X9:An unknown error occured.
X	Internal error.
X
X10:No more memory available.
X	Requests for additional memory to either grow the edit buffer
X	or macro definitions failed.
X
X11:File \"%s\" is too big to load.
X	The file is too large to load into available memory.  %s is the
X	name of the file that could not be loaded.
X
X12:Scrap is empty.  Nothing to paste.
X	An attempt to paste the scrap buffer failed because is was empty.
X
X13:Failed to find file \"%s\".
X	%s is a file that could not be found.
X
X14:Failed to open file \"%s\".
X	%s is a file that could not be opened.
X
X15:Failed to close file \"%s\".
X	%s is a file that could not be closed.
X
X16:Failed to read file \"%s\".
X	A read error occur for a file %s.
X
X17:Failed to write file \"%s\".
X	A write error occur for a file %s.
X
X18:Not a portable POSIX file name.
X	File names must be portable POSIX file names.
X
X19:File \"%s\" %ld bytes.
X	%ld is the current length of the file named by %s in the buffer.
X
X20:File \"%s\" %ld bytes saved.
X	%ld is the length of the file named by %s just saved.
X	
X21:File \"%s\" %ld bytes read.
X	%ld is the length of the file named by %s just read.
X
X22:File \"%s\" modified.
X	The file named by %s has been modified.
X
X23:Invalid control character or \\number not 0..255.
X	An invalid control character was specified by ^X, or a
X	numeric escape is not in the range 0 .. 255.
X
X24:No such macro defined.
X	The left-hand-side of a macro is not currently defined and so
X	cannot be changed or deleted.
X
X25:No more macro space.
X	All the macro space, allocated in the configuration file, is 
X	currently being used.
X
X26:Interrupt.
X	An interrupt occured.
X
X27:<< EOF >>
X	End of file marker.
X
X28:Macro :
X	Prompt for a macro to define, delete, or list.
X
X29:File not saved.  Quit (y/n) ?
X	Ask the user if he really wants to quit before he has saved
X	his changes.
X
X30:[ Press a key to continue. ]
X	Prompt the user for a key press in order to proceed.
X
X31:Read file :
X	Prompt the user for a file name to read.
X
X32:Write file :
X	Prompt the user for a file name to save the buffer to.
X
X33:Write block :
X	Prompt the user for a file name to save a block of text to.
X
X34:\smore\s
X	Pause output till user responds with either Q, q, or another key.
X
X35:\sy\b
X	Yes response.
X
X36:\sn\b
X	No response.
X
X37:\sq\b
X	Quit response.
X
X38:Nothing to undo.
X	An attempt was made to undo a change when the buffer had not yet
X	been modified.
X	
X
X6.  EXIT STATUS
X
X0	Success.
X1	Unknown error.
X2	Usage error.
X3	Understood failure.
X
X
X7.  INSTALLATION 
X
XThe source has been know to compile on a wide variety of machines and 
Xcompilers like BSD and System V Unix with GNU C, PC mahcines with 
XWatCom C or Turbo C, and ATARI ST machines with Sozobon C.  Any machine 
Xthat provides at least K&R C and a BSD CURSES library (as described by 
XKen Arnolds's paper) should have no trouble getting AE to compile.
X
XTo build AE on most unix-like systems, type
X
X	make
X
XThe supplied makefile is configured for a BSD environment.  Some
Xsystems may require that the macros CC, CFLAGS, LD, LDFLAGS, and LIBS
Xbe configured.
X
XThe minimum Curses implementation supported is that defined by Kenneth 
XArnold's paper "Screen Updating and Cursor Movement Optimization: A Library
XPackage".  Some BSD Curses implementations have been noted to omit the 
Xfunctions erasechar(), killchar(), and idlok().  For BSD systems with poor
XCurses implementations, alter the following macro:
X
X	CFLAGS = -O -DBADCURSES
X
XFor a System V environment alter the following macros to:
X
X	CFLAGS = -O
X	LIBS = -lcurses
X
XTo build AE on systems that have POSIX.1 or System V termios library,
Xmodify the CFLAGS macro to
X
X	CFLAGS = -O -DTERMIOS=1
X
XIf the constants CHUNK or CONFIG are not defined by CFLAGS then
Xthe defaults used are
X
X	CHUNK	= 8096L
X	CONFIG	= "ae.rc"
X
XCHUNK is the size by which the buffer is expanded when the buffer
Xbecomes full while inserting text.  CONFIG is the name of the default 
Xconfiguration file.  The name chosen aims to satisfy both unix and 
Xpersonal systems.  Unix affectionados may want to reconfigure this 
Xto ".aerc".
X
XTERMIOS should be defined for systems that have POSIX.1 termios
Xsupport (which is based on System V termios).  This has the affect of
Xdisabling the INTR, QUIT, and SUSP signals.  XON/XOFF is left
Xunchanged.  If TERMIOS is not defined, then cbreak() and nocbreak()
Xare used which do not disable the above mentioned signals.
X
XMost EBCDIC machines use block mode terminals.  This is a problem
Xthat has not been addressed and/or tested for.
X
X
X8.  BUGS
X
XNo known bugs.
X
X
X9.  REFERENCES
X
X[Fin80]	Craig A. Finseth, "Theory and Practice of Text Editors or 
X	A Cookbook For An EMACS", TM-165, MIT Lab. for Computer 
X	Science
X
X[KeP81]	Kernighan & Plauger, "Software Tools in Pascal", 
X	Addison-Wesley, 81, chapter 6
X
X[Mil86]	Eugene W. Myers & Webb Miller, "Row-replacement Algorithums
X	for Screen Editors", TR 86-19, Dept. of Compter Science, 
X	U. of Arizona
X
X[MyM86]	Eugene W. Myers & Webb Miller, "A simple row-replacement 
X	method", TR 86-28, Dept. of Compter Science, U. of Arizona
X
X[Mil87]	Webb Miller, "A Software Tools Sampler", Prentice Hall, 87
X	ISBN 0-13-822305-X, chapter 5
X
X[net90]	"Editor 101/102" articles from comp.editors
X
X
X10.  FILES
X
Xae.man		Manual.
Xae.rc		Default configuration file used by AE.
Xmode.rc		Sample configuration for modual style.
Xmodeless.rc	Sample configuration for modeless style (ansi cursor keys).
Xmodeless.tc	Sample configuration for modeless style (TERMCAP).
Xmodeless.ti	Sample configuration for modeless style (TERMINFO).
X
X
X11.  NOTICES
X
XCopyright 1993, 1995 by Anthony Howe.  All rights reserved.  No warranty.
X
END-of-ae.man
echo x - header.h
sed 's/^X//' >header.h << 'END-of-header.h'
X/*
X * header.h		
X *
X * Anthony's Editor October 95
X *
X * Copyright 1993, 1995 by Anthony Howe.  All rights reserved.  No warranty.
X */
X
X#ifndef __header_h__
X#define __header_h__	1
X
X#ifdef __STDC__
X#include <stdlib.h>
X#include <stdarg.h>
X#include <string.h>
X#include <signal.h>
X#endif /* __STDC__ */
X
X#ifdef ATARI_ST
X/* Atari's Sozobon C has ANSI-like libraries 
X * and headers but no prototypes. 
X */
X#include <stdlib.h>
X#include <stdarg.h>
X#include <string.h>
X#include <sys\osbind.h>
X
X#define	DRIVE_COLON	1
X#define EITHER_SLASH	1
X
X#ifndef FILE_MODE
X#define FILE_MODE	0
X#endif
X#endif /* ATARI_ST */
X
X#ifdef __WATCOMC__
X#ifdef MSDOS
X#define __MSDOS__	1
X#endif
X#endif /* __WATCOMC__ */
X
X#ifdef __MSDOS__
X#define DRIVE_COLON	1
X#define EITHER_SLASH	1
X
X#ifndef FILE_MODE
X#define FILE_MODE	0
X#endif
X#endif /* __MSDOS__ */
X
X#ifdef BSD
X#ifndef __STDC__
X#include <signal.h>
X#include <varargs.h>
X#include <strings.h>
Xextern char *getenv();
Xextern char *malloc();
Xextern char *realloc();
Xextern char *strtok();
X#endif /* __STDC__ */
X#endif /* BSD */
X
X#ifndef SIG_ERR
X#define	SIG_ERR		((void (*) _((int))) -1)
X#endif
X
X#include <assert.h>
X#include <curses.h>
X#include "key.h"
X
X#ifdef BADCURSES
X#define erasechar()	'\b'
X#define killchar()	CTRL('x')
X#define idlok(w,f)	OK
X#endif /* BADCURSES */
X
X#undef _
X#ifdef __STDC__
X#define _(x)		x
X#else
X#define _(x)		()
X#define const
X#endif
X
X#define VERSION		\
X"0:AE July 93.  Copyright 1993, 1993 by Anthony Howe.  No warranty."
X
X#ifndef CONFIG
X#define CONFIG		"ae.rc"
X#endif /* CONFIG */
X
X#ifndef CHUNK
X#define CHUNK		8096L
X#endif /* CHUNK */
X
X#ifndef FILE_MODE
X#define FILE_MODE	0600
X#endif /* FILE_MODE */
X
X/* Screen partitioning. */
X#define MSGLINE		0
X#define HELPLINE	1
X#undef  TEXTLINE	
X
X#define NOMARK		-1
X
Xtypedef long SSIZE_T;			/* ssize_t not defined all systems. */
Xtypedef char *t_msg;
Xtypedef unsigned char t_char;
Xtypedef long t_point;
X
Xtypedef struct t_keytable {
X	short key;
X	void (*func) _((void));
X	void (*disp) _((void));
X} t_keytable;
X
Xtypedef struct t_region {
X	t_point left;
X	t_point right;
X} t_region;
X
X/*
X * Function return codes.
X */
X#define GETBLOCK_EOF		(-1L)
X#define GETBLOCK_ERROR		(-2L)
X#define GETBLOCK_ALLOC		(-3L)
X
X/*
X * Some compilers define size_t as a unsigned 16 bit number while 
X * t_point and off_t might be defined as a signed 32 bit number.  
X * malloc(), realloc(), fread(), and fwrite() take size_t parameters,
X * which means there will be some size limits because size_t is too
X * small of a type.
X */
X#define MAX_SIZE_T	((unsigned long) (size_t) ~0)
X#define MAX_SSIZE_T	((unsigned long) (SSIZE_T) ~(size_t) 0 >> 1)
X
X/*
X *
X */
Xextern int done;		/* Quit flag. */
Xextern int modified;		/* Text buffer modified flag. */
Xextern int modeless;		/* Command-set style. */
Xextern int msgflag;		/* True if msgline should be displayed. */
X
Xextern int row;			/* Cursor screen row */
Xextern int col;			/* Cursor screen column. */
Xextern int textline;		/* First screen line used for text. */
X
Xextern t_point point;		/* Cursor offset in text buffer. */
Xextern t_point pointline;	/* Cursor line number. */
Xextern t_point page;		/* Top of screen page. */
Xextern t_point epage;		/* End of screen page +1 */
Xextern t_point marker;		/* Block anchor point. */
X
Xextern t_char *buf;		/* Base of allocated text buffer. */
Xextern t_char *ebuf;		/* End of text buffer +1 */
Xextern t_char *gap;		/* Start of gap. */
Xextern t_char *egap;		/* End of gap +1 */
X
Xextern t_point nscrap;		/* Length of scrap buffer. */
Xextern t_char *scrap;		/* Allocated scrap buffer. */
X
Xextern int count;		/* Command repeat count. */
Xextern int input;		/* Current input character. */
Xextern char msgline[];		/* Message line input/output buffer. */
Xextern char filename[];		/* Current filename for text buffer. */
Xextern char temp[];		/* Temporary buffer. */
Xextern char *prog_name;		/* Name used to invoke editor. */
X
Xextern t_keytable table[];	/* Command jump table. */
Xextern t_keymap *key_map;	/* Command key mappings. */
Xextern t_keymap key_mode[];	/* Key mappings used in insert_mode() */
X
X/* fatal() messages. */
Xextern t_msg f_ok;		/* EXIT_OK */
Xextern t_msg f_error;		/* EXIT_ERROR */
Xextern t_msg f_usage;		/* EXIT_USAGE */
Xextern t_msg f_initscr;		/* EXIT_FAILURE ... */
Xextern t_msg f_config;
Xextern t_msg f_alloc;
X
X/* Messages. */
Xextern t_msg m_version;
Xextern t_msg m_help;
Xextern t_msg m_ok;
Xextern t_msg m_error;
Xextern t_msg m_alloc;
Xextern t_msg m_toobig;
Xextern t_msg m_scrap;
Xextern t_msg m_stat;
Xextern t_msg m_open;
Xextern t_msg m_close;
Xextern t_msg m_read;
Xextern t_msg m_write;
Xextern t_msg m_badname;
Xextern t_msg m_file;
Xextern t_msg m_modified;
Xextern t_msg m_saved;
Xextern t_msg m_loaded;
Xextern t_msg m_badescape;
Xextern t_msg m_nomacro;
Xextern t_msg m_slots;
Xextern t_msg m_interrupt;
Xextern t_msg m_eof;
Xextern t_msg m_undo;
X
X/* Prompts */
Xextern t_msg p_macro;
Xextern t_msg p_notsaved;
Xextern t_msg p_press;
Xextern t_msg p_read;
Xextern t_msg p_write;
Xextern t_msg p_bwrite;
Xextern t_msg p_yes;
Xextern t_msg p_no;
Xextern t_msg p_quit;
Xextern t_msg p_more;
X
Xextern t_msg message[];
X
X/*
X *
X */
X#ifdef TERMIOS
Xextern void lineinput _((int));
X#else
X#define lineinput(bf)		(bf ? nocbreak() : cbreak())
X#endif /* TERMIOS */
X
Xextern void fatal _((t_msg));
Xextern void msg _((t_msg, ...));
Xextern char *getmsg _((t_msg));
Xextern char *strlwr _((char *));
Xextern char *strdup _((const char *));
Xextern char *strrep _((char *, int, int, int));
Xextern char *pathname _((char *, char *));
Xextern FILE *openrc _((char *));
Xextern long getblock _((FILE *, char **));
Xextern char *encode _((char *));
X
Xextern void display _((void (*)(void)));
Xextern void dispfull _((void));
Xextern void dispcursor _((void));
Xextern t_point lnstart _((t_point));
Xextern t_point lnnext _((t_point));
Xextern t_point lncolumn _((t_point, int));
Xextern t_point segstart _((t_point, t_point));
Xextern t_point segnext _((t_point, t_point));
Xextern t_point upup _((t_point));
Xextern t_point dndn _((t_point));
Xextern void ruler _((int));
Xextern char *printable _((unsigned));
X
Xextern int growgap _((t_point));
Xextern t_point movegap _((t_point));
Xextern t_point pos _((t_char *));
Xextern t_char *ptr _((t_point));
Xextern void getregion _((t_region *));
Xextern int posix_file _((char *));
Xextern int save _((char *));
Xextern int load _((char *));
Xextern void undoset _((void));
Xextern void undosave _((void));
Xextern void undo _((void));
X
Xextern void backsp _((void));
Xextern void block _((void));
Xextern void bottom _((void));
Xextern void cut _((void));
Xextern void delete _((void));
Xextern void down _((void));
Xextern void help _((void));
Xextern void insert _((void));
Xextern void insert_mode _((void));
Xextern void left _((void));
Xextern void lnbegin _((void));
Xextern void lnend _((void));
Xextern void macro _((void));
Xextern void paste _((void));
Xextern void pgdown _((void));
Xextern void pgup _((void));
Xextern void quit _((void));
Xextern void quit_ask _((void));
Xextern void redraw _((void));
Xextern void readfile _((void));
Xextern void right _((void));
Xextern void top _((void));
Xextern void up _((void));
Xextern void version _((void));
Xextern void wleft _((void));
Xextern void wright _((void));
Xextern void writefile _((void));
Xextern void flipcase _((void));
Xextern int iscrlf _((t_point));
X
X#endif /* __header_h__ */
END-of-header.h
echo x - command.c
sed 's/^X//' >command.c << 'END-of-command.c'
X/*
X * command.c		
X *
X * Anthony's Editor October 95
X *
X * Copyright 1993, 1995 by Anthony Howe.  All rights reserved.  No warranty.
X */
X
X#include <ctype.h>
X#include "header.h"
X
Xvoid prt_macros _((void));
Xint yesno _((int));
Xint more _((int));
Xvoid prompt _((t_msg, char *, size_t));
X
Xvoid
Xtop()
X{
X	point = 0;
X}
X
Xvoid
Xbottom()
X{
X	epage = point = pos(ebuf);
X}
X
Xvoid
Xquit_ask()
X{
X	if (modified) {
X		standout();
X		mvaddstr(MSGLINE, 0, getmsg(p_notsaved));
X		standend();
X		clrtoeol();
X		if (!yesno(FALSE))
X			return;
X	}
X	quit();
X}
X
Xint
Xyesno(flag)
Xint flag;
X{
X	int ch;
X
X	addstr(getmsg(flag ? p_yes : p_no));
X	refresh();
X	ch = getliteral();
X	if (ch == '\r' || ch == '\n')
X		return (flag);
X	return (ch == getmsg(p_yes)[1]);
X}
X
Xvoid
Xquit()
X{
X	done = 1;
X}
X
Xvoid
Xredraw()
X{
X	int col;
X
X	clear();
X	if (textline != HELPLINE) {
X		move(HELPLINE, 0);
X		addstr(getmsg(m_help));
X		ruler(COLS);
X		getyx(stdscr, textline, col);
X	}
X	display(dispfull);
X}
X
Xvoid
Xleft()
X{
X	if (0 < point && iscrlf(--point) == 2)
X		--point;
X} 
X
Xvoid
Xright()
X{
X	if (point < pos(ebuf) && iscrlf(point++) == 1)
X		++point;
X}
X
Xvoid
Xup()
X{
X	point = lncolumn(upup(point), col);
X	if (iscrlf(point) == 2)
X		--point;
X}
X
Xvoid
Xdown()
X{
X	point = lncolumn(dndn(point), col);
X	if (iscrlf(point) == 2)
X		--point;
X}
X
Xvoid
Xlnbegin()
X{
X	point = segstart(lnstart(point), point);
X}
X
Xvoid
Xlnend()
X{
X	point = dndn(point);
X	left();
X}
X
Xvoid
Xwleft()
X{
X	while (!isalnum(*ptr(--point)) && 0 < point)
X		;
X	while (isalnum(*ptr(--point)) && 0 <= point)
X		;
X	++point;
X}
X
Xvoid
Xwright()
X{
X	t_point epoint = pos(ebuf);
X	while (isalnum(*ptr(point)) && point < epoint)
X		++point;
X	while (!isalnum(*ptr(point)) && point < epoint) 
X		++point;
X}
X
Xvoid
Xpgdown()
X{
X	page = point = upup(epage);
X	while (textline < row--)
X		down();
X	epage = pos(ebuf);
X}
X
Xvoid
Xpgup()
X{
X	int i = LINES;
X	while (textline < --i) {
X		page = upup(page);
X		up();
X	}
X}
X
Xvoid
Xinsert()
X{
X	assert(gap <= egap);
X	if (gap == egap && !growgap(CHUNK))
X		return;
X	point = movegap(point);
X	*gap++ = input == K_LITERAL ? getliteral() : input;
X	if (input == '\r' && (gap < egap || growgap(CHUNK)))
X		*gap++ = '\n';
X	modified = TRUE;
X	point = pos(egap);
X}
X
Xvoid
Xinsert_mode()
X{
X	int ch;
X	t_point opoint;
X	point = opoint = movegap(point);
X	undoset();
X	while ((ch = getkey(key_mode)) != K_INSERT_EXIT) {
X		if (ch == K_STTY_ERASE) {
X			if (opoint < point) {
X				if (*--gap == '\n' 
X				&& buf < gap && gap[-1] == '\r')
X					--gap;
X				modified = TRUE;
X			}
X		} else {
X			assert(gap <= egap);
X			if (gap == egap && !growgap(CHUNK)) 
X				break;
X			*gap++ = ch == K_LITERAL ? getliteral() : ch;
X			if (ch == '\r' && (gap < egap || growgap(CHUNK)))
X				*gap++ = '\n';
X			modified = TRUE;
X		}
X		point = pos(egap);
X		display(dispfull);
X	}
X}
X
Xvoid
Xbacksp()
X{
X	point = movegap(point);
X	undoset();
X	if (buf < gap) {
X		if (*--gap == '\n' && buf < gap && gap[-1] == '\r')
X			--gap;
X		point = pos(egap);
X		modified = TRUE;
X	}
X}
X
Xvoid
Xdelete()
X{
X	point = movegap(point);
X	undoset();
X	if (egap < ebuf) {
X		if (*egap++ == '\r' && egap < ebuf && *egap == '\n')
X			++egap;
X		point = pos(egap);
X		modified = TRUE;
X	}
X}
X
Xvoid
Xreadfile()
X{
X	temp[0] = '\0';
X	prompt(p_read, temp, BUFSIZ);
X	(void) load(temp);
X	if (filename[0] == '\0') {
X		strcpy(filename, temp);
X		modified = FALSE;
X	}
X}
X
Xvoid
Xwritefile()
X{
X	standout();
X	if (marker == NOMARK || point == marker) {
X		strcpy(temp, filename);
X		prompt(p_write, temp, BUFSIZ);
X	} else {
X		temp[0] = '\0';
X		prompt(p_bwrite, temp, BUFSIZ);
X	}
X	(void) save(temp);
X	if (marker == NOMARK && filename[0] == '\0') 
X		strcpy(filename, temp);
X}
X
Xvoid
Xhelp()
X{
X	textline = textline == HELPLINE ? -1 : HELPLINE;
X	/* When textline != HELPLINE, then redraw() will compute the 
X	 * actual textline that follows the help text.
X	 */
X	redraw();
X}
X
Xvoid
Xblock()
X{
X	marker = marker == NOMARK ? point : NOMARK;
X}
X
Xvoid
Xcut()
X{
X	if (marker == NOMARK || point == marker)
X		return;
X	if (scrap != NULL) {
X		free(scrap);
X		scrap = NULL;
X	}
X	if (point < marker) {
X		(void) movegap(point);
X		nscrap = marker - point;
X	} else {
X		(void) movegap(marker);
X		nscrap = point - marker;
X	}
X	if ((scrap = (t_char*) malloc(nscrap)) == NULL) {
X		msg(m_alloc);
X	} else {
X		undoset();
X		(void) memcpy(scrap, egap, nscrap * sizeof (t_char));
X		egap += nscrap;
X		block();
X		point = pos(egap);
X		modified = TRUE;
X	}
X}
X
Xvoid
Xpaste()
X{
X	if (nscrap <= 0) {
X		msg(m_scrap);
X	} else if (nscrap < egap-gap || growgap(nscrap)) {
X		point = movegap(point);
X		undoset();
X		memcpy(gap, scrap, nscrap * sizeof (t_char));
X		gap += nscrap;
X		point = pos(egap);
X		modified = TRUE;
X	}
X}
X
Xvoid
Xversion()
X{
X	msg(m_version);
X}
X
Xvoid
Xmacro()
X{
X	t_keymap *kp;
X	size_t buflen, rhsoff;
X	char *buf, *lhs, *rhs;
X
X	if ((buf = (char *) malloc(BUFSIZ)) == NULL) {
X		msg(m_alloc);
X		return;
X	}
X	buf[0] = '\0';
X	prompt(p_macro, buf, BUFSIZ);
X	buflen = strlen(buf)+1;
X
X	if ((lhs = strtok(buf, " \t")) == NULL) {
X		prt_macros();
X	} else if (buf < lhs) {
X		/* Ideally we should shuffle the buffer down so that
X		 * the lhs starts at the beginning of buffer.
X		 */
X		msg(m_error);
X	} else if ((lhs = encode(lhs)) == (char *) 0) {
X		msg(m_badescape);
X	} else {
X		kp = findkey(key_map, lhs);
X		if ((rhs = strtok(NULL, " \t")) == NULL) {
X			/* Delete macro. */
X			if (kp == NULL || kp->code != K_MACRO_DEFINE) {
X				msg(m_nomacro);
X			} else {
X				free(kp->lhs);
X				free(kp->rhs);
X				kp->lhs = kp->rhs = NULL;
X			}
X		} else if ((rhs = encode(rhs)) == (char *) 0) { 
X			msg(m_badescape);
X		} else {
X			if (kp == NULL) {
X				/* Find free slot to add macro. */
X				for (kp = key_map; kp->code != K_ERROR; ++kp) {
X					if (kp->code == K_MACRO_DEFINE
X					&& kp->lhs == NULL)
X						break;
X				}
X			}
X			if (kp->code == K_ERROR) {
X				msg(m_slots);
X			} else if (kp->code == K_MACRO_DEFINE) {
X				/* Change macro. */
X				kp->lhs = lhs;
X				kp->rhs = rhs;
X			} else {
X				msg(m_nomacro);
X			}
X		}
X	}
X	free(buf);
X}
X
Xvoid
Xprt_macros()
X{
X	t_keymap *kp;
X	int used, total;
X	unsigned char *ptr;
X
X	erase();
X	scrollok(stdscr, TRUE);
X	for (used = total = 0, kp = key_map; kp->code != K_ERROR; ++kp) {
X		if (kp->code == K_MACRO_DEFINE) {
X			++total;
X			if (kp->rhs != NULL) {
X				++used;
X				addch('{');
X				ptr = (unsigned char *) kp->lhs; 
X				for (; *ptr != '\0'; ++ptr) 
X					addstr(printable(*ptr));
X				addstr("}\t{");
X				ptr = (unsigned char *) kp->rhs; 
X				for (; *ptr != '\0'; ++ptr) 
X					addstr(printable(*ptr));
X				addstr("}\n");
X				(void) more(used);
X			}
X		}
X	}
X	printw("\n%d/%d\n", used, total);
X	scrollok(stdscr, FALSE);
X	(void) more(-1);
X	redraw();
X}
X
X/*
X * Return true if more should continue.
X */
Xint
Xmore(row)
Xint row;
X{
X	int ch;
X
X	if (0 < row % (LINES-1))
X		return (TRUE);
X	standout();
X	addstr(getmsg(p_more));
X	standend();
X	clrtoeol();
X	refresh();
X	ch = getliteral();
X	addch('\r');
X	clrtoeol();
X	return (ch != getmsg(p_quit)[1] && ch != getmsg(p_no)[1]);
X}
X
X/*
X * Flip the case of a region.  
X */
Xvoid
Xflipcase()
X{
X	t_char *p;
X	t_region r;
X	for (getregion(&r); r.left <= r.right; ++r.left) {
X		p = ptr(r.left);
X		if (islower(*p)) {
X			*p = toupper(*p);
X			modified = TRUE;
X		} else if (isupper(*p)) {
X			*p = tolower(*p);
X			modified = TRUE;
X		}
X	}
X	if (marker == NOMARK)
X		right();
X}
X
Xvoid
Xprompt(m, buf, len)
Xt_msg m;
Xchar *buf;
Xsize_t len;
X{
X	standout();
X	mvaddstr(MSGLINE, 0, getmsg(m));
X	standend();
X	clrtoeol();
X	addch(' ');
X	refresh();
X	getinput(buf, len, TRUE);
X}
X
X/*
X * Return 1 if offset points to first-half of CR-LF; 
X * 2 if offset points to second-half of CR-LF; 0 otherwise.
X */
Xint
Xiscrlf(offset)
Xregister t_point offset;
X{
X	register t_char *p;
X
X	p = ptr(offset);
X	if (*p == '\r') {
X		/* Look to the right for '\n'. */
X		if (++offset < pos(ebuf) && *ptr(offset) == '\n')
X			return (1);
X	} else if (*p == '\n') {
X		/* Look to the left for '\r'. */
X		if (pos(buf) < offset && *ptr(--offset) == '\r')
X			return (2);
X	}
X	return (0);
X}
END-of-command.c
echo x - key.c
sed 's/^X//' >key.c << 'END-of-key.c'
X/*
X * key.c		
X *
X * Anthony's Editor October 95
X *
X * Copyright 1993, 1995 by Anthony Howe.  All rights reserved.  No warranty.
X */
X
X#include <ctype.h>
X#include <stdio.h>
X#include <sys/types.h>
X#include "header.h"
X#include "key.h"
X
X/* Variable length structure. */
Xtypedef struct t_input {
X	struct t_input *next;
X	char *ptr;
X	char buf[1];
X} t_input;
X
Xstatic t_input *istack = NULL;
Xstatic char blank[] = " \t\r\n";
X
Xstatic int k_default _((t_keymap *));
Xstatic int k_define _((t_keymap *));
Xstatic int k_erase  _((t_keymap *));
Xstatic int k_itself _((t_keymap *));
Xstatic int k_kill _((t_keymap *));
Xstatic int k_token _((t_keymap *));
Xstatic t_keymap *growkey _((t_keymap *, size_t));
Xstatic int ipush _((char *));
Xstatic int ipop _((void));
Xstatic void iflush _((void));
X
Xt_keyinit keywords[] = {
X	{ K_INSERT_ENTER, ".insert_enter", k_default },
X	{ K_INSERT_EXIT, ".insert_exit", k_default },
X	{ K_DELETE_LEFT, ".delete_left", k_default },
X	{ K_DELETE_RIGHT, ".delete_right", k_default },
X	{ K_FLIP_CASE, ".flip_case", k_default },
X	{ K_BLOCK, ".block", k_default },
X	{ K_CUT, ".cut", k_default },
X	{ K_PASTE, ".paste", k_default },
X	{ K_UNDO, ".undo", k_default },
X	{ K_CURSOR_UP, ".cursor_up", k_default },
X	{ K_CURSOR_DOWN, ".cursor_down", k_default },
X	{ K_CURSOR_LEFT, ".cursor_left", k_default },
X	{ K_CURSOR_RIGHT, ".cursor_right", k_default },
X	{ K_PAGE_UP, ".page_up", k_default },
X	{ K_PAGE_DOWN, ".page_down", k_default },
X	{ K_WORD_LEFT, ".word_left", k_default },
X	{ K_WORD_RIGHT, ".word_right", k_default },
X	{ K_LINE_LEFT, ".line_left", k_default },
X	{ K_LINE_RIGHT, ".line_right", k_default },
X	{ K_FILE_TOP, ".file_top", k_default },
X	{ K_FILE_BOTTOM, ".file_bottom", k_default },
X	{ K_HELP, ".help", k_default },
X	{ K_HELP_OFF, ".help_off", k_token },
X	{ K_MACRO, ".macro", k_default },
X	{ K_MACRO_DEFINE, ".macro_define", k_define },
X	{ K_QUIT, ".quit", k_default },
X	{ K_QUIT_ASK, ".quit_ask", k_default },
X	{ K_FILE_READ, ".file_read", k_default },
X	{ K_FILE_WRITE, ".file_write", k_default },
X	{ K_STTY_ERASE, ".stty_erase", k_erase },
X	{ K_STTY_KILL, ".stty_kill", k_kill },
X	{ K_ITSELF, ".itself", k_itself },
X	{ K_REDRAW, ".redraw", k_default },
X	{ K_SHOW_VERSION, ".show_version", k_default },
X	{ K_LITERAL, ".literal", k_default },
X	{ K_ERROR, NULL, NULL }
X};
X
Xint
Xismsg(str)
Xchar *str;
X{
X	char *ptr;
X	for (ptr = str; isdigit(*ptr); ++ptr)
X		;
X	return (str < ptr && *ptr == ':');
X}
X
X/*
X * Read a configuration file from either the current directory or
X * the user's home directory.  Return an error status.  Pass-back
X * either a pointer to a key mapping table, or NULL if an error
X * occured.
X */
Xint
Xinitkey(fn, keys)
Xchar *fn;
Xt_keymap **keys;
X{
X	FILE *fp;
X	int error;
X	t_keyinit *kp;
X	t_keymap *array;
X	size_t len, count;
X	char *buf, *token, *lhs, *rhs;
X
X	*keys = NULL;
X	if ((fp = openrc(fn)) == NULL)
X		return (INITKEY_OPEN);
X
X	/* Allocate an array big enough to hold at least one of everything. */
X	if ((array = growkey(NULL, len = K_MAX_CODES)) == NULL) {
X		error = INITKEY_ALLOC;
X		goto error1;
X	}
X
X	count = 0;
X	for ( ; (error = getblock(fp, &buf)) != GETBLOCK_EOF; free(buf)) {
X		if (error == GETBLOCK_ALLOC) {
X			error = INITKEY_ALLOC;
X			goto error1;
X		}
X	
X		/* Strip \r\n from end of buffer. */
X		if ((token = strrchr(buf, '\n')) != NULL) {
X			if (buf < token && token[-1] == '\r')
X				--token;
X			*token = '\0';
X		}
X
X		if (ismsg(buf)) {
X			long index;
X
X			token = encode(buf);
X			if (token == (char *) 0) {
X				error = INITKEY_ALLOC;
X				goto error1;
X			}
X
X			index = strtol(token, &token, 0);
X			if (0 < index) 
X				message[index] = token+1;
X			continue;
X		}
X			
X		if (buf[0] != '.' 
X		|| (token = strtok(buf, blank)) == NULL
X		|| (kp = findikey(keywords, strlwr(token))) == NULL)
X			continue;
X	
X		array[count].code = kp->code;
X
X		/* Determine lhs and rhs parameters. */
X		if ((lhs = strtok((char *) 0, blank)) != (char *) 0) {
X			rhs = strtok((char *) 0, blank);
X
X			array[count].lhs = encode(lhs);
X			if (array[count].lhs == (char *) 0) {
X				error = INITKEY_ERROR;
X				goto error1;
X			}
X
X			/* Find rhs if present. */
X			if (rhs != (char *) 0
X			&& (array[count].rhs = encode(token)) == (char *) 0) {
X				error = INITKEY_ERROR;
X				goto error1;
X			}
X		} else {
X			/* No parameters for keyword. */
X			array[count].lhs = array[count].rhs = (char *) 0;
X		}
X
X		if (kp->fn != NULL && !(*kp->fn)(&array[count])) {
X			error = INITKEY_ERROR;
X			goto error1;
X		}
X		++count;
X
X		if (len <= count) {
X			t_keymap *new;
X			len += K_MAX_CODES;
X			if ((new = growkey(array, len)) == NULL) {
X				error = INITKEY_ALLOC;
X				goto error1;
X			}
X			array = new;
X		}
X	}
X	error = INITKEY_OK;
X	*keys = array;
Xerror1:
X	(void) fclose(fp);
X	array[count].code = K_ERROR;
X	if (error != INITKEY_OK)
X		finikey(array);
X
X	return (error);
X}
X
Xvoid
Xfinikey(keys)
Xt_keymap *keys;
X{
X	t_keymap *kp;
X	if (keys != NULL) {
X		for (kp = keys; kp->code != K_ERROR; ++kp) {
X			if (kp->lhs != (char *) 0)
X				free(kp->lhs);
X			if (kp->rhs != (char *) 0)
X				free(kp->rhs);
X		}
X		free(keys);
X	}
X}
X
X/*
X * .function string
X */
Xstatic int
Xk_default(kp)
Xt_keymap *kp;
X{
X	if (kp->lhs == NULL)
X		return (FALSE);
X	if (kp->rhs != NULL) {
X		free(kp->lhs);
X		return (FALSE);
X	}
X	return (TRUE);
X}
X
X/*
X * .macro_define
X * .macro_define lhs rhs
X *
X * The first case is used as a place holder to reserve macro
X * space.  The second case actual defines a macro.
X */
Xstatic int
Xk_define(kp)
Xt_keymap *kp;
X{
X	if (kp->lhs != NULL && kp->rhs == NULL) {
X		free(kp->lhs);
X		return (FALSE);
X	}
X	return (TRUE);
X}
X
X/*
X * .token
X */
Xstatic int
Xk_token(kp)
Xt_keymap *kp;
X{
X	if (kp->lhs != NULL) {
X		free(kp->lhs);
X		return (FALSE);
X	}
X	return (TRUE);
X}
X
X/*
X * .itself character
X */
Xstatic int
Xk_itself(kp)
Xt_keymap *kp;
X{
X	if (!k_default(kp))
X		return (FALSE);
X	kp->code = *(unsigned char *) kp->lhs;
X	kp->lhs[1] = '\0';
X	return (TRUE);
X}
X
X/*
X * .stty_erase
X */
Xstatic int
Xk_erase(kp)
Xt_keymap *kp;
X{
X	char buf[2];
X
X	if (!k_token(kp))
X		return (FALSE);
X	buf[0] = erasechar();
X	buf[1] = '\0';
X	return ((kp->lhs = strdup(buf)) != NULL);
X}
X
X/*
X * .stty_kill
X */
Xstatic int
Xk_kill(kp)
Xt_keymap *kp;
X{
X	char buf[2];
X
X	if (!k_token(kp))
X		return (FALSE);
X	buf[0] = killchar();
X	buf[1] = '\0';
X	return ((kp->lhs = strdup(buf)) != NULL);
X}
X
X/*
X * Find token and return corresponding table entry; else NULL.
X */
Xt_keymap *
Xfindkey(kp, token)
Xt_keymap *kp;
Xchar *token;
X{
X	for (; kp->code != K_ERROR; ++kp)
X		if (kp->lhs != NULL && strcmp(token, kp->lhs) == 0)
X			return (kp);
X	return (NULL);
X}
X
Xt_keyinit *
Xfindikey(kp, token)
Xt_keyinit *kp;
Xchar *token;
X{
X	for (; kp->code != K_ERROR; ++kp)
X		if (kp->lhs != NULL && strcmp(token, kp->lhs) == 0)
X			return (kp);
X	return (NULL);
X}
X
X/*
X *
X */
Xstatic t_keymap *
Xgrowkey(array, len)
Xt_keymap *array;
Xsize_t len;
X{
X	t_keymap *new;
X	if (len == 0)
X		return (NULL);
X	len *= sizeof (t_keymap);
X	if (array == NULL)
X		return ((t_keymap *) malloc(len));
X	return ((t_keymap *) realloc(array, len));
X}
X
Xint
Xgetkey(keys)
Xt_keymap *keys;
X{
X	t_keymap *k;
X	int submatch;
X	static char buffer[K_BUFFER_LENGTH];
X	static char *record = buffer;
X
X	/* If recorded bytes remain, return next recorded byte. */
X	if (*record != '\0')
X		return (*(unsigned char *)record++);
X	/* Reset record buffer. */
X	record = buffer;
X	do {
X		if (K_BUFFER_LENGTH < record - buffer) {
X			record = buffer;
X			buffer[0] = '\0';
X			return (K_ERROR); 
X		}
X		/* Read and record one byte. */
X		*record++ = getliteral();
X		*record = '\0';
X
X		/* If recorded bytes match any multi-byte sequence... */
X		for (k = keys, submatch = FALSE; k->code != K_ERROR; ++k) {
X			if (k->lhs == NULL || k->code == K_DISABLED)
X				continue;
X			if (strncmp(buffer, k->lhs, record-buffer) != 0)
X				continue;
X			if (k->lhs[record-buffer] == '\0') {
X				/* Exact match. */
X				if (k->code != K_MACRO_DEFINE) {
X					/* Return extended key code. */
X					return (k->code);
X				}
X				if (k->rhs != NULL) {
X					(void) ipush(k->rhs);
X					record = buffer;
X				}
X			}
X			/* Recorded bytes match anchored substring. */
X			submatch = TRUE;
X			break;
X		}
X		/* If recorded bytes matched an anchored substring, loop. */
X	} while (submatch);
X	/* Return first recorded byte. */
X	record = buffer;
X	return (*(unsigned char *)record++);
X}
X
Xint
Xgetliteral()
X{
X	int ch;
X
X	ch = ipop();
X	if (ch == EOF)
X		return ((unsigned) getch());
X	return (ch);
X}
X
X/*
X * Return true if a new input string was pushed onto the stack,
X * else false if there was no more memory for the stack.
X */
Xstatic int
Xipush(buf)
Xchar *buf;
X{
X	t_input *new;
X
X	new = (t_input *) malloc(sizeof (t_input) + strlen (buf));
X	if (new == NULL)
X		return (FALSE);
X	(void) strcpy(new->buf, buf);
X	new->ptr = new->buf;
X	new->next = istack;
X	istack = new;
X	return (TRUE);
X}
X
X/*
X * Pop and return a character off the input stack.  Return EOF if
X * the stack is empty.  If the end of an input string is reached, 
X * then free the node.  This will allow clean tail recursion that 
X * won't blow the stack.  
X */
Xstatic int
Xipop()
X{
X	int ch;
X	t_input *node;
X
X	if (istack == NULL)
X		return (EOF);
X	ch = (unsigned) *istack->ptr++;
X	if (*istack->ptr == '\0') {
X		node = istack;
X		istack = istack->next;
X		free(node);
X	}
X	return (ch);
X}
X
X/*
X * Flush the entire input stack.
X */
Xstatic void
Xiflush()
X{
X	t_input *node;
X
X	while (istack != NULL) {
X		node = istack;
X		istack = istack->next;
X		free(node);
X	}
X}
X
Xint
Xismacro()
X{
X	return (istack != NULL);
X}
X
X/*
X * Field input.
X */
Xtypedef struct t_keyfield {
X	int code;
X	int (*func) _((void));
X} t_keyfield;
X
Xstatic int fld_done _((void));
Xstatic int fld_erase _((void));
Xstatic int fld_kill _((void));
Xstatic int fld_left _((void));
Xstatic int fld_insert _((void));
X
X#define ERASE_KEY	0
X#define KILL_KEY	1
X
Xstatic t_keyfield ktable[] = {
X	{ K_STTY_ERASE, fld_erase },
X	{ K_STTY_KILL, fld_kill },
X	{ '\r', fld_done },
X	{ '\n', fld_done },
X	{ '\b', fld_erase },
X	{ -1, fld_insert }
X};
X
Xstatic int fld_row;
Xstatic int fld_col;
Xstatic int fld_key;
Xstatic int fld_echo;
Xstatic int fld_index;
Xstatic int fld_length;
Xstatic char *fld_buffer;
X
X#ifndef getmaxyx
X#define getmaxyx(w,r,c)		(r=LINES,c=COLS)
X#endif
X
Xint
Xgetinput(buf, len, echoing)
Xchar *buf;
Xint len, echoing;
X{
X	int first;
X	t_keyfield *k;
X	fld_buffer = buf;
X	fld_index = (int) strlen(fld_buffer);
X	fld_length = len < 0 ? COLS : len;
X	if (--fld_length < 1)
X		return (FALSE);
X	ktable[ERASE_KEY].code = erasechar();
X	ktable[KILL_KEY].code = killchar();	
X	fld_echo = echoing;
X	getyx(stdscr, fld_row, fld_col);
X	addstr(fld_buffer);
X	move(fld_row, fld_col);
X	for (first = TRUE;; first = FALSE) {
X		refresh();
X		fld_key = getliteral();
X		for (k = ktable; k->code != -1 && k->code != fld_key; ++k)
X			;
X		if (first && k->func == fld_insert)
X			fld_kill();
X		if (k->func != NULL && !(*k->func)()) {
X			fld_buffer[fld_index] = '\0';
X			break;
X		}
X	}
X	return (TRUE);
X}
X	
Xstatic int
Xfld_done()
X{
X	return (FALSE);
X}
X
Xstatic int
Xfld_left()
X{
X	int row, col, max_row, max_col;
X	getyx(stdscr, row, col);
X	getmaxyx(stdscr, max_row, max_col);
X	if (0 < fld_index) {
X		--fld_index;
X		/* Assume that if 0 < fld_index then fld_row <= row 
X		 * and fld_col < col.  So when fld_index == 0, then
X		 * fld_row == row and fld_col == col. 
X		 */
X		if (0 < col) {
X			--col;
X		} else if (0 < row) {
X			/* Handle reverse line wrap. */
X			--row;
X			col = max_col-1;
X		}
X		move(row, col);
X	}
X	return (TRUE);
X}
X
Xstatic int
Xfld_erase()
X{
X	int row, col;
X	if (0 < fld_index) {
X		fld_left();
X		getyx(stdscr, row, col);
X		addch(' ');
X		move(row, col);
X		fld_buffer[fld_index] = '\0';
X	}
X	return (TRUE);
X}
X
Xstatic int
Xfld_kill()
X{
X	move(fld_row, fld_col);
X	while (0 < fld_index--)
X		addch(' ');
X	move(fld_row, fld_col);
X	fld_buffer[0] = '\0';
X	fld_index = 0;
X	return (TRUE);
X}
X	
Xstatic int
Xfld_insert()
X{
X	if (fld_index < fld_length) {
X		if (!ISFUNCKEY(fld_key)) {
X			fld_buffer[fld_index++] = fld_key;
X			if (fld_echo)
X				addch(fld_key);
X		}
X	}
X	return (fld_index < fld_length);
X}
X
X
END-of-key.c
echo x - main.c
sed 's/^X//' >main.c << 'END-of-main.c'
X/*
X * main.c		
X *
X * Anthony's Editor October 95
X *
X * Copyright 1993, 1995 by Anthony Howe.  All rights reserved.  No warranty.
X */
X
X#include <ctype.h>
X#include <errno.h>
X#include "header.h"
X
Xstatic int intsig = FALSE;
X
X#ifdef SIGINT
Xstatic void
Xsigint(sig)
Xint sig;
X{
X	intsig = TRUE;
X}
X#endif
X
X#ifdef ATARI_ST
X#include <setjmp.h>
X
Xstatic jmp_buf ignore;
Xstatic void (*old_sigint) _((int));
X
Xstatic void
Xsigint(sig)
Xint sig;
X{
X	intsig = TRUE;
X	longjmp(ignore, 1);
X}
X#endif /* ATARI_ST */
X
X#ifndef KEY_LENGTH
X#define KEY_LENGTH	10
X#endif
X
X#ifdef TERMCAP
Xextern char *tgetstr _((char *, char **));
Xchar termcap[1024];
X#endif
X
Xint
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	int i;
X	t_keymap *kp;
X	char *ap, *config;
X
X	/* Find basename. */
X	prog_name = *argv; 
X	i = strlen(prog_name);
X	while (0 <= i && prog_name[i] != '\\' && prog_name[i] != '/')
X		--i;
X	prog_name += i+1;
X
X	/* Parse options. */
X	config = CONFIG;
X	for (--argc, ++argv; 0 < argc && **argv == '-'; --argc, ++argv) {
X		ap = &argv[0][1];
X		if (*ap == '-' && ap[1] == '\0') {
X			/* -- terminates options. */
X			--argc;
X			++argv;
X			break;
X		}
X		while (*ap != '\0') {
X			switch (*ap++) {
X			case 'f':
X				/* -f <config_file>  or -f<config_file> */
X
X				if (*ap != '\0') {
X					config = ap;
X				} else if (1 < argc) {
X					config = *++argv;
X					--argc;
X				} else {
X					fatal(f_usage);
X				}
X				break;
X			default:
X				fatal(f_usage);
X			}
X			break;
X		}
X	}
X
X	if (initscr() == NULL)
X		fatal(f_initscr);
X
X#ifdef TERMCAP
X	(void) tgetent(termcap, getenv("TERM"));
X#endif
X
X	if (initkey(config, &key_map) != INITKEY_OK)
X		fatal(f_config);
X
X	/* Determine if editor is modeless or not.
X	 * Define insert mode keys from the master table. 
X	 */
X	for (modeless = TRUE, kp = key_map; kp->code != K_ERROR; ++kp) {
X		switch (kp->code) {
X		case K_INSERT_ENTER:
X			modeless = FALSE;
X			break;
X		case K_INSERT_EXIT:
X			kp->code = K_DISABLED;
X			key_mode[0].lhs = kp->lhs;
X			break;
X		case K_STTY_ERASE:
X			key_mode[1].lhs = kp->lhs;
X			break;
X		case K_LITERAL:
X			key_mode[2].lhs = kp->lhs;
X			break;
X		case K_HELP_OFF:
X			textline = 0;
X			break;
X		}
X	}
X
X	noecho();
X	lineinput(FALSE);
X	idlok(stdscr, TRUE);
X
X	if (0 < argc) {
X		(void) load(*argv);
X		/* Save filename irregardless of load() success. */
X		strcpy(filename, *argv);
X		modified = FALSE;
X	}
X	if (!growgap(CHUNK))
X		fatal(f_alloc);
X
X	top();
X	i = msgflag;
X	help();
X	msgflag = i;
X
X	/* Disable recognition of user interrupt. */
X#ifdef SIGQUIT
X	if (signal(SIGQUIT, SIG_IGN) == SIG_ERR)
X		fatal(f_error);
X#endif
X#ifdef SIGINT
X	if (signal(SIGINT, SIG_IGN) == SIG_ERR)
X		fatal(f_error);
X#endif
X#ifdef ATARI_ST
X	old_sigint = (void (*)()) Setexc(0x102, sigint);
X	if (setjmp(ignore) != 0)
X		msg(m_interrupt);
X#endif
X	while (!done) {
X		i = 0;
X		input = getkey(key_map);
X		while (table[i].key != 0 && input != table[i].key)
X			++i;
X		if (table[i].func != NULL) 
X			(*table[i].func)();
X		else if (modeless)
X			insert();
X		display(table[i].disp);
X	}
X
X#ifdef SIGQUIT
X	(void) signal(SIGQUIT, SIG_DFL);
X#endif
X#ifdef SIGINT
X	(void) signal(SIGINT, SIG_DFL);
X#else
X#ifdef ATARI_ST
X	(void) Setexc(0x102, old_sigint);
X#endif
X#ifdef __MSDOS__
X#endif
X#endif /* SIGINT */	
X
X	if (scrap != NULL)
X		free(scrap);
X	finikey(key_map);
X	move(LINES-1, 0);
X	refresh();
X	endwin();
X	putchar('\n');
X	return (0);
X}
X
X#ifdef TERMIOS
X#include <termios.h>
X
X/*
X *	Set the desired input mode.
X *
X *	FALSE enables immediate character processing (disable line processing
X *	and signals for INTR, QUIT, and SUSP).  TRUE enables line processing 
X *	and signals (disables immediate character processing).  In either 
X *	case flow control (XON/XOFF) is still active.  
X *
X *	If the termios function calls fail, then fall back on using 
X *	CURSES' cbreak()/nocbreak() functions; however signals will be
X *	still be in effect.
X */
Xvoid
Xlineinput(bf)
Xint bf;
X{
X	int error;
X	struct termios term;
X	error = tcgetattr(fileno(stdin), &term) < 0;
X	if (!error) {
X		if (bf)
X			term.c_lflag |= ISIG | ICANON;
X		else
X			term.c_lflag &= ~(ISIG | ICANON);
X		error = tcsetattr(fileno(stdin), TCSANOW, &term) < 0;
X	}
X	/* Fall back on CURSES functions that do almost what we need if
X	 * either tcgetattr() or tcsetattr() fail.
X	 */
X	if (error) {
X		if (bf)
X			nocbreak();
X		else
X			cbreak();
X	}
X}
X#endif /* TERMIOS */
X
Xvoid
Xfatal(m)
Xt_msg m;
X{
X	if (curscr != NULL) {
X		move(LINES-1, 0);
X		refresh();
X		endwin();
X		putchar('\n');
X	}
X	fprintf(stderr, getmsg(m), prog_name);
X	if (m == f_ok)
X		exit(0);
X	if (m == f_error)
X		exit(1);
X	if (m == f_usage)
X		exit(2);
X	exit(3);
X}
X
X#ifdef va_dcl
Xvoid
Xmsg(va_alist)
Xva_dcl
X{
X	long num;
X	char *f, *m;
X	va_list args;
X
X	va_start(args);
X	f = getmsg(va_arg(args, t_msg));
X	for (m = msgline; *f != '\0'; ) { 
X		if (*f == '%') {
X			switch (*++f) {
X			case 's':
X				(void) strcpy(m, va_arg(args, char *));
X				break;
X			case 'l':
X				if (*++f != 'd') {
X					(void) strcpy(m, "UNSUPPORTED");
X					break;
X				}
X				num = va_arg(args, long);
X				/* fall */
X			case 'd':
X				if (f[-1] == '%')
X					num = (long) va_arg(args, int);
X				sprintf(m, "%ld", num);
X				break;
X			}
X			m += strlen(m);
X			++f;
X		} else {
X			*m++ = *f++;
X		}
X	}
X	*m = '\0';
X	va_end(args);
X	msgflag = TRUE;
X}
X#else /* not va_dcl */
X#ifdef __STDC__
Xvoid
Xmsg(t_msg m, ...)
X#else
Xvoid
Xmsg(m)
Xt_msg m;
X#endif /* __STDC__ */
X{
X	va_list args;
X	va_start(args, m);
X	(void) vsprintf(msgline, getmsg(m), args);
X	va_end(args);
X	msgflag = TRUE;
X}
X#endif /* va_dcl */
X
X/*
X * Return a pointer to a message.
X * Messages have the format "number:text", where
X * number is an index into a message table and text
X * is the default text if no message defined.
X */
Xchar *
Xgetmsg(m)
Xt_msg m;
X{
X	char *text;
X	long index;
X
X	index = strtol(m, &text, 0);
X	if (0 <= index && message[index] != NULL)
X		return (message[index]);
X	return (text+1);
X}
X 
X/*
X *	Convert a string to lower case.  Return the string pointer.
X */
Xchar *
Xstrlwr(str)
Xchar *str;
X{
X	register char *s;
X	for (s = str; *s != '\0'; ++s)
X		if (isupper(*s))
X			*s = tolower(*s);
X	return (str);
X}
X
X/*
X *	Make a duplicate of a string.  Return a pointer to an allocated
X *	copy of the string, or NULL if malloc() failed.
X */
Xchar *
Xstrdup(str)
Xconst char *str;
X{
X	char *new;
X	if ((new = (char*) malloc(strlen(str)+1)) != NULL)
X		(void) strcpy(new, str);
X	return (new);
X}	
X
X/*
X * Replace old with new characters.  If method
X *	negative	Nth occurence from the end;
X *	0		all occurences;
X *	positive	Nth occurence from the beginning.
X */
Xchar *
Xstrrep(str, old, new, method)
Xchar *str;
Xint old, new, method;
X{
X	register char *ptr = str;
X	register int direction = 1;
X
X	if (method == 0) {
X		/* All occurences. */
X		for (; *ptr != '\0'; ++ptr)
X			if (*ptr == old)
X				*ptr = new;
X		return (str);
X	} else if (method < 0) {
X		/* Start from the end going backwards. */
X		direction = -1;
X		ptr = &str[strlen(str)] - 1;
X		method = -method;
X	}
X
X	/* Change the Nth occurence. */
X	for (; *ptr != '\0'; ptr += direction) {
X		if (*ptr == old && --method <= 0) {
X			*ptr = new;
X			break;
X		}
X	}
X
X	return (str);
X}
X
X/*
X *
X */
Xchar *
Xpathname(path, file)
Xchar *path, *file;
X{
X	char *buf;
X	size_t plen, flen;
X
X	plen = path == NULL ? 0 : strlen(path);
X	flen = file == NULL ? 0 : strlen(file);
X	buf = (char*) malloc(plen + flen + 2);
X	if (buf == NULL)
X		return (NULL);
X	(void) strcpy(buf, path);
X	buf[plen] = '/';
X	(void) strcpy(&buf[plen+1], file);
X	return (buf);
X}
X
X/*
X * Open resource file.
X * Search order is: abs, ./rel, $HOME/rel, $ETCDIR/rel
X */
XFILE *
Xopenrc(fn)
Xchar *fn;
X{
X	FILE *fp;
X	char *ptr, *buf;
X
X	if ((fp = fopen(fn, "r")) != NULL)
X		return (fp);
X
X	if ((ptr = getenv("HOME")) != NULL 
X	&& (buf = pathname(ptr, fn)) != NULL) {
X		fp = fopen(buf, "r");
X#ifdef EITHER_SLASH
X		if (fp == NULL)
X			fp = fopen(strrep(buf, '/', '\\', 0), "r");
X#endif /* EITHER_SLASH */
X		free(buf);
X		if (fp != NULL)
X			return (fp);
X	}
X
X	if ((ptr = getenv("ETCDIR")) != NULL 
X	&& (buf = pathname(ptr, fn)) != NULL) {
X		fp = fopen(buf, "r");
X#ifdef EITHER_SLASH
X		if (fp == NULL)
X			fp = fopen(strrep(buf, '/', '\\', 0), "r");
X#endif /* EITHER_SLASH */
X		free(buf);
X		if (fp != NULL)
X			return (fp);
X	}
X
X	return (NULL);
X}
X
X/*
X * Get an arbitrarily long line of text from a file.
X * The read is terminated when an unescaped newline is found.
X * The buffer that is passed back in ptr will be '\0' terminated.  
X * If an error occurs, the contents of ptr will be undefined.
X */
Xlong
Xgetblock(fp, ptr)
XFILE *fp;
Xchar **ptr;
X{
X	int ch, escape;
X	char *buf, *new;
X	size_t blen, len = 0;
X
X	*ptr = NULL;
X	if ((buf = (char *) malloc(blen = BUFSIZ)) == NULL)
X		return (GETBLOCK_ALLOC);
X
X	escape = FALSE;
X	while ((ch = fgetc(fp)) != EOF) {
X		buf[len++] = ch;
X
X		if (ch == '\n') {
X			if (escape) {
X				len -= 2;
X				escape = FALSE;
X				continue;
X			}
X			buf[len] = '\0';
X			break;
X		}
X		escape = !escape && ch == '\\'; 
X			
X		if (blen <= len) {
X			blen += BUFSIZ;
X			if ((new = (char*) realloc(buf, blen)) == NULL) {
X				free(buf);
X				return (GETBLOCK_ALLOC);
X			}
X			buf = new;
X		}
X	}
X
X	if (ferror(fp)) {
X		free(buf);
X		return (GETBLOCK_ERROR);
X	}
X	if (feof(fp)) {
X		free(buf);
X		return (GETBLOCK_EOF);
X	} 
X
X	buf[len++] = '\0';
X
X	/* Shrink buffer to exact size required for the string. */
X	if ((new = (char *) realloc(buf, len)) == NULL)
X		new = buf;
X	*ptr = new;
X	return (len);
X}
X
X/*
X * Return a pointer to an encoded dynamic string, else null.
X */
Xchar *
Xencode(buf)
Xchar *buf;
X{
X	int count;
X	unsigned long number;
X	char *new, *store, *fetch, *ctrl;
X	static char escmap[] = "\033\033bfnrst";
X	static char escvalue[] = "eE\b\f\n\r \t";
X	static char control[] = "@abcdefghijklmnopqrstuvwxyz[\\]^_";
X
X	/* Find end of string and count '$'. */
X	for (count = 0, fetch = buf; *fetch != '\0'; ++fetch) 
X		switch (*fetch) {
X		case '\\':
X			if (*++fetch == '\0')
X				--fetch;
X			break;
X		case '$':
X			++count;
X			break;
X		}
X
X	/* Allocate new string buffer with room for expansion of
X	 * $key_name strings.
X	 */
X	new = (char *) malloc((fetch - buf) + 1 + count * KEY_LENGTH);
X	if (new == (char *) 0)
X		goto error1;
X
X	for (store = new, fetch = buf; *fetch != '\0'; ) {
X		switch (*fetch) {
X		case '$':
X			if (*++fetch != '(')
X				goto error2;
X			++fetch;
X#ifdef TERMCAP
X			/* Termcap ids are two characters long. */
X			if (fetch[2] != ')')
X				goto error2;
X
X			if (tgetstr(fetch, &store) == (char *) 0) 
X				*store++ = '\a';
X			
X			fetch += 3;
X#else
X			/* Terminfo capnames are 2 to 5 characters long. */
X			for (ctrl = fetch; *fetch != ')'; ++fetch)
X				if (*fetch == '\0')
X					goto error2;
X
X			/* Modify the source buffer! */
X			*fetch++ = '\0';
X
X			if ((ctrl = tigetstr(ctrl)) == (char *) -1)
X				goto error2;
X
X			(void) strcpy(store, ctrl);
X			store += strlen(ctrl);
X#endif
X			break;
X		case '^':
X			++fetch;
X			if (*fetch == '?') {
X				/* ^? equals ASCII DEL character. */ 
X				*store++ = 0x7f;
X			} else {
X				/* ASCII dependant control key mapping. */
X				if (isupper(*fetch))
X					*fetch = tolower(*fetch);
X				if ((ctrl = strchr(control, *fetch)) == NULL)
X					/* Not a control key mapping. */
X					goto error2;
X				*store++ = (char) (ctrl - control);	
X			}
X			++fetch;
X			break;
X		case '\\':
X			/* Escapes. */
X			++fetch;
X			if (isdigit(*fetch)) {
X				/* Numeric escapes allow for
X				 *  octal	\0nnn
X				 *  hex		\0xnn
X				 *  decimal	\nnn 
X				 */
X				number = strtol(fetch, &fetch, 0);
X				if (number < 0 || 255 < number)
X					/* Number not in range 0..255. */
X					goto error2;
X				*store++ = (char) number;
X				break;
X			}
X			if ((ctrl = strchr(escmap, *fetch)) != NULL) {
X				*store++ = escvalue[ctrl - escmap];
X				++fetch;
X				break;
X			}
X			/* Literal escapes. */
X		default:
X			/* Character. */
X			*store++ = *fetch++;
X		}
X	}
X	*store++ = '\0';
X
X	return new;
Xerror2:
X	free(new);
Xerror1:
X	return (char *) 0;
X}
X
END-of-main.c
echo x - modeless.tc
sed 's/^X//' >modeless.tc << 'END-of-modeless.tc'
XSample Configuration File 
XModeless Interface with TERMCAP Function Keys
XAnthony's Editor Oct 95
XCopyright 1993, 1995 by Anthony Howe.  All rights reserved.  No warranty.
X
X1:\
XFile read and write\t\^R  \^W\t\tLeft, down, up, right\tarrow keys\n\
XVersion, quit\t\t\^K\^V  \^C  \^K\^C\tWord left and right\t\^A  \^D\n\
XMacros\t\t\t\^KM\t\tPage down and up\t\^N  \^P\n\
XHelp on and off\t\tF1\t\tFront and end of line\t\^F  \^E\n\
XRedraw\t\t\t\^L\t\tTop and bottom of file\t\^T  \^B\n\
XInsert \t\t\ttyped keys\tDelete left and right\tBACKSPACE \^X\n\
XLiteral escape\t\t\^V\t\tBlock, cut, paste\tF2  F3  F4\n\
XUndo\t\t\t\^U\t\tInvert case\t\t\^\^\n
X
X#.help_off
X.literal	^V
X.cursor_up	$(ku)
X.cursor_down	$(kd)
X.cursor_left	$(kl)
X.cursor_right	$(kr)
X.page_up	^P
X.page_down	^N
X.word_left	^A
X.word_right	^D
X.line_left	^F
X.line_right	^E
X.file_top	^T
X.file_bottom	^B
X.delete_left	^H
X.delete_right	^X
X.help		$(k1)
X.block		$(k2)
X.cut		$(k3)
X.paste		$(k4)
X.flip_case	^^
X.undo		^U
X.file_read	^R
X.file_write	^W
X.redraw		^L
X.quit_ask	^C
X.quit		^K^C
X.quit		^K^X
X.show_version	^K^V
X.macro		^KM
X.macro_define
X.macro_define
X.macro_define
X.macro_define
X.macro_define
X
X2:%s: Terminated successfully.\n
X3:%s: Unspecified error.\n
X4:usage: %s [-f <config>] [file]\n
X5:%s: Failed to initialize the screen.\n
X6:%s: Problem with configuration file.\n
X7:%s: Failed to allocate required memory.\n
X8:Ok.
X9:An error occured.
X10:No more memory available.
X11:File \"%s\" is too big to load.
X12:Scrap is empty.  Nothing to paste.
X13:Failed to find file \"%s\".
X14:Failed to open file \"%s\".
X15:Failed to close file \"%s\".
X16:Failed to read file \"%s\".
X17:Failed to write file \"%s\".
X18:Not a portable POSIX file name.
X19:File \"%s\" %ld bytes.
X20:File \"%s\" %ld bytes saved.
X21:File \"%s\" %ld bytes read.
X22:File \"%s\" modified.
X23:Invalid control character or \\number not 0..255.
X24:No such macro defined.
X25:No more macro space.
X26:Interrupt.
X27:<< EOF >>
X28:Macro :
X29:File not saved.  Quit (y/n) ?
X30:[ Press a key to continue. ]
X31:Read file :
X32:Write file :
X33:Write block :
X34:\smore\s
X35:\sy\b
X36:\sn\b
X37:\sq\b
X38:Nothing to undo.
END-of-modeless.tc
echo x - modeless.ti
sed 's/^X//' >modeless.ti << 'END-of-modeless.ti'
XSample Configuration File 
XModeless Interface with TERMINFO Function Keys
XAnthony's Editor Oct 95
XCopyright 1993, 1995 by Anthony Howe.  All rights reserved.  No warranty.
X
X1:\
XFile read and write\t\^R  \^W\t\tLeft, down, up, right\tarrow keys\n\
XVersion, quit\t\t\^K\^V  \^C  \^K\^C\tWord left and right\t\^A  \^D\n\
XMacros\t\t\t\^KM\t\tPage down and up\t\^N  \^P\n\
XHelp on and off\t\tF1\t\tFront and end of line\t\^F  \^E\n\
XRedraw\t\t\t\^L\t\tTop and bottom of file\t\^T  \^B\n\
XInsert \t\t\ttyped keys\tDelete left and right\tBACKSPACE \^X\n\
XLiteral escape\t\t\^V\t\tBlock, cut, paste\tF2  F3  F4\n\
XUndo\t\t\t\^U\t\tInvert case\t\tF5\n
X
X#.help_off
X.literal	^V
X.cursor_up	$(kcuu1)
X.cursor_down	$(kcud1)
X.cursor_left	$(kcub1)
X.cursor_right	$(kcuf1)
X.page_up	^P
X.page_down	^N
X.word_left	^A
X.word_right	^D
X.line_left	^F
X.line_right	^E
X.file_top	^T
X.file_bottom	^B
X.delete_left	^H
X.delete_right	^X
X.help		$(kf1)
X.block		$(kf2)
X.cut		$(kf3)
X.paste		$(kf4)
X.flip_case	$(kf5)
X.undo		^U
X.file_read	^R
X.file_write	^W
X.redraw		^L
X.quit_ask	^C
X.quit		^K^C
X.quit		^K^X
X.show_version	^K^V
X.macro		^KM
X.macro_define
X.macro_define
X.macro_define
X.macro_define
X.macro_define
X
X2:%s: Terminated successfully.\n
X3:%s: Unspecified error.\n
X4:usage: %s [-f <config>] [file]\n
X5:%s: Failed to initialize the screen.\n
X6:%s: Problem with configuration file.\n
X7:%s: Failed to allocate required memory.\n
X8:Ok.
X9:An error occured.
X10:No more memory available.
X11:File \"%s\" is too big to load.
X12:Scrap is empty.  Nothing to paste.
X13:Failed to find file \"%s\".
X14:Failed to open file \"%s\".
X15:Failed to close file \"%s\".
X16:Failed to read file \"%s\".
X17:Failed to write file \"%s\".
X18:Not a portable POSIX file name.
X19:File \"%s\" %ld bytes.
X20:File \"%s\" %ld bytes saved.
X21:File \"%s\" %ld bytes read.
X22:File \"%s\" modified.
X23:Invalid control character or \\number not 0..255.
X24:No such macro defined.
X25:No more macro space.
X26:Interrupt.
X27:<< EOF >>
X28:Macro :
X29:File not saved.  Quit (y/n) ?
X30:[ Press a key to continue. ]
X31:Read file :
X32:Write file :
X33:Write block :
X34:\smore\s
X35:\sy\b
X36:\sn\b
X37:\sq\b
X38:Nothing to undo.
END-of-modeless.ti
exit



Acknowledgement sent to Anthony Howe <achowe@sentex.net>:
Extra info received and forwarded. Full text available.
Information forwarded to debian-devel@pixar.com:
Bug#1724; Package ae. Full text available.

Message received at debian-bugs:


From mdd.comm.mot.com!mitchell Mon Oct 23 07:42:18 1995
Return-Path: <mitchell@mdd.comm.mot.com>
Received: from pixar.com by mongo.pixar.com with smtp
	(Smail3.1.28.1 #15) id m0t7O4v-0005n8C; Mon, 23 Oct 95 07:42 PDT
Received: from motgate.mot.com by pixar.com with SMTP id AA26809
  (5.67b/IDA-1.5 for debian-bugs-pipe@mongo.pixar.com); Mon, 23 Oct 1995 07:41:50 -0700
Received: from pobox.mot.com (pobox.mot.com [129.188.137.100]) by motgate.mot.com (8.7.1/8.6.10/MOT-3.8) with ESMTP id JAA26309; Mon, 23 Oct 1995 09:42:05 -0500 (CDT)
Received: from mdd.comm.mot.com (mdisea.mdd.comm.mot.com [138.242.64.201]) by pobox.mot.com (8.7.1/8.6.10/MOT-3.8) with SMTP id JAA24446; Mon, 23 Oct 1995 09:41:32 -0500 (CDT)
Received: from bb29c.mdd.comm.mot.com by mdd.comm.mot.com (4.1/SMI-4.1)
	id AA07608; Mon, 23 Oct 95 07:41:28 PDT
Received: (from mitchell@localhost) by bb29c.mdd.comm.mot.com (8.7.1/8.7.1) id HAA12310; Mon, 23 Oct 1995 07:41:26 -0700 (PDT)
Date: Mon, 23 Oct 1995 07:41:26 -0700 (PDT)
From: Bill Mitchell <mitchell@mdd.comm.mot.com>
Message-Id: <199510231441.HAA12310@bb29c.mdd.comm.mot.com>
To: achowe@sentex.net
Subject: Re: Bug#1724: unexpected keypress translations (fwd)
Cc: debian-bugs@pixar.com

Anthony,

Thanks for the prompt response.  I'd appreciate it if you'd copy
debian-bugs@pixar.com on future emails regarding this, and retain
the Subject line intact so that our bug tracking system can handle
the email properly.

achowe@sentex.net said:

> The choice for AE to handle multibyte functions itself instead of using
> termcap or terminfo, was due to the fact that I couldn't figure out a 
> portable way to map AE operations to terminfo or termcap, because at the 
> time there was no standard for Curses.  (Now there is XOpen's XCurses
> which specifies terminfo.)  It was a cheap bypass.
> 
> The workaround for now is to have different config files for each terminal
> type and then specify the config file for the terminal in question on
> the command line using -f option 
> 
> Mean while I'll attempt to solve this problem for you.  BTW does Linux
> use termcap or terminfo?

There are many linux distributions, and the answer to this
question will differ from one to another.  I'm building ae
for inclusion in the Debian GNU/Linux distribution.

Currently, debian supports both curses and terminfo.  The ae
program for debian currently uses libcurses (and termcap) because
that's a shared library and executable size is a primary concern.
The plan for future releases, when libncurses is released as a
shared library, is to switch to libncurses (and terminfo).

Acknowledgement sent to Bill Mitchell <mitchell@mdd.comm.mot.com>:
Extra info received and forwarded. Full text available.
Information forwarded to debian-devel@pixar.com:
Bug#1724; Package ae. Full text available.
Bug reassigned from package `xstd' to `ae'. Request was from Ian Jackson <ian@chiark.chu.cam.ac.uk> to debian-bugs-request@pixar.com. Full text available.
Bug reopened, originator set to Ian Jackson <ian@chiark.chu.cam.ac.uk>. Request was from Ian Jackson <ian@chiark.chu.cam.ac.uk> to debian-bugs-request@pixar.com. Full text available.

Message received at debian-bugs:


From chiark.chu.cam.ac.uk!ian Sun Oct 22 19:38:08 1995
Return-Path: <ian@chiark.chu.cam.ac.uk>
Received: from pixar.com by mongo.pixar.com with smtp
	(Smail3.1.28.1 #15) id m0t7Cm7-0005OHC; Sun, 22 Oct 95 19:38 PDT
Received: from artemis.chu.cam.ac.uk by pixar.com with SMTP id AA25881
  (5.67b/IDA-1.5 for debian-bugs-pipe@mongo.pixar.com); Sun, 22 Oct 1995 19:37:06 -0700
Received: from chiark.chu.cam.ac.uk by artemis.chu.cam.ac.uk with smtp
	(Smail3.1.29.1 #33) id m0t7ClC-0007ubC; Mon, 23 Oct 95 02:37 GMT
Received: by chiark.chu.cam.ac.uk
	id m0t7Cl6-0002bCC
	(Debian /\oo/\ Smail3.1.29.1 #29.33); Mon, 23 Oct 95 02:37 GMT
Message-Id: <m0t7Cl6-0002bCC@chiark.chu.cam.ac.uk>
Date: Mon, 23 Oct 95 02:37 GMT
From: Ian Jackson <ian@chiark.chu.cam.ac.uk>
To: Debian bugs submission address <debian-bugs@pixar.com>
Cc: achowe@sentex.net
Subject: Re: Bug#1724: unexpected keypress translations (fwd)
In-Reply-To: <Pine.SUN.3.91.951022122835.11776F-100000@bb29c>
References: <Pine.SUN.3.91.951022122835.11776F-100000@bb29c>

Bill Mitchell writes ("Re: Bug#1724: unexpected keypress translations (fwd)"):
> The program in question is ae.  I thought I'd pass this on
> to you.  ae uses raw keypress defs in the config file, leading
> to this problem.  I'm guessing that may have been a size or
> complexity tradeoff.  The keypresses in question are PC
> function keys, which generate different escape sequences
> at the non-X11 linux console and in an xterm.

Well, that won't work.  How does ae drive the screen ?  Whatever
library it's using for that will provide a facility for interpreting
(or at least determining) function key sequences.

I've reopened this bug and assigned it to the `ae' package.

Ian.

> ---------- Forwarded message ----------
> Date: Sun, 22 Oct 95 18:40 GMT
> From: Ian Jackson <ian@chiark.chu.cam.ac.uk>
> To: Bill Mitchell <mitchell@mdd.comm.mot.com>, debian-bugs-done@Pixar.com,
>     Debian developers list <debian-devel@Pixar.com>
> Subject: Re: Bug#1724: unexpected keypress translations
> 
> Bill Mitchell writes ("Bug#1724: unexpected keypress translations"):
> > I noticed today that keypress translations are different in an
> > xterm window than on a VC not running X.  I'm really not sure
> > if this is a bug or a case of "you should have expected that",
> > but it caused a program expecting the VC-style keypress
> > translations to misbehave when it got unexpected keypress
> > translations in an xterm window.  It seems to me that, unless
> > there's some good reason otherwise, default keypress translations
> > shouldn't change.
> 
> You should have expected that.  Different terminals have different
> escape sequences, and an xterm is not the same as a Linux console.
> 
> I'm marking this bug as done.
> 
> If you have a program that doesn't correctly use the terminal
> information databases (termcap or terminfo) to interpret keystroke
> escapes then that program is buggy.
> 
> > To duplicate, type "cat -v", F1, ^D in a VC; observe the results;
> > startx; and do the same thing in an xterm.  I know that TERM=linux
> > doesn't work right in an xterm and it's necessary to set TERM=xterm,
> > but that's another issue (or at least I think it is).
> 
> No, it's not another issue.
> 
> Ian.
> 

Acknowledgement sent to Ian Jackson <ian@chiark.chu.cam.ac.uk>:
Extra info received and forwarded. Full text available.
Information forwarded to debian-devel@pixar.com:
Bug#1724; Package xstd. Full text available.

Message received at debian-bugs-done:


From chiark.chu.cam.ac.uk!ian Sun Oct 22 11:41:25 1995
Return-Path: <ian@chiark.chu.cam.ac.uk>
Received: from pixar.com by mongo.pixar.com with smtp
	(Smail3.1.28.1 #15) id m0t75Kn-0006PjC; Sun, 22 Oct 95 11:41 PDT
Received: from artemis.chu.cam.ac.uk by pixar.com with SMTP id AA02145
  (5.67b/IDA-1.5 for debian-bugs-done-pipe@mongo.pixar.com); Sun, 22 Oct 1995 11:40:56 -0700
Received: from chiark.chu.cam.ac.uk by artemis.chu.cam.ac.uk with smtp
	(Smail3.1.29.1 #33) id m0t75Jf-0007uYC; Sun, 22 Oct 95 18:40 GMT
Received: by chiark.chu.cam.ac.uk
	id m0t75JV-0002bVC
	(Debian /\oo/\ Smail3.1.29.1 #29.33); Sun, 22 Oct 95 18:40 GMT
Message-Id: <m0t75JV-0002bVC@chiark.chu.cam.ac.uk>
Date: Sun, 22 Oct 95 18:40 GMT
From: Ian Jackson <ian@chiark.chu.cam.ac.uk>
To: Bill Mitchell <mitchell@mdd.comm.mot.com>, debian-bugs-done@Pixar.com,
        Debian developers list <debian-devel@pixar.com>
Subject: Re: Bug#1724: unexpected keypress translations

Bill Mitchell writes ("Bug#1724: unexpected keypress translations"):
> I noticed today that keypress translations are different in an
> xterm window than on a VC not running X.  I'm really not sure
> if this is a bug or a case of "you should have expected that",
> but it caused a program expecting the VC-style keypress
> translations to misbehave when it got unexpected keypress
> translations in an xterm window.  It seems to me that, unless
> there's some good reason otherwise, default keypress translations
> shouldn't change.

You should have expected that.  Different terminals have different
escape sequences, and an xterm is not the same as a Linux console.

I'm marking this bug as done.

If you have a program that doesn't correctly use the terminal
information databases (termcap or terminfo) to interpret keystroke
escapes then that program is buggy.

> To duplicate, type "cat -v", F1, ^D in a VC; observe the results;
> startx; and do the same thing in an xterm.  I know that TERM=linux
> doesn't work right in an xterm and it's necessary to set TERM=xterm,
> but that's another issue (or at least I think it is).

No, it's not another issue.

Ian.

Notification sent to Bill Mitchell <mitchell@mdd.comm.mot.com>:
Bug acknowledged by developer. Full text available.
Reply sent to Ian Jackson <ian@chiark.chu.cam.ac.uk>:
You have taken responsibility. Full text available.

Message received at debian-bugs:


From bb29c.mdd.comm.mot.com!mitchell Sat Oct 21 11:49:43 1995
Return-Path: <mitchell@bb29c.mdd.comm.mot.com>
Received: from pixar.com by mongo.pixar.com with smtp
	(Smail3.1.28.1 #15) id m0t6izH-000BA6C; Sat, 21 Oct 95 11:49 PDT
Received: from motgate.mot.com by pixar.com with SMTP id AA23571
  (5.67b/IDA-1.5 for debian-bugs-pipe@mongo.pixar.com); Sat, 21 Oct 1995 11:49:17 -0700
Received: from pobox.mot.com (pobox.mot.com [129.188.137.100]) by motgate.mot.com (8.6.11/8.6.10/MOT-3.8) with ESMTP id NAA18648 for <debian-bugs@pixar.com>; Sat, 21 Oct 1995 13:49:37 -0500
Received: from mdisea.mdd.comm.mot.com (mdisea.mdd.comm.mot.com [138.242.64.201]) by pobox.mot.com (8.6.11/8.6.10/MOT-3.8) with ESMTP id NAA22063 for <debian-bugs@pixar.com>; Sat, 21 Oct 1995 13:49:35 -0500
Received: from bb29c.mdd.comm.mot.com (bb29c.mdd.comm.mot.com [138.242.72.29]) by mdisea.mdd.comm.mot.com (8.7.1/8.7.1) with ESMTP id KAA04425 for <debian-bugs@pixar.com>; Sat, 21 Oct 1995 10:06:37 -0700 (PDT)
Received: (from mitchell@localhost) by bb29c.mdd.comm.mot.com (8.7.1/8.7.1) id KAA11010; Sat, 21 Oct 1995 10:06:32 -0700 (PDT)
Date: Sat, 21 Oct 1995 10:06:31 -0700 (PDT)
From: Bill Mitchell <mitchell@mdd.comm.mot.com>
X-Sender: mitchell@bb29c
To: debian-bugs@pixar.com
Subject: unexpected keypress translations
Message-Id: <Pine.SUN.3.91.951021095500.11005A-100000@bb29c>
Mime-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII


PACKAGE:  xstd
VERSION:  3.1.2-3

I noticed today that keypress translations are different in an
xterm window than on a VC not running X.  I'm really not sure 
if this is a bug or a case of "you should have expected that",
but it caused a program expecting the VC-style keypress
translations to misbehave when it got unexpected keypress
translations in an xterm window.  It seems to me that, unless
there's some good reason otherwise, default keypress translations
shouldn't change.

To duplicate, type "cat -v", F1, ^D in a VC; observe the results;
startx; and do the same thing in an xterm.  I know that TERM=linux
doesn't work right in an xterm and it's necessary to set TERM=xterm,
but that's another issue (or at least I think it is).

I'm no X-windows jock, as must be apparent by now.  Just reporting
unexpected behavior.

mitchell@mdd.comm.mot.com (Bill Mitchell)

Acknowledgement sent to Bill Mitchell <mitchell@mdd.comm.mot.com>:
New bug report received and forwarded. Full text available.
Report forwarded to debian-devel@pixar.com:
Bug#1724; Package xstd. Full text available.
Ian Jackson / iwj10@thor.cam.ac.uk, with the debian-bugs tracking mechanism
This page last modified 07:43:01 GMT Wed 01 Nov