Initial revision
authorStu Grossman <grossman@cygnus>
Tue, 19 Nov 1991 05:16:47 +0000 (05:16 +0000)
committerStu Grossman <grossman@cygnus>
Tue, 19 Nov 1991 05:16:47 +0000 (05:16 +0000)
13 files changed:
readline/doc/Makefile [new file with mode: 0644]
readline/doc/hist.texinfo [new file with mode: 0644]
readline/doc/history.info [new file with mode: 0644]
readline/doc/hstech.texinfo [new file with mode: 0644]
readline/doc/hsuser.texinfo [new file with mode: 0644]
readline/doc/readline.info [new file with mode: 0644]
readline/doc/rlman.texinfo [new file with mode: 0644]
readline/doc/rltech.texinfo [new file with mode: 0644]
readline/doc/rluser.texinfo [new file with mode: 0644]
readline/doc/texindex.c [new file with mode: 0644]
readline/doc/texinfo.tex [new file with mode: 0644]
readline/examples/Makefile [new file with mode: 0644]
readline/examples/fileman.c [new file with mode: 0644]

diff --git a/readline/doc/Makefile b/readline/doc/Makefile
new file mode 100644 (file)
index 0000000..6ea7eb8
--- /dev/null
@@ -0,0 +1,36 @@
+# This makefile for Readline library documentation is in -*- text -*- mode.
+# Emacs likes it that way.
+
+DVIOBJ = readline.dvi history.dvi
+INFOBJ = readline.info history.info
+
+all: $(DVIOBJ) $(INFOBJ)
+
+readline.dvi: texindex rlman.texinfo rluser.texinfo rltech.texinfo
+       tex rlman.texinfo
+       ./texindex rlman.??
+       tex rlman.texinfo
+       mv rlman.dvi readline.dvi
+
+history.dvi: texindex hist.texinfo hsuser.texinfo hstech.texinfo
+       tex hist.texinfo
+       tex hist.texinfo
+       mv hist.dvi history.dvi
+
+readline.info: rlman.texinfo rluser.texinfo rltech.texinfo
+       makeinfo rlman.texinfo
+
+history.info: hist.texinfo hsuser.texinfo hstech.texinfo
+       makeinfo hist.texinfo
+
+texindex: texindex.o
+       $(CC) -o $@ $(LDFLAGS) $(CFLAGS) $?
+texindex.o: texindex.c
+
+clean:
+       rm -f *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \
+             *.fns *.kys *.tps *.vrs *.o core texindex
+
+squeaky-clean:
+       rm -f *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \
+             *.dvi *.info *.info-* *.fns *.kys *.tps *.vrs *.o core texindex
diff --git a/readline/doc/hist.texinfo b/readline/doc/hist.texinfo
new file mode 100644 (file)
index 0000000..6292738
--- /dev/null
@@ -0,0 +1,106 @@
+\input texinfo    @c -*-texinfo-*-
+@comment %**start of header (This is for running Texinfo on a region.)
+@setfilename history.info
+@settitle GNU Readline Library
+@comment %**end of header (This is for running Texinfo on a region.)
+@synindex vr fn
+@setchapternewpage odd
+
+@ifinfo
+This document describes the GNU History library, a programming tool that
+provides a consistent user interface for recalling lines of previously
+typed input.
+
+Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+pare preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
+
+@titlepage
+@sp 10
+@center @titlefont{GNU History Library}
+@center Brian Fox
+@center Free Software Foundation
+@center Version 1.1
+@center April 1991
+
+@c Include the Distribution inside the titlepage environment so
+@c that headings are turned off. 
+
+@page
+
+This document describes the GNU History library, a programming tool that
+provides a consistent user interface for recalling lines of previously
+typed input.
+
+Published by the Free Software Foundation @*
+675 Massachusetts Avenue, @*
+Cambridge, MA 02139 USA
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+@end titlepage
+
+@ifinfo
+@node Top
+@top GNU History Library
+
+This document describes the GNU History library, a programming tool that
+provides a consistent user interface for recalling lines of previously
+typed input.
+
+@menu
+* Using History Interactively::          GNU History User's Manual.
+* Programming with GNU History::  GNU History Programmer's Manual.
+* Concept Index::                Index of concepts described in this manual.
+* Function and Variable Index::          Index of externally visible functions
+                                 and variables.
+@end menu
+@end ifinfo
+
+@include hsuser.texinfo
+@include hstech.texinfo
+
+@node Concept Index
+@appendix Concept Index
+@printindex cp
+
+@node Function and Variable Index
+@appendix Function and Variable Index
+@printindex vr
+@contents
+
+@bye
diff --git a/readline/doc/history.info b/readline/doc/history.info
new file mode 100644 (file)
index 0000000..df7651d
--- /dev/null
@@ -0,0 +1,514 @@
+Info file history.info, produced by Makeinfo, -*- Text -*- from input
+file hist.texinfo.
+
+   This document describes the GNU History library, a programming tool
+that provides a consistent user interface for recalling lines of
+previously typed input.
+
+   Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+
+   Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+pare preserved on all copies.
+
+   Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+   Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+\1f
+File: history.info,  Node: Top,  Next: Using History Interactively,  Prev: (DIR),  Up: (DIR)
+
+GNU History Library
+*******************
+
+   This document describes the GNU History library, a programming tool
+that provides a consistent user interface for recalling lines of
+previously typed input.
+
+* Menu:
+
+* Using History Interactively::          GNU History User's Manual.
+* Programming with GNU History::  GNU History Programmer's Manual.
+* Concept Index::                Index of concepts described in this manual.
+* Function and Variable Index::          Index of externally visible functions
+                                 and variables.
+
+\1f
+File: history.info,  Node: Using History Interactively,  Next: Programming with GNU History,  Prev: Top,  Up: Top
+
+Using History Interactively
+***************************
+
+   This chapter describes how to use the GNU History Library
+interactively, from a user's standpoint.  It should be considered a
+user's guide.  For information on using the GNU History Library in
+your own programs, *note Programming with GNU History::..
+
+* Menu:
+
+* History Interaction::                What it feels like using History as a user.
+
+\1f
+File: history.info,  Node: History Interaction,  Up: Using History Interactively
+
+History Interaction
+===================
+
+   The History library provides a history expansion feature that is
+similar to the history expansion in Csh.  The following text describes
+the sytax that you use to manipulate the history information.
+
+   History expansion takes place in two parts.  The first is to
+determine which line from the previous history should be used during
+substitution.  The second is to select portions of that line for
+inclusion into the current one.  The line selected from the previous
+history is called the "event", and the portions of that line that are
+acted upon are called "words".  The line is broken into words in the
+same fashion that the Bash shell does, so that several English (or
+Unix) words surrounded by quotes are considered as one word.
+
+* Menu:
+
+* Event Designators::  How to specify which history line to use.
+* Word Designators::   Specifying which words are of interest.
+* Modifiers::          Modifying the results of susbstitution.
+
+\1f
+File: history.info,  Node: Event Designators,  Next: Word Designators,  Up: History Interaction
+
+Event Designators
+-----------------
+
+   An event designator is a reference to a command line entry in the
+history list.
+
+`!'
+     Start a history subsititution, except when followed by a space,
+     tab, or the end of the line... = or (.
+
+`!!'
+     Refer to the previous command.  This is a synonym for `!-1'.
+
+`!n'
+     Refer to command line N.
+
+`!-n'
+     Refer to the command line N lines back.
+
+`!string'
+     Refer to the most recent command starting with STRING.
+
+`!?string'[`?']
+     Refer to the most recent command containing STRING.
+
+\1f
+File: history.info,  Node: Word Designators,  Next: Modifiers,  Prev: Event Designators,  Up: History Interaction
+
+Word Designators
+----------------
+
+   A : separates the event specification from the word designator.  It
+can be omitted if the word designator begins with a ^, $, * or %. 
+Words are numbered from the beginning of the line, with the first word
+being denoted by a 0 (zero).
+
+`0 (zero)'
+     The zero'th word.  For many applications, this is the command
+     word.
+
+`n'
+     The N'th word.
+
+`^'
+     The first argument.  that is, word 1.
+
+`$'
+     The last argument.
+
+`%'
+     The word matched by the most recent `?string?' search.
+
+`x-y'
+     A range of words; `-Y' Abbreviates `0-Y'.
+
+`*'
+     All of the words, excepting the zero'th.  This is a synonym for
+     `1-$'.  It is not an error to use * if there is just one word in
+     the event.  The empty string is returned in that case.
+
+\1f
+File: history.info,  Node: Modifiers,  Prev: Word Designators,  Up: History Interaction
+
+Modifiers
+---------
+
+   After the optional word designator, you can add a sequence of one
+or more of the following modifiers, each preceded by a :.
+
+`#'
+     The entire command line typed so far.  This means the current
+     command, not the previous command, so it really isn't a word
+     designator, and doesn't belong in this section.
+
+`h'
+     Remove a trailing pathname component, leaving only the head.
+
+`r'
+     Remove a trailing suffix of the form `.'SUFFIX, leaving the
+     basename.
+
+`e'
+     Remove all but the suffix.
+
+`t'
+     Remove all leading  pathname  components, leaving the tail.
+
+`p'
+     Print the new command but do not execute it.
+
+\1f
+File: history.info,  Node: Programming with GNU History,  Next: Concept Index,  Prev: Using History Interactively,  Up: Top
+
+Programming with GNU History
+****************************
+
+   This chapter describes how to interface the GNU History Library with
+programs that you write.  It should be considered a technical guide. 
+For information on the interactive use of GNU History, *note Using
+History Interactively::..
+
+* Menu:
+
+* Introduction to History::    What is the GNU History library for?
+* History Storage::            How information is stored.
+* History Functions::          Functions that you can use.
+* History Variables::          Variables that control behaviour.
+* History Programming Example::        Example of using the GNU History Library.
+
+\1f
+File: history.info,  Node: Introduction to History,  Next: History Storage,  Up: Programming with GNU History
+
+Introduction to History
+=======================
+
+   Many programs read input from the user a line at a time.  The GNU
+history library is able to keep track of those lines, associate
+arbitrary data with each line, and utilize information from previous
+lines in making up new ones.
+
+   The programmer using the History library has available to him
+functions for remembering lines on a history stack, associating
+arbitrary data with a line, removing lines from the stack, searching
+through the stack for a line containing an arbitrary text string, and
+referencing any line on the stack directly.  In addition, a history
+"expansion" function is available which provides for a consistent user
+interface across many different programs.
+
+   The end-user using programs written with the History library has the
+benifit of a consistent user interface, with a set of well-known
+commands for manipulating the text of previous lines and using that
+text in new commands.  The basic history manipulation commands are
+similar to the history substitution used by `Csh'.
+
+   If the programmer desires, he can use the Readline library, which
+includes some history manipulation by default, and has the added
+advantage of Emacs style command line editing.
+
+\1f
+File: history.info,  Node: History Storage,  Next: History Functions,  Prev: Introduction to History,  Up: Programming with GNU History
+
+History Storage
+===============
+
+     typedef struct _hist_entry {
+       char *line;
+       char *data;
+     } HIST_ENTRY;
+
+\1f
+File: history.info,  Node: History Functions,  Next: History Variables,  Prev: History Storage,  Up: Programming with GNU History
+
+History Functions
+=================
+
+   This section describes the calling sequence for the various
+functions present in GNU History.
+
+ * Function: void using_history ()
+     Begin a session in which the history functions might be used. 
+     This just initializes the interactive variables.
+
+ * Function: void add_history (CHAR *STRING)
+     Place STRING at the end of the history list.  The associated data
+     field (if any) is set to `NULL'.
+
+ * Function: int where_history ()
+     Returns the number which says what history element we are now
+     looking at.
+
+ * Function: int history_set_pos (INT POS)
+     Set the position in the history list to POS.
+
+ * Function: int history_search_pos (CHAR *STRING, INT DIRECTION, INT
+          POS)
+     Search for STRING in the history list, starting at POS, an
+     absolute index into the list.  DIRECTION, if negative, says to
+     search backwards from POS, else forwards.  Returns the absolute
+     index of the history element where STRING was found, or -1
+     otherwise.
+
+ * Function: HIST_ENTRY *remove_history ();
+     Remove history element WHICH from the history.  The removed
+     element is returned to you so you can free the line, data, and
+     containing structure.
+
+ * Function: void stifle_history (INT MAX)
+     Stifle the history list, remembering only MAX number of entries.
+
+ * Function: int unstifle_history ();
+     Stop stifling the history.  This returns the previous amount the
+     history was stifled by.  The value is positive if the history was
+     stifled, negative if it wasn't.
+
+ * Function: int read_history (CHAR *FILENAME)
+     Add the contents of FILENAME to the history list, a line at a
+     time.  If FILENAME is `NULL', then read from `~/.history'. 
+     Returns 0 if successful, or errno if not.
+
+ * Function: int read_history_range (CHAR *FILENAME, INT FROM, INT TO)
+     Read a range of lines from FILENAME, adding them to the history
+     list.  Start reading at the FROM'th line and end at the TO'th.  If
+     FROM is zero, start at the beginning.  If TO is less than FROM,
+     then read until the end of the file.  If FILENAME is `NULL', then
+     read from `~/.history'.  Returns 0 if successful, or `errno' if
+     not.
+
+ * Function: int write_history (CHAR *FILENAME)
+     Append the current history to FILENAME.  If FILENAME is `NULL',
+     then append the history list to `~/.history'.  Values returned
+     are as in `read_history ()'.
+
+ * Function: int append_history (INT NELEMENTS, CHAR *FILENAME)
+     Append NELEMENT entries to FILENAME.  The entries appended are
+     from the end of the list minus NELEMENTS up to the end of the
+     list.
+
+ * Function: HIST_ENTRY *replace_history_entry ()
+     Make the history entry at WHICH have LINE and DATA.  This returns
+     the old entry so you can dispose of the data.  In the case of an
+     invalid WHICH, a `NULL' pointer is returned.
+
+ * Function: HIST_ENTRY *current_history ()
+     Return the history entry at the current position, as determined by
+     `history_offset'.  If there is no entry there, return a `NULL'
+     pointer.
+
+ * Function: HIST_ENTRY *previous_history ()
+     Back up HISTORY_OFFSET to the previous history entry, and return a
+     pointer to that entry.  If there is no previous entry, return a
+     `NULL' pointer.
+
+ * Function: HIST_ENTRY *next_history ()
+     Move `history_offset' forward to the next history entry, and
+     return the a pointer to that entry.  If there is no next entry,
+     return a `NULL' pointer.
+
+ * Function: HIST_ENTRY **history_list ()
+     Return a `NULL' terminated array of `HIST_ENTRY' which is the
+     current input history.  Element 0 of this list is the beginning
+     of time.  If there is no history, return `NULL'.
+
+ * Function: int history_search (CHAR *STRING, INT DIRECTION)
+     Search the history for STRING, starting at `history_offset'.  If
+     DIRECTION < 0, then the search is through previous entries, else
+     through subsequent.  If STRING is found, then `current_history
+     ()' is the history entry, and the value of this function is the
+     offset in the line of that history entry that the STRING was
+     found in.  Otherwise, nothing is changed, and a -1 is returned.
+
+ * Function: int history_expand (CHAR *STRING, CHAR **OUTPUT)
+     Expand STRING, placing the result into OUTPUT, a pointer to a
+     string.  Returns:
+
+    `0'
+          If no expansions took place (or, if the only change in the
+          text was the de-slashifying of the history expansion
+          character),
+
+    `1'
+          if expansions did take place, or
+
+    `-1'
+          if there was an error in expansion.
+
+          If an error ocurred in expansion, then OUTPUT contains a
+     descriptive error message.
+
+ * Function: char *history_arg_extract (INT FIRST, INT LAST, CHAR
+          *STRING)
+     Extract a string segment consisting of the FIRST through LAST
+     arguments present in STRING.  Arguments are broken up as in the
+     GNU Bash shell.
+
+ * Function: int history_total_bytes ();
+     Return the number of bytes that the primary history entries are
+     using.  This just adds up the lengths of `the_history->lines'.
+
+\1f
+File: history.info,  Node: History Variables,  Next: History Programming Example,  Prev: History Functions,  Up: Programming with GNU History
+
+History Variables
+=================
+
+   This section describes the variables in GNU History that are
+externally visible.
+
+ * Variable: int history_base
+     For convenience only.  You set this when interpreting history
+     commands.  It is the logical offset of the first history element.
+
+\1f
+File: history.info,  Node: History Programming Example,  Prev: History Variables,  Up: Programming with GNU History
+
+History Programming Example
+===========================
+
+   The following snippet of code demonstrates simple use of the GNU
+History Library.
+
+     main ()
+     {
+       char line[1024], *t;
+       int done = 0;
+     
+       line[0] = 0;
+     
+       while (!done)
+         {
+           fprintf (stdout, "history%% ");
+           t = gets (line);
+     
+           if (!t)
+             strcpy (line, "quit");
+     
+           if (line[0])
+             {
+               char *expansion;
+               int result;
+     
+               using_history ();
+     
+               result = history_expand (line, &expansion);
+               strcpy (line, expansion);
+               free (expansion);
+               if (result)
+                 fprintf (stderr, "%s\n", line);
+     
+               if (result < 0)
+                 continue;
+     
+               add_history (line);
+             }
+     
+           if (strcmp (line, "quit") == 0) done = 1;
+           if (strcmp (line, "save") == 0) write_history (0);
+           if (strcmp (line, "read") == 0) read_history (0);
+           if (strcmp (line, "list") == 0)
+             {
+               register HIST_ENTRY **the_list = history_list ();
+               register int i;
+     
+               if (the_list)
+                 for (i = 0; the_list[i]; i++)
+                   fprintf (stdout, "%d: %s\n",
+                      i + history_base, the_list[i]->line);
+             }
+           if (strncmp (line, "delete", strlen ("delete")) == 0)
+             {
+               int which;
+               if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1)
+                 {
+                   HIST_ENTRY *entry = remove_history (which);
+                   if (!entry)
+                     fprintf (stderr, "No such entry %d\n", which);
+                   else
+                     {
+                       free (entry->line);
+                       free (entry);
+                     }
+                 }
+               else
+                 {
+                   fprintf (stderr, "non-numeric arg given to `delete'\n");
+                 }
+             }
+         }
+     }
+
+\1f
+File: history.info,  Node: Concept Index,  Next: Function and Variable Index,  Prev: Programming with GNU History,  Up: Top
+
+Concept Index
+*************
+
+* Menu:
+
+* event designators:                    Event Designators.
+* expansion:                            History Interaction.
+
+\1f
+File: history.info,  Node: Function and Variable Index,  Prev: Concept Index,  Up: Top
+
+Function and Variable Index
+***************************
+
+* Menu:
+
+* HIST_ENTRY **history_list:            History Functions.
+* HIST_ENTRY *current_history:          History Functions.
+* HIST_ENTRY *next_history:             History Functions.
+* HIST_ENTRY *previous_history:         History Functions.
+* HIST_ENTRY *remove_history:           History Functions.
+* HIST_ENTRY *replace_history_entry:    History Functions.
+* char *history_arg_extract:            History Functions.
+* int append_history:                   History Functions.
+* int history_base:                     History Variables.
+* int history_expand:                   History Functions.
+* int history_search:                   History Functions.
+* int history_search_pos:               History Functions.
+* int history_set_pos:                  History Functions.
+* int history_total_bytes:              History Functions.
+* int read_history:                     History Functions.
+* int read_history_range:               History Functions.
+* int unstifle_history:                 History Functions.
+* int where_history:                    History Functions.
+* int write_history:                    History Functions.
+* void add_history:                     History Functions.
+* void stifle_history:                  History Functions.
+* void using_history:                   History Functions.
+
+
+\1f
+Tag Table:
+Node: Top\7f973
+Node: Using History Interactively\7f1567
+Node: History Interaction\7f2075
+Node: Event Designators\7f3127
+Node: Word Designators\7f3770
+Node: Modifiers\7f4676
+Node: Programming with GNU History\7f5425
+Node: Introduction to History\7f6152
+Node: History Storage\7f7502
+Node: History Functions\7f7766
+Node: History Variables\7f13063
+Node: History Programming Example\7f13499
+Node: Concept Index\7f15744
+Node: Function and Variable Index\7f16030
+\1f
+End Tag Table
diff --git a/readline/doc/hstech.texinfo b/readline/doc/hstech.texinfo
new file mode 100644 (file)
index 0000000..c3fe3f6
--- /dev/null
@@ -0,0 +1,311 @@
+@ignore
+This file documents the user interface to the GNU History library.
+
+Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+Authored by Brian Fox.
+
+Permission is granted to make and distribute verbatim copies of this manual
+provided the copyright notice and this permission notice are preserved on
+all copies.
+
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission notice
+identical to this one except for the removal of this paragraph (this
+paragraph not being relevant to the printed manual).
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+GNU Copyright statement is available to the distributee, and provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ignore
+
+@node Programming with GNU History
+@chapter Programming with GNU History
+
+This chapter describes how to interface the GNU History Library with
+programs that you write.  It should be considered a technical guide.
+For information on the interactive use of GNU History, @pxref{Using
+History Interactively}.
+
+@menu
+* Introduction to History::    What is the GNU History library for?
+* History Storage::            How information is stored.
+* History Functions::          Functions that you can use.
+* History Variables::          Variables that control behaviour.
+* History Programming Example::        Example of using the GNU History Library.
+@end menu
+
+@node Introduction to History
+@section Introduction to History
+
+Many programs read input from the user a line at a time.  The GNU history
+library is able to keep track of those lines, associate arbitrary data with
+each line, and utilize information from previous lines in making up new
+ones.
+
+The programmer using the History library has available to him functions
+for remembering lines on a history stack, associating arbitrary data
+with a line, removing lines from the stack, searching through the stack
+for a line containing an arbitrary text string, and referencing any line
+on the stack directly.  In addition, a history @dfn{expansion} function
+is available which provides for a consistent user interface across many
+different programs.
+
+The end-user using programs written with the History library has the
+benifit of a consistent user interface, with a set of well-known
+commands for manipulating the text of previous lines and using that text
+in new commands.  The basic history manipulation commands are similar to
+the history substitution used by @code{Csh}.
+
+If the programmer desires, he can use the Readline library, which
+includes some history manipulation by default, and has the added
+advantage of Emacs style command line editing.
+
+@node History Storage
+@section History Storage
+
+@example
+typedef struct _hist_entry @{
+  char *line;
+  char *data;
+@} HIST_ENTRY;
+@end example
+
+@node History Functions
+@section History Functions
+
+This section describes the calling sequence for the various functions
+present in GNU History.
+
+@defun {void using_history} ()
+Begin a session in which the history functions might be used.  This
+just initializes the interactive variables.
+@end defun
+
+@defun {void add_history} (char *string)
+Place @var{string} at the end of the history list.  The associated data
+field (if any) is set to @code{NULL}.
+@end defun
+
+@defun {int where_history} ()
+Returns the number which says what history element we are now looking
+at.
+@end defun
+  
+@defun {int history_set_pos} (int pos)
+Set the position in the history list to @var{pos}.
+@end defun
+
+@defun {int history_search_pos} (char *string, int direction, int pos)
+Search for @var{string} in the history list, starting at @var{pos}, an
+absolute index into the list.  @var{direction}, if negative, says to search
+backwards from @var{pos}, else forwards.  Returns the absolute index of
+the history element where @var{string} was found, or -1 otherwise.
+@end defun
+
+@defun {HIST_ENTRY *remove_history} ();
+Remove history element @var{which} from the history.  The removed
+element is returned to you so you can free the line, data,
+and containing structure.
+@end defun
+
+@defun {void stifle_history} (int max)
+Stifle the history list, remembering only @var{max} number of entries.
+@end defun
+
+@defun {int unstifle_history} ();
+Stop stifling the history.  This returns the previous amount the
+history was stifled by.  The value is positive if the history was
+stifled, negative if it wasn't.
+@end defun
+
+@defun {int read_history} (char *filename)
+Add the contents of @var{filename} to the history list, a line at a
+time.  If @var{filename} is @code{NULL}, then read from
+@file{~/.history}.  Returns 0 if successful, or errno if not.
+@end defun
+
+@defun {int read_history_range} (char *filename, int from, int to)
+Read a range of lines from @var{filename}, adding them to the history list.
+Start reading at the @var{from}'th line and end at the @var{to}'th.  If
+@var{from} is zero, start at the beginning.  If @var{to} is less than
+@var{from}, then read until the end of the file.  If @var{filename} is
+@code{NULL}, then read from @file{~/.history}.  Returns 0 if successful,
+or @code{errno} if not.
+@end defun
+
+@defun {int write_history} (char *filename)
+Append the current history to @var{filename}.  If @var{filename} is
+@code{NULL}, then append the history list to @file{~/.history}.  Values
+returned are as in @code{read_history ()}.
+@end defun
+
+@defun {int append_history} (int nelements, char *filename)
+Append @var{nelement} entries to @var{filename}.  The entries appended
+are from the end of the list minus @var{nelements} up to the end of the
+list.
+@end defun
+
+@defun {HIST_ENTRY *replace_history_entry} ()
+Make the history entry at @var{which} have @var{line} and @var{data}.
+This returns the old entry so you can dispose of the data.  In the case
+of an invalid @var{which}, a @code{NULL} pointer is returned.
+@end defun
+
+@defun {HIST_ENTRY *current_history} ()
+Return the history entry at the current position, as determined by
+@code{history_offset}.  If there is no entry there, return a @code{NULL}
+pointer.
+@end defun
+
+@defun {HIST_ENTRY *previous_history} ()
+Back up @var{history_offset} to the previous history entry, and return a
+pointer to that entry.  If there is no previous entry, return a
+@code{NULL} pointer.
+@end defun
+
+@defun {HIST_ENTRY *next_history} ()
+Move @code{history_offset} forward to the next history entry, and return
+the a pointer to that entry.  If there is no next entry, return a
+@code{NULL} pointer.
+@end defun
+
+@defun {HIST_ENTRY **history_list} ()
+Return a @code{NULL} terminated array of @code{HIST_ENTRY} which is the
+current input history.  Element 0 of this list is the beginning of time.
+If there is no history, return @code{NULL}.
+@end defun
+
+@defun {int history_search} (char *string, int direction)
+Search the history for @var{string}, starting at @code{history_offset}.
+If @var{direction} < 0, then the search is through previous entries,
+else through subsequent.  If @var{string} is found, then
+@code{current_history ()} is the history entry, and the value of this
+function is the offset in the line of that history entry that the
+@var{string} was found in.  Otherwise, nothing is changed, and a -1 is
+returned.
+@end defun
+
+@defun {int history_expand} (char *string, char **output)
+Expand @var{string}, placing the result into @var{output}, a pointer
+to a string.  Returns:
+@table @code
+@item 0
+If no expansions took place (or, if the only change in
+the text was the de-slashifying of the history expansion
+character),
+@item 1
+if expansions did take place, or
+@item -1
+if there was an error in expansion.
+@end table
+
+If an error ocurred in expansion, then @var{output} contains a descriptive
+error message.
+@end defun
+
+@defun {char *history_arg_extract} (int first, int last, char *string)
+Extract a string segment consisting of the @var{first} through @var{last}
+arguments present in @var{string}.  Arguments are broken up as in
+the GNU Bash shell.
+@end defun
+
+@defun {int history_total_bytes} ();
+Return the number of bytes that the primary history entries are using.
+This just adds up the lengths of @code{the_history->lines}.
+@end defun
+
+@node History Variables
+@section History Variables
+
+This section describes the variables in GNU History that are externally
+visible.
+
+@defvar {int history_base}
+For convenience only.  You set this when interpreting history commands.
+It is the logical offset of the first history element.
+@end defvar
+
+@node History Programming Example
+@section History Programming Example
+
+The following snippet of code demonstrates simple use of the GNU History
+Library.
+
+@smallexample
+main ()
+@{
+  char line[1024], *t;
+  int done = 0;
+
+  line[0] = 0;
+
+  while (!done)
+    @{
+      fprintf (stdout, "history%% ");
+      t = gets (line);
+
+      if (!t)
+        strcpy (line, "quit");
+
+      if (line[0])
+        @{
+          char *expansion;
+          int result;
+
+          using_history ();
+
+          result = history_expand (line, &expansion);
+          strcpy (line, expansion);
+          free (expansion);
+          if (result)
+            fprintf (stderr, "%s\n", line);
+
+          if (result < 0)
+            continue;
+
+          add_history (line);
+        @}
+
+      if (strcmp (line, "quit") == 0) done = 1;
+      if (strcmp (line, "save") == 0) write_history (0);
+      if (strcmp (line, "read") == 0) read_history (0);
+      if (strcmp (line, "list") == 0)
+        @{
+          register HIST_ENTRY **the_list = history_list ();
+          register int i;
+
+          if (the_list)
+            for (i = 0; the_list[i]; i++)
+              fprintf (stdout, "%d: %s\n",
+                 i + history_base, the_list[i]->line);
+        @}
+      if (strncmp (line, "delete", strlen ("delete")) == 0)
+        @{
+          int which;
+          if ((sscanf (line + strlen ("delete"), "%d", &which)) == 1)
+            @{
+              HIST_ENTRY *entry = remove_history (which);
+              if (!entry)
+                fprintf (stderr, "No such entry %d\n", which);
+              else
+                @{
+                  free (entry->line);
+                  free (entry);
+                @}
+            @}
+          else
+            @{
+              fprintf (stderr, "non-numeric arg given to `delete'\n");
+            @}
+        @}
+    @}
+@}
+@end smallexample
+
+
+
diff --git a/readline/doc/hsuser.texinfo b/readline/doc/hsuser.texinfo
new file mode 100644 (file)
index 0000000..cda0a68
--- /dev/null
@@ -0,0 +1,153 @@
+@ignore
+This file documents the user interface to the GNU History library.
+
+Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+Authored by Brian Fox.
+
+Permission is granted to make and distribute verbatim copies of this manual
+provided the copyright notice and this permission notice are preserved on
+all copies.
+
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission notice
+identical to this one except for the removal of this paragraph (this
+paragraph not being relevant to the printed manual).
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+GNU Copyright statement is available to the distributee, and provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ignore
+
+@node Using History Interactively
+@chapter Using History Interactively
+
+This chapter describes how to use the GNU History Library interactively,
+from a user's standpoint.  It should be considered a user's guide.  For
+information on using the GNU History Library in your own programs,
+@pxref{Programming with GNU History}.
+
+@menu
+* History Interaction::                What it feels like using History as a user.
+@end menu
+
+@node History Interaction
+@section History Interaction
+@cindex expansion
+
+The History library provides a history expansion feature that is similar
+to the history expansion in Csh.  The following text describes the sytax
+that you use to manipulate the history information.
+
+History expansion takes place in two parts.  The first is to determine
+which line from the previous history should be used during substitution.
+The second is to select portions of that line for inclusion into the
+current one.  The line selected from the previous history is called the
+@dfn{event}, and the portions of that line that are acted upon are
+called @dfn{words}.  The line is broken into words in the same fashion
+that the Bash shell does, so that several English (or Unix) words
+surrounded by quotes are considered as one word.
+
+@menu
+* Event Designators::  How to specify which history line to use.
+* Word Designators::   Specifying which words are of interest.
+* Modifiers::          Modifying the results of susbstitution.
+@end menu
+
+@node Event Designators
+@subsection Event Designators
+@cindex event designators
+
+An event designator is a reference to a command line entry in the
+history list.
+
+@table @asis
+
+@item @code{!}
+Start a history subsititution, except when followed by a space, tab, or
+the end of the line... @key{=} or @key{(}.
+
+@item @code{!!}
+Refer to the previous command.  This is a synonym for @code{!-1}.
+
+@item @code{!n}
+Refer to command line @var{n}.
+
+@item @code{!-n}
+Refer to the command line @var{n} lines back.
+
+@item @code{!string}
+Refer to the most recent command starting with @var{string}.
+
+@item @code{!?string}[@code{?}]
+Refer to the most recent command containing @var{string}.
+
+@end table
+
+@node Word Designators
+@subsection Word Designators
+
+A @key{:} separates the event specification from the word designator.  It
+can be omitted if the word designator begins with a @key{^}, @key{$},
+@key{*} or @key{%}.  Words are numbered from the beginning of the line,
+with the first word being denoted by a 0 (zero).
+
+@table @code
+
+@item 0 (zero)
+The zero'th word.  For many applications, this is the command word.
+
+@item n
+The @var{n}'th word.
+
+@item ^
+The first argument.  that is, word 1.
+
+@item $
+The last argument.
+
+@item %
+The word matched by the most recent @code{?string?} search.
+
+@item x-y
+A range of words; @code{-@var{y}} Abbreviates @code{0-@var{y}}.
+
+@item *
+All of the words, excepting the zero'th.  This is a synonym for @code{1-$}.
+It is not an error to use @key{*} if there is just one word in the event.
+The empty string is returned in that case.
+
+@end table
+
+@node Modifiers
+@subsection Modifiers
+
+After the optional word designator, you can add a sequence of one or more
+of the following modifiers, each preceded by a @key{:}.
+
+@table @code
+
+@item #
+The entire command line typed so far.  This means the current command,
+not the previous command, so it really isn't a word designator, and doesn't
+belong in this section.
+
+@item h
+Remove a trailing pathname component, leaving only the head.
+
+@item r
+Remove a trailing suffix of the form @samp{.}@var{suffix}, leaving the basename.
+
+@item e
+Remove all but the suffix.
+
+@item t
+Remove all leading  pathname  components, leaving the tail.
+
+@item p
+Print the new command but do not execute it.
+@end table
diff --git a/readline/doc/readline.info b/readline/doc/readline.info
new file mode 100644 (file)
index 0000000..a93489f
--- /dev/null
@@ -0,0 +1,1720 @@
+Info file readline.info, produced by Makeinfo, -*- Text -*- from input
+file rlman.texinfo.
+
+   This document describes the GNU Readline Library, a utility which
+aids in the consistency of user interface across discrete programs
+that need to provide a command line interface.
+
+   Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+
+   Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+pare preserved on all copies.
+
+   Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+   Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+\1f
+File: readline.info,  Node: Top,  Next: Command Line Editing,  Prev: (DIR),  Up: (DIR)
+
+GNU Readline Library
+********************
+
+   This document describes the GNU Readline Library, a utility which
+aids in the consistency of user interface across discrete programs
+that need to provide a command line interface.
+
+* Menu:
+
+* Command Line Editing::          GNU Readline User's Manual.
+* Programming with GNU Readline::  GNU Readline Programmer's Manual.
+* Concept Index::                 Index of concepts described in this manual.
+* Function and Variable Index::           Index of externally visible functions
+                                  and variables.
+
+\1f
+File: readline.info,  Node: Command Line Editing,  Next: Programming with GNU Readline,  Prev: Top,  Up: Top
+
+Command Line Editing
+********************
+
+   This text describes GNU's command line editing interface.
+
+* Menu:
+
+* Introduction and Notation::  Notation used in this text.
+* Readline Interaction::       The minimum set of commands for editing a line.
+* Readline Init File::         Customizing Readline from a user's view.
+
+\1f
+File: readline.info,  Node: Introduction and Notation,  Next: Readline Interaction,  Up: Command Line Editing
+
+Introduction to Line Editing
+============================
+
+   The following paragraphs describe the notation we use to represent
+keystrokes.
+
+   The text C-k is read as `Control-K' and describes the character
+produced when the Control key is depressed and the k key is struck.
+
+   The text M-k is read as `Meta-K' and describes the character
+produced when the meta key (if you have one) is depressed, and the k
+key is struck.  If you do not have a meta key, the identical keystroke
+can be generated by typing ESC first, and then typing k.  Either
+process is known as "metafying" the k key.
+
+   The text M-C-k is read as `Meta-Control-k' and describes the
+character produced by "metafying" C-k.
+
+   In addition, several keys have their own names.  Specifically, DEL,
+ESC, LFD, SPC, RET, and TAB all stand for themselves when seen in this
+text, or in an init file (*note Readline Init File::., for more info).
+
+\1f
+File: readline.info,  Node: Readline Interaction,  Next: Readline Init File,  Prev: Introduction and Notation,  Up: Command Line Editing
+
+Readline Interaction
+====================
+
+   Often during an interactive session you type in a long line of text,
+only to notice that the first word on the line is misspelled.  The
+Readline library gives you a set of commands for manipulating the text
+as you type it in, allowing you to just fix your typo, and not forcing
+you to retype the majority of the line.  Using these editing commands,
+you move the cursor to the place that needs correction, and delete or
+insert the text of the corrections.  Then, when you are satisfied with
+the line, you simply press RETURN.  You do not have to be at the end
+of the line to press RETURN; the entire line is accepted regardless of
+the location of the cursor within the line.
+
+* Menu:
+
+* Readline Bare Essentials::   The least you need to know about Readline.
+* Readline Movement Commands:: Moving about the input line.
+* Readline Killing Commands::  How to delete text, and how to get it back!
+* Readline Arguments::         Giving numeric arguments to commands.
+
+\1f
+File: readline.info,  Node: Readline Bare Essentials,  Next: Readline Movement Commands,  Up: Readline Interaction
+
+Readline Bare Essentials
+------------------------
+
+   In order to enter characters into the line, simply type them.  The
+typed character appears where the cursor was, and then the cursor
+moves one space to the right.  If you mistype a character, you can use
+DEL to back up, and delete the mistyped character.
+
+   Sometimes you may miss typing a character that you wanted to type,
+and not notice your error until you have typed several other
+characters.  In that case, you can type C-b to move the cursor to the
+left, and then correct your mistake.  Aftwerwards, you can move the
+cursor to the right with C-f.
+
+   When you add text in the middle of a line, you will notice that
+characters to the right of the cursor get `pushed over' to make room
+for the text that you have inserted.  Likewise, when you delete text
+behind the cursor, characters to the right of the cursor get `pulled
+back' to fill in the blank space created by the removal of the text. 
+A list of the basic bare essentials for editing the text of an input
+line follows.
+
+C-b
+     Move back one character.
+
+C-f
+     Move forward one character.
+
+DEL
+     Delete the character to the left of the cursor.
+
+C-d
+     Delete the character underneath the cursor.
+
+Printing characters
+     Insert itself into the line at the cursor.
+
+C-_
+     Undo the last thing that you did.  You can undo all the way back
+     to an empty line.
+
+\1f
+File: readline.info,  Node: Readline Movement Commands,  Next: Readline Killing Commands,  Prev: Readline Bare Essentials,  Up: Readline Interaction
+
+Readline Movement Commands
+--------------------------
+
+   The above table describes the most basic possible keystrokes that
+you need in order to do editing of the input line.  For your
+convenience, many other commands have been added in addition to C-b,
+C-f, C-d, and DEL.  Here are some commands for moving more rapidly
+about the line.
+
+C-a
+     Move to the start of the line.
+
+C-e
+     Move to the end of the line.
+
+M-f
+     Move forward a word.
+
+M-b
+     Move backward a word.
+
+C-l
+     Clear the screen, reprinting the current line at the top.
+
+   Notice how C-f moves forward a character, while M-f moves forward a
+word.  It is a loose convention that control keystrokes operate on
+characters while meta keystrokes operate on words.
+
+\1f
+File: readline.info,  Node: Readline Killing Commands,  Next: Readline Arguments,  Prev: Readline Movement Commands,  Up: Readline Interaction
+
+Readline Killing Commands
+-------------------------
+
+   The act of "cutting" text means to delete the text from the line,
+and to save away the deleted text for later use, just as if you had
+cut the text out of the line with a pair of scissors.  There is a
+
+   "Killing" text means to delete the text from the line, but to save
+it away for later use, usually by "yanking" it back into the line.  If
+the description for a command says that it `kills' text, then you can
+be sure that you can get the text back in a different (or the same)
+place later.
+
+   Here is the list of commands for killing text.
+
+C-k
+     Kill the text from the current cursor position to the end of the
+     line.
+
+M-d
+     Kill from the cursor to the end of the current word, or if between
+     words, to the end of the next word.
+
+M-DEL
+     Kill fromthe cursor the start of the previous word, or if between
+     words, to the start of the previous word.
+
+C-w
+     Kill from the cursor to the previous whitespace.  This is
+     different than M-DEL because the word boundaries differ.
+
+   And, here is how to "yank" the text back into the line.  Yanking is
+
+C-y
+     Yank the most recently killed text back into the buffer at the
+     cursor.
+
+M-y
+     Rotate the kill-ring, and yank the new top.  You can only do this
+     if the prior command is C-y or M-y.
+
+   When you use a kill command, the text is saved in a "kill-ring". 
+Any number of consecutive kills save all of the killed text together,
+so that when you yank it back, you get it in one clean sweep.  The kill
+ring is not line specific; the text that you killed on a previously
+typed line is available to be yanked back later, when you are typing
+another line.
+
+\1f
+File: readline.info,  Node: Readline Arguments,  Prev: Readline Killing Commands,  Up: Readline Interaction
+
+Readline Arguments
+------------------
+
+   You can pass numeric arguments to Readline commands.  Sometimes the
+argument acts as a repeat count, other times it is the sign of the
+argument that is significant.  If you pass a negative argument to a
+command which normally acts in a forward direction, that command will
+act in a backward direction.  For example, to kill text back to the
+start of the line, you might type M-- C-k.
+
+   The general way to pass numeric arguments to a command is to type
+meta digits before the command.  If the first `digit' you type is a
+minus sign (-), then the sign of the argument will be negative.  Once
+you have typed one meta digit to get the argument started, you can type
+the remainder of the digits, and then the command.  For example, to
+give the C-d command an argument of 10, you could type M-1 0 C-d.
+
+\1f
+File: readline.info,  Node: Readline Init File,  Prev: Readline Interaction,  Up: Command Line Editing
+
+Readline Init File
+==================
+
+   Although the Readline library comes with a set of Emacs-like
+keybindings, it is possible that you would like to use a different set
+of keybindings.  You can customize programs that use Readline by
+putting commands in an "init" file in your home directory.  The name
+of this file is `~/.inputrc'.
+
+   When a program which uses the Readline library starts up, the
+`~/.inputrc' file is read, and the keybindings are set.
+
+   In addition, the `C-x C-r' command re-reads this init file, thus
+incorporating any changes that you might have made to it.
+
+* Menu:
+
+* Readline Init Syntax::       Syntax for the commands in `~/.inputrc'.
+* Readline Vi Mode::           Switching to `vi' mode in Readline.
+
+\1f
+File: readline.info,  Node: Readline Init Syntax,  Next: Readline Vi Mode,  Up: Readline Init File
+
+Readline Init Syntax
+--------------------
+
+   There are only four constructs allowed in the `~/.inputrc' file:
+
+Variable Settings
+     You can change the state of a few variables in Readline.  You do
+     this by using the `set' command within the init file.  Here is
+     how you would specify that you wish to use Vi line editing
+     commands:
+
+          set editing-mode vi
+
+          Right now, there are only a few variables which can be set; so
+     few in fact, that we just iterate them here:
+
+    `editing-mode'
+          The `editing-mode' variable controls which editing mode you
+          are using.  By default, GNU Readline starts up in Emacs
+          editing mode, where the keystrokes are most similar to
+          Emacs.  This variable can either be set to `emacs' or `vi'.
+
+    `horizontal-scroll-mode'
+          This variable can either be set to `On' or `Off'.  Setting it
+          to `On' means that the text of the lines that you edit will
+          scroll horizontally on a single screen line when they are
+          larger than the width of the screen, instead of wrapping
+          onto a new screen line.  By default, this variable is set to
+          `Off'.
+
+    `mark-modified-lines'
+          This variable when set to `On', says to display an asterisk
+          (`*') at the starts of history lines which have been
+          modified.  This variable is off by default.
+
+    `prefer-visible-bell'
+          If this variable is set to `On' it means to use a visible
+          bell if one is available, rather than simply ringing the
+          terminal bell.  By default, the value is `Off'.
+
+Key Bindings
+     The syntax for controlling keybindings in the `~/.inputrc' file is
+     simple.  First you have to know the name of the command that you
+     want to change.  The following pages contain tables of the
+     command name, the default keybinding, and a short description of
+     what the command does.
+
+     Once you know the name of the command, simply place the name of
+     the key you wish to bind the command to, a colon, and then the
+     name of the command on a line in the `~/.inputrc' file.  The name
+     of the key can be expressed in different ways, depending on which
+     is most comfortable for you.
+
+    KEYNAME: FUNCTION-NAME or MACRO
+          KEYNAME is the name of a key spelled out in English.  For
+          example:
+
+               Control-u: universal-argument
+               Meta-Rubout: backward-kill-word
+               Control-o: ">&output"
+
+                    In the above example, `C-u' is bound to the function
+          `universal-argument', and `C-o' is bound to run the macro
+          expressed on the right hand side (that is, to insert the text
+          `>&output' into the line).
+
+    "KEYSEQ": FUNCTION-NAME or MACRO
+          KEYSEQ differs from KEYNAME above in that strings denoting
+          an entire key sequence can be specified.  Simply place the
+          key sequence in double quotes.  GNU Emacs style key escapes
+          can be used, as in the following example:
+
+               "\C-u": universal-argument
+               "\C-x\C-r": re-read-init-file
+               "\e[11~": "Function Key 1"
+
+                    In the above example, `C-u' is bound to the function
+          `universal-argument' (just as it was in the first example),
+          `C-x C-r' is bound to the function `re-read-init-file', and
+          `ESC [ 1 1 ~' is bound to insert the text `Function Key 1'.
+
+* Menu:
+
+* Commands For Moving::                Moving about the line.
+* Commands For History::       Getting at previous lines.
+* Commands For Text::          Commands for changing text.
+* Commands For Killing::       Commands for killing and yanking.
+* Numeric Arguments::          Specifying numeric arguments, repeat counts.
+* Commands For Completion::    Getting Readline to do the typing for you.
+* Miscellaneous Commands::     Other miscillaneous commands.
+
+\1f
+File: readline.info,  Node: Commands For Moving,  Next: Commands For History,  Up: Readline Init Syntax
+
+Commands For Moving
+...................
+
+`beginning-of-line (C-a)'
+     Move to the start of the current line.
+
+`end-of-line (C-e)'
+     Move to the end of the line.
+
+`forward-char (C-f)'
+     Move forward a character.
+
+`backward-char (C-b)'
+     Move back a character.
+
+`forward-word (M-f)'
+     Move forward to the end of the next word.
+
+`backward-word (M-b)'
+     Move back to the start of this, or the previous, word.
+
+`clear-screen (C-l)'
+     Clear the screen leaving the current line at the top of the
+     screen.
+
+\1f
+File: readline.info,  Node: Commands For History,  Next: Commands For Text,  Prev: Commands For Moving,  Up: Readline Init Syntax
+
+Commands For Manipulating The History
+.....................................
+
+`accept-line (Newline, Return)'
+     Accept the line regardless of where the cursor is.  If this line
+     is non-empty, add it to the history list.  If this line was a
+     history line, then restore the history line to its original state.
+
+`previous-history (C-p)'
+     Move `up' through the history list.
+
+`next-history (C-n)'
+     Move `down' through the history list.
+
+`beginning-of-history (M-<)'
+     Move to the first line in the history.
+
+`end-of-history (M->)'
+     Move to the end of the input history, i.e., the line you are
+     entering!
+
+`reverse-search-history (C-r)'
+     Search backward starting at the current line and moving `up'
+     through the history as necessary.  This is an incremental search.
+
+`forward-search-history (C-s)'
+     Search forward starting at the current line and moving `down'
+     through the the history as neccessary.
+
+\1f
+File: readline.info,  Node: Commands For Text,  Next: Commands For Killing,  Prev: Commands For History,  Up: Readline Init Syntax
+
+Commands For Changing Text
+..........................
+
+`delete-char (C-d)'
+     Delete the character under the cursor.  If the cursor is at the
+     beginning of the line, and there are no characters in the line,
+     and the last character typed was not C-d, then return EOF.
+
+`backward-delete-char (Rubout)'
+     Delete the character behind the cursor.  A numeric arg says to
+     kill the characters instead of deleting them.
+
+`quoted-insert (C-q, C-v)'
+     Add the next character that you type to the line verbatim.  This
+     is how to insert things like C-q for example.
+
+`tab-insert (M-TAB)'
+     Insert a tab character.
+
+`self-insert (a, b, A, 1, !, ...)'
+     Insert yourself.
+
+`transpose-chars (C-t)'
+     Drag the character before point forward over the character at
+     point.  Point moves forward as well.  If point is at the end of
+     the line, then transpose the two characters before point. 
+     Negative args don't work.
+
+`transpose-words (M-t)'
+     Drag the word behind the cursor past the word in front of the
+     cursor moving the cursor over that word as well.
+
+`upcase-word (M-u)'
+     Uppercase the current (or following) word.  With a negative
+     argument, do the previous word, but do not move point.
+
+`downcase-word (M-l)'
+     Lowercase the current (or following) word.  With a negative
+     argument, do the previous word, but do not move point.
+
+`capitalize-word (M-c)'
+     Uppercase the current (or following) word.  With a negative
+     argument, do the previous word, but do not move point.
+
+\1f
+File: readline.info,  Node: Commands For Killing,  Next: Numeric Arguments,  Prev: Commands For Text,  Up: Readline Init Syntax
+
+Killing And Yanking
+...................
+
+`kill-line (C-k)'
+     Kill the text from the current cursor position to the end of the
+     line.
+
+`backward-kill-line ()'
+     Kill backward to the beginning of the line.  This is normally
+     unbound.
+
+`kill-word (M-d)'
+     Kill from the cursor to the end of the current word, or if between
+     words, to the end of the next word.
+
+`backward-kill-word (M-DEL)'
+     Kill the word behind the cursor.
+
+`unix-line-discard (C-u)'
+     Do what C-u used to do in Unix line input.  We save the killed
+     text on the kill-ring, though.
+
+`unix-word-rubout (C-w)'
+     Do what C-w used to do in Unix line input.  The killed text is
+     saved on the kill-ring.  This is different than
+     backward-kill-word because the word boundaries differ.
+
+`yank (C-y)'
+     Yank the top of the kill ring into the buffer at point.
+
+`yank-pop (M-y)'
+     Rotate the kill-ring, and yank the new top.  You can only do this
+     if the prior command is yank or yank-pop.
+
+\1f
+File: readline.info,  Node: Numeric Arguments,  Next: Commands For Completion,  Prev: Commands For Killing,  Up: Readline Init Syntax
+
+Specifying Numeric Arguments
+............................
+
+`digit-argument (M-0, M-1, ... M--)'
+     Add this digit to the argument already accumulating, or start a
+     new argument.  M-- starts a negative argument.
+
+`universal-argument ()'
+     Do what C-u does in emacs.  By default, this is not bound.
+
+\1f
+File: readline.info,  Node: Commands For Completion,  Next: Miscellaneous Commands,  Prev: Numeric Arguments,  Up: Readline Init Syntax
+
+Letting Readline Type For You
+.............................
+
+`complete (TAB)'
+     Attempt to do completion on the text before point.  This is
+     implementation defined.  Generally, if you are typing a filename
+     argument, you can do filename completion; if you are typing a
+     command, you can do command completion, if you are typing in a
+     symbol to GDB, you can do symbol name completion, if you are
+     typing in a variable to Bash, you can do variable name
+     completion...
+
+`possible-completions (M-?)'
+     List the possible completions of the text before point.
+
+\1f
+File: readline.info,  Node: Miscellaneous Commands,  Prev: Commands For Completion,  Up: Readline Init Syntax
+
+Some Miscellaneous Commands
+...........................
+
+`re-read-init-file (C-x C-r)'
+     Read in the contents of your `~/.inputrc' file, and incorporate
+     any bindings found there.
+
+`abort (C-g)'
+     Ding!  Stops things.
+
+`do-uppercase-version (M-a, M-b, ...)'
+     Run the command that is bound to your uppercase brother.
+
+`prefix-meta (ESC)'
+     Make the next character that you type be metafied.  This is for
+     people without a meta key.  Typing `ESC f' is equivalent to typing
+     `M-f'.
+
+`undo (C-_)'
+     Incremental undo, separately remembered for each line.
+
+`revert-line (M-r)'
+     Undo all changes made to this line.  This is like typing the
+     `undo' command enough times to get back to the beginning.
+
+\1f
+File: readline.info,  Node: Readline Vi Mode,  Prev: Readline Init Syntax,  Up: Readline Init File
+
+Readline Vi Mode
+----------------
+
+   While the Readline library does not have a full set of Vi editing
+functions, it does contain enough to allow simple editing of the line.
+
+   In order to switch interactively between Emacs and Vi editing
+modes, use the command M-C-j (toggle-editing-mode).
+
+   When you enter a line in Vi mode, you are already placed in
+`insertion' mode, as if you had typed an `i'.  Pressing ESC switches
+you into `edit' mode, where you can edit the text of the line with the
+standard Vi movement keys, move to previous history lines with `k',
+and following lines with `j', and so forth.
+
+   This document describes the GNU Readline Library, a utility for
+aiding in the consitency of user interface across discrete programs
+that need to provide a command line interface.
+
+   Copyright (C) 1988 Free Software Foundation, Inc.
+
+   Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+pare preserved on all copies.
+
+   Permission is granted to copy and distribute modified versions of
+this manual under the conditions for verbatim copying, provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+   Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be stated in a
+translation approved by the Foundation.
+
+\1f
+File: readline.info,  Node: Programming with GNU Readline,  Next: Concept Index,  Prev: Command Line Editing,  Up: Top
+
+Programming with GNU Readline
+*****************************
+
+   This manual describes the interface between the GNU Readline
+Library and user programs.  If you are a programmer, and you wish to
+include the features found in GNU Readline in your own programs, such
+as completion, line editing, and interactive history manipulation,
+this documentation is for you.
+
+* Menu:
+
+* Default Behaviour::  Using the default behaviour of Readline.
+* Custom Functions::   Adding your own functions to Readline.
+* Custom Completers::  Supplanting or supplementing Readline's
+                       completion functions.
+
+\1f
+File: readline.info,  Node: Default Behaviour,  Next: Custom Functions,  Up: Programming with GNU Readline
+
+Default Behaviour
+=================
+
+   Many programs provide a command line interface, such as `mail',
+`ftp', and `sh'.  For such programs, the default behaviour of Readline
+is sufficient.  This section describes how to use Readline in the
+simplest way possible, perhaps to replace calls in your code to `gets
+()'.
+
+   The function `readline' prints a prompt and then reads and returns
+a single line of text from the user.  The line which `readline ()'
+returns is allocated with `malloc ()'; you should `free ()' the line
+when you are done with it.  The declaration for `readline' in ANSI C is
+
+     `char *readline (char *PROMPT);'
+
+   So, one might say
+
+     `char *line = readline ("Enter a line: ");'
+
+   in order to read a line of text from the user.
+
+   The line which is returned has the final newline removed, so only
+the text of the line remains.
+
+   If readline encounters an `EOF' while reading the line, and the
+line is empty at that point, then `(char *)NULL' is returned. 
+Otherwise, the line is ended just as if a newline was typed.
+
+   If you want the user to be able to get at the line later, (with C-p
+for example), you must call `add_history ()' to save the line away in
+a "history" list of such lines.
+
+     `add_history (line)';
+
+   For full details on the GNU History Library, see the associated
+manual.
+
+   It is polite to avoid saving empty lines on the history list, since
+it is rare than someone has a burning need to reuse a blank line. 
+Here is a function which usefully replaces the standard `gets ()'
+library function:
+
+     /* A static variable for holding the line. */
+     static char *line_read = (char *)NULL;
+     
+     /* Read a string, and return a pointer to it.  Returns NULL on EOF. */
+     char *
+     do_gets ()
+     {
+       /* If the buffer has already been allocated, return the memory
+          to the free pool. */
+       if (line_read != (char *)NULL)
+         {
+           free (line_read);
+           line_read = (char *)NULL;
+         }
+     
+       /* Get a line from the user. */
+       line_read = readline ("");
+     
+       /* If the line has any text in it, save it on the history. */
+       if (line_read && *line_read)
+         add_history (line_read);
+     
+       return (line_read);
+     }
+
+   The above code gives the user the default behaviour of TAB
+completion: completion on file names.  If you do not want readline to
+complete on filenames, you can change the binding of the TAB key with
+`rl_bind_key ()'.
+
+     `int rl_bind_key (int KEY, (int (*)())FUNCTION);'
+
+   `rl_bind_key ()' takes 2 arguments; KEY is the character that you
+want to bind, and FUNCTION is the address of the function to run when
+KEY is pressed.  Binding TAB to `rl_insert ()' makes TAB just insert
+itself.
+
+   `rl_bind_key ()' returns non-zero if KEY is not a valid ASCII
+character code (between 0 and 255).
+
+     `rl_bind_key ('\t', rl_insert);'
+
+   This code should be executed once at the start of your program; you
+might write a function called `initialize_readline ()' which performs
+this and other desired initializations, such as installing custom
+completers, etc.
+
+\1f
+File: readline.info,  Node: Custom Functions,  Next: Custom Completers,  Prev: Default Behaviour,  Up: Programming with GNU Readline
+
+Custom Functions
+================
+
+   Readline provides a great many functions for manipulating the text
+of the line.  But it isn't possible to anticipate the needs of all
+programs.  This section describes the various functions and variables
+defined in within the Readline library which allow a user program to
+add customized functionality to Readline.
+
+* Menu:
+
+* The Function Type::  C declarations to make code readable.
+* Function Naming::    How to give a function you write a name.
+* Keymaps::            Making keymaps.
+* Binding Keys::       Changing Keymaps.
+* Function Writing::   Variables and calling conventions.
+* Allowing Undoing::   How to make your functions undoable.
+
+\1f
+File: readline.info,  Node: The Function Type,  Next: Function Naming,  Up: Custom Functions
+
+The Function Type
+-----------------
+
+   For the sake of readabilty, we declare a new type of object, called
+"Function".  A `Function' is a C language function which returns an
+`int'.  The type declaration for `Function' is:
+
+`typedef int Function ();'
+
+   The reason for declaring this new type is to make it easier to write
+code describing pointers to C functions.  Let us say we had a variable
+called FUNC which was a pointer to a function.  Instead of the classic
+C declaration
+
+   `int (*)()func;'
+
+   we have
+
+   `Function *func;'
+
+\1f
+File: readline.info,  Node: Function Naming,  Next: Keymaps,  Prev: The Function Type,  Up: Custom Functions
+
+Naming a Function
+-----------------
+
+   The user can dynamically change the bindings of keys while using
+Readline.  This is done by representing the function with a descriptive
+name.  The user is able to type the descriptive name when referring to
+the function.  Thus, in an init file, one might find
+
+     Meta-Rubout:      backward-kill-word
+
+   This binds the keystroke Meta-Rubout to the function
+*descriptively* named `backward-kill-word'.  You, as the programmer,
+should bind the functions you write to descriptive names as well. 
+Readline provides a function for doing that:
+
+ * Function: rl_add_defun (CHAR *NAME, FUNCTION *FUNCTION, INT KEY)
+     Add NAME to the list of named functions.  Make FUNCTION be the
+     function that gets called.  If KEY is not -1, then bind it to
+     FUNCTION using `rl_bind_key ()'.
+
+   Using this function alone is sufficient for most applications.  It
+is the recommended way to add a few functions to the default functions
+that Readline has built in already.  If you need to do more or
+different things than adding a function to Readline, you may need to
+use the underlying functions described below.
+
+\1f
+File: readline.info,  Node: Keymaps,  Next: Binding Keys,  Prev: Function Naming,  Up: Custom Functions
+
+Selecting a Keymap
+------------------
+
+   Key bindings take place on a "keymap".  The keymap is the
+association between the keys that the user types and the functions that
+get run.  You can make your own keymaps, copy existing keymaps, and
+tell Readline which keymap to use.
+
+ * Function: Keymap rl_make_bare_keymap ()
+     Returns a new, empty keymap.  The space for the keymap is
+     allocated with `malloc ()'; you should `free ()' it when you are
+     done.
+
+ * Function: Keymap rl_copy_keymap (KEYMAP MAP)
+     Return a new keymap which is a copy of MAP.
+
+ * Function: Keymap rl_make_keymap ()
+     Return a new keymap with the printing characters bound to
+     rl_insert, the lowercase Meta characters bound to run their
+     equivalents, and the Meta digits bound to produce numeric
+     arguments.
+
+\1f
+File: readline.info,  Node: Binding Keys,  Next: Function Writing,  Prev: Keymaps,  Up: Custom Functions
+
+Binding Keys
+------------
+
+   You associate keys with functions through the keymap.  Here are
+functions for doing that.
+
+ * Function: int rl_bind_key (INT KEY, FUNCTION *FUNCTION)
+     Binds KEY to FUNCTION in the currently selected keymap.  Returns
+     non-zero in the case of an invalid KEY.
+
+ * Function: int rl_bind_key_in_map (INT KEY, FUNCTION *FUNCTION,
+          KEYMAP MAP)
+     Bind KEY to FUNCTION in MAP.  Returns non-zero in the case of an
+     invalid KEY.
+
+ * Function: int rl_unbind_key (INT KEY)
+     Make KEY do nothing in the currently selected keymap.  Returns
+     non-zero in case of error.
+
+ * Function: int rl_unbind_key_in_map (INT KEY, KEYMAP MAP)
+     Make KEY be bound to the null function in MAP.  Returns non-zero
+     in case of error.
+
+ * Function: rl_generic_bind (INT TYPE, CHAR *KEYSEQ, CHAR *DATA,
+          KEYMAP MAP)
+     Bind the key sequence represented by the string KEYSEQ to the
+     arbitrary pointer DATA.  TYPE says what kind of data is pointed
+     to by DATA; right now this can be a function (`ISFUNC'), a macro
+     (`ISMACR'), or a keymap (`ISKMAP').  This makes new keymaps as
+     necessary.  The initial place to do bindings is in MAP.
+
+\1f
+File: readline.info,  Node: Function Writing,  Next: Allowing Undoing,  Prev: Binding Keys,  Up: Custom Functions
+
+Writing a New Function
+----------------------
+
+   In order to write new functions for Readline, you need to know the
+calling conventions for keyboard invoked functions, and the names of
+the variables that describe the current state of the line gathered so
+far.
+
+ * Variable: char *rl_line_buffer
+     This is the line gathered so far.  You are welcome to modify the
+     contents of this, but see Undoing, below.
+
+ * Variable: int rl_point
+     The offset of the current cursor position in RL_LINE_BUFFER.
+
+ * Variable: int rl_end
+     The number of characters present in `rl_line_buffer'.  When
+     `rl_point' is at the end of the line, then `rl_point' and
+     `rl_end' are equal.
+
+   The calling sequence for a command `foo' looks like
+
+     `foo (int count, int key)'
+
+   where COUNT is the numeric argument (or 1 if defaulted) and KEY is
+the key that invoked this function.
+
+   It is completely up to the function as to what should be done with
+the numeric argument; some functions use it as a repeat count, other
+functions as a flag, and some choose to ignore it.  In general, if a
+function uses the numeric argument as a repeat count, it should be able
+to do something useful with a negative argument as well as a positive
+argument.  At the very least, it should be aware that it can be passed
+a negative argument.
+
+\1f
+File: readline.info,  Node: Allowing Undoing,  Prev: Function Writing,  Up: Custom Functions
+
+Allowing Undoing
+----------------
+
+   Supporting the undo command is a painless thing to do, and makes
+your functions much more useful to the end user.  It is certainly easy
+to try something if you know you can undo it.  I could use an undo
+function for the stock market.
+
+   If your function simply inserts text once, or deletes text once,
+and it calls `rl_insert_text ()' or `rl_delete_text ()' to do it, then
+undoing is already done for you automatically, and you can safely skip
+this section.
+
+   If you do multiple insertions or multiple deletions, or any
+combination of these operations, you should group them together into
+one operation.  This can be done with `rl_begin_undo_group ()' and
+`rl_end_undo_group ()'.
+
+ * Function: rl_begin_undo_group ()
+     Begins saving undo information in a group construct.  The undo
+     information usually comes from calls to `rl_insert_text ()' and
+     `rl_delete_text ()', but they could be direct calls to
+     `rl_add_undo ()'.
+
+ * Function: rl_end_undo_group ()
+     Closes the current undo group started with `rl_begin_undo_group
+     ()'.  There should be exactly one call to `rl_end_undo_group ()'
+     for every call to `rl_begin_undo_group ()'.
+
+   Finally, if you neither insert nor delete text, but directly modify
+the existing text (e.g. change its case), you call `rl_modifying ()'
+once, just before you modify the text.  You must supply the indices of
+the text range that you are going to modify.
+
+ * Function: rl_modifying (INT START, INT END)
+     Tell Readline to save the text between START and END as a single
+     undo unit.  It is assumed that subsequent to this call you will
+     modify that range of text in some way.
+
+An Example
+----------
+
+   Here is a function which changes lowercase characters to the
+uppercase equivalents, and uppercase characters to the lowercase
+equivalents.  If this function was bound to `M-c', then typing `M-c'
+would change the case of the character under point.  Typing `10 M-c'
+would change the case of the following 10 characters, leaving the
+cursor on the last character changed.
+
+     /* Invert the case of the COUNT following characters. */
+     invert_case_line (count, key)
+          int count, key;
+     {
+       register int start, end;
+     
+       start = rl_point;
+     
+       if (count < 0)
+         {
+           direction = -1;
+           count = -count;
+         }
+       else
+         direction = 1;
+     
+       /* Find the end of the range to modify. */
+       end = start + (count * direction);
+     
+       /* Force it to be within range. */
+       if (end > rl_end)
+         end = rl_end;
+       else if (end < 0)
+         end = -1;
+     
+       if (start > end)
+         {
+           int temp = start;
+           start = end;
+           end = temp;
+         }
+     
+       if (start == end)
+         return;
+     
+       /* Tell readline that we are modifying the line, so save the undo
+          information. */
+       rl_modifying (start, end);
+     
+       for (; start != end; start += direction)
+         {
+           if (uppercase_p (rl_line_buffer[start]))
+             rl_line_buffer[start] = to_lower (rl_line_buffer[start]);
+           else if (lowercase_p (rl_line_buffer[start]))
+             rl_line_buffer[start] = to_upper (rl_line_buffer[start]);
+         }
+       /* Move point to on top of the last character changed. */
+       rl_point = end - direction;
+     }
+
+\1f
+File: readline.info,  Node: Custom Completers,  Prev: Custom Functions,  Up: Programming with GNU Readline
+
+Custom Completers
+=================
+
+   Typically, a program that reads commands from the user has a way of
+disambiguating commands and data.  If your program is one of these,
+then it can provide completion for either commands, or data, or both
+commands and data.  The following sections describe how your program
+and Readline cooperate to provide this service to end users.
+
+* Menu:
+
+* How Completing Works::       The logic used to do completion.
+* Completion Functions::       Functions provided by Readline.
+* Completion Variables::       Variables which control completion.
+* A Short Completion Example:: An example of writing completer subroutines.
+
+\1f
+File: readline.info,  Node: How Completing Works,  Next: Completion Functions,  Up: Custom Completers
+
+How Completing Works
+--------------------
+
+   In order to complete some text, the full list of possible
+completions must be available.  That is to say, it is not possible to
+accurately expand a partial word without knowing what all of the
+possible words that make sense in that context are.  The GNU Readline
+library provides the user interface to completion, and additionally,
+two of the most common completion functions; filename and username. 
+For completing other types of text, you must write your own completion
+function.  This section describes exactly what those functions must
+do, and provides an example function.
+
+   There are three major functions used to perform completion:
+
+  1. The user-interface function `rl_complete ()'.  This function is
+     called interactively with the same calling conventions as other
+     functions in readline intended for interactive use; i.e. COUNT,
+     and INVOKING-KEY.  It isolates the word to be completed and calls
+     `completion_matches ()' to generate a list of possible
+     completions.  It then either lists the possible completions or
+     actually performs the completion, depending on which behaviour is
+     desired.
+
+  2. The internal function `completion_matches ()' uses your
+     "generator" function to generate the list of possible matches, and
+     then returns the array of these matches.  You should place the
+     address of your generator function in
+     `rl_completion_entry_function'.
+
+  3. The generator function is called repeatedly from
+     `completion_matches ()', returning a string each time.  The
+     arguments to the generator function are TEXT and STATE.  TEXT is
+     the partial word to be completed.  STATE is zero the first time
+     the function is called, and a positive non-zero integer for each
+     subsequent call.  When the generator function returns `(char
+     *)NULL' this signals `completion_matches ()' that there are no
+     more possibilities left.
+
+ * Function: rl_complete (INT IGNORE, INT INVOKING_KEY)
+     Complete the word at or before point.  You have supplied the
+     function that does the initial simple matching selection
+     algorithm (see `completion_matches ()').  The default is to do
+     filename completion.
+
+   Note that `rl_complete ()' has the identical calling conventions as
+any other key-invokable function; this is because by default it is
+bound to the `TAB' key.
+
+ * Variable: Function *rl_completion_entry_function
+     This is a pointer to the generator function for
+     `completion_matches ()'.  If the value of
+     `rl_completion_entry_function' is `(Function *)NULL' then the
+     default filename generator function is used, namely
+     `filename_entry_function ()'.
+
+\1f
+File: readline.info,  Node: Completion Functions,  Next: Completion Variables,  Prev: How Completing Works,  Up: Custom Completers
+
+Completion Functions
+--------------------
+
+   Here is the complete list of callable completion functions present
+in Readline.
+
+ * Function: rl_complete_internal (INT WHAT_TO_DO)
+     Complete the word at or before point.  WHAT_TO_DO says what to do
+     with the completion.  A value of `?' means list the possible
+     completions.  `TAB' means do standard completion.  `*' means
+     insert all of the possible completions.
+
+ * Function: rl_complete (INT IGNORE, INT INVOKING_KEY)
+     Complete the word at or before point.  You have supplied the
+     function that does the initial simple matching selection
+     algorithm (see `completion_matches ()').  The default is to do
+     filename completion.  This just calls `rl_complete_internal ()'
+     with an argument of `TAB'.
+
+ * Function: rl_possible_completions ()
+     List the possible completions.  See description of `rl_complete
+     ()'.  This just calls `rl_complete_internal ()' with an argument
+     of `?'.
+
+ * Function: char **completion_matches (CHAR *TEXT, CHAR
+          *(*ENTRY_FUNCTION) ())
+     Returns an array of `(char *)' which is a list of completions for
+     TEXT.  If there are no completions, returns `(char **)NULL'.  The
+     first entry in the returned array is the substitution for TEXT. 
+     The remaining entries are the possible completions.  The array is
+     terminated with a `NULL' pointer.
+
+     ENTRY_FUNCTION is a function of two args, and returns a `(char
+     *)'.  The first argument is TEXT.  The second is a state
+     argument; it is zero on the first call, and non-zero on subsequent
+     calls.  It returns a `NULL'  pointer to the caller when there are
+     no more matches.
+
+ * Function: char *filename_completion_function (CHAR *TEXT, INT STATE)
+     A generator function for filename completion in the general case.
+      Note that completion in the Bash shell is a little different
+     because of all the pathnames that must be followed when looking
+     up the completion for a command.
+
+ * Function: char *username_completion_function (CHAR *TEXT, INT STATE)
+     A completion generator for usernames.  TEXT contains a partial
+     username preceded by a random character (usually `~').
+
+\1f
+File: readline.info,  Node: Completion Variables,  Next: A Short Completion Example,  Prev: Completion Functions,  Up: Custom Completers
+
+Completion Variables
+--------------------
+
+ * Variable: Function *rl_completion_entry_function
+     A pointer to the generator function for `completion_matches ()'. 
+     `NULL' means to use `filename_entry_function ()', the default
+     filename completer.
+
+ * Variable: Function *rl_attempted_completion_function
+     A pointer to an alternative function to create matches.  The
+     function is called with TEXT, START, and END.  START and END are
+     indices in `rl_line_buffer' saying what the boundaries of TEXT
+     are.  If this function exists and returns `NULL' then
+     `rl_complete ()' will call the value of
+     `rl_completion_entry_function' to generate matches, otherwise the
+     array of strings returned will be used.
+
+ * Variable: int rl_completion_query_items
+     Up to this many items will be displayed in response to a
+     possible-completions call.  After that, we ask the user if she is
+     sure she wants to see them all.  The default value is 100.
+
+ * Variable: char *rl_basic_word_break_characters
+     The basic list of characters that signal a break between words
+     for the completer routine.  The contents of this variable is what
+     breaks words in the Bash shell, i.e. " \t\n\"\\'`@$><=;|&{(".
+
+ * Variable: char *rl_completer_word_break_characters
+     The list of characters that signal a break between words for
+     `rl_complete_internal ()'.  The default list is the contents of
+     `rl_basic_word_break_characters'.
+
+ * Variable: char *rl_special_prefixes
+     The list of characters that are word break characters, but should
+     be left in TEXT when it is passed to the completion function. 
+     Programs can use this to help determine what kind of completing
+     to do.
+
+ * Variable: int rl_ignore_completion_duplicates
+     If non-zero, then disallow duplicates in the matches.  Default is
+     1.
+
+ * Variable: int rl_filename_completion_desired
+     Non-zero means that the results of the matches are to be treated
+     as filenames.  This is *always* zero on entry, and can only be
+     changed within a completion entry generator function.
+
+ * Variable: Function *rl_ignore_some_completions_function
+     This function, if defined, is called by the completer when real
+     filename completion is done, after all the matching names have
+     been generated.  It is passed a `NULL' terminated array of `(char
+     *)' known as MATCHES in the code.  The 1st element (`matches[0]')
+     is the maximal substring that is common to all matches. This
+     function can re-arrange the list of matches as required, but each
+     deleted element of the array must be `free()''d.
+
+\1f
+File: readline.info,  Node: A Short Completion Example,  Prev: Completion Variables,  Up: Custom Completers
+
+A Short Completion Example
+--------------------------
+
+   Here is a small application demonstrating the use of the GNU
+Readline library.  It is called `fileman', and the source code resides
+in `readline/examples/fileman.c'.  This sample application provides
+completion of command names, line editing features, and access to the
+history list.
+
+     /* fileman.c -- A tiny application which demonstrates how to use the
+        GNU Readline library.  This application interactively allows users
+        to manipulate files and their modes. */
+     
+     #include <stdio.h>
+     #include <readline/readline.h>
+     #include <readline/history.h>
+     #include <sys/types.h>
+     #include <sys/file.h>
+     #include <sys/stat.h>
+     #include <sys/errno.h>
+     
+     /* The names of functions that actually do the manipulation. */
+     int com_list (), com_view (), com_rename (), com_stat (), com_pwd ();
+     int com_delete (), com_help (), com_cd (), com_quit ();
+     
+     /* A structure which contains information on the commands this program
+        can understand. */
+     
+     typedef struct {
+       char *name;                   /* User printable name of the function. */
+       Function *func;               /* Function to call to do the job. */
+       char *doc;                    /* Documentation for this function.  */
+     } COMMAND;
+     
+     COMMAND commands[] = {
+       { "cd", com_cd, "Change to directory DIR" },
+       { "delete", com_delete, "Delete FILE" },
+       { "help", com_help, "Display this text" },
+       { "?", com_help, "Synonym for `help'" },
+       { "list", com_list, "List files in DIR" },
+       { "ls", com_list, "Synonym for `list'" },
+       { "pwd", com_pwd, "Print the current working directory" },
+       { "quit", com_quit, "Quit using Fileman" },
+       { "rename", com_rename, "Rename FILE to NEWNAME" },
+       { "stat", com_stat, "Print out statistics on FILE" },
+       { "view", com_view, "View the contents of FILE" },
+       { (char *)NULL, (Function *)NULL, (char *)NULL }
+     };
+     
+     /* The name of this program, as taken from argv[0]. */
+     char *progname;
+     
+     /* When non-zero, this global means the user is done using this program. */
+     int done = 0;
+     
+     main (argc, argv)
+          int argc;
+          char **argv;
+     {
+       progname = argv[0];
+     
+       initialize_readline ();       /* Bind our completer. */
+     
+       /* Loop reading and executing lines until the user quits. */
+       while (!done)
+         {
+           char *line;
+     
+           line = readline ("FileMan: ");
+     
+           if (!line)
+             {
+               done = 1;             /* Encountered EOF at top level. */
+             }
+           else
+             {
+               /* Remove leading and trailing whitespace from the line.
+                  Then, if there is anything left, add it to the history list
+                  and execute it. */
+               stripwhite (line);
+     
+               if (*line)
+                 {
+                   add_history (line);
+                   execute_line (line);
+                 }
+             }
+     
+           if (line)
+             free (line);
+         }
+       exit (0);
+     }
+     
+     /* Execute a command line. */
+     execute_line (line)
+          char *line;
+     {
+       register int i;
+       COMMAND *find_command (), *command;
+       char *word;
+     
+       /* Isolate the command word. */
+       i = 0;
+       while (line[i] && !whitespace (line[i]))
+         i++;
+     
+       word = line;
+     
+       if (line[i])
+         line[i++] = '\0';
+     
+       command = find_command (word);
+     
+       if (!command)
+         {
+           fprintf (stderr, "%s: No such command for FileMan.\n", word);
+           return;
+         }
+     
+       /* Get argument to command, if any. */
+       while (whitespace (line[i]))
+         i++;
+     
+       word = line + i;
+     
+       /* Call the function. */
+       (*(command->func)) (word);
+     }
+     
+     /* Look up NAME as the name of a command, and return a pointer to that
+        command.  Return a NULL pointer if NAME isn't a command name. */
+     COMMAND *
+     find_command (name)
+          char *name;
+     {
+       register int i;
+     
+       for (i = 0; commands[i].name; i++)
+         if (strcmp (name, commands[i].name) == 0)
+           return (&commands[i]);
+     
+       return ((COMMAND *)NULL);
+     }
+     
+     /* Strip whitespace from the start and end of STRING. */
+     stripwhite (string)
+          char *string;
+     {
+       register int i = 0;
+     
+       while (whitespace (string[i]))
+         i++;
+     
+       if (i)
+         strcpy (string, string + i);
+     
+       i = strlen (string) - 1;
+     
+       while (i > 0 && whitespace (string[i]))
+         i--;
+     
+       string[++i] = '\0';
+     }
+     
+     /* **************************************************************** */
+     /*                                                                  */
+     /*                  Interface to Readline Completion                */
+     /*                                                                  */
+     /* **************************************************************** */
+     
+     /* Tell the GNU Readline library how to complete.  We want to try to complete
+        on command names if this is the first word in the line, or on filenames
+        if not. */
+     initialize_readline ()
+     {
+       char **fileman_completion ();
+     
+       /* Allow conditional parsing of the ~/.inputrc file. */
+       rl_readline_name = "FileMan";
+     
+       /* Tell the completer that we want a crack first. */
+       rl_attempted_completion_function = (Function *)fileman_completion;
+     }
+     
+     /* Attempt to complete on the contents of TEXT.  START and END show the
+        region of TEXT that contains the word to complete.  We can use the
+        entire line in case we want to do some simple parsing.  Return the
+        array of matches, or NULL if there aren't any. */
+     char **
+     fileman_completion (text, start, end)
+          char *text;
+          int start, end;
+     {
+       char **matches;
+       char *command_generator ();
+     
+       matches = (char **)NULL;
+     
+       /* If this word is at the start of the line, then it is a command
+          to complete.  Otherwise it is the name of a file in the current
+          directory. */
+       if (start == 0)
+         matches = completion_matches (text, command_generator);
+     
+       return (matches);
+     }
+     
+     /* Generator function for command completion.  STATE lets us know whether
+        to start from scratch; without any state (i.e. STATE == 0), then we
+        start at the top of the list. */
+     char *
+     command_generator (text, state)
+          char *text;
+          int state;
+     {
+       static int list_index, len;
+       char *name;
+     
+       /* If this is a new word to complete, initialize now.  This includes
+          saving the length of TEXT for efficiency, and initializing the index
+          variable to 0. */
+       if (!state)
+         {
+           list_index = 0;
+           len = strlen (text);
+         }
+     
+       /* Return the next name which partially matches from the command list. */
+       while (name = commands[list_index].name)
+         {
+           list_index++;
+     
+           if (strncmp (name, text, len) == 0)
+             return (name);
+         }
+     
+       /* If no names matched, then return NULL. */
+       return ((char *)NULL);
+     }
+     
+     /* **************************************************************** */
+     /*                                                                  */
+     /*                       FileMan Commands                           */
+     /*                                                                  */
+     /* **************************************************************** */
+     
+     /* String to pass to system ().  This is for the LIST, VIEW and RENAME
+        commands. */
+     static char syscom[1024];
+     
+     /* List the file(s) named in arg. */
+     com_list (arg)
+          char *arg;
+     {
+       if (!arg)
+         arg = "*";
+     
+       sprintf (syscom, "ls -FClg %s", arg);
+       system (syscom);
+     }
+     
+     com_view (arg)
+          char *arg;
+     {
+       if (!valid_argument ("view", arg))
+         return;
+     
+       sprintf (syscom, "cat %s | more", arg);
+       system (syscom);
+     }
+     
+     com_rename (arg)
+          char *arg;
+     {
+       too_dangerous ("rename");
+     }
+     
+     com_stat (arg)
+          char *arg;
+     {
+       struct stat finfo;
+     
+       if (!valid_argument ("stat", arg))
+         return;
+     
+       if (stat (arg, &finfo) == -1)
+         {
+           perror (arg);
+           return;
+         }
+     
+       printf ("Statistics for `%s':\n", arg);
+     
+       printf ("%s has %d link%s, and is %d bytes in length.\n", arg,
+               finfo.st_nlink, (finfo.st_nlink == 1) ? "" : "s",  finfo.st_size);
+       printf ("      Created on: %s", ctime (&finfo.st_ctime));
+       printf ("  Last access at: %s", ctime (&finfo.st_atime));
+       printf ("Last modified at: %s", ctime (&finfo.st_mtime));
+     }
+     
+     com_delete (arg)
+          char *arg;
+     {
+       too_dangerous ("delete");
+     }
+     
+     /* Print out help for ARG, or for all of the commands if ARG is
+        not present. */
+     com_help (arg)
+          char *arg;
+     {
+       register int i;
+       int printed = 0;
+     
+       for (i = 0; commands[i].name; i++)
+         {
+           if (!*arg || (strcmp (arg, commands[i].name) == 0))
+             {
+               printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
+               printed++;
+             }
+         }
+     
+       if (!printed)
+         {
+           printf ("No commands match `%s'.  Possibilties are:\n", arg);
+     
+           for (i = 0; commands[i].name; i++)
+             {
+               /* Print in six columns. */
+               if (printed == 6)
+                 {
+                   printed = 0;
+                   printf ("\n");
+                 }
+     
+               printf ("%s\t", commands[i].name);
+               printed++;
+             }
+     
+           if (printed)
+             printf ("\n");
+         }
+     }
+     
+     /* Change to the directory ARG. */
+     com_cd (arg)
+          char *arg;
+     {
+       if (chdir (arg) == -1)
+         perror (arg);
+     
+       com_pwd ("");
+     }
+     
+     /* Print out the current working directory. */
+     com_pwd (ignore)
+          char *ignore;
+     {
+       char dir[1024];
+     
+       (void) getwd (dir);
+     
+       printf ("Current directory is %s\n", dir);
+     }
+     
+     /* The user wishes to quit using this program.  Just set DONE non-zero. */
+     com_quit (arg)
+          char *arg;
+     {
+       done = 1;
+     }
+     
+     /* Function which tells you that you can't do this. */
+     too_dangerous (caller)
+          char *caller;
+     {
+       fprintf (stderr,
+                "%s: Too dangerous for me to distribute.  Write it yourself.\n",
+                caller);
+     }
+     
+     /* Return non-zero if ARG is a valid argument for CALLER, else print
+        an error message and return zero. */
+     int
+     valid_argument (caller, arg)
+          char *caller, *arg;
+     {
+       if (!arg || !*arg)
+         {
+           fprintf (stderr, "%s: Argument required.\n", caller);
+           return (0);
+         }
+     
+       return (1);
+     }
+
+\1f
+File: readline.info,  Node: Concept Index,  Next: Function and Variable Index,  Prev: Programming with GNU Readline,  Up: Top
+
+Concept Index
+*************
+
+* Menu:
+
+* interaction, readline:                Readline Interaction.
+* readline, function:                   Default Behaviour.
+
+\1f
+File: readline.info,  Node: Function and Variable Index,  Prev: Concept Index,  Up: Top
+
+Function and Variable Index
+***************************
+
+* Menu:
+
+* Function *rl_attempted_completion_function: Completion Variables.
+* Function *rl_completion_entry_function: Completion Variables.
+* Function *rl_completion_entry_function: How Completing Works.
+* Function *rl_ignore_some_completions_function: Completion Variables.
+* Keymap rl_copy_keymap:                Keymaps.
+* Keymap rl_make_bare_keymap:           Keymaps.
+* Keymap rl_make_keymap:                Keymaps.
+* abort (C-g):                          Miscellaneous Commands.
+* accept-line (Newline, Return):        Commands For History.
+* backward-char (C-b):                  Commands For Moving.
+* backward-delete-char (Rubout):        Commands For Text.
+* backward-kill-line ():                Commands For Killing.
+* backward-kill-word (M-DEL):           Commands For Killing.
+* backward-word (M-b):                  Commands For Moving.
+* beginning-of-history (M-<):           Commands For History.
+* beginning-of-line (C-a):              Commands For Moving.
+* capitalize-word (M-c):                Commands For Text.
+* char **completion_matches:            Completion Functions.
+* char *filename_completion_function:   Completion Functions.
+* char *rl_basic_word_break_characters: Completion Variables.
+* char *rl_completer_word_break_characters: Completion Variables.
+* char *rl_line_buffer:                 Function Writing.
+* char *rl_special_prefixes:            Completion Variables.
+* char *username_completion_function:   Completion Functions.
+* clear-screen (C-l):                   Commands For Moving.
+* complete (TAB):                       Commands For Completion.
+* delete-char (C-d):                    Commands For Text.
+* digit-argument (M-0, M-1, ... M--):   Numeric Arguments.
+* do-uppercase-version (M-a, M-b, ...): Miscellaneous Commands.
+* downcase-word (M-l):                  Commands For Text.
+* editing-mode:                         Readline Init Syntax.
+* end-of-history (M->):                 Commands For History.
+* end-of-line (C-e):                    Commands For Moving.
+* forward-char (C-f):                   Commands For Moving.
+* forward-search-history (C-s):         Commands For History.
+* forward-word (M-f):                   Commands For Moving.
+* horizontal-scroll-mode:               Readline Init Syntax.
+* int rl_bind_key:                      Binding Keys.
+* int rl_bind_key_in_map:               Binding Keys.
+* int rl_completion_query_items:        Completion Variables.
+* int rl_end:                           Function Writing.
+* int rl_filename_completion_desired:   Completion Variables.
+* int rl_ignore_completion_duplicates:  Completion Variables.
+* int rl_point:                         Function Writing.
+* int rl_unbind_key:                    Binding Keys.
+* int rl_unbind_key_in_map:             Binding Keys.
+* kill-line (C-k):                      Commands For Killing.
+* kill-word (M-d):                      Commands For Killing.
+* mark-modified-lines:                  Readline Init Syntax.
+* next-history (C-n):                   Commands For History.
+* possible-completions (M-?):           Commands For Completion.
+* prefer-visible-bell:                  Readline Init Syntax.
+* prefix-meta (ESC):                    Miscellaneous Commands.
+* previous-history (C-p):               Commands For History.
+* quoted-insert (C-q, C-v):             Commands For Text.
+* re-read-init-file (C-x C-r):          Miscellaneous Commands.
+* readline ():                          Default Behaviour.
+* reverse-search-history (C-r):         Commands For History.
+* revert-line (M-r):                    Miscellaneous Commands.
+* rl_add_defun:                         Function Naming.
+* rl_begin_undo_group:                  Allowing Undoing.
+* rl_bind_key ():                       Default Behaviour.
+* rl_complete:                          How Completing Works.
+* rl_complete:                          Completion Functions.
+* rl_complete_internal:                 Completion Functions.
+* rl_end_undo_group:                    Allowing Undoing.
+* rl_generic_bind:                      Binding Keys.
+* rl_modifying:                         Allowing Undoing.
+* rl_possible_completions:              Completion Functions.
+* self-insert (a, b, A, 1, !, ...):     Commands For Text.
+* tab-insert (M-TAB):                   Commands For Text.
+* transpose-chars (C-t):                Commands For Text.
+* transpose-words (M-t):                Commands For Text.
+* undo (C-_):                           Miscellaneous Commands.
+* universal-argument ():                Numeric Arguments.
+* unix-line-discard (C-u):              Commands For Killing.
+* unix-word-rubout (C-w):               Commands For Killing.
+* upcase-word (M-u):                    Commands For Text.
+* yank (C-y):                           Commands For Killing.
+* yank-pop (M-y):                       Commands For Killing.
+
+
+\1f
+Tag Table:
+Node: Top\7f998
+Node: Command Line Editing\7f1611
+Node: Introduction and Notation\7f2034
+Node: Readline Interaction\7f3056
+Node: Readline Bare Essentials\7f4195
+Node: Readline Movement Commands\7f5703
+Node: Readline Killing Commands\7f6594
+Node: Readline Arguments\7f8438
+Node: Readline Init File\7f9390
+Node: Readline Init Syntax\7f10218
+Node: Commands For Moving\7f14208
+Node: Commands For History\7f14838
+Node: Commands For Text\7f15913
+Node: Commands For Killing\7f17581
+Node: Numeric Arguments\7f18708
+Node: Commands For Completion\7f19152
+Node: Miscellaneous Commands\7f19876
+Node: Readline Vi Mode\7f20718
+Node: Programming with GNU Readline\7f22328
+Node: Default Behaviour\7f23033
+Node: Custom Functions\7f26258
+Node: The Function Type\7f27057
+Node: Function Naming\7f27690
+Node: Keymaps\7f28942
+Node: Binding Keys\7f29857
+Node: Function Writing\7f31158
+Node: Allowing Undoing\7f32599
+Node: Custom Completers\7f36101
+Node: How Completing Works\7f36849
+Node: Completion Functions\7f39664
+Node: Completion Variables\7f42000
+Node: A Short Completion Example\7f44772
+Node: Concept Index\7f56398
+Node: Function and Variable Index\7f56687
+\1f
+End Tag Table
diff --git a/readline/doc/rlman.texinfo b/readline/doc/rlman.texinfo
new file mode 100644 (file)
index 0000000..f2e7fb6
--- /dev/null
@@ -0,0 +1,103 @@
+\input texinfo    @c -*-texinfo-*-
+@comment %**start of header (This is for running Texinfo on a region.)
+@setfilename readline.info
+@settitle GNU Readline Library
+@comment %**end of header (This is for running Texinfo on a region.)
+@synindex vr fn
+@setchapternewpage odd
+
+@ifinfo
+This document describes the GNU Readline Library, a utility which aids
+in the consistency of user interface across discrete programs that need
+to provide a command line interface.
+
+Copyright (C) 1988, 1991 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+pare preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
+
+@titlepage
+@sp 10
+@center @titlefont{GNU Readline Library}
+@center Brian Fox
+@center Free Software Foundation
+@center Version 1.1
+@center April 1991
+
+@page
+This document describes the GNU Readline Library, a utility which aids
+in the consistency of user interface across discrete programs that need
+to provide a command line interface.
+
+Published by the Free Software Foundation @*
+675 Massachusetts Avenue, @*
+Cambridge, MA 02139 USA
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc.
+@end titlepage
+
+@ifinfo
+@node Top
+@top GNU Readline Library
+
+This document describes the GNU Readline Library, a utility which aids
+in the consistency of user interface across discrete programs that need
+to provide a command line interface.
+
+@menu
+* Command Line Editing::          GNU Readline User's Manual.
+* Programming with GNU Readline::  GNU Readline Programmer's Manual.
+* Concept Index::                 Index of concepts described in this manual.
+* Function and Variable Index::           Index of externally visible functions
+                                  and variables.
+@end menu
+@end ifinfo
+
+@include rluser.texinfo
+@include rltech.texinfo
+
+@node Concept Index
+@unnumbered Concept Index
+@printindex cp
+
+@node Function and Variable Index
+@unnumbered Function and Variable Index
+@printindex fn
+
+@contents
+@bye
+
diff --git a/readline/doc/rltech.texinfo b/readline/doc/rltech.texinfo
new file mode 100644 (file)
index 0000000..2048b7c
--- /dev/null
@@ -0,0 +1,1012 @@
+@comment %**start of header (This is for running Texinfo on a region.)
+@setfilename rltech.info
+@comment %**end of header (This is for running Texinfo on a region.)
+@setchapternewpage odd
+
+@ifinfo
+This document describes the GNU Readline Library, a utility for aiding
+in the consitency of user interface across discrete programs that need
+to provide a command line interface.
+
+Copyright (C) 1988 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+pare preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Foundation.
+@end ifinfo
+
+@node Programming with GNU Readline
+@chapter Programming with GNU Readline
+
+This manual describes the interface between the GNU Readline Library and
+user programs.  If you are a programmer, and you wish to include the
+features found in GNU Readline in your own programs, such as completion,
+line editing, and interactive history manipulation, this documentation
+is for you.
+
+@menu
+* Default Behaviour::  Using the default behaviour of Readline.
+* Custom Functions::   Adding your own functions to Readline.
+* Custom Completers::  Supplanting or supplementing Readline's
+                       completion functions.
+@end menu
+
+@node Default Behaviour
+@section Default Behaviour
+
+Many programs provide a command line interface, such as @code{mail},
+@code{ftp}, and @code{sh}.  For such programs, the default behaviour of
+Readline is sufficient.  This section describes how to use Readline in
+the simplest way possible, perhaps to replace calls in your code to
+@code{gets ()}.
+
+@findex readline ()
+@cindex readline, function
+The function @code{readline} prints a prompt and then reads and returns
+a single line of text from the user.  The line which @code{readline ()}
+returns is allocated with @code{malloc ()}; you should @code{free ()}
+the line when you are done with it.  The declaration for @code{readline}
+in ANSI C is
+
+@example
+@code{char *readline (char *@var{prompt});}
+@end example
+
+So, one might say
+@example
+@code{char *line = readline ("Enter a line: ");}
+@end example
+in order to read a line of text from the user.
+
+The line which is returned has the final newline removed, so only the
+text of the line remains.
+
+If readline encounters an @code{EOF} while reading the line, and the
+line is empty at that point, then @code{(char *)NULL} is returned.
+Otherwise, the line is ended just as if a newline was typed.
+
+If you want the user to be able to get at the line later, (with
+@key{C-p} for example), you must call @code{add_history ()} to save the
+line away in a @dfn{history} list of such lines.
+
+@example
+@code{add_history (line)};
+@end example
+
+For full details on the GNU History Library, see the associated manual.
+
+It is polite to avoid saving empty lines on the history list, since it
+is rare than someone has a burning need to reuse a blank line.  Here is
+a function which usefully replaces the standard @code{gets ()} library
+function:
+
+@example
+/* A static variable for holding the line. */
+static char *line_read = (char *)NULL;
+
+/* Read a string, and return a pointer to it.  Returns NULL on EOF. */
+char *
+do_gets ()
+@{
+  /* If the buffer has already been allocated, return the memory
+     to the free pool. */
+  if (line_read != (char *)NULL)
+    @{
+      free (line_read);
+      line_read = (char *)NULL;
+    @}
+
+  /* Get a line from the user. */
+  line_read = readline ("");
+
+  /* If the line has any text in it, save it on the history. */
+  if (line_read && *line_read)
+    add_history (line_read);
+
+  return (line_read);
+@}
+@end example
+
+The above code gives the user the default behaviour of @key{TAB}
+completion: completion on file names.  If you do not want readline to
+complete on filenames, you can change the binding of the @key{TAB} key
+with @code{rl_bind_key ()}.
+
+@findex rl_bind_key ()
+@example
+@code{int rl_bind_key (int @var{key}, int (*@var{function})());}
+@end example
+
+@code{rl_bind_key ()} takes 2 arguments; @var{key} is the character that
+you want to bind, and @var{function} is the address of the function to
+run when @var{key} is pressed.  Binding @key{TAB} to @code{rl_insert ()}
+makes @key{TAB} just insert itself.
+
+@code{rl_bind_key ()} returns non-zero if @var{key} is not a valid
+ASCII character code (between 0 and 255).
+
+@example
+@code{rl_bind_key ('\t', rl_insert);}
+@end example
+
+This code should be executed once at the start of your program; you
+might write a function called @code{initialize_readline ()} which
+performs this and other desired initializations, such as installing
+custom completers, etc.
+
+@node Custom Functions
+@section Custom Functions
+
+Readline provides a great many functions for manipulating the text of
+the line.  But it isn't possible to anticipate the needs of all
+programs.  This section describes the various functions and variables
+defined in within the Readline library which allow a user program to add
+customized functionality to Readline.
+
+@menu
+* The Function Type::  C declarations to make code readable.
+* Function Naming::    How to give a function you write a name.
+* Keymaps::            Making keymaps.
+* Binding Keys::       Changing Keymaps.
+* Function Writing::   Variables and calling conventions.
+* Allowing Undoing::   How to make your functions undoable.
+@end menu
+
+@node The Function Type
+@subsection The Function Type
+
+For the sake of readabilty, we declare a new type of object, called
+@dfn{Function}.  A @code{Function} is a C language function which
+returns an @code{int}.  The type declaration for @code{Function} is:
+
+@noindent
+@code{typedef int Function ();}
+
+The reason for declaring this new type is to make it easier to write
+code describing pointers to C functions.  Let us say we had a variable
+called @var{func} which was a pointer to a function.  Instead of the
+classic C declaration
+
+@code{int (*)()func;}
+
+we have
+
+@code{Function *func;}
+
+@node Function Naming
+@subsection Naming a Function
+
+The user can dynamically change the bindings of keys while using
+Readline.  This is done by representing the function with a descriptive
+name.  The user is able to type the descriptive name when referring to
+the function.  Thus, in an init file, one might find
+
+@example
+Meta-Rubout:   backward-kill-word
+@end example
+
+This binds the keystroke @key{Meta-Rubout} to the function
+@emph{descriptively} named @code{backward-kill-word}.  You, as the
+programmer, should bind the functions you write to descriptive names as
+well.  Readline provides a function for doing that:
+
+@defun rl_add_defun (char *name, Function *function, int key)
+Add @var{name} to the list of named functions.  Make @var{function} be
+the function that gets called.  If @var{key} is not -1, then bind it to
+@var{function} using @code{rl_bind_key ()}.
+@end defun
+
+Using this function alone is sufficient for most applications.  It is
+the recommended way to add a few functions to the default functions that
+Readline has built in already.  If you need to do more or different
+things than adding a function to Readline, you may need to use the
+underlying functions described below.
+
+@node Keymaps
+@subsection Selecting a Keymap
+
+Key bindings take place on a @dfn{keymap}.  The keymap is the
+association between the keys that the user types and the functions that
+get run.  You can make your own keymaps, copy existing keymaps, and tell
+Readline which keymap to use.
+
+@defun {Keymap rl_make_bare_keymap} ()
+Returns a new, empty keymap.  The space for the keymap is allocated with
+@code{malloc ()}; you should @code{free ()} it when you are done.
+@end defun
+
+@defun {Keymap rl_copy_keymap} (Keymap map)
+Return a new keymap which is a copy of @var{map}.
+@end defun
+
+@defun {Keymap rl_make_keymap} ()
+Return a new keymap with the printing characters bound to rl_insert,
+the lowercase Meta characters bound to run their equivalents, and
+the Meta digits bound to produce numeric arguments.
+@end defun
+
+@node Binding Keys
+@subsection Binding Keys
+
+You associate keys with functions through the keymap.  Here are
+functions for doing that.
+
+@defun {int rl_bind_key} (int key, Function *function)
+Binds @var{key} to @var{function} in the currently selected keymap.
+Returns non-zero in the case of an invalid @var{key}.
+@end defun
+
+@defun {int rl_bind_key_in_map} (int key, Function *function, Keymap map)
+Bind @var{key} to @var{function} in @var{map}.  Returns non-zero in the case
+of an invalid @var{key}.
+@end defun
+
+@defun {int rl_unbind_key} (int key)
+Make @var{key} do nothing in the currently selected keymap.
+Returns non-zero in case of error.
+@end defun
+
+@defun {int rl_unbind_key_in_map} (int key, Keymap map)
+Make @var{key} be bound to the null function in @var{map}.
+Returns non-zero in case of error.
+@end defun
+
+@defun rl_generic_bind (int type, char *keyseq, char *data, Keymap map)
+Bind the key sequence represented by the string @var{keyseq} to the arbitrary
+pointer @var{data}.  @var{type} says what kind of data is pointed to by
+@var{data}; right now this can be a function (@code{ISFUNC}), a macro
+(@code{ISMACR}), or a keymap (@code{ISKMAP}).  This makes new keymaps as
+necessary.  The initial place to do bindings is in @var{map}.
+@end defun
+
+@node Function Writing
+@subsection Writing a New Function
+
+In order to write new functions for Readline, you need to know the
+calling conventions for keyboard invoked functions, and the names of the
+variables that describe the current state of the line gathered so far.
+
+@defvar {char *rl_line_buffer}
+This is the line gathered so far.  You are welcome to modify the
+contents of this, but see Undoing, below.
+@end defvar
+
+@defvar {int rl_point}
+The offset of the current cursor position in @var{rl_line_buffer}.
+@end defvar
+
+@defvar {int rl_end}
+The number of characters present in @code{rl_line_buffer}.  When
+@code{rl_point} is at the end of the line, then @code{rl_point} and
+@code{rl_end} are equal.
+@end defvar
+
+The calling sequence for a command @code{foo} looks like
+
+@example
+@code{foo (int count, int key)}
+@end example
+
+where @var{count} is the numeric argument (or 1 if defaulted) and
+@var{key} is the key that invoked this function.
+
+It is completely up to the function as to what should be done with the
+numeric argument; some functions use it as a repeat count, other
+functions as a flag, and some choose to ignore it.  In general, if a
+function uses the numeric argument as a repeat count, it should be able
+to do something useful with a negative argument as well as a positive
+argument.  At the very least, it should be aware that it can be passed a
+negative argument.
+
+@node Allowing Undoing
+@subsection Allowing Undoing
+
+Supporting the undo command is a painless thing to do, and makes your
+functions much more useful to the end user.  It is certainly easy to try
+something if you know you can undo it.  I could use an undo function for
+the stock market.
+
+If your function simply inserts text once, or deletes text once, and it
+calls @code{rl_insert_text ()} or @code{rl_delete_text ()} to do it, then
+undoing is already done for you automatically, and you can safely skip
+this section.
+
+If you do multiple insertions or multiple deletions, or any combination
+of these operations, you should group them together into one operation.
+This can be done with @code{rl_begin_undo_group ()} and
+@code{rl_end_undo_group ()}.
+
+@defun rl_begin_undo_group ()
+Begins saving undo information in a group construct.  The undo
+information usually comes from calls to @code{rl_insert_text ()} and
+@code{rl_delete_text ()}, but they could be direct calls to
+@code{rl_add_undo ()}.
+@end defun
+
+@defun rl_end_undo_group ()
+Closes the current undo group started with @code{rl_begin_undo_group
+()}.  There should be exactly one call to @code{rl_end_undo_group ()}
+for every call to @code{rl_begin_undo_group ()}.
+@end defun
+
+Finally, if you neither insert nor delete text, but directly modify the
+existing text (e.g. change its case), you call @code{rl_modifying ()}
+once, just before you modify the text.  You must supply the indices of
+the text range that you are going to modify.
+
+@defun rl_modifying (int start, int end)
+Tell Readline to save the text between @var{start} and @var{end} as a
+single undo unit.  It is assumed that subsequent to this call you will
+modify that range of text in some way.
+@end defun
+
+@subsection An Example
+
+Here is a function which changes lowercase characters to the uppercase
+equivalents, and uppercase characters to the lowercase equivalents.  If
+this function was bound to @samp{M-c}, then typing @samp{M-c} would
+change the case of the character under point.  Typing @samp{10 M-c}
+would change the case of the following 10 characters, leaving the cursor on
+the last character changed.
+
+@example
+/* Invert the case of the COUNT following characters. */
+invert_case_line (count, key)
+     int count, key;
+@{
+  register int start, end;
+
+  start = rl_point;
+
+  if (count < 0)
+    @{
+      direction = -1;
+      count = -count;
+    @}
+  else
+    direction = 1;
+      
+  /* Find the end of the range to modify. */
+  end = start + (count * direction);
+
+  /* Force it to be within range. */
+  if (end > rl_end)
+    end = rl_end;
+  else if (end < 0)
+    end = -1;
+
+  if (start > end)
+    @{
+      int temp = start;
+      start = end;
+      end = temp;
+    @}
+
+  if (start == end)
+    return;
+
+  /* Tell readline that we are modifying the line, so save the undo
+     information. */
+  rl_modifying (start, end);
+
+  for (; start != end; start += direction)
+    @{
+      if (uppercase_p (rl_line_buffer[start]))
+        rl_line_buffer[start] = to_lower (rl_line_buffer[start]);
+      else if (lowercase_p (rl_line_buffer[start]))
+        rl_line_buffer[start] = to_upper (rl_line_buffer[start]);
+    @}
+  /* Move point to on top of the last character changed. */
+  rl_point = end - direction;
+@}
+@end example
+
+@node Custom Completers
+@section Custom Completers
+
+Typically, a program that reads commands from the user has a way of
+disambiguating commands and data.  If your program is one of these, then
+it can provide completion for either commands, or data, or both commands
+and data.  The following sections describe how your program and Readline
+cooperate to provide this service to end users.
+
+@menu
+* How Completing Works::       The logic used to do completion.
+* Completion Functions::       Functions provided by Readline.
+* Completion Variables::       Variables which control completion.
+* A Short Completion Example:: An example of writing completer subroutines.
+@end menu
+
+@node How Completing Works
+@subsection How Completing Works
+
+In order to complete some text, the full list of possible completions
+must be available.  That is to say, it is not possible to accurately
+expand a partial word without knowing what all of the possible words
+that make sense in that context are.  The GNU Readline library provides
+the user interface to completion, and additionally, two of the most common
+completion functions; filename and username.  For completing other types
+of text, you must write your own completion function.  This section
+describes exactly what those functions must do, and provides an example
+function.
+
+There are three major functions used to perform completion:
+
+@enumerate
+@item
+The user-interface function @code{rl_complete ()}.  This function is
+called interactively with the same calling conventions as other
+functions in readline intended for interactive use; i.e. @var{count},
+and @var{invoking-key}.  It isolates the word to be completed and calls
+@code{completion_matches ()} to generate a list of possible completions.
+It then either lists the possible completions or actually performs the
+completion, depending on which behaviour is desired.
+
+@item
+The internal function @code{completion_matches ()} uses your
+@dfn{generator} function to generate the list of possible matches, and
+then returns the array of these matches.  You should place the address
+of your generator function in @code{rl_completion_entry_function}.
+
+@item
+The generator function is called repeatedly from
+@code{completion_matches ()}, returning a string each time.  The
+arguments to the generator function are @var{text} and @var{state}.
+@var{text} is the partial word to be completed.  @var{state} is zero the
+first time the function is called, and a positive non-zero integer for
+each subsequent call.  When the generator function returns @code{(char
+*)NULL} this signals @code{completion_matches ()} that there are no more
+possibilities left.
+
+@end enumerate
+
+@defun rl_complete (int ignore, int invoking_key)
+Complete the word at or before point.  You have supplied the function
+that does the initial simple matching selection algorithm (see
+@code{completion_matches ()}).  The default is to do filename completion.
+@end defun
+
+Note that @code{rl_complete ()} has the identical calling conventions as
+any other key-invokable function; this is because by default it is bound
+to the @samp{TAB} key.
+
+@defvar {Function *rl_completion_entry_function}
+This is a pointer to the generator function for @code{completion_matches
+()}.  If the value of @code{rl_completion_entry_function} is
+@code{(Function *)NULL} then the default filename generator function is
+used, namely @code{filename_entry_function ()}.
+@end defvar
+
+@node Completion Functions
+@subsection Completion Functions
+
+Here is the complete list of callable completion functions present in
+Readline.
+
+@defun rl_complete_internal (int what_to_do)
+Complete the word at or before point.  @var{what_to_do} says what to do
+with the completion.  A value of @samp{?} means list the possible
+completions.  @samp{TAB} means do standard completion.  @samp{*} means
+insert all of the possible completions.
+@end defun
+
+@defun rl_complete (int ignore, int invoking_key)
+Complete the word at or before point.  You have supplied the function
+that does the initial simple matching selection algorithm (see
+@code{completion_matches ()}).  The default is to do filename
+completion.  This just calls @code{rl_complete_internal ()} with an
+argument of @samp{TAB}.
+@end defun
+
+@defun rl_possible_completions ()
+List the possible completions.  See description of @code{rl_complete
+()}.  This just calls @code{rl_complete_internal ()} with an argument of
+@samp{?}.
+@end defun
+
+@defun {char **completion_matches} (char *text, char *(*entry_function) ())
+Returns an array of @code{(char *)} which is a list of completions for
+@var{text}.  If there are no completions, returns @code{(char **)NULL}.
+The first entry in the returned array is the substitution for @var{text}.
+The remaining entries are the possible completions.  The array is
+terminated with a @code{NULL} pointer.
+
+@var{entry_function} is a function of two args, and returns a
+@code{(char *)}.  The first argument is @var{text}.  The second is a
+state argument; it is zero on the first call, and non-zero on subsequent
+calls.  It returns a @code{NULL}  pointer to the caller when there are
+no more matches.
+@end defun
+
+@defun {char *filename_completion_function} (char *text, int state)
+A generator function for filename completion in the general case.  Note
+that completion in the Bash shell is a little different because of all
+the pathnames that must be followed when looking up the completion for a
+command.
+@end defun
+
+@defun {char *username_completion_function} (char *text, int state)
+A completion generator for usernames.  @var{text} contains a partial
+username preceded by a random character (usually @samp{~}).
+@end defun
+
+@node Completion Variables
+@subsection Completion Variables
+
+@defvar {Function *rl_completion_entry_function}
+A pointer to the generator function for @code{completion_matches ()}.
+@code{NULL} means to use @code{filename_entry_function ()}, the default
+filename completer.
+@end defvar
+
+@defvar {Function *rl_attempted_completion_function}
+A pointer to an alternative function to create matches.
+The function is called with @var{text}, @var{start}, and @var{end}.
+@var{start} and @var{end} are indices in @code{rl_line_buffer} saying
+what the boundaries of @var{text} are.  If this function exists and
+returns @code{NULL} then @code{rl_complete ()} will call the value of
+@code{rl_completion_entry_function} to generate matches, otherwise the
+array of strings returned will be used.
+@end defvar
+
+@defvar {int rl_completion_query_items}
+Up to this many items will be displayed in response to a
+possible-completions call.  After that, we ask the user if she is sure
+she wants to see them all.  The default value is 100.
+@end defvar
+
+@defvar {char *rl_basic_word_break_characters}
+The basic list of characters that signal a break between words for the
+completer routine.  The contents of this variable is what breaks words
+in the Bash shell, i.e. " \t\n\"\\'`@@$><=;|&@{(".
+@end defvar
+
+@defvar {char *rl_completer_word_break_characters}
+The list of characters that signal a break between words for
+@code{rl_complete_internal ()}.  The default list is the contents of
+@code{rl_basic_word_break_characters}.
+@end defvar
+
+@defvar {char *rl_special_prefixes}
+The list of characters that are word break characters, but should be
+left in @var{text} when it is passed to the completion function.
+Programs can use this to help determine what kind of completing to do.
+@end defvar
+
+@defvar {int rl_ignore_completion_duplicates}
+If non-zero, then disallow duplicates in the matches.  Default is 1.
+@end defvar
+
+@defvar {int rl_filename_completion_desired}
+Non-zero means that the results of the matches are to be treated as
+filenames.  This is @emph{always} zero on entry, and can only be changed
+within a completion entry generator function.
+@end defvar
+
+@defvar {Function *rl_ignore_some_completions_function}
+This function, if defined, is called by the completer when real filename
+completion is done, after all the matching names have been generated.
+It is passed a @code{NULL} terminated array of @code{(char *)} known as
+@var{matches} in the code.  The 1st element (@code{matches[0]}) is the
+maximal substring that is common to all matches. This function can
+re-arrange the list of matches as required, but each deleted element of
+the array must be @code{free()}'d.
+@end defvar
+
+@node A Short Completion Example
+@subsection A Short Completion Example
+
+Here is a small application demonstrating the use of the GNU Readline
+library.  It is called @code{fileman}, and the source code resides in
+@file{readline/examples/fileman.c}.  This sample application provides
+completion of command names, line editing features, and access to the
+history list.
+
+@page
+@smallexample
+/* fileman.c -- A tiny application which demonstrates how to use the
+   GNU Readline library.  This application interactively allows users
+   to manipulate files and their modes. */
+
+#include <stdio.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+
+/* The names of functions that actually do the manipulation. */
+int com_list (), com_view (), com_rename (), com_stat (), com_pwd ();
+int com_delete (), com_help (), com_cd (), com_quit ();
+
+/* A structure which contains information on the commands this program
+   can understand. */
+
+typedef struct @{
+  char *name;                   /* User printable name of the function. */
+  Function *func;               /* Function to call to do the job. */
+  char *doc;                    /* Documentation for this function.  */
+@} COMMAND;
+
+COMMAND commands[] = @{
+  @{ "cd", com_cd, "Change to directory DIR" @},
+  @{ "delete", com_delete, "Delete FILE" @},
+  @{ "help", com_help, "Display this text" @},
+  @{ "?", com_help, "Synonym for `help'" @},
+  @{ "list", com_list, "List files in DIR" @},
+  @{ "ls", com_list, "Synonym for `list'" @},
+  @{ "pwd", com_pwd, "Print the current working directory" @},
+  @{ "quit", com_quit, "Quit using Fileman" @},
+  @{ "rename", com_rename, "Rename FILE to NEWNAME" @},
+  @{ "stat", com_stat, "Print out statistics on FILE" @},
+  @{ "view", com_view, "View the contents of FILE" @},
+  @{ (char *)NULL, (Function *)NULL, (char *)NULL @}
+@};
+
+/* The name of this program, as taken from argv[0]. */
+char *progname;
+
+/* When non-zero, this global means the user is done using this program. */
+int done = 0;
+@page
+main (argc, argv)
+     int argc;
+     char **argv;
+@{
+  progname = argv[0];
+
+  initialize_readline ();       /* Bind our completer. */
+
+  /* Loop reading and executing lines until the user quits. */
+  while (!done)
+    @{
+      char *line;
+
+      line = readline ("FileMan: ");
+
+      if (!line)
+        @{
+          done = 1;             /* Encountered EOF at top level. */
+        @}
+      else
+        @{
+          /* Remove leading and trailing whitespace from the line.
+             Then, if there is anything left, add it to the history list
+             and execute it. */
+          stripwhite (line);
+
+          if (*line)
+            @{
+              add_history (line);
+              execute_line (line);
+            @}
+        @}
+
+      if (line)
+        free (line);
+    @}
+  exit (0);
+@}
+
+/* Execute a command line. */
+execute_line (line)
+     char *line;
+@{
+  register int i;
+  COMMAND *find_command (), *command;
+  char *word;
+
+  /* Isolate the command word. */
+  i = 0;
+  while (line[i] && !whitespace (line[i]))
+    i++;
+
+  word = line;
+
+  if (line[i])
+    line[i++] = '\0';
+
+  command = find_command (word);
+
+  if (!command)
+    @{
+      fprintf (stderr, "%s: No such command for FileMan.\n", word);
+      return;
+    @}
+
+  /* Get argument to command, if any. */
+  while (whitespace (line[i]))
+    i++;
+
+  word = line + i;
+
+  /* Call the function. */
+  (*(command->func)) (word);
+@}
+
+/* Look up NAME as the name of a command, and return a pointer to that
+   command.  Return a NULL pointer if NAME isn't a command name. */
+COMMAND *
+find_command (name)
+     char *name;
+@{
+  register int i;
+
+  for (i = 0; commands[i].name; i++)
+    if (strcmp (name, commands[i].name) == 0)
+      return (&commands[i]);
+
+  return ((COMMAND *)NULL);
+@}
+
+/* Strip whitespace from the start and end of STRING. */
+stripwhite (string)
+     char *string;
+@{
+  register int i = 0;
+
+  while (whitespace (string[i]))
+    i++;
+
+  if (i)
+    strcpy (string, string + i);
+
+  i = strlen (string) - 1;
+
+  while (i > 0 && whitespace (string[i]))
+    i--;
+
+  string[++i] = '\0';
+@}
+@page
+/* **************************************************************** */
+/*                                                                  */
+/*                  Interface to Readline Completion                */
+/*                                                                  */
+/* **************************************************************** */
+
+/* Tell the GNU Readline library how to complete.  We want to try to complete
+   on command names if this is the first word in the line, or on filenames
+   if not. */
+initialize_readline ()
+@{
+  char **fileman_completion ();
+
+  /* Allow conditional parsing of the ~/.inputrc file. */
+  rl_readline_name = "FileMan";
+
+  /* Tell the completer that we want a crack first. */
+  rl_attempted_completion_function = (Function *)fileman_completion;
+@}
+
+/* Attempt to complete on the contents of TEXT.  START and END show the
+   region of TEXT that contains the word to complete.  We can use the
+   entire line in case we want to do some simple parsing.  Return the
+   array of matches, or NULL if there aren't any. */
+char **
+fileman_completion (text, start, end)
+     char *text;
+     int start, end;
+@{
+  char **matches;
+  char *command_generator ();
+
+  matches = (char **)NULL;
+
+  /* If this word is at the start of the line, then it is a command
+     to complete.  Otherwise it is the name of a file in the current
+     directory. */
+  if (start == 0)
+    matches = completion_matches (text, command_generator);
+
+  return (matches);
+@}
+
+/* Generator function for command completion.  STATE lets us know whether
+   to start from scratch; without any state (i.e. STATE == 0), then we
+   start at the top of the list. */
+char *
+command_generator (text, state)
+     char *text;
+     int state;
+@{
+  static int list_index, len;
+  char *name;
+
+  /* If this is a new word to complete, initialize now.  This includes
+     saving the length of TEXT for efficiency, and initializing the index
+     variable to 0. */
+  if (!state)
+    @{
+      list_index = 0;
+      len = strlen (text);
+    @}
+
+  /* Return the next name which partially matches from the command list. */
+  while (name = commands[list_index].name)
+    @{
+      list_index++;
+
+      if (strncmp (name, text, len) == 0)
+        return (name);
+    @}
+
+  /* If no names matched, then return NULL. */
+  return ((char *)NULL);
+@}
+@page
+/* **************************************************************** */
+/*                                                                  */
+/*                       FileMan Commands                           */
+/*                                                                  */
+/* **************************************************************** */
+
+/* String to pass to system ().  This is for the LIST, VIEW and RENAME
+   commands. */
+static char syscom[1024];
+
+/* List the file(s) named in arg. */
+com_list (arg)
+     char *arg;
+@{
+  if (!arg)
+    arg = "*";
+
+  sprintf (syscom, "ls -FClg %s", arg);
+  system (syscom);
+@}
+
+com_view (arg)
+     char *arg;
+@{
+  if (!valid_argument ("view", arg))
+    return;
+
+  sprintf (syscom, "cat %s | more", arg);
+  system (syscom);
+@}
+
+com_rename (arg)
+     char *arg;
+@{
+  too_dangerous ("rename");
+@}
+
+com_stat (arg)
+     char *arg;
+@{
+  struct stat finfo;
+
+  if (!valid_argument ("stat", arg))
+    return;
+
+  if (stat (arg, &finfo) == -1)
+    @{
+      perror (arg);
+      return;
+    @}
+
+  printf ("Statistics for `%s':\n", arg);
+
+  printf ("%s has %d link%s, and is %d bytes in length.\n", arg,
+          finfo.st_nlink, (finfo.st_nlink == 1) ? "" : "s",  finfo.st_size);
+  printf ("      Created on: %s", ctime (&finfo.st_ctime));
+  printf ("  Last access at: %s", ctime (&finfo.st_atime));
+  printf ("Last modified at: %s", ctime (&finfo.st_mtime));
+@}
+
+com_delete (arg)
+     char *arg;
+@{
+  too_dangerous ("delete");
+@}
+
+/* Print out help for ARG, or for all of the commands if ARG is
+   not present. */
+com_help (arg)
+     char *arg;
+@{
+  register int i;
+  int printed = 0;
+
+  for (i = 0; commands[i].name; i++)
+    @{
+      if (!*arg || (strcmp (arg, commands[i].name) == 0))
+        @{
+          printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
+          printed++;
+        @}
+    @}
+
+  if (!printed)
+    @{
+      printf ("No commands match `%s'.  Possibilties are:\n", arg);
+
+      for (i = 0; commands[i].name; i++)
+        @{
+          /* Print in six columns. */
+          if (printed == 6)
+            @{
+              printed = 0;
+              printf ("\n");
+            @}
+
+          printf ("%s\t", commands[i].name);
+          printed++;
+        @}
+
+      if (printed)
+        printf ("\n");
+    @}
+@}
+
+/* Change to the directory ARG. */
+com_cd (arg)
+     char *arg;
+@{
+  if (chdir (arg) == -1)
+    perror (arg);
+
+  com_pwd ("");
+@}
+
+/* Print out the current working directory. */
+com_pwd (ignore)
+     char *ignore;
+@{
+  char dir[1024];
+
+  (void) getwd (dir);
+
+  printf ("Current directory is %s\n", dir);
+@}
+
+/* The user wishes to quit using this program.  Just set DONE non-zero. */
+com_quit (arg)
+     char *arg;
+@{
+  done = 1;
+@}
+
+/* Function which tells you that you can't do this. */
+too_dangerous (caller)
+     char *caller;
+@{
+  fprintf (stderr,
+           "%s: Too dangerous for me to distribute.  Write it yourself.\n",
+           caller);
+@}
+
+/* Return non-zero if ARG is a valid argument for CALLER, else print
+   an error message and return zero. */
+int
+valid_argument (caller, arg)
+     char *caller, *arg;
+@{
+  if (!arg || !*arg)
+    @{
+      fprintf (stderr, "%s: Argument required.\n", caller);
+      return (0);
+    @}
+
+  return (1);
+@}
+@end smallexample
diff --git a/readline/doc/rluser.texinfo b/readline/doc/rluser.texinfo
new file mode 100644 (file)
index 0000000..c6aa4da
--- /dev/null
@@ -0,0 +1,559 @@
+@comment %**start of header (This is for running Texinfo on a region.)
+@setfilename rluser.info
+@comment %**end of header (This is for running Texinfo on a region.)
+@setchapternewpage odd
+
+@ignore
+This file documents the end user interface to the GNU command line
+editing feautres.  It is to be an appendix to manuals for programs which
+use these features.  There is a document entitled "readline.texinfo"
+which contains both end-user and programmer documentation for the GNU
+Readline Library.
+
+Copyright (C) 1988 Free Software Foundation, Inc.
+
+Authored by Brian Fox.
+
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission notice
+identical to this one except for the removal of this paragraph (this
+paragraph not being relevant to the printed manual).
+
+Permission is granted to make and distribute verbatim copies of this manual
+provided the copyright notice and this permission notice are preserved on
+all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+GNU Copyright statement is available to the distributee, and provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions.
+@end ignore
+
+@node Command Line Editing
+@chapter Command Line Editing
+
+This text describes GNU's command line editing interface.
+
+@menu
+* Introduction and Notation::  Notation used in this text.
+* Readline Interaction::       The minimum set of commands for editing a line.
+* Readline Init File::         Customizing Readline from a user's view.
+@end menu
+
+@node Introduction and Notation
+@section Introduction to Line Editing
+
+The following paragraphs describe the notation we use to represent
+keystrokes.
+
+The text @key{C-k} is read as `Control-K' and describes the character
+produced when the Control key is depressed and the @key{k} key is struck.
+
+The text @key{M-k} is read as `Meta-K' and describes the character
+produced when the meta key (if you have one) is depressed, and the @key{k}
+key is struck.  If you do not have a meta key, the identical keystroke
+can be generated by typing @key{ESC} @i{first}, and then typing @key{k}.
+Either process is known as @dfn{metafying} the @key{k} key.
+
+The text @key{M-C-k} is read as `Meta-Control-k' and describes the
+character produced by @dfn{metafying} @key{C-k}.
+
+In addition, several keys have their own names.  Specifically,
+@key{DEL}, @key{ESC}, @key{LFD}, @key{SPC}, @key{RET}, and @key{TAB} all
+stand for themselves when seen in this text, or in an init file
+(@pxref{Readline Init File}, for more info).
+
+@node Readline Interaction
+@section Readline Interaction
+@cindex interaction, readline
+
+Often during an interactive session you type in a long line of text,
+only to notice that the first word on the line is misspelled.  The
+Readline library gives you a set of commands for manipulating the text
+as you type it in, allowing you to just fix your typo, and not forcing
+you to retype the majority of the line.  Using these editing commands,
+you move the cursor to the place that needs correction, and delete or
+insert the text of the corrections.  Then, when you are satisfied with
+the line, you simply press @key{RETURN}.  You do not have to be at the
+end of the line to press @key{RETURN}; the entire line is accepted
+regardless of the location of the cursor within the line.
+
+@menu
+* Readline Bare Essentials::   The least you need to know about Readline.
+* Readline Movement Commands:: Moving about the input line.
+* Readline Killing Commands::  How to delete text, and how to get it back!
+* Readline Arguments::         Giving numeric arguments to commands.
+@end menu
+
+@node Readline Bare Essentials
+@subsection Readline Bare Essentials
+
+In order to enter characters into the line, simply type them.  The typed
+character appears where the cursor was, and then the cursor moves one
+space to the right.  If you mistype a character, you can use @key{DEL} to
+back up, and delete the mistyped character.
+
+Sometimes you may miss typing a character that you wanted to type, and
+not notice your error until you have typed several other characters.  In
+that case, you can type @key{C-b} to move the cursor to the left, and then
+correct your mistake.  Aftwerwards, you can move the cursor to the right
+with @key{C-f}.
+
+When you add text in the middle of a line, you will notice that characters
+to the right of the cursor get `pushed over' to make room for the text
+that you have inserted.  Likewise, when you delete text behind the cursor,
+characters to the right of the cursor get `pulled back' to fill in the
+blank space created by the removal of the text.  A list of the basic bare
+essentials for editing the text of an input line follows.
+
+@table @asis
+@item @key{C-b}
+Move back one character.
+@item @key{C-f}
+Move forward one character.
+@item @key{DEL}
+Delete the character to the left of the cursor.
+@item @key{C-d}
+Delete the character underneath the cursor.
+@item @w{Printing characters}
+Insert itself into the line at the cursor.
+@item @key{C-_}
+Undo the last thing that you did.  You can undo all the way back to an
+empty line.
+@end table
+
+@node Readline Movement Commands
+@subsection Readline Movement Commands
+
+
+The above table describes the most basic possible keystrokes that you need
+in order to do editing of the input line.  For your convenience, many
+other commands have been added in addition to @key{C-b}, @key{C-f},
+@key{C-d}, and @key{DEL}.  Here are some commands for moving more rapidly
+about the line.
+
+@table @key
+@item C-a
+Move to the start of the line.
+@item C-e
+Move to the end of the line.
+@item M-f
+Move forward a word.
+@item M-b
+Move backward a word.
+@item C-l
+Clear the screen, reprinting the current line at the top.
+@end table
+
+Notice how @key{C-f} moves forward a character, while @key{M-f} moves
+forward a word.  It is a loose convention that control keystrokes
+operate on characters while meta keystrokes operate on words.
+
+@node Readline Killing Commands
+@subsection Readline Killing Commands
+
+The act of @dfn{cutting} text means to delete the text from the line, and
+to save away the deleted text for later use, just as if you had cut the
+text out of the line with a pair of scissors.  There is a
+
+@dfn{Killing} text means to delete the text from the line, but to save
+it away for later use, usually by @dfn{yanking} it back into the line.
+If the description for a command says that it `kills' text, then you can
+be sure that you can get the text back in a different (or the same)
+place later.
+
+Here is the list of commands for killing text.
+
+@table @key
+@item C-k
+Kill the text from the current cursor position to the end of the line.
+
+@item M-d
+Kill from the cursor to the end of the current word, or if between
+words, to the end of the next word.
+
+@item M-DEL
+Kill fromthe cursor the start of the previous word, or if between words, to the start of the previous word.
+
+@item C-w
+Kill from the cursor to the previous whitespace.  This is different than
+@key{M-DEL} because the word boundaries differ.
+
+@end table
+
+And, here is how to @dfn{yank} the text back into the line.  Yanking
+is
+
+@table @key
+@item C-y
+Yank the most recently killed text back into the buffer at the cursor.
+
+@item M-y
+Rotate the kill-ring, and yank the new top.  You can only do this if
+the prior command is @key{C-y} or @key{M-y}.
+@end table
+
+When you use a kill command, the text is saved in a @dfn{kill-ring}.
+Any number of consecutive kills save all of the killed text together, so
+that when you yank it back, you get it in one clean sweep.  The kill
+ring is not line specific; the text that you killed on a previously
+typed line is available to be yanked back later, when you are typing
+another line.
+
+@node Readline Arguments
+@subsection Readline Arguments
+
+You can pass numeric arguments to Readline commands.  Sometimes the
+argument acts as a repeat count, other times it is the @i{sign} of the
+argument that is significant.  If you pass a negative argument to a
+command which normally acts in a forward direction, that command will
+act in a backward direction.  For example, to kill text back to the
+start of the line, you might type @key{M--} @key{C-k}.
+
+The general way to pass numeric arguments to a command is to type meta
+digits before the command.  If the first `digit' you type is a minus
+sign (@key{-}), then the sign of the argument will be negative.  Once
+you have typed one meta digit to get the argument started, you can type
+the remainder of the digits, and then the command.  For example, to give
+the @key{C-d} command an argument of 10, you could type @key{M-1 0 C-d}.
+
+
+@node Readline Init File
+@section Readline Init File
+
+Although the Readline library comes with a set of Emacs-like
+keybindings, it is possible that you would like to use a different set
+of keybindings.  You can customize programs that use Readline by putting
+commands in an @dfn{init} file in your home directory.  The name of this
+file is @file{~/.inputrc}.
+
+When a program which uses the Readline library starts up, the
+@file{~/.inputrc} file is read, and the keybindings are set.
+
+In addition, the @code{C-x C-r} command re-reads this init file, thus
+incorporating any changes that you might have made to it.
+
+@menu
+* Readline Init Syntax::       Syntax for the commands in @file{~/.inputrc}.
+* Readline Vi Mode::           Switching to @code{vi} mode in Readline.
+@end menu
+
+@node Readline Init Syntax
+@subsection Readline Init Syntax
+
+There are only four constructs allowed in the @file{~/.inputrc}
+file:
+
+@table @asis
+@item Variable Settings
+You can change the state of a few variables in Readline.  You do this by
+using the @code{set} command within the init file.  Here is how you
+would specify that you wish to use Vi line editing commands:
+
+@example
+set editing-mode vi
+@end example
+
+Right now, there are only a few variables which can be set; so few in
+fact, that we just iterate them here:
+
+@table @code
+
+@item editing-mode
+@vindex editing-mode
+The @code{editing-mode} variable controls which editing mode you are
+using.  By default, GNU Readline starts up in Emacs editing mode, where
+the keystrokes are most similar to Emacs.  This variable can either be
+set to @code{emacs} or @code{vi}.
+
+@item horizontal-scroll-mode
+@vindex horizontal-scroll-mode
+This variable can either be set to @code{On} or @code{Off}.  Setting it
+to @code{On} means that the text of the lines that you edit will scroll
+horizontally on a single screen line when they are larger than the width
+of the screen, instead of wrapping onto a new screen line.  By default,
+this variable is set to @code{Off}.
+
+@item mark-modified-lines
+@vindex mark-modified-lines
+This variable when set to @code{On}, says to display an asterisk
+(@samp{*}) at the starts of history lines which have been modified.
+This variable is off by default.
+
+@item prefer-visible-bell
+@vindex prefer-visible-bell
+If this variable is set to @code{On} it means to use a visible bell if
+one is available, rather than simply ringing the terminal bell.  By
+default, the value is @code{Off}.
+@end table
+
+@item Key Bindings
+The syntax for controlling keybindings in the @file{~/.inputrc} file is
+simple.  First you have to know the @i{name} of the command that you
+want to change.  The following pages contain tables of the command name,
+the default keybinding, and a short description of what the command
+does.
+
+Once you know the name of the command, simply place the name of the key
+you wish to bind the command to, a colon, and then the name of the
+command on a line in the @file{~/.inputrc} file.  The name of the key
+can be expressed in different ways, depending on which is most
+comfortable for you.
+
+@table @asis
+@item @w{@var{keyname}: @var{function-name} or @var{macro}}
+@var{keyname} is the name of a key spelled out in English.  For example:
+@example
+Control-u: universal-argument
+Meta-Rubout: backward-kill-word
+Control-o: ">&output"
+@end example
+
+In the above example, @samp{C-u} is bound to the function
+@code{universal-argument}, and @samp{C-o} is bound to run the macro
+expressed on the right hand side (that is, to insert the text
+@samp{>&output} into the line).
+
+@item @w{"@var{keyseq}": @var{function-name} or @var{macro}}
+@var{keyseq} differs from @var{keyname} above in that strings denoting
+an entire key sequence can be specified.  Simply place the key sequence
+in double quotes.  GNU Emacs style key escapes can be used, as in the
+following example:
+
+@example
+"\C-u": universal-argument
+"\C-x\C-r": re-read-init-file
+"\e[11~": "Function Key 1"
+@end example
+
+In the above example, @samp{C-u} is bound to the function
+@code{universal-argument} (just as it was in the first example),
+@samp{C-x C-r} is bound to the function @code{re-read-init-file}, and
+@samp{ESC [ 1 1 ~} is bound to insert the text @samp{Function Key 1}.
+
+@end table
+@end table
+
+@menu
+* Commands For Moving::                Moving about the line.
+* Commands For History::       Getting at previous lines.
+* Commands For Text::          Commands for changing text.
+* Commands For Killing::       Commands for killing and yanking.
+* Numeric Arguments::          Specifying numeric arguments, repeat counts.
+* Commands For Completion::    Getting Readline to do the typing for you.
+* Miscellaneous Commands::     Other miscillaneous commands.
+@end menu
+
+@node Commands For Moving
+@subsubsection Commands For Moving
+@ftable @code
+@item beginning-of-line (C-a)
+Move to the start of the current line.
+
+@item end-of-line (C-e)
+Move to the end of the line.
+
+@item forward-char (C-f)
+Move forward a character.
+
+@item backward-char (C-b)
+Move back a character.
+
+@item forward-word (M-f)
+Move forward to the end of the next word.
+
+@item backward-word (M-b)
+Move back to the start of this, or the previous, word.
+
+@item clear-screen (C-l)
+Clear the screen leaving the current line at the top of the screen.
+
+@end ftable
+
+@node Commands For History
+@subsubsection Commands For Manipulating The History
+
+@ftable @code
+@item accept-line (Newline, Return)
+Accept the line regardless of where the cursor is.  If this line is
+non-empty, add it to the history list.  If this line was a history
+line, then restore the history line to its original state.
+
+@item previous-history (C-p)
+Move `up' through the history list.
+
+@item next-history (C-n)
+Move `down' through the history list.
+
+@item beginning-of-history (M-<)
+Move to the first line in the history.
+
+@item end-of-history (M->)
+Move to the end of the input history, i.e., the line you are entering!
+
+@item reverse-search-history (C-r)
+Search backward starting at the current line and moving `up' through
+the history as necessary.  This is an incremental search.
+
+@item forward-search-history (C-s)
+Search forward starting at the current line and moving `down' through
+the the history as neccessary.
+
+@end ftable
+
+@node Commands For Text
+@subsubsection Commands For Changing Text
+
+@ftable @code
+@item delete-char (C-d)
+Delete the character under the cursor.  If the cursor is at the
+beginning of the line, and there are no characters in the line, and
+the last character typed was not C-d, then return EOF.
+
+@item backward-delete-char (Rubout)
+Delete the character behind the cursor.  A numeric arg says to kill
+the characters instead of deleting them.
+
+@item quoted-insert (C-q, C-v)
+Add the next character that you type to the line verbatim.  This is
+how to insert things like C-q for example.
+
+@item tab-insert (M-TAB)
+Insert a tab character.
+
+@item self-insert (a, b, A, 1, !, ...)
+Insert yourself.
+
+@item transpose-chars (C-t)
+Drag the character before point forward over the character at point.
+Point moves forward as well.  If point is at the end of the line, then
+transpose the two characters before point.  Negative args don't work.
+
+@item transpose-words (M-t)
+Drag the word behind the cursor past the word in front of the cursor
+moving the cursor over that word as well.
+
+@item upcase-word (M-u)
+Uppercase the current (or following) word.  With a negative argument,
+do the previous word, but do not move point.
+
+@item downcase-word (M-l)
+Lowercase the current (or following) word.  With a negative argument,
+do the previous word, but do not move point.
+
+@item capitalize-word (M-c)
+Uppercase the current (or following) word.  With a negative argument,
+do the previous word, but do not move point.
+
+@end ftable
+
+@node Commands For Killing
+@subsubsection Killing And Yanking
+
+@ftable @code
+
+@item kill-line (C-k)
+Kill the text from the current cursor position to the end of the line.
+
+@item backward-kill-line ()
+Kill backward to the beginning of the line.  This is normally unbound.
+
+@item kill-word (M-d)
+Kill from the cursor to the end of the current word, or if between
+words, to the end of the next word.
+
+@item backward-kill-word (M-DEL)
+Kill the word behind the cursor.
+
+@item unix-line-discard (C-u)
+Do what C-u used to do in Unix line input.  We save the killed text on
+the kill-ring, though.
+
+@item unix-word-rubout (C-w)
+Do what C-w used to do in Unix line input.  The killed text is saved
+on the kill-ring.  This is different than backward-kill-word because
+the word boundaries differ.
+
+@item yank (C-y)
+Yank the top of the kill ring into the buffer at point.
+
+@item yank-pop (M-y)
+Rotate the kill-ring, and yank the new top.  You can only do this if
+the prior command is yank or yank-pop.
+@end ftable
+
+@node Numeric Arguments
+@subsubsection Specifying Numeric Arguments
+@ftable @code
+
+@item digit-argument (M-0, M-1, ... M--)
+Add this digit to the argument already accumulating, or start a new
+argument.  M-- starts a negative argument.
+
+@item universal-argument ()
+Do what C-u does in emacs.  By default, this is not bound.
+@end ftable
+
+
+@node Commands For Completion
+@subsubsection Letting Readline Type For You
+
+@ftable @code
+@item complete (TAB)
+Attempt to do completion on the text before point.  This is
+implementation defined.  Generally, if you are typing a filename
+argument, you can do filename completion; if you are typing a command,
+you can do command completion, if you are typing in a symbol to GDB, you
+can do symbol name completion, if you are typing in a variable to Bash,
+you can do variable name completion...
+
+@item possible-completions (M-?)
+List the possible completions of the text before point.
+@end ftable
+
+@node Miscellaneous Commands
+@subsubsection Some Miscellaneous Commands
+@ftable @code
+
+@item re-read-init-file (C-x C-r)
+Read in the contents of your @file{~/.inputrc} file, and incorporate
+any bindings found there.
+
+@item abort (C-g)
+Ding!  Stops things.
+
+@item do-uppercase-version (M-a, M-b, ...)
+Run the command that is bound to your uppercase brother.
+
+@item prefix-meta (ESC)
+Make the next character that you type be metafied.  This is for people
+without a meta key.  Typing @samp{ESC f} is equivalent to typing
+@samp{M-f}.
+
+@item undo (C-_)
+Incremental undo, separately remembered for each line.
+
+@item revert-line (M-r)
+Undo all changes made to this line.  This is like typing the `undo'
+command enough times to get back to the beginning.
+@end ftable
+
+@node Readline Vi Mode
+@subsection Readline Vi Mode
+
+While the Readline library does not have a full set of Vi editing
+functions, it does contain enough to allow simple editing of the line.
+
+In order to switch interactively between Emacs and Vi editing modes, use
+the command M-C-j (toggle-editing-mode).
+
+When you enter a line in Vi mode, you are already placed in `insertion'
+mode, as if you had typed an `i'.  Pressing @key{ESC} switches you into
+`edit' mode, where you can edit the text of the line with the standard
+Vi movement keys, move to previous history lines with `k', and following
+lines with `j', and so forth.
+
diff --git a/readline/doc/texindex.c b/readline/doc/texindex.c
new file mode 100644 (file)
index 0000000..cb979da
--- /dev/null
@@ -0,0 +1,1606 @@
+/* Prepare Tex index dribble output into an actual index.
+   Copyright (C) 1987 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 1, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;
+
+#ifdef VMS
+#ifndef VAX11C
+#define noshare
+#endif
+
+#include <perror.h>
+#include <file.h>
+
+#define EXIT_SUCCESS ((1 << 28) | 1)
+#define EXIT_FATAL ((1 << 28) | 4)
+#define unlink delete
+#define tell(fd) lseek(fd, 0L, 1)
+
+#else /* Not VMS */
+
+#ifdef USG
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#endif
+#include <sys/file.h>
+
+#define EXIT_SUCCESS 0
+#define EXIT_FATAL 1
+
+#endif /* Not VMS */
+
+
+#ifndef L_XTND
+#define L_XTND 2
+#endif
+
+#ifdef VMS
+extern noshare int sys_nerr;
+extern noshare char *sys_errlist[];
+#else
+extern int sys_nerr;
+extern char *sys_errlist[];
+#endif
+
+/* When sorting in core, this structure describes one line
+ and the position and length of its first keyfield.  */
+
+struct lineinfo
+  {
+    char *text;                /* The actual text of the line */
+    union
+      {                        /* The start of the key (for textual comparison) */
+       char *text;
+       long number;    /* or the numeric value (for numeric comparison) */
+      } key;
+    long keylen;       /* Length of key field */
+  };
+
+/* This structure describes a field to use as a sort key */
+
+struct keyfield
+  {
+    int startwords;            /* # words to skip  */
+    int startchars;            /*  and # additional chars to skip, to start of field */
+    int endwords;              /* similar, from beg (or end) of line, to find end of field */
+    int endchars;
+    char ignore_blanks;                /* Ignore spaces and tabs within the field */
+    char fold_case;            /* Convert upper case to lower before comparing */
+    char reverse;              /* Compare in reverse order */
+    char numeric;              /* Parse text as an integer and compare the integers */
+    char positional;           /* Sort according to position within the file */
+    char braced;               /* Count balanced-braced groupings as fields */
+  };
+
+/* Vector of keyfields to use */
+
+struct keyfield keyfields[3];
+
+/* Number of keyfields stored in that vector.  */
+
+int num_keyfields = 3;
+
+/* Vector of input file names, terminated with a zero (null pointer) */
+
+char **infiles;
+
+/* Vector of corresponding output file names, or zero meaning default it */
+
+char **outfiles;
+
+/* Length of `infiles' */
+
+int num_infiles;
+
+/* Pointer to the array of pointers to lines being sorted */
+
+char **linearray;
+
+/* The allocated length of `linearray'. */
+
+long nlines;
+
+/* Directory to use for temporary files.  On Unix, it ends with a slash.  */
+
+char *tempdir;
+
+/* Start of filename to use for temporary files.  */
+
+char *tempbase;
+
+/* Number of last temporary file.  */
+
+int tempcount;
+
+/* Number of last temporary file already deleted.
+ Temporary files are deleted by `flush_tempfiles' in order of creation.  */
+
+int last_deleted_tempcount;
+
+/* During in-core sort, this points to the base of the data block
+ which contains all the lines of data.  */
+
+char *text_base;
+
+/* Additional command switches */
+
+int keep_tempfiles;    /* Nonzero means do not delete tempfiles -- for debugging */
+
+/* Forward declarations of functions in this file */
+
+void decode_command ();
+void sort_in_core ();
+void sort_offline ();
+char **parsefile ();
+char *find_field ();
+char *find_pos ();
+long find_value ();
+char *find_braced_pos ();
+char *find_braced_end ();
+void writelines ();
+int compare_full ();
+long readline ();
+int merge_files ();
+int merge_direct ();
+char *concat ();
+char *maketempname ();
+void flush_tempfiles ();
+char *tempcopy ();
+
+extern char *mktemp ();
+\f
+#define MAX_IN_CORE_SORT 500000
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int i;
+
+  tempcount = 0;
+  last_deleted_tempcount = 0;
+
+  /* Describe the kind of sorting to do. */
+  /* The first keyfield uses the first braced field and folds case */
+  keyfields[0].braced = 1;
+  keyfields[0].fold_case = 1;
+  keyfields[0].endwords = -1;
+  keyfields[0].endchars = -1;
+  /* The second keyfield uses the second braced field, numerically */
+  keyfields[1].braced = 1;
+  keyfields[1].numeric = 1;
+  keyfields[1].startwords = 1;
+  keyfields[1].endwords = -1;
+  keyfields[1].endchars = -1;
+  /* The third keyfield (which is ignored while discarding duplicates)
+     compares the whole line */
+  keyfields[2].endwords = -1;
+  keyfields[2].endchars = -1;
+
+  decode_command (argc, argv);
+
+  tempbase = mktemp (concat ("txiXXXXXX", "", ""));
+
+  /* Process input files completely, one by one.  */
+
+  for (i = 0; i < num_infiles; i++)
+    {
+      int desc;
+      long ptr;
+      char *outfile;
+      char *p;
+
+      desc = open (infiles[i], 0, 0);
+      if (desc < 0) pfatal_with_name (infiles[i]);
+      lseek (desc, 0, L_XTND);
+      ptr = tell (desc);
+      close (desc);
+
+      outfile = outfiles[i];
+      if (!outfile)
+       {
+         outfile = concat (infiles[i], "s", "");
+       }
+
+      if (ptr < MAX_IN_CORE_SORT)
+        /* Sort a small amount of data */
+        sort_in_core (infiles[i], ptr, outfile);
+      else
+        sort_offline (infiles[i], ptr, outfile);
+    }
+
+  flush_tempfiles (tempcount);
+  exit (EXIT_SUCCESS);
+}
+\f
+/* This page decodes the command line arguments to set the parameter variables
+ and set up the vector of keyfields and the vector of input files */
+
+void
+decode_command (argc, argv)
+     int argc;
+     char **argv;
+{
+  int i;
+  char **ip;
+  char **op;
+
+  /* Store default values into parameter variables */
+
+#ifdef VMS
+  tempdir = "sys$scratch:";
+#else
+  tempdir = "/tmp/";
+#endif
+
+  keep_tempfiles = 0;
+
+  /* Allocate argc input files, which must be enough.  */
+
+  infiles = (char **) xmalloc (argc * sizeof (char *));
+  outfiles = (char **) xmalloc (argc * sizeof (char *));
+  ip = infiles;
+  op = outfiles;
+
+  /* First find all switches that control the default kind-of-sort */
+
+  for (i = 1; i < argc; i++)
+    {
+      int tem = classify_arg (argv[i]);
+      char c;
+      char *p;
+
+      if (tem <= 0)
+       {
+         *ip++ = argv[i];
+         *op++ = 0;
+         continue;
+       }
+      if (tem > 1)
+       {
+         if (i + 1 == argc)
+           fatal ("switch %s given with no argument following it", argv[i]);
+         else if (!strcmp (argv[i], "-T"))
+           tempdir = argv[i + 1];
+         else if (!strcmp (argv[i], "-o"))
+           *(op - 1) = argv[i + 1];
+         i += tem - 1;
+         continue;
+       }
+
+      p = &argv[i][1];
+      while (c = *p++)
+       switch (c)
+         {
+         case 'k':
+           keep_tempfiles = 1;
+           break;
+
+         default:
+           fatal ("invalid command switch %c", c);
+         }
+    switchdone: ;
+    }
+
+  /* Record number of keyfields, terminate list of filenames */
+
+  num_infiles = ip - infiles;
+  *ip = 0;
+}
+
+/* Return 0 for an argument that is not a switch;
+ for a switch, return 1 plus the number of following arguments that the switch swallows.
+*/
+
+int
+classify_arg (arg)
+     char *arg;
+{
+  if (!strcmp (arg, "-T") || !strcmp (arg, "-o"))
+    return 2;
+  if (arg[0] == '-')
+    return 1;
+  return 0;
+}
+\f
+/* Create a name for a temporary file */
+
+char *
+maketempname (count)
+     int count;
+{
+  char tempsuffix[10];
+  sprintf (tempsuffix, "%d", count);
+  return concat (tempdir, tempbase, tempsuffix);
+}
+
+/* Delete all temporary files up to the specified count */
+
+void
+flush_tempfiles (to_count)
+     int to_count;
+{
+  if (keep_tempfiles) return;
+  while (last_deleted_tempcount < to_count)
+    unlink (maketempname (++last_deleted_tempcount));
+}
+
+/* Copy an input file into a temporary file, and return the temporary file name */
+
+#define BUFSIZE 1024
+
+char *
+tempcopy (idesc)
+     int idesc;
+{
+  char *outfile = maketempname (++tempcount);
+  int odesc;
+  char buffer[BUFSIZE];
+
+  odesc = open (outfile, O_WRONLY | O_CREAT, 0666);
+
+  if (odesc < 0) pfatal_with_name (outfile);
+
+  while (1)
+    {
+      int nread = read (idesc, buffer, BUFSIZE);
+      write (odesc, buffer, nread);
+      if (!nread) break;
+    }
+
+  close (odesc);
+
+  return outfile;
+}
+\f
+/* Compare two lines, provided as pointers to pointers to text,
+ according to the specified set of keyfields */
+
+int
+compare_full (line1, line2)
+     char **line1, **line2;
+{
+  int i;
+
+  /* Compare using the first keyfield;
+     if that does not distinguish the lines, try the second keyfield; and so on. */
+
+  for (i = 0; i < num_keyfields; i++)
+    {
+      long length1, length2;
+      char *start1 = find_field (&keyfields[i], *line1, &length1);
+      char *start2 = find_field (&keyfields[i], *line2, &length2);
+      int tem = compare_field (&keyfields[i], start1, length1, *line1 - text_base,
+                                             start2, length2, *line2 - text_base);
+      if (tem)
+       {
+         if (keyfields[i].reverse)
+           return - tem;
+          return tem;
+       }
+    }
+
+  return 0;    /* Lines match exactly */
+}
+
+/* Compare two lines described by structures
+ in which the first keyfield is identified in advance.
+ For positional sorting, assumes that the order of the lines in core
+ reflects their nominal order.  */
+
+int
+compare_prepared (line1, line2)
+     struct lineinfo *line1, *line2;
+{
+  int i;
+  int tem;
+  char *text1, *text2;
+
+  /* Compare using the first keyfield, which has been found for us already */
+  if (keyfields->positional)
+    {
+      if (line1->text - text_base > line2->text - text_base)
+       tem = 1;
+      else
+       tem = -1;
+    }
+  else if (keyfields->numeric)
+    tem = line1->key.number - line2->key.number;
+  else
+    tem = compare_field (keyfields, line1->key.text, line1->keylen, 0, line2->key.text, line2->keylen, 0);
+  if (tem)
+    {
+      if (keyfields->reverse)
+       return - tem;
+      return tem;
+    }
+
+  text1 = line1->text;
+  text2 = line2->text;
+
+  /* Compare using the second keyfield;
+     if that does not distinguish the lines, try the third keyfield; and so on. */
+
+  for (i = 1; i < num_keyfields; i++)
+    {
+      long length1, length2;
+      char *start1 = find_field (&keyfields[i], text1, &length1);
+      char *start2 = find_field (&keyfields[i], text2, &length2);
+      int tem = compare_field (&keyfields[i], start1, length1, text1 - text_base,
+                                             start2, length2, text2 - text_base);
+      if (tem)
+       {
+         if (keyfields[i].reverse)
+           return - tem;
+          return tem;
+       }
+    }
+
+  return 0;    /* Lines match exactly */
+}
+
+/* Like compare_full but more general.
+ You can pass any strings, and you can say how many keyfields to use.
+ `pos1' and `pos2' should indicate the nominal positional ordering of
+ the two lines in the input.  */
+
+int
+compare_general (str1, str2, pos1, pos2, use_keyfields)
+     char *str1, *str2;
+     long pos1, pos2;
+     int use_keyfields;
+{
+  int i;
+
+  /* Compare using the first keyfield;
+     if that does not distinguish the lines, try the second keyfield; and so on. */
+
+  for (i = 0; i < use_keyfields; i++)
+    {
+      long length1, length2;
+      char *start1 = find_field (&keyfields[i], str1, &length1);
+      char *start2 = find_field (&keyfields[i], str2, &length2);
+      int tem = compare_field (&keyfields[i], start1, length1, pos1, start2, length2, pos2);
+      if (tem)
+       {
+         if (keyfields[i].reverse)
+           return - tem;
+          return tem;
+       }
+    }
+
+  return 0;    /* Lines match exactly */
+}
+
+/* Find the start and length of a field in `str' according to `keyfield'.
+ A pointer to the starting character is returned, and the length
+ is stored into the int that `lengthptr' points to.  */
+
+char *
+find_field (keyfield, str, lengthptr)
+     struct keyfield *keyfield;
+     char *str;
+     long *lengthptr;
+{
+  char *start;
+  char *end;
+  char *(*fun) ();
+
+  if (keyfield->braced) fun = find_braced_pos;
+  else fun = find_pos;
+
+  start = ( *fun )(str, keyfield->startwords, keyfield->startchars,
+              keyfield->ignore_blanks);
+  if (keyfield->endwords < 0)
+    {
+      if (keyfield->braced)
+       end = find_braced_end (start);
+      else
+       {
+         end = start;
+         while (*end && *end != '\n') end++;
+       }
+    }
+  else
+    {
+      end = ( *fun )(str, keyfield->endwords, keyfield->endchars, 0);
+      if (end - str < start - str) end = start;
+    }
+  *lengthptr = end - start;
+  return start;
+}
+
+/* Find a pointer to a specified place within `str',
+ skipping (from the beginning) `words' words and then `chars' chars.
+ If `ignore_blanks' is nonzero, we skip all blanks
+ after finding the specified word.  */
+
+char *
+find_pos (str, words, chars, ignore_blanks)
+     char *str;
+     int words, chars;
+     int ignore_blanks;
+{
+  int i;
+  char *p = str;
+
+  for (i = 0; i < words; i++)
+    {
+      char c;
+      /* Find next bunch of nonblanks and skip them. */
+      while ((c = *p) == ' ' || c == '\t') p++;
+      while ((c = *p) && c != '\n' && !(c == ' ' || c == '\t')) p++;
+      if (!*p || *p == '\n') return p;
+    }
+
+  while (*p == ' ' || *p == '\t') p++;
+
+  for (i = 0; i < chars; i++)
+    {
+      if (!*p  || *p == '\n') break;
+      p++;
+    }
+  return p;
+}
+
+/* Like find_pos but assumes that each field is surrounded by braces
+ and that braces within fields are balanced. */
+
+char *
+find_braced_pos (str, words, chars, ignore_blanks)
+     char *str;
+     int words, chars;
+     int ignore_blanks;
+{
+  int i;
+  int bracelevel;
+  char *p = str;
+  char c;
+
+  for (i = 0; i < words; i++)
+    {
+      bracelevel = 1;
+      while ((c = *p++) != '{' && c != '\n' && c);
+      if (c != '{')
+       return p - 1;
+      while (bracelevel)
+       {
+         c = *p++;
+         if (c == '{') bracelevel++;
+         if (c == '}') bracelevel--;
+#if 0
+         if (c == '\\' || c == '@') c = *p++;  /* \ quotes braces and \ */
+#endif
+         if (c == 0 || c == '\n') return p-1;
+       }
+    }
+
+  while ((c = *p++) != '{' && c != '\n' && c);
+
+  if (c != '{')
+    return p-1;
+
+  if (ignore_blanks)
+    while ((c = *p) == ' ' || c == '\t') p++;
+  
+  for (i = 0; i < chars; i++)
+    {
+      if (!*p  || *p == '\n') break;
+      p++;
+    }
+  return p;
+}
+
+/* Find the end of the balanced-brace field which starts at `str'.
+  The position returned is just before the closing brace. */
+
+char *
+find_braced_end (str)
+     char *str;
+{
+  int bracelevel;
+  char *p = str;
+  char c;
+
+  bracelevel = 1;
+  while (bracelevel)
+    {
+      c = *p++;
+      if (c == '{') bracelevel++;
+      if (c == '}') bracelevel--;
+#if 0
+      if (c == '\\' || c == '@') c = *p++;
+#endif
+      if (c == 0 || c == '\n') return p-1;
+    }
+  return p - 1;
+}
+
+long
+find_value (start, length)
+     char *start;
+     long length;
+{
+  while (length != 0L) {
+    if (isdigit(*start))
+      return atol(start);
+    length--;
+    start++;
+  }
+  return 0l;
+}
+
+/* Vector used to translate characters for comparison.
+   This is how we make all alphanumerics follow all else,
+   and ignore case in the first sorting.  */
+int char_order[256];
+
+init_char_order ()
+{
+  int i;
+  for (i = 1; i < 256; i++)
+    char_order[i] = i;
+
+  for (i = '0'; i <= '9'; i++)
+    char_order[i] += 512;
+
+  for (i = 'a'; i <= 'z'; i++) {
+    char_order[i] = 512 + i;
+    char_order[i + 'A' - 'a'] = 512 + i;
+  }
+}
+
+/* Compare two fields (each specified as a start pointer and a character count)
+ according to `keyfield'.  The sign of the value reports the relation between the fields */
+
+int
+compare_field (keyfield, start1, length1, pos1, start2, length2, pos2)
+     struct keyfield *keyfield;
+     char *start1;
+     long length1;
+     long pos1;
+     char *start2;
+     long length2;
+     long pos2;
+{
+  if (keyfields->positional)
+    {
+      if (pos1 > pos2)
+       return 1;
+      else
+       return -1;
+    }
+  if (keyfield->numeric)
+    {
+       long value = find_value (start1, length1) - find_value (start2, length2);
+      if (value > 0) return 1;
+      if (value < 0) return -1;
+      return 0;
+    }
+  else
+    {
+      char *p1 = start1;
+      char *p2 = start2;
+      char *e1 = start1 + length1;
+      char *e2 = start2 + length2;
+
+      int fold_case = keyfield->fold_case;
+
+      while (1)
+       {
+         int c1, c2;
+
+         if (p1 == e1) c1 = 0;
+         else c1 = *p1++;
+         if (p2 == e2) c2 = 0;
+         else c2 = *p2++;
+
+         if (char_order[c1] != char_order[c2])
+           return char_order[c1] - char_order[c2];
+         if (!c1) break;
+       }
+
+      /* Strings are equal except possibly for case.  */
+      p1 = start1;
+      p2 = start2;
+      while (1)
+       {
+         int c1, c2;
+
+         if (p1 == e1) c1 = 0;
+         else c1 = *p1++;
+         if (p2 == e2) c2 = 0;
+         else c2 = *p2++;
+
+         if (c1 != c2)
+           /* Reverse sign here so upper case comes out last.  */
+           return c2 - c1;
+         if (!c1) break;
+       }
+
+      return 0;
+    }
+}
+\f
+/* A `struct linebuffer' is a structure which holds a line of text.
+ `readline' reads a line from a stream into a linebuffer
+ and works regardless of the length of the line.  */
+
+struct linebuffer
+  {
+    long size;
+    char *buffer;
+  };
+
+/* Initialize a linebuffer for use */
+
+void
+initbuffer (linebuffer)
+     struct linebuffer *linebuffer;
+{
+  linebuffer->size = 200;
+  linebuffer->buffer = (char *) xmalloc (200);
+}
+
+/* Read a line of text from `stream' into `linebuffer'.
+ Return the length of the line.  */
+
+long
+readline (linebuffer, stream)
+     struct linebuffer *linebuffer;
+     FILE *stream;
+{
+  char *buffer = linebuffer->buffer;
+  char *p = linebuffer->buffer;
+  char *end = p + linebuffer->size;
+
+  while (1)
+    {
+      int c = getc (stream);
+      if (p == end)
+       {
+         buffer = (char *) xrealloc (buffer, linebuffer->size *= 2);
+         p += buffer - linebuffer->buffer;
+         end += buffer - linebuffer->buffer;
+         linebuffer->buffer = buffer;
+       }
+      if (c < 0 || c == '\n')
+       {
+         *p = 0;
+         break;
+       }
+      *p++ = c;
+    }
+
+  return p - buffer;
+}
+\f
+/* Sort an input file too big to sort in core.  */
+
+void
+sort_offline (infile, nfiles, total, outfile)
+     char *infile;
+     long total;
+     char *outfile;
+{
+  int ntemps = 2 * (total + MAX_IN_CORE_SORT - 1) / MAX_IN_CORE_SORT;  /* More than enough */
+  char **tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
+  FILE *istream = fopen (infile, "r");
+  int i;
+  struct linebuffer lb;
+  long linelength;
+  int failure = 0;
+
+  initbuffer (&lb);
+
+  /* Read in one line of input data.  */
+
+  linelength = readline (&lb, istream);
+
+  if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
+    {
+      error ("%s: not a texinfo index file", infile);
+      return;
+    }
+
+  /* Split up the input into `ntemps' temporary files, or maybe fewer,
+    and put the new files' names into `tempfiles' */
+
+  for (i = 0; i < ntemps; i++)
+    {
+      char *outname = maketempname (++tempcount);
+      FILE *ostream = fopen (outname, "w");
+      long tempsize = 0;
+
+      if (!ostream) pfatal_with_name (outname);
+      tempfiles[i] = outname;
+
+      /* Copy lines into this temp file as long as it does not make file "too big"
+       or until there are no more lines.  */
+
+      while (tempsize + linelength + 1 <= MAX_IN_CORE_SORT)
+       {
+         tempsize += linelength + 1;
+         fputs (lb.buffer, ostream);
+         putc ('\n', ostream);
+
+         /* Read another line of input data.  */
+
+         linelength = readline (&lb, istream);
+         if (!linelength && feof (istream)) break;
+
+         if (lb.buffer[0] != '\\' && lb.buffer[0] != '@')
+           {
+             error ("%s: not a texinfo index file", infile);
+             failure = 1;
+             goto fail;
+           }
+       }
+      fclose (ostream);
+      if (feof (istream)) break;
+    }
+
+  free (lb.buffer);
+
+ fail:
+  /* Record number of temp files we actually needed.  */
+
+  ntemps = i;
+
+  /* Sort each tempfile into another tempfile.
+    Delete the first set of tempfiles and put the names of the second into `tempfiles' */
+
+  for (i = 0; i < ntemps; i++)
+    {
+      char *newtemp = maketempname (++tempcount);
+      sort_in_core (&tempfiles[i], MAX_IN_CORE_SORT, newtemp);
+      if (!keep_tempfiles)
+        unlink (tempfiles[i]);
+      tempfiles[i] = newtemp;
+    }
+
+  if (failure)
+    return;
+
+  /* Merge the tempfiles together and indexify */
+
+  merge_files (tempfiles, ntemps, outfile);
+}
+\f
+/* Sort `infile', whose size is `total',
+ assuming that is small enough to be done in-core,
+ then indexify it and send the output to `outfile' (or to stdout).  */
+
+void
+sort_in_core (infile, total, outfile)
+     char *infile;
+     long total;
+     char *outfile;
+{
+  char **nextline;
+  char *data = (char *) xmalloc (total + 1);
+  char *file_data;
+  long file_size;
+  int i;
+  FILE *ostream = stdout;
+  struct lineinfo *lineinfo;
+
+  /* Read the contents of the file into the moby array `data' */
+
+  int desc = open (infile, 0, 0);
+
+  if (desc < 0)
+    fatal ("failure reopening %s", infile);
+  for (file_size = 0; ; )
+    {
+      if ((i = read (desc, data + file_size, total - file_size)) <= 0)
+       break;
+      file_size += i;
+    }
+  file_data = data;
+  data[file_size] = 0;
+
+  close (desc);
+
+  if (file_size > 0 && data[0] != '\\' && data[0] != '@')
+    {
+      error ("%s: not a texinfo index file", infile);
+      return;
+    }
+
+  init_char_order ();
+
+  /* Sort routines want to know this address */
+
+  text_base = data;
+
+  /* Create the array of pointers to lines, with a default size frequently enough.  */
+
+  nlines = total / 50;
+  if (!nlines) nlines = 2;
+  linearray = (char **) xmalloc (nlines * sizeof (char *));
+
+  /* `nextline' points to the next free slot in this array.
+     `nlines' is the allocated size.  */
+
+  nextline = linearray;
+
+  /* Parse the input file's data, and make entries for the lines.  */
+
+  nextline = parsefile (infile, nextline, file_data, file_size);
+  if (nextline == 0)
+    {
+      error ("%s: not a texinfo index file", infile);
+      return;
+    }
+
+  /* Sort the lines */
+
+  /* If we have enough space, find the first keyfield of each line in advance.
+    Make a `struct lineinfo' for each line, which records the keyfield
+    as well as the line, and sort them.  */
+
+  lineinfo = (struct lineinfo *) malloc ((nextline - linearray) * sizeof (struct lineinfo));
+
+  if (lineinfo)
+    {
+      struct lineinfo *lp;
+      char **p;
+
+      for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
+       {
+         lp->text = *p;
+         lp->key.text = find_field (keyfields, *p, &lp->keylen);
+         if (keyfields->numeric)
+           lp->key.number = find_value (lp->key.text, lp->keylen);
+       }
+
+      qsort (lineinfo, nextline - linearray, sizeof (struct lineinfo), compare_prepared);
+
+      for (lp = lineinfo, p = linearray; p != nextline; lp++, p++)
+       *p = lp->text;
+
+      free (lineinfo);
+    }
+  else
+    qsort (linearray, nextline - linearray, sizeof (char *), compare_full);
+
+  /* Open the output file */
+
+  if (outfile)
+    {
+      ostream = fopen (outfile, "w");
+      if (!ostream)
+       pfatal_with_name (outfile);
+    }
+
+  writelines (linearray, nextline - linearray, ostream);
+  if (outfile) fclose (ostream);
+
+  free (linearray);
+  free (data);
+}
+\f
+/* Parse an input string in core into lines.
+   DATA is the input string, and SIZE is its length.
+   Data goes in LINEARRAY starting at NEXTLINE.
+   The value returned is the first entry in LINEARRAY still unused.
+   Value 0 means input file contents are invalid.  */
+
+char **
+parsefile (filename, nextline, data, size)
+     char *filename;
+     char **nextline;
+     char *data;
+     long size;
+{
+  char *p, *end;
+  char **line = nextline;
+
+  p = data;
+  end = p + size;
+  *end = 0;
+
+  while (p != end)
+    {
+      if (p[0] != '\\' && p[0] != '@')
+       return 0;
+
+      *line = p;
+      while (*p && *p != '\n') p++;
+      if (p != end) p++;
+
+      line++;
+      if (line == linearray + nlines)
+       {
+         char **old = linearray;
+         linearray = (char **) xrealloc (linearray, sizeof (char *) * (nlines *= 4));
+         line += linearray - old;
+       }
+    }
+
+  return line;
+}
+\f
+/* Indexification is a filter applied to the sorted lines
+ as they are being written to the output file.
+ Multiple entries for the same name, with different page numbers,
+ get combined into a single entry with multiple page numbers.
+ The first braced field, which is used for sorting, is discarded.
+ However, its first character is examined, folded to lower case,
+ and if it is different from that in the previous line fed to us
+ a \initial line is written with one argument, the new initial.
+
+ If an entry has four braced fields, then the second and third
+ constitute primary and secondary names.
+ In this case, each change of primary name
+ generates a \primary line which contains only the primary name,
+ and in between these are \secondary lines which contain
+ just a secondary name and page numbers.
+*/
+
+/* The last primary name we wrote a \primary entry for.
+ If only one level of indexing is being done, this is the last name seen */
+char *lastprimary;
+int lastprimarylength;  /* Length of storage allocated for lastprimary */
+
+/* Similar, for the secondary name. */
+char *lastsecondary;
+int lastsecondarylength;
+
+/* Zero if we are not in the middle of writing an entry.
+ One if we have written the beginning of an entry but have not
+  yet written any page numbers into it.
+ Greater than one if we have written the beginning of an entry
+  plus at least one page number. */
+int pending;
+
+/* The initial (for sorting purposes) of the last primary entry written.
+ When this changes, a \initial {c} line is written */
+
+char * lastinitial;
+
+int lastinitiallength;
+
+/* When we need a string of length 1 for the value of lastinitial,
+   store it here.  */
+
+char lastinitial1[2];
+
+/* Initialize static storage for writing an index */
+
+void
+init_index ()
+{
+  pending = 0;
+  lastinitial = lastinitial1;
+  lastinitial1[0] = 0;
+  lastinitial1[1] = 0;
+  lastinitiallength = 0;
+  lastprimarylength = 100;
+  lastprimary = (char *) xmalloc (lastprimarylength + 1);
+  bzero (lastprimary, lastprimarylength + 1);
+  lastsecondarylength = 100;
+  lastsecondary = (char *) xmalloc (lastsecondarylength + 1);
+  bzero (lastsecondary, lastsecondarylength + 1);
+}
+
+/* Indexify.  Merge entries for the same name,
+ insert headers for each initial character, etc.  */
+
+indexify (line, ostream)
+     char *line;
+     FILE *ostream;
+{
+  char *primary, *secondary, *pagenumber;
+  int primarylength, secondarylength, pagelength;
+  int len = strlen (line);
+  int nosecondary;
+  int initiallength;
+  char *initial;
+  char initial1[2];
+  register char *p;
+
+  /* First, analyze the parts of the entry fed to us this time */
+
+  p = find_braced_pos (line, 0, 0, 0);
+  if (*p == '{')
+    {
+      initial = p;
+      /* Get length of inner pair of braces starting at p,
+        including that inner pair of braces.  */
+      initiallength = find_braced_end (p + 1) + 1 - p;
+    }
+  else
+    {
+      initial = initial1;
+      initial1[0] = *p;
+      initial1[1] = 0;
+      initiallength = 1;
+
+      if (initial1[0] >= 'a' && initial1[0] <= 'z')
+       initial1[0] -= 040;
+    }
+
+  pagenumber = find_braced_pos (line, 1, 0, 0);
+  pagelength = find_braced_end (pagenumber) - pagenumber;
+  if (pagelength == 0)
+    abort ();
+
+  primary = find_braced_pos (line, 2, 0, 0);
+  primarylength = find_braced_end (primary) - primary;
+
+  secondary = find_braced_pos (line, 3, 0, 0);
+  nosecondary = !*secondary;
+  if (!nosecondary)
+    secondarylength = find_braced_end (secondary) - secondary;
+
+  /* If the primary is different from before, make a new primary entry */
+  if (strncmp (primary, lastprimary, primarylength))
+    {
+      /* Close off current secondary entry first, if one is open */
+      if (pending)
+       {
+         fputs ("}\n", ostream);
+         pending = 0;
+       }
+
+      /* If this primary has a different initial, include an entry for the initial */
+      if (initiallength != lastinitiallength ||
+         strncmp (initial, lastinitial, initiallength))
+       {
+         fprintf (ostream, "\\initial {");
+         fwrite (initial, 1, initiallength, ostream);
+         fprintf (ostream, "}\n", initial);
+         if (initial == initial1)
+           {
+             lastinitial = lastinitial1;
+             *lastinitial1 = *initial1;
+           }
+         else
+           {
+             lastinitial = initial;
+           }
+         lastinitiallength = initiallength;
+       }
+
+      /* Make the entry for the primary.  */
+      if (nosecondary)
+       fputs ("\\entry {", ostream);
+      else
+       fputs ("\\primary {", ostream);
+      fwrite (primary, primarylength, 1, ostream);
+      if (nosecondary)
+       {
+         fputs ("}{", ostream);
+         pending = 1;
+       }
+      else
+       fputs ("}\n", ostream);
+
+      /* Record name of most recent primary */
+      if (lastprimarylength < primarylength)
+       {
+          lastprimarylength = primarylength + 100;
+         lastprimary = (char *) xrealloc (lastprimary,
+                                          1 + lastprimarylength);
+       }
+      strncpy (lastprimary, primary, primarylength);
+      lastprimary[primarylength] = 0;
+
+      /* There is no current secondary within this primary, now */
+      lastsecondary[0] = 0;
+    }
+
+  /* Should not have an entry with no subtopic following one with a subtopic */
+
+  if (nosecondary && *lastsecondary)
+    error ("entry %s follows an entry with a secondary name", line);
+
+  /* Start a new secondary entry if necessary */
+  if (!nosecondary && strncmp (secondary, lastsecondary, secondarylength))
+    {
+      if (pending)
+       {
+         fputs ("}\n", ostream);
+         pending = 0;
+       }
+
+      /* Write the entry for the secondary.  */
+      fputs ("\\secondary {", ostream);
+      fwrite (secondary, secondarylength, 1, ostream);
+      fputs ("}{", ostream);
+      pending = 1;
+
+      /* Record name of most recent secondary */
+      if (lastsecondarylength < secondarylength)
+       {
+          lastsecondarylength = secondarylength + 100;
+         lastsecondary = (char *) xrealloc (lastsecondary,
+                                          1 + lastsecondarylength);
+       }
+      strncpy (lastsecondary, secondary, secondarylength);
+      lastsecondary[secondarylength] = 0;
+    }
+
+  /* Here to add one more page number to the current entry */
+  if (pending++ != 1)
+    fputs (", ", ostream);     /* Punctuate first, if this is not the first */
+  fwrite (pagenumber, pagelength, 1, ostream);
+}
+
+/* Close out any unfinished output entry */
+
+void
+finish_index (ostream)
+     FILE *ostream;
+{
+  if (pending)
+    fputs ("}\n", ostream);
+  free (lastprimary);
+  free (lastsecondary);
+}
+\f
+/* Copy the lines in the sorted order.
+ Each line is copied out of the input file it was found in. */
+
+void
+writelines (linearray, nlines, ostream)
+     char **linearray;
+     int nlines;
+     FILE *ostream;
+{
+  char **stop_line = linearray + nlines;
+  char **next_line;
+
+  init_index ();
+
+  /* Output the text of the lines, and free the buffer space */
+
+  for (next_line = linearray; next_line != stop_line; next_line++)
+    {
+      /* If -u was specified, output the line only if distinct from previous one.  */
+      if (next_line == linearray
+         /* Compare previous line with this one, using only the explicitly specd keyfields */
+         || compare_general (*(next_line - 1), *next_line, 0L, 0L, num_keyfields - 1))
+       {
+         char *p = *next_line;
+         char c;
+         while ((c = *p++) && c != '\n');
+         *(p-1) = 0;
+         indexify (*next_line, ostream);
+       }
+    }
+
+  finish_index (ostream);
+}
+\f
+/* Assume (and optionally verify) that each input file is sorted;
+ merge them and output the result.
+ Returns nonzero if any input file fails to be sorted.
+
+ This is the high-level interface that can handle an unlimited number of files.  */
+
+#define MAX_DIRECT_MERGE 10
+
+int
+merge_files (infiles, nfiles, outfile)
+     char **infiles;
+     int nfiles;
+     char *outfile;
+{
+  char **tempfiles;
+  int ntemps;
+  int i;
+  int value = 0;
+  int start_tempcount = tempcount;
+
+  if (nfiles <= MAX_DIRECT_MERGE)
+    return merge_direct (infiles, nfiles, outfile);
+
+  /* Merge groups of MAX_DIRECT_MERGE input files at a time,
+     making a temporary file to hold each group's result.  */
+
+  ntemps = (nfiles + MAX_DIRECT_MERGE - 1) / MAX_DIRECT_MERGE;
+  tempfiles = (char **) xmalloc (ntemps * sizeof (char *));
+  for (i = 0; i < ntemps; i++)
+    {
+      int nf = MAX_DIRECT_MERGE;
+      if (i + 1 == ntemps)
+       nf = nfiles - i * MAX_DIRECT_MERGE;
+      tempfiles[i] = maketempname (++tempcount);
+      value |= merge_direct (&infiles[i * MAX_DIRECT_MERGE], nf, tempfiles[i]);
+    }
+
+  /* All temporary files that existed before are no longer needed
+     since their contents have been merged into our new tempfiles.
+     So delete them.  */
+  flush_tempfiles (start_tempcount);
+
+  /* Now merge the temporary files we created.  */
+
+  merge_files (tempfiles, ntemps, outfile);
+
+  free (tempfiles);
+
+  return value;
+}  
+\f
+/* Assume (and optionally verify) that each input file is sorted;
+ merge them and output the result.
+ Returns nonzero if any input file fails to be sorted.
+
+ This version of merging will not work if the number of
+ input files gets too high.  Higher level functions
+ use it only with a bounded number of input files.  */
+
+int
+merge_direct (infiles, nfiles, outfile)
+     char **infiles;
+     int nfiles;
+     char *outfile;
+{
+  char **ip = infiles;
+  struct linebuffer *lb1, *lb2;
+  struct linebuffer **thisline, **prevline;
+  FILE **streams;
+  int i;
+  int nleft;
+  int lossage = 0;
+  int *file_lossage;
+  struct linebuffer *prev_out = 0;
+  FILE *ostream = stdout;
+
+  if (outfile)
+    {
+      ostream = fopen (outfile, "w");
+    }
+  if (!ostream) pfatal_with_name (outfile);
+
+  init_index ();
+
+  if (nfiles == 0)
+    {
+      if (outfile)
+        fclose (ostream);
+      return 0;
+    }
+
+  /* For each file, make two line buffers.
+     Also, for each file, there is an element of `thisline'
+     which points at any time to one of the file's two buffers,
+     and an element of `prevline' which points to the other buffer.
+     `thisline' is supposed to point to the next available line from the file,
+     while `prevline' holds the last file line used,
+     which is remembered so that we can verify that the file is properly sorted. */
+
+  /* lb1 and lb2 contain one buffer each per file */
+  lb1 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
+  lb2 = (struct linebuffer *) xmalloc (nfiles * sizeof (struct linebuffer));
+
+  /* thisline[i] points to the linebuffer holding the next available line in file i,
+     or is zero if there are no lines left in that file.  */
+  thisline = (struct linebuffer **) xmalloc (nfiles * sizeof (struct linebuffer *));
+  /* prevline[i] points to the linebuffer holding the last used line from file i.
+     This is just for verifying that file i is properly sorted.  */
+  prevline = (struct linebuffer **) xmalloc (nfiles * sizeof (struct linebuffer *));
+  /* streams[i] holds the input stream for file i.  */
+  streams = (FILE **) xmalloc (nfiles * sizeof (FILE *));
+  /* file_lossage[i] is nonzero if we already know file i is not properly sorted.  */
+  file_lossage = (int *) xmalloc (nfiles * sizeof (int));
+
+  /* Allocate and initialize all that storage */
+
+  for (i = 0; i < nfiles; i++)
+    {
+      initbuffer (&lb1[i]);
+      initbuffer (&lb2[i]);
+      thisline[i] = &lb1[i];
+      prevline[i] = &lb2[i];
+      file_lossage[i] = 0;
+      streams[i] = fopen (infiles[i], "r");
+      if (!streams[i])
+       pfatal_with_name (infiles[i]);
+
+      readline (thisline[i], streams[i]);
+    }
+
+  /* Keep count of number of files not at eof */
+  nleft = nfiles;
+
+  while (nleft)
+    {
+      struct linebuffer *best = 0;
+      struct linebuffer *exch;
+      int bestfile = -1;
+      int i;
+
+      /* Look at the next avail line of each file; choose the least one.  */
+
+      for (i = 0; i < nfiles; i++)
+       {
+         if (thisline[i] &&
+             (!best ||
+              0 < compare_general (best->buffer, thisline[i]->buffer,
+                                   (long) bestfile, (long) i, num_keyfields)))
+           {
+             best = thisline[i];
+             bestfile = i;
+           }
+       }
+
+      /* Output that line, unless it matches the previous one and we don't want duplicates */
+
+      if (!(prev_out &&
+           !compare_general (prev_out->buffer, best->buffer, 0L, 1L, num_keyfields - 1)))
+       indexify (best->buffer, ostream);
+      prev_out = best;
+
+      /* Now make the line the previous of its file, and fetch a new line from that file */
+
+      exch = prevline[bestfile];
+      prevline[bestfile] = thisline[bestfile];
+      thisline[bestfile] = exch;
+
+      while (1)
+       {
+         /* If the file has no more, mark it empty */
+
+         if (feof (streams[bestfile]))
+           {
+             thisline[bestfile] = 0;
+             nleft--;          /* Update the number of files still not empty */
+             break;
+           }
+         readline (thisline[bestfile], streams[bestfile]);
+         if (thisline[bestfile]->buffer[0] || !feof (streams[bestfile])) break;
+       }
+    }
+
+  finish_index (ostream);
+
+  /* Free all storage and close all input streams */
+
+  for (i = 0; i < nfiles; i++)
+    {
+      fclose (streams[i]);
+      free (lb1[i].buffer);
+      free (lb2[i].buffer);
+    }
+  free (file_lossage);
+  free (lb1);
+  free (lb2);
+  free (thisline);
+  free (prevline);
+  free (streams);
+
+  if (outfile)
+    fclose (ostream);
+
+  return lossage;
+}
+\f
+/* Print error message and exit.  */
+
+fatal (s1, s2)
+     char *s1, *s2;
+{
+  error (s1, s2);
+  exit (EXIT_FATAL);
+}
+
+/* Print error message.  `s1' is printf control string, `s2' is arg for it. */
+
+error (s1, s2)
+     char *s1, *s2;
+{
+  printf ("texindex: ");
+  printf (s1, s2);
+  printf ("\n");
+}
+
+perror_with_name (name)
+     char *name;
+{
+  char *s;
+
+  if (errno < sys_nerr)
+    s = concat ("", sys_errlist[errno], " for %s");
+  else
+    s = "cannot open %s";
+  error (s, name);
+}
+
+pfatal_with_name (name)
+     char *name;
+{
+  char *s;
+
+  if (errno < sys_nerr)
+    s = concat ("", sys_errlist[errno], " for %s");
+  else
+    s = "cannot open %s";
+  fatal (s, name);
+}
+
+/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */
+
+char *
+concat (s1, s2, s3)
+     char *s1, *s2, *s3;
+{
+  int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+  char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+  strcpy (result, s1);
+  strcpy (result + len1, s2);
+  strcpy (result + len1 + len2, s3);
+  *(result + len1 + len2 + len3) = 0;
+
+  return result;
+}
+
+/* Like malloc but get fatal error if memory is exhausted.  */
+
+int
+xmalloc (size)
+     int size;
+{
+  int result = malloc (size);
+  if (!result)
+    fatal ("virtual memory exhausted", 0);
+  return result;
+}
+
+
+int
+xrealloc (ptr, size)
+     char *ptr;
+     int size;
+{
+  int result = realloc (ptr, size);
+  if (!result)
+    fatal ("virtual memory exhausted");
+  return result;
+}
+
+bzero (b, length)
+     register char *b;
+     register int length;
+{
+#ifdef VMS
+  short zero = 0;
+  long max_str = 65535;
+  long len;
+
+  while (length > max_str)
+    {
+      (void) LIB$MOVC5 (&zero, &zero, &zero, &max_str, b);
+      length -= max_str;
+      b += max_str;
+    }
+  len = length;
+  (void) LIB$MOVC5 (&zero, &zero, &zero, &len, b);
+#else
+  while (length-- > 0)
+    *b++ = 0;
+#endif /* not VMS */
+}
diff --git a/readline/doc/texinfo.tex b/readline/doc/texinfo.tex
new file mode 100644 (file)
index 0000000..1652c55
--- /dev/null
@@ -0,0 +1,2883 @@
+%% TeX macros to handle texinfo files
+
+%   Copyright (C) 1985, 1986, 1988, 1990, 1991 Free Software Foundation, Inc.
+
+%This texinfo.tex file is free software; you can redistribute it and/or
+%modify it under the terms of the GNU General Public License as
+%published by the Free Software Foundation; either version 2, or (at
+%your option) any later version.
+
+%This texinfo.tex file is distributed in the hope that it will be
+%useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+%of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+%General Public License for more details.
+
+%You should have received a copy of the GNU General Public License
+%along with this texinfo.tex file; see the file COPYING.  If not, write
+%to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+%USA.
+
+
+%In other words, you are welcome to use, share and improve this program.
+%You are forbidden to forbid anyone else to use, share and improve
+%what you give them.   Help stamp out software-hoarding!
+
+\def\texinfoversion{2.46}
+\message{Loading texinfo package [Version \texinfoversion]:}
+\message{}
+
+% Print the version number if in a .fmt file.
+\everyjob{\message{[Texinfo version \texinfoversion]}\message{}}
+
+% Save some parts of plain tex whose names we will redefine.
+
+\let\ptexlbrace=\{
+\let\ptexrbrace=\}
+\let\ptexdots=\dots
+\let\ptexdot=\.
+\let\ptexstar=\*
+\let\ptexend=\end
+\let\ptexbullet=\bullet
+\let\ptexb=\b
+\let\ptexc=\c
+\let\ptexi=\i
+\let\ptext=\t
+\let\ptexl=\l
+\let\ptexL=\L
+
+\def\tie{\penalty 10000\ }     % Save plain tex definition of ~.
+
+\message{Basics,}
+\chardef\other=12
+
+\hyphenation{ap-pen-dix}
+\hyphenation{mini-buf-fer mini-buf-fers}
+\hyphenation{eshell}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen \bindingoffset  \bindingoffset=0pt
+\newdimen \normaloffset   \normaloffset=\hoffset
+\newdimen\pagewidth \newdimen\pageheight
+\pagewidth=\hsize \pageheight=\vsize
+
+%---------------------Begin change-----------------------
+%
+% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\cornerlong \newdimen\cornerthick
+\newdimen \topandbottommargin
+\newdimen \outerhsize \newdimen \outervsize
+\cornerlong=1pc\cornerthick=.3pt       % These set size of cropmarks
+\outerhsize=7in
+\outervsize=9.5in
+\topandbottommargin=.75in
+%
+%---------------------End change-----------------------
+
+% \onepageout takes a vbox as an argument.  Note that \pagecontents
+% does insertions itself, but you have to call it yourself.
+\chardef\PAGE=255  \output={\onepageout{\pagecontents\PAGE}}
+\def\onepageout#1{\hoffset=\normaloffset
+\ifodd\pageno  \advance\hoffset by \bindingoffset
+\else \advance\hoffset by -\bindingoffset\fi
+{\escapechar=`\\\relax % makes sure backslash is used in output files.
+\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}%
+{\let\hsize=\pagewidth \makefootline}}}%
+\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+
+
+% Here is a modification of the main output routine for Near East Publications
+% This provides right-angle cropmarks at all four corners.
+% The contents of the page are centerlined into the cropmarks,
+% and any desired binding offset is added as an \hskip on either
+% site of the centerlined box.  (P. A. MacKay, 12 November, 1986)
+%
+\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up
+                \shipout
+                \vbox to \outervsize{\hsize=\outerhsize
+                 \vbox{\line{\ewtop\hfill\ewtop}}
+                 \nointerlineskip
+                 \line{\vbox{\moveleft\cornerthick\nstop}
+                       \hfill
+                       \vbox{\moveright\cornerthick\nstop}}
+                 \vskip \topandbottommargin
+                 \centerline{\ifodd\pageno\hskip\bindingoffset\fi
+                       \vbox{
+                       {\let\hsize=\pagewidth \makeheadline}
+                       \pagebody{#1}
+                       {\let\hsize=\pagewidth \makefootline}}
+                       \ifodd\pageno\else\hskip\bindingoffset\fi}
+                \vskip \topandbottommargin plus1fill minus1fill
+                 \boxmaxdepth\cornerthick
+                 \line{\vbox{\moveleft\cornerthick\nsbot}
+                       \hfill
+                       \vbox{\moveright\cornerthick\nsbot}}
+                 \nointerlineskip
+                 \vbox{\line{\ewbot\hfill\ewbot}}
+       }
+  \advancepageno 
+  \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
+%
+% Do @cropmarks to get crop marks
+\def\cropmarks{\let\onepageout=\croppageout }
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+\dimen@=\dp#1 \unvbox#1
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+%
+% Here are the rules for the cropmarks.  Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+  {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+  {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1.
+% The argument can be delimited with [...] or with "..." or braces
+% or it can be a whole line.
+% #1 should be a macro which expects
+% an ordinary undelimited TeX argument.
+
+\def\parsearg #1{\let\next=#1\begingroup\obeylines\futurelet\temp\parseargx}
+
+\def\parseargx{%
+\ifx \obeyedspace\temp \aftergroup\parseargdiscardspace \else%
+\aftergroup \parseargline %
+\fi \endgroup}
+
+{\obeyspaces %
+\gdef\parseargdiscardspace {\begingroup\obeylines\futurelet\temp\parseargx}}
+
+\gdef\obeyedspace{\ }
+
+\def\parseargline{\begingroup \obeylines \parsearglinex}
+{\obeylines %
+\gdef\parsearglinex #1^^M{\endgroup \next {#1}}}
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+%% These are used to keep @begin/@end levels from running away
+%% Call \inENV within environments (after a \begingroup)
+\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi}
+\def\ENVcheck{%
+\ifENV\errmessage{Still within an environment.  Type Return to continue.}
+\endgroup\fi} % This is not perfect, but it should reduce lossage
+
+% @begin foo  is the same as @foo, for now.
+\newhelp\EMsimple{Type <Return> to continue}
+
+\outer\def\begin{\parsearg\beginxxx}
+
+\def\beginxxx #1{%
+\expandafter\ifx\csname #1\endcsname\relax
+{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else
+\csname #1\endcsname\fi}
+
+%% @end foo executes the definition of \Efoo.
+%% foo can be delimited by doublequotes or brackets.
+
+\def\end{\parsearg\endxxx}
+
+\def\endxxx #1{%
+\expandafter\ifx\csname E#1\endcsname\relax
+\expandafter\ifx\csname #1\endcsname\relax
+\errmessage{Undefined command @end #1}\else
+\errorE{#1}\fi\fi
+\csname E#1\endcsname}
+\def\errorE#1{
+{\errhelp=\EMsimple \errmessage{@end #1 not within #1 environment}}}
+
+% Single-spacing is done by various environments.
+
+\newskip\singlespaceskip \singlespaceskip = \baselineskip
+\def\singlespace{%
+{\advance \baselineskip by -\singlespaceskip
+\kern \baselineskip}%
+\baselineskip=\singlespaceskip
+}
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\tt \char '100}}
+
+% Define @` and @' to be the same as ` and '
+% but suppressing ligatures.
+\def\`{{`}}
+\def\'{{'}}
+
+% Used to generate quoted braces.
+
+\def\mylbrace {{\tt \char '173}}
+\def\myrbrace {{\tt \char '175}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break\hbox{}\ignorespaces}
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=3000 }
+
+% @w prevents a word break
+\def\w #1{\hbox{#1}}
+
+% @group ... @end group  forces ... to be all on one page.
+
+\def\group{\begingroup% \inENV ???
+\def \Egroup{\egroup\endgroup}
+\vbox\bgroup}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil  \mil=0.001in
+
+\def\need{\parsearg\needx}
+
+\def\needx #1{\par %
+% This method tries to make TeX break the page naturally
+% if the depth of the box does not fit.
+{\baselineskip=0pt%
+\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000
+\prevdepth=-1000pt
+}}
+
+% @br   forces paragraph break
+
+\let\br = \par
+
+% @dots{}  output some dots
+
+\def\dots{$\ldots$}
+
+% @page    forces the start of a new page
+
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+\def\exdent{\errmessage{@exdent in filled text}}
+  % @lisp, etc, define \exdent locally from \internalexdent
+
+{\obeyspaces
+\gdef\internalexdent{\parsearg\exdentzzz}}
+
+\def\exdentzzz #1{{\advance \leftskip by -\lispnarrowing
+\advance \hsize by -\leftskip
+\advance \hsize by -\rightskip
+\leftline{{\rm#1}}}}
+
+% @include file    insert text of that file as input.
+
+\def\include{\parsearg\includezzz}
+\def\includezzz #1{{\def\thisfile{#1}\input #1
+}}
+
+\def\thisfile{}
+
+% @center line   outputs that line, centered
+
+\def\center{\parsearg\centerzzz}
+\def\centerzzz #1{{\advance\hsize by -\leftskip
+\advance\hsize by -\rightskip
+\centerline{#1}}}
+
+% @sp n   outputs n lines of vertical space
+
+\def\sp{\parsearg\spxxx}
+\def\spxxx #1{\par \vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore  is another way to write a comment
+
+\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other%
+\parsearg \commentxxx}
+
+\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 }
+
+\let\c=\comment
+
+% Prevent errors for section commands.
+% Used in @ignore and in failing conditionals.
+\def\ignoresections{%
+\let\chapter=\relax
+\let\unnumbered=\relax
+\let\top=\relax
+\let\unnumberedsec=\relax
+\let\unnumberedsection=\relax
+\let\unnumberedsubsec=\relax
+\let\unnumberedsubsection=\relax
+\let\unnumberedsubsubsec=\relax
+\let\unnumberedsubsubsection=\relax
+\let\section=\relax
+\let\subsec=\relax
+\let\subsubsec=\relax
+\let\subsection=\relax
+\let\subsubsection=\relax
+\let\appendix=\relax
+\let\appendixsec=\relax
+\let\appendixsection=\relax
+\let\appendixsubsec=\relax
+\let\appendixsubsection=\relax
+\let\appendixsubsubsec=\relax
+\let\appendixsubsubsection=\relax
+\let\contents=\relax
+\let\smallbook=\relax
+\let\titlepage=\relax
+}
+
+\def\ignore{\begingroup\ignoresections
+% Make sure that spaces turn into tokens that match what \ignorexxx wants.
+\catcode32=10
+\ignorexxx}
+\long\def\ignorexxx #1\end ignore{\endgroup\ignorespaces}
+
+\def\direntry{\begingroup\direntryxxx}
+\long\def\direntryxxx #1\end direntry{\endgroup\ignorespaces}
+
+% Conditionals to test whether a flag is set.
+
+\outer\def\ifset{\begingroup\ignoresections\parsearg\ifsetxxx}
+
+\def\ifsetxxx #1{\endgroup
+\expandafter\ifx\csname IF#1\endcsname\relax \let\temp=\ifsetfail
+\else \let\temp=\relax \fi
+\temp}
+\def\Eifset{}
+\def\ifsetfail{\begingroup\ignoresections\ifsetfailxxx}
+\long\def\ifsetfailxxx #1\end ifset{\endgroup\ignorespaces}
+
+\outer\def\ifclear{\begingroup\ignoresections\parsearg\ifclearxxx}
+
+\def\ifclearxxx #1{\endgroup
+\expandafter\ifx\csname IF#1\endcsname\relax \let\temp=\relax
+\else \let\temp=\ifclearfail \fi
+\temp}
+\def\Eifclear{}
+\def\ifclearfail{\begingroup\ignoresections\ifclearfailxxx}
+\long\def\ifclearfailxxx #1\end ifclear{\endgroup\ignorespaces}
+
+% Some texinfo constructs that are trivial in tex
+
+\def\iftex{}
+\def\Eiftex{}
+\def\ifinfo{\begingroup\ignoresections\ifinfoxxx}
+\long\def\ifinfoxxx #1\end ifinfo{\endgroup\ignorespaces}
+
+\long\def\menu #1\end menu{}
+\def\asis#1{#1}
+
+% @math means output in math mode.
+% We don't use $'s directly in the definition of \math because control
+% sequences like \math are expanded when the toc file is written.  Then,
+% we read the toc file back, the $'s will be normal characters (as they
+% should be, according to the definition of Texinfo).  So we must use a
+% control sequence to switch into and out of math mode.
+% 
+% This isn't quite enough for @math to work properly in indices, but it
+% seems unlikely it will ever be needed there.
+% 
+\let\implicitmath = $
+\def\math#1{\implicitmath #1\implicitmath}
+
+\def\node{\ENVcheck\parsearg\nodezzz}
+\def\nodezzz#1{\nodexxx [#1,]}
+\def\nodexxx[#1,#2]{\gdef\lastnode{#1}}
+\let\lastnode=\relax
+
+\def\donoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\setref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\def\unnumbnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\def\appendixnoderef{\ifx\lastnode\relax\else
+\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi
+\let\lastnode=\relax}
+
+\let\refill=\relax
+  
+% @setfilename is done at the beginning of every texinfo file.
+% So open here the files we need to have open while reading the input.
+% This makes it possible to make a .fmt file for texinfo.
+\def\setfilename{%
+   \readauxfile
+   \opencontents
+   \openindices
+   \fixbackslash  % Turn off hack to swallow `\input texinfo'.
+   \global\let\setfilename=\comment % Ignore extra @setfilename cmds.
+   \comment % Ignore the actual filename.
+}
+
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{See Info file \file{\losespace#3{}},
+  node \samp{\losespace#1{}}}
+\def\losespace #1{#1}
+
+\message{fonts,}
+
+% Font-change commands.
+
+% Texinfo supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf analogous to plain's \rm, etc.
+\newfam\sffam
+\def\sf{\fam=\sffam \tensf}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+%% Try out Computer Modern fonts at \magstephalf
+\font\textrm=cmr10 scaled \magstephalf
+\font\texttt=cmtt10 scaled \magstephalf
+% Instead of cmb10, you many want to use cmbx10.
+% cmbx10 is a prettier font on its own, but cmb10
+% looks better when embedded in a line with cmr10.
+\font\textbf=cmb10 scaled \magstephalf 
+\font\textit=cmti10 scaled \magstephalf
+\font\textsl=cmsl10 scaled \magstephalf
+\font\textsf=cmss10 scaled \magstephalf
+\font\textsc=cmcsc10 scaled \magstephalf
+\font\texti=cmmi10 scaled \magstephalf
+\font\textsy=cmsy10 scaled \magstephalf
+
+% A few fonts for @defun, etc.
+\font\defbf=cmbx10 scaled \magstep1 %was 1314
+\font\deftt=cmtt10 scaled \magstep1
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf}
+
+% Fonts for indices and small examples.
+% We actually use the slanted font rather than the italic, 
+% because texinfo normally uses the slanted fonts for that.
+% Do not make many font distinctions in general in the index, since they
+% aren't very useful.
+\font\ninett=cmtt9
+\font\indrm=cmr9
+\font\indit=cmsl9
+\let\indsl=\indit
+\let\indtt=\ninett
+\let\indsf=\indrm
+\let\indbf=\indrm
+\let\indsc=\indrm
+\font\indi=cmmi9
+\font\indsy=cmsy9
+
+% Fonts for headings
+\font\chaprm=cmbx12 scaled \magstep2
+\font\chapit=cmti12 scaled \magstep2
+\font\chapsl=cmsl12 scaled \magstep2
+\font\chaptt=cmtt12 scaled \magstep2
+\font\chapsf=cmss12 scaled \magstep2
+\let\chapbf=\chaprm
+\font\chapsc=cmcsc10 scaled\magstep3
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+
+\font\secrm=cmbx12 scaled \magstep1
+\font\secit=cmti12 scaled \magstep1
+\font\secsl=cmsl12 scaled \magstep1
+\font\sectt=cmtt12 scaled \magstep1
+\font\secsf=cmss12 scaled \magstep1
+\font\secbf=cmbx12 scaled \magstep1
+\font\secsc=cmcsc10 scaled\magstep2
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+
+% \font\ssecrm=cmbx10 scaled \magstep1    % This size an font looked bad.
+% \font\ssecit=cmti10 scaled \magstep1    % The letters were too crowded.
+% \font\ssecsl=cmsl10 scaled \magstep1
+% \font\ssectt=cmtt10 scaled \magstep1
+% \font\ssecsf=cmss10 scaled \magstep1
+
+%\font\ssecrm=cmb10 scaled 1315        % Note the use of cmb rather than cmbx.
+%\font\ssecit=cmti10 scaled 1315       % Also, the size is a little larger than
+%\font\ssecsl=cmsl10 scaled 1315       % being scaled magstep1.
+%\font\ssectt=cmtt10 scaled 1315
+%\font\ssecsf=cmss10 scaled 1315
+
+%\let\ssecbf=\ssecrm
+
+\font\ssecrm=cmbx12 scaled \magstephalf
+\font\ssecit=cmti12 scaled \magstephalf
+\font\ssecsl=cmsl12 scaled \magstephalf
+\font\ssectt=cmtt12 scaled \magstephalf
+\font\ssecsf=cmss12 scaled \magstephalf
+\font\ssecbf=cmbx12 scaled \magstephalf
+\font\ssecsc=cmcsc10 scaled \magstep1 
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled \magstep1
+% The smallcaps and symbol fonts should actually be scaled \magstep1.5,
+% but that is not a standard magnification.
+
+% Fonts for title page:
+\font\titlerm = cmbx12 scaled \magstep3
+\let\authorrm = \secrm
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families.  Since
+% texinfo doesn't allow for producing subscripts and superscripts, we
+% don't bother to reset \scriptfont and \scriptscriptfont (which would
+% also require loading a lot more fonts).
+% 
+\def\resetmathfonts{%
+  \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy
+  \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf
+  \textfont\ttfam = \tentt \textfont\sffam = \tensf
+}
+
+
+% The font-changing commands redefine the meanings of \tenSTYLE, instead
+% of just \STYLE.  We do this so that font changes will continue to work
+% in math mode, where it is the current \fam that is relevant in most
+% cases, not the current.  Plain TeX does, for example,
+% \def\bf{\fam=\bffam \tenbf}  By redefining \tenbf, we obviate the need
+% to redefine \bf itself.  
+\def\textfonts{%
+  \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
+  \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
+  \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy
+  \resetmathfonts}
+\def\chapfonts{%
+  \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl 
+  \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
+  \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy
+  \resetmathfonts}
+\def\secfonts{%
+  \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
+  \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\sectt
+  \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy
+  \resetmathfonts}
+\def\subsecfonts{%
+  \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
+  \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
+  \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy
+  \resetmathfonts}
+\def\indexfonts{%
+  \let\tenrm=\indrm \let\tenit=\tenit \let\tensl=\indsl
+  \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc
+  \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy
+  \resetmathfonts}
+
+% Set up the default fonts, so we can use them for creating boxes.
+% 
+\textfonts
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Fonts for short table of contents.
+\font\shortcontrm=cmr12
+\font\shortcontbf=cmbx12
+\font\shortcontsl=cmsl12
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+% \smartitalic{ARG} outputs arg in italics, followed by an italic correction
+% unless the following character is such as not to need one.
+\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi}
+\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx}
+
+\let\i=\smartitalic
+\let\var=\smartitalic
+\let\dfn=\smartitalic
+\let\emph=\smartitalic
+\let\cite=\smartitalic
+
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+\def\t#1{{\tt \exhyphenpenalty=10000\rawbackslash \frenchspacing #1}\null}
+\let\ttfont = \t
+%\def\samp #1{`{\tt \rawbackslash \frenchspacing #1}'\null}
+\def\samp #1{`\tclose{#1}'\null}
+\def\key #1{{\tt \exhyphenpenalty=10000\uppercase{#1}}\null}
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+\let\file=\samp
+
+% @code is a modification of @t,
+% which makes spaces the same size as normal in the surrounding text.
+\newdimen\tclosesave
+\newdimen\tcloserm
+\def\tclose#1{{\rm \tcloserm=\fontdimen2\font \tt \tclosesave=\fontdimen2\font
+\fontdimen2\font=\tcloserm
+% prevent breaking lines at hyphens.
+\exhyphenpenalty=10000
+\def\ {{\fontdimen2\font=\tclosesave{} }}%
+ \rawbackslash \frenchspacing #1\fontdimen2\font=\tclosesave}\null}
+\let\code=\tclose
+%\let\exp=\tclose  %Was temporary
+
+% @kbd is like @code, except that if the argument is just one @key command, 
+% then @kbd has no effect.
+
+\def\xkey{\key}
+\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}%
+\ifx\one\xkey\ifx\threex\three \key{#2}%
+\else\tclose{\look}\fi
+\else\tclose{\look}\fi}
+
+% Typeset a dimension, e.g., `in' or `pt'.  The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of
+% @dmn{}pt.
+% 
+\def\dmn#1{\thinspace #1}
+
+\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par}
+
+\def\l#1{{\li #1}\null}                % 
+
+\def\r#1{{\rm #1}}             % roman font
+% Use of \lowercase was suggested.
+\def\sc#1{{\smallcaps#1}}      % smallcaps font
+\def\ii#1{{\it #1}}            % italic font
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page.  Must do @settitle before @titlepage.
+\def\titlefont#1{{\titlerm #1}}
+
+\newtoks\realeverypar
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+\def\titlepage{\begingroup \parindent=0pt \textfonts
+   \let\subtitlerm=\tenrm
+% I deinstalled the following change because \cmr12 is undefined.
+% This change was not in the ChangeLog anyway.  --rms.
+%   \let\subtitlerm=\cmr12
+   \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}%
+   %
+   \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}%
+   %
+   % Leave some space at the very top of the page.
+   \vglue\titlepagetopglue
+   %
+   % Now you can print the title using @title.
+   \def\title{\parsearg\titlezzz}%
+   \def\titlezzz##1{\leftline{\titlefont{##1}}
+                   % print a rule at the page bottom also.
+                   \finishedtitlepagefalse
+                   \vskip4pt \hrule height 4pt \vskip4pt}%
+   % No rule at page bottom unless we print one at the top with @title.
+   \finishedtitlepagetrue
+   %
+   % Now you can put text using @subtitle.
+   \def\subtitle{\parsearg\subtitlezzz}%
+   \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}%
+   %
+   % @author should come last, but may come many times.
+   \def\author{\parsearg\authorzzz}%
+   \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi
+      {\authorfont \leftline{##1}}}%
+   %  
+   % Most title ``pages'' are actually two pages long, with space
+   % at the top of the second.  We don't want the ragged left on the second.
+   \let\oldpage = \page
+   \def\page{%
+      \iffinishedtitlepage\else
+        \finishtitlepage
+      \fi
+      \oldpage
+      \let\page = \oldpage
+      \hbox{}}%
+%   \def\page{\oldpage \hbox{}}
+}
+
+\def\Etitlepage{%
+   \iffinishedtitlepage\else
+      \finishtitlepage
+   \fi
+   % It is important to do the page break before ending the group,
+   % because the headline and footline are only empty inside the group.
+   % If we use the new definition of \page, we always get a blank page
+   % after the title page, which we certainly don't want.
+   \oldpage
+   \endgroup
+   \HEADINGSon
+}
+
+\def\finishtitlepage{%
+   \vskip4pt \hrule height 2pt
+   \vskip\titlepagebottomglue
+   \finishedtitlepagetrue
+}
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks \evenheadline    % Token sequence for heading line of even pages
+\newtoks \oddheadline     % Token sequence for heading line of odd pages
+\newtoks \evenfootline    % Token sequence for footing line of even pages
+\newtoks \oddfootline     % Token sequence for footing line of odd pages
+
+% Now make Tex use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+                            \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+                            \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what  @headings on  does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\everyheading{\parsearg\everyheadingxxx}
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\everyfooting{\parsearg\everyfootingxxx}
+
+{\catcode`\@=0 %
+
+\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish}
+\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish}
+\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish}
+\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish}
+\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish}
+\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish}
+\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+%
+}% unbind the catcode of @.
+
+% @headings double     turns headings on for double-sided printing.
+% @headings single     turns headings on for single-sided printing.
+% @headings off                turns them off.
+% @headings on         same as @headings double, retained for compatibility.
+% @headings after      turns on double-sided headings after this page.
+% @headings doubleafter        turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{
+%\pagealignmacro
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+}
+
+% Subroutines used in generating headings
+% Produces Day Month Year style of output.
+\def\today{\number\day\space
+\ifcase\month\or
+January\or February\or March\or April\or May\or June\or
+July\or August\or September\or October\or November\or December\fi
+\space\number\year}
+
+% Use this if you want the Month Day, Year style of output.
+%\def\today{\ifcase\month\or
+%January\or February\or March\or April\or May\or June\or
+%July\or August\or September\or October\or November\or December\fi
+%\space\number\day, \number\year}
+
+% @settitle line...  specifies the title of the document, for headings
+% It generates no output of its own
+
+\def\thistitle{No Title}
+\def\settitle{\parsearg\settitlezzz}
+\def\settitlezzz #1{\gdef\thistitle{#1}}
+
+\message{tables,}
+
+% @tabs -- simple alignment
+
+% These don't work.  For one thing, \+ is defined as outer.
+% So these macros cannot even be defined.
+
+%\def\tabs{\parsearg\tabszzz}
+%\def\tabszzz #1{\settabs\+#1\cr}
+%\def\tabline{\parsearg\tablinezzz}
+%\def\tablinezzz #1{\+#1\cr}
+%\def\&{&}
+
+% Tables -- @table, @ftable, @item(x), @kitem(x), @xitem(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent  \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin  \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table and @ftable define @item, @itemx, etc., with these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\par \parsearg\itemzzz}
+
+\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz}
+\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \par \parsearg\xitemzzz}
+
+\def\internalBkitem{\smallbreak \parsearg\kitemzzz}
+\def\internalBkitemx{\par \parsearg\kitemzzz}
+
+\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}%
+                 \itemzzz {#1}}
+
+\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}%
+                 \itemzzz {#1}}
+
+\def\itemzzz #1{\begingroup %
+\advance \hsize by -\rightskip %
+\advance \hsize by -\leftskip %
+\setbox0=\hbox{\itemfont{#1}}%
+\itemindex{#1}%
+\parskip=0in %
+\noindent %
+\ifdim \wd0>\itemmax %
+\vadjust{\penalty 10000}%
+\hbox to \hsize{\hskip -\tableindent\box0\hss}\ %
+\else %
+\hbox to 0pt{\hskip -\tableindent\box0\hss}%
+\fi %
+\endgroup %
+}
+
+\def\item{\errmessage{@item while not in a table}}
+\def\itemx{\errmessage{@itemx while not in a table}}
+\def\kitem{\errmessage{@kitem while not in a table}}
+\def\kitemx{\errmessage{@kitemx while not in a table}}
+\def\xitem{\errmessage{@xitem while not in a table}}
+\def\xitemx{\errmessage{@xitemx while not in a table}}
+
+%% Contains a kludge to get @end[description] to work
+\def\description{\tablez{\dontindex}{1}{}{}{}{}}
+
+\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex}
+{\obeylines\obeyspaces%
+\gdef\tablex #1^^M{%
+\tabley\dontindex#1        \endtabley}}
+
+\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex}
+{\obeylines\obeyspaces%
+\gdef\ftablex #1^^M{%
+\tabley\fnitemindex#1        \endtabley
+\def\Eftable{\endgraf\endgroup\afterenvbreak}%
+\let\Etable=\relax}}
+
+\def\dontindex #1{}
+\def\fnitemindex #1{\doind {fn}{\code{#1}}}%
+
+{\obeyspaces %
+\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup%
+\tablez{#1}{#2}{#3}{#4}{#5}{#6}}}
+
+\def\tablez #1#2#3#4#5#6{%
+\aboveenvbreak %
+\begingroup %
+\def\Edescription{\Etable}% Neccessary kludge.
+\let\itemindex=#1%
+\ifnum 0#3>0 \advance \leftskip by #3\mil \fi %
+\ifnum 0#4>0 \tableindent=#4\mil \fi %
+\ifnum 0#5>0 \advance \rightskip by #5\mil \fi %
+\def\itemfont{#2}%
+\itemmax=\tableindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \tableindent %
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def\Etable{\endgraf\endgroup\afterenvbreak}%
+\let\item = \internalBitem %
+\let\itemx = \internalBitemx %
+\let\kitem = \internalBkitem %
+\let\kitemx = \internalBkitemx %
+\let\xitem = \internalBxitem %
+\let\xitemx = \internalBxitemx %
+}
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\def\itemize{\parsearg\itemizezzz}
+
+\def\itemizezzz #1{\itemizey {#1}{\Eitemize}}
+
+\def\itemizey #1#2{%
+\aboveenvbreak %
+\begingroup %
+\itemno = 0 %
+\itemmax=\itemindent %
+\advance \itemmax by -\itemmargin %
+\advance \leftskip by \itemindent %
+\parindent = 0pt
+\parskip = \smallskipamount
+\ifdim \parskip=0pt \parskip=2pt \fi%
+\def#2{\endgraf\endgroup\afterenvbreak}%
+\def\itemcontents{#1}%
+\let\item=\itemizeitem}
+
+\def\bullet{$\ptexbullet$}
+\def\minus{$-$}
+
+% Set sfcode to normal for the chars that usually have another value.
+% These are `.?!:;,'
+\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000
+  \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 }
+
+\def\enumerate{\itemizey{\the\itemno.}\Eenumerate\flushcr}
+
+\def\alphaenumerate{\itemizey{\ifcase\itemno\or
+a\or b\or c\or d\or e\or f\or g\or h\or i\or j\or k\or l\or m\or n\or o\or
+p\or q\or r\or s\or t\or u\or v\or w\or x\or y\or z\else
+\errmessage{More than 26 items in @ecapitate; get a bigger alphabet.}\fi.}%
+\Ealphaenumerate\flushcr}
+
+\def\capsenumerate{\itemizey{\ifcase\itemno\or
+A\or B\or C\or D\or E\or F\or G\or H\or I\or J\or K\or L\or M\or N\or O\or
+P\or Q\or R\or S\or T\or U\or V\or W\or X\or Y\or Z\else
+\errmessage{More than 26 items in @capsenumerate; get a bigger alphabet.}\fi.}%
+\Ecapsenumerate\flushcr}
+
+% Definition of @item while inside @itemize.
+
+\def\itemizeitem{%
+\advance\itemno by 1
+{\let\par=\endgraf \smallbreak}%
+\ifhmode \errmessage{\in hmode at itemizeitem}\fi
+{\parskip=0in \hskip 0pt
+\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}%
+\vadjust{\penalty 300}}%
+\flushcr}
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within \newindex.
+{\catcode`\@=11
+\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that        accumulates this index.  The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+
+\def\newindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1        % Open the file
+\expandafter\xdef\csname#1index\endcsname{%    % Define \xxxindex
+\noexpand\doindex {#1}}
+}
+
+% @defindex foo  ==  \newindex{foo}
+
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+
+\def\newcodeindex #1{
+\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file
+\openout \csname#1indfile\endcsname \jobname.#1        % Open the file
+\expandafter\xdef\csname#1index\endcsname{%    % Define \xxxindex
+\noexpand\docodeindex {#1}}
+}
+
+\def\defcodeindex{\parsearg\newcodeindex}
+
+% @synindex foo bar    makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+\def\synindex #1 #2 {%
+\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+\expandafter\let\csname#1indfile\endcsname=\synindexfoo
+\expandafter\xdef\csname#1index\endcsname{%    % Define \xxxindex
+\noexpand\doindex {#2}}%
+}
+
+% @syncodeindex foo bar   similar, but put all entries made for index foo
+% inside @code.
+\def\syncodeindex #1 #2 {%
+\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname
+\expandafter\let\csname#1indfile\endcsname=\synindexfoo
+\expandafter\xdef\csname#1index\endcsname{%    % Define \xxxindex
+\noexpand\docodeindex {#2}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+%  and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+\def\indexdummies{%
+\def\_{{\realbackslash _}}%
+\def\w{\realbackslash w }%
+\def\bf{\realbackslash bf }%
+\def\rm{\realbackslash rm }%
+\def\sl{\realbackslash sl }%
+\def\sf{\realbackslash sf}%
+\def\tt{\realbackslash tt}%
+\def\gtr{\realbackslash gtr}%
+\def\less{\realbackslash less}%
+\def\hat{\realbackslash hat}%
+\def\char{\realbackslash char}%
+\def\TeX{\realbackslash TeX}%
+\def\dots{\realbackslash dots }%
+\def\copyright{\realbackslash copyright }%
+\def\tclose##1{\realbackslash tclose {##1}}%
+\def\code##1{\realbackslash code {##1}}%
+\def\samp##1{\realbackslash samp {##1}}%
+\def\t##1{\realbackslash r {##1}}%
+\def\r##1{\realbackslash r {##1}}%
+\def\i##1{\realbackslash i {##1}}%
+\def\b##1{\realbackslash b {##1}}%
+\def\cite##1{\realbackslash cite {##1}}%
+\def\key##1{\realbackslash key {##1}}%
+\def\file##1{\realbackslash file {##1}}%
+\def\var##1{\realbackslash var {##1}}%
+\def\kbd##1{\realbackslash kbd {##1}}%
+}
+
+% \indexnofonts no-ops all font-change commands.
+% This is used when outputting the strings to sort the index by.
+\def\indexdummyfont#1{#1}
+\def\indexdummytex{TeX}
+\def\indexdummydots{...}
+
+\def\indexnofonts{%
+\let\w=\indexdummyfont
+\let\t=\indexdummyfont
+\let\r=\indexdummyfont
+\let\i=\indexdummyfont
+\let\b=\indexdummyfont
+\let\emph=\indexdummyfont
+\let\strong=\indexdummyfont
+\let\cite=\indexdummyfont
+\let\sc=\indexdummyfont
+%Don't no-op \tt, since it isn't a user-level command
+% and is used in the definitions of the active chars like <, >, |...
+%\let\tt=\indexdummyfont
+\let\tclose=\indexdummyfont
+\let\code=\indexdummyfont
+\let\file=\indexdummyfont
+\let\samp=\indexdummyfont
+\let\kbd=\indexdummyfont
+\let\key=\indexdummyfont
+\let\var=\indexdummyfont
+\let\TeX=\indexdummytex
+\let\dots=\indexdummydots
+}
+
+% To define \realbackslash, we must make \ not be an escape.
+% We must first make another character (@) an escape
+% so we do not become unable to do a definition.
+
+{\catcode`\@=0 \catcode`\\=\other
+@gdef@realbackslash{\}}
+
+\let\indexbackslash=0  %overridden during \printindex.
+
+\def\doind #1#2{%
+{\count10=\lastpenalty %
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\escapechar=`\\%
+{\let\folio=0% Expand all macros now EXCEPT \folio
+\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now
+% so it will be output as is; and it will print as backslash in the indx.
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2}%
+}%
+% Now produce the complete index entry.  We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}}}%
+\temp }%
+}\penalty\count10}}
+
+\def\dosubind #1#2#3{%
+{\count10=\lastpenalty %
+{\indexdummies % Must do this here, since \bf, etc expand at this stage
+\escapechar=`\\%
+{\let\folio=0%
+\def\rawbackslashxx{\indexbackslash}%
+%
+% Now process the index-string once, with all font commands turned off,
+% to get the string to sort the index by.
+{\indexnofonts
+\xdef\temp1{#2 #3}%
+}%
+% Now produce the complete index entry.  We process the index-string again,
+% this time with font commands expanded, to get what to print in the index.
+\edef\temp{%
+\write \csname#1indfile\endcsname{%
+\realbackslash entry {\temp1}{\folio}{#2}{#3}}}%
+\temp }%
+}\penalty\count10}}
+
+% The index entry written in the file actually looks like
+%  \entry {sortstring}{page}{topic}
+% or
+%  \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+%  \initial {c}
+%     before the first topic whose initial is c
+%  \entry {topic}{pagelist}
+%     for a topic that is used without subtopics
+%  \primary {topic}
+%     for the beginning of a topic that is used with subtopics
+%  \secondary {subtopic}{pagelist}
+%     for each subtopic.
+
+% Define the user-accessible indexing commands 
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% This is what you call to cause a particular index to get printed.
+% Write
+% @unnumbered Function Index
+% @printindex fn
+
+\def\printindex{\parsearg\doprintindex}
+
+\def\doprintindex#1{\tex %
+\dobreak \chapheadingskip {10000}
+\catcode`\%=\other\catcode`\&=\other\catcode`\#=\other
+\catcode`\$=\other\catcode`\_=\other
+\catcode`\~=\other
+% The following don't help, since the chars were translated
+% when the raw index was written, and their fonts were discarded
+% due to \indexnofonts.
+%\catcode`\"=\active
+%\catcode`\^=\active
+%\catcode`\_=\active
+%\catcode`\|=\active
+%\catcode`\<=\active
+%\catcode`\>=\active
+\def\indexbackslash{\rawbackslashxx}
+\indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt
+\begindoublecolumns
+\openin 1 \jobname.#1s
+\ifeof 1 
+% \enddoublecolumns gets confused if there is no text in the index,
+% and it loses the chapter title and the aux file entries for the index.
+% The easiest way to prevent this problem is to make sure there is some text.
+(Index is empty)
+\else \closein 1 \input \jobname.#1s
+\fi
+\enddoublecolumns
+\Etex}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+% Same as \bigskipamount except no shrink.
+% \balancecolumns gets confused if there is any shrink.
+\newskip\initialskipamount \initialskipamount 12pt plus4pt
+
+\outer\def\initial #1{%
+{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+\ifdim\lastskip<\initialskipamount
+\removelastskip \penalty-200 \vskip \initialskipamount\fi
+\line{\secbf#1\hfill}\kern 2pt\penalty10000}}
+
+\outer\def\entry #1#2{
+{\parfillskip=0in \parskip=0in \parindent=0in
+\hangindent=1in \hangafter=1%
+\noindent\hbox{#1}\indexdotfill #2\par
+}}
+
+% Like \dotfill except takes at least 1 em.
+\def\indexdotfill{\cleaders
+  \hbox{$\mathsurround=0pt \mkern1.5mu . \mkern1.5mu$}\hskip 1em plus 1fill}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+
+\def\secondary #1#2{
+{\parfillskip=0in \parskip=0in
+\hangindent =1in \hangafter=1
+\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par
+}}
+
+%% Define two-column mode, which is used in indexes.
+%% Adapted from the TeXBook, page 416
+\catcode `\@=11
+
+\newbox\partialpage
+
+\newdimen\doublecolumnhsize  \doublecolumnhsize = 3.11in
+\newdimen\doublecolumnvsize  \doublecolumnvsize = 19.1in
+\newdimen\availdimen@
+
+\def\begindoublecolumns{\begingroup
+  \output={\global\setbox\partialpage=
+    \vbox{\unvbox255\kern -\topskip \kern \baselineskip}}\eject
+  \output={\doublecolumnout}%
+  \hsize=\doublecolumnhsize \vsize=\doublecolumnvsize}
+\def\enddoublecolumns{\output={\balancecolumns}\eject
+  \endgroup \pagegoal=\vsize}
+
+\def\doublecolumnout{\splittopskip=\topskip \splitmaxdepth=\maxdepth
+  \dimen@=\pageheight \advance\dimen@ by-\ht\partialpage
+  \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+  \onepageout\pagesofar \unvbox255 \penalty\outputpenalty}
+\def\pagesofar{\unvbox\partialpage %
+  \hsize=\doublecolumnhsize % have to restore this since output routine
+%            changes it to set cropmarks (P. A. MacKay, 12 Nov. 1986)
+  \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}}
+\def\balancecolumns{%
+% Unset the glue.
+  \setbox255=\vbox{\unvbox255}
+  \dimen@=\ht255
+  \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip
+  \divide\dimen@ by2
+  \availdimen@=\pageheight \advance\availdimen@ by-\ht\partialpage
+% If the remaining data is too big for one page,
+% output one page normally, then work with what remains.
+  \ifdim \dimen@>\availdimen@
+   {
+     \splittopskip=\topskip \splitmaxdepth=\maxdepth
+     \dimen@=\pageheight \advance\dimen@ by-\ht\partialpage
+     \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+     \onepageout\pagesofar
+   }
+% Recompute size of what remains, in case we just output some of it.
+  \dimen@=\ht255
+  \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip
+  \divide\dimen@ by2
+  \fi
+  \setbox0=\vbox{\unvbox255}
+  \splittopskip=\topskip
+  {\vbadness=10000 \loop \global\setbox3=\copy0
+    \global\setbox1=\vsplit3 to\dimen@
+    \ifdim\ht3>\dimen@ \global\advance\dimen@ by1pt \repeat}
+  \setbox0=\vbox to\dimen@{\unvbox1}  \setbox2=\vbox to\dimen@{\unvbox3}
+  \pagesofar}
+
+\catcode `\@=\other
+\message{sectioning,}
+% Define chapters, sections, etc.
+
+\newcount \chapno
+\newcount \secno
+\newcount \subsecno
+\newcount \subsubsecno
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount \appendixno  \appendixno = `\@
+\def\appendixletter{\char\the\appendixno}
+
+\newwrite \contentsfile
+% This is called from \setfilename.
+\def\opencontents{\openout \contentsfile = \jobname.toc}
+
+% Each @chapter defines this as the name of the chapter.
+% page headings and footings can use it.  @section does likewise
+
+\def\thischapter{} \def\thissection{}
+\def\seccheck#1{\if \pageno<0 %
+\errmessage{@#1 not allowed after generating table of contents}\fi
+%
+}
+
+\def\chapternofonts{%
+\let\rawbackslash=\relax%
+\let\frenchspacing=\relax%
+\def\TeX{\realbackslash TeX}
+\def\dots{\realbackslash dots}
+\def\copyright{\realbackslash copyright}
+\def\tt{\realbackslash tt}
+\def\bf{\realbackslash bf }
+\def\w{\realbackslash w}
+\def\less{\realbackslash less}
+\def\gtr{\realbackslash gtr}
+\def\hat{\realbackslash hat}
+\def\char{\realbackslash char}
+\def\tclose##1{\realbackslash tclose {##1}}
+\def\code##1{\realbackslash code {##1}}
+\def\samp##1{\realbackslash samp {##1}}
+\def\r##1{\realbackslash r {##1}}
+\def\b##1{\realbackslash b {##1}}
+\def\key##1{\realbackslash key {##1}}
+\def\file##1{\realbackslash file {##1}}
+\def\kbd##1{\realbackslash kbd {##1}}
+% These are redefined because @smartitalic wouldn't work inside xdef.
+\def\i##1{\realbackslash i {##1}}
+\def\cite##1{\realbackslash cite {##1}}
+\def\var##1{\realbackslash var {##1}}
+\def\emph##1{\realbackslash emph {##1}}
+\def\dfn##1{\realbackslash dfn {##1}}
+}
+
+\outer\def\chapter{\parsearg\chapterzzz}
+\def\chapterzzz #1{\seccheck{chapter}%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \chapno by 1 \message{Chapter \the\chapno}%
+\chapmacro {#1}{\the\chapno}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+% We don't substitute the actual chapter name into \thischapter
+% because we don't want its macros evaluated now.
+\xdef\thischapter{Chapter \the\chapno: \noexpand\thischaptername}%
+{\chapternofonts%
+\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\donoderef %
+\global\let\section = \numberedsection
+}}
+
+\outer\def\appendix{\parsearg\appendixzzz}
+\def\appendixzzz #1{\seccheck{appendix}%
+\secno=0 \subsecno=0 \subsubsecno=0
+\global\advance \appendixno by 1 \message{Appendix \appendixletter}%
+\chapmacro {#1}{Appendix \appendixletter}%
+\gdef\thissection{#1}%
+\gdef\thischaptername{#1}%
+\xdef\thischapter{Appendix \appendixletter: \noexpand\thischaptername}%
+{\chapternofonts%
+\edef\temp{{\realbackslash chapentry 
+  {#1}{Appendix \appendixletter}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\appendixnoderef %
+\global\let\section = \appendixsec
+}}
+
+\outer\def\top{\parsearg\unnumberedzzz}
+\outer\def\unnumbered{\parsearg\unnumberedzzz}
+\def\unnumberedzzz #1{\seccheck{unnumbered}%
+\secno=0 \subsecno=0 \subsubsecno=0 \message{(#1)}
+\unnumbchapmacro {#1}%
+\gdef\thischapter{#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp  %
+\unnumbnoderef %
+\global\let\section = \unnumberedsec
+}}
+
+\outer\def\numberedsection{\parsearg\sectionzzz}
+\def\sectionzzz #1{\seccheck{section}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash secentry %
+{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+\global\let\subsection = \numberedsubsection
+}}
+
+\outer\def\appendixsection{\parsearg\appendixsectionzzz}
+\outer\def\appendixsec{\parsearg\appendixsectionzzz}
+\def\appendixsectionzzz #1{\seccheck{appendixsection}%
+\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 %
+\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash secentry %
+{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+\global\let\subsection = \appendixsubsec
+}}
+
+\outer\def\unnumberedsec{\parsearg\unnumberedseczzz}
+\def\unnumberedseczzz #1{\seccheck{unnumberedsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+\global\let\subsection = \unnumberedsubsec
+}}
+
+\outer\def\numberedsubsection{\parsearg\subsectionzzz}
+\def\subsectionzzz #1{\seccheck{subsection}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+\global\let\subsubsection = \numberedsubsubsection
+}}
+
+\outer\def\appendixsubsec{\parsearg\appendixsubseczzz}
+\def\appendixsubseczzz #1{\seccheck{appendixsubsec}%
+\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 %
+\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsecentry %
+{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+\global\let\subsubsection = \appendixsubsubsec
+}}
+
+\outer\def\unnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+\global\let\subsubsection = \unnumberedsubsubsec
+}}
+
+\outer\def\numberedsubsubsection{\parsearg\subsubsectionzzz}
+\def\subsubsectionzzz #1{\seccheck{subsubsection}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+  {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsubsecentry %
+  {#1}
+  {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}
+  {\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\donoderef %
+\penalty 10000 %
+}}
+
+\outer\def\appendixsubsubsec{\parsearg\appendixsubsubseczzz}
+\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}%
+\gdef\thissection{#1}\global\advance \subsubsecno by 1 %
+\subsubsecheading {#1}
+  {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}%
+{\chapternofonts%
+\edef\temp{{\realbackslash subsubsecentry{#1}%
+  {\appendixletter}
+  {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\appendixnoderef %
+\penalty 10000 %
+}}
+
+\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}%
+\plainsecheading {#1}\gdef\thissection{#1}%
+{\chapternofonts%
+\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}%
+\escapechar=`\\%
+\write \contentsfile \temp %
+\unnumbnoderef %
+\penalty 10000 %
+}}
+
+% These are variants which are not "outer", so they can appear in @ifinfo.
+\def\infotop{\parsearg\unnumberedzzz}
+\def\infounnumbered{\parsearg\unnumberedzzz}
+\def\infounnumberedsec{\parsearg\unnumberedseczzz}
+\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz}
+\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz}
+
+\def\infoappendix{\parsearg\appendixzzz}
+\def\infoappendixsec{\parsearg\appendixseczzz}
+\def\infoappendixsubsec{\parsearg\appendixsubseczzz}
+\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz}
+
+\def\infochapter{\parsearg\chapterzzz}
+\def\infosection{\parsearg\sectionzzz}
+\def\infosubsection{\parsearg\subsectionzzz}
+\def\infosubsubsection{\parsearg\subsubsectionzzz}
+
+% Define @majorheading, @heading and @subheading
+
+\def\majorheading{\parsearg\majorheadingzzz}
+\def\majorheadingzzz #1{%
+{\advance\chapheadingskip by 10pt \chapbreak }%
+{\chapfonts \line{\rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\chapheading{\parsearg\chapheadingzzz}
+\def\chapheadingzzz #1{\chapbreak %
+{\chapfonts \line{\rm #1\hfill}}\bigskip \par\penalty 200}
+
+\def\heading{\parsearg\secheadingi}
+
+\def\subheading{\parsearg\subsecheadingi}
+
+\def\subsubheading{\parsearg\subsubsecheadingi}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+\def\CHAPFplain{
+\global\let\chapmacro=\chfplain
+\global\let\unnumbchapmacro=\unnchfplain}
+
+\def\chfplain #1#2{%
+  \pchapsepmacro
+  {%
+    \chapfonts
+    \leftline{\rm #2\enspace #1}%
+  }%
+  \bigskip
+  \penalty5000
+}
+
+\def\unnchfplain #1{%
+\pchapsepmacro %
+{\chapfonts \line{\rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+\CHAPFplain % The default
+
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \line{\rm #1\hfill}}\bigskip \par\penalty 10000 %
+}
+
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+
+\def\CHAPFopen{
+\global\let\chapmacro=\chfopen
+\global\let\unnumbchapmacro=\unnchfopen}
+
+% Parameter controlling skip before section headings.
+
+\newskip \subsecheadingskip  \subsecheadingskip = 17pt plus 8pt minus 4pt
+\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}}
+
+\newskip \secheadingskip  \secheadingskip = 21pt plus 8pt minus 4pt
+\def\secheadingbreak{\dobreak \secheadingskip {-1000}}
+
+
+% Section fonts are the base font at magstep2, which produces
+% a size a bit more than 14 points in the default situation.   
+
+\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}}
+\def\plainsecheading #1{\secheadingi {#1}}
+\def\secheadingi #1{{\advance \secheadingskip by \parskip %
+\secheadingbreak}%
+{\secfonts \line{\rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+
+% Subsection fonts are the base font at magstep1, 
+% which produces a size of 12 points.
+
+\def\subsecheading #1#2#3#4{\subsecheadingi {#2.#3.#4\enspace #1}}
+\def\subsecheadingi #1{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsecfonts \line{\rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 }
+
+\def\subsubsecfonts{\subsecfonts} % Maybe this should change:
+                                 % Perhaps make sssec fonts scaled
+                                 % magstep half
+\def\subsubsecheading #1#2#3#4#5{\subsubsecheadingi {#2.#3.#4.#5\enspace #1}}
+\def\subsubsecheadingi #1{{\advance \subsecheadingskip by \parskip %
+\subsecheadingbreak}%
+{\subsubsecfonts \line{\rm #1\hfill}}%
+\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000}
+
+
+\message{toc printing,}
+
+% Finish up the main text and prepare to read what we've written
+% to \contentsfile.
+
+\def\startcontents#1{%
+   \ifnum \pageno>0
+      \pagealignmacro
+      \immediate\closeout \contentsfile
+      \pageno = -1             % Request roman numbered pages.
+   \fi
+   % Don't need to put `Contents' or `Short Contents' in the headline. 
+   % It is abundantly clear what they are.
+   \unnumbchapmacro{#1}\def\thischapter{}%
+   \begingroup                 % Set up to handle contents files properly.
+      \catcode`\\=0  \catcode`\{=1  \catcode`\}=2  \catcode`\@=11
+      \raggedbottom             % Worry more about breakpoints than the bottom.
+      \advance\hsize by -1in    % Don't use the full line length.
+}
+
+  
+% Normal (long) toc.
+\outer\def\contents{%
+   \startcontents{Table of Contents}%
+      \input \jobname.toc
+   \endgroup
+   \vfill \eject
+}
+
+% And just the chapters.
+\outer\def\summarycontents{%
+   \startcontents{Short Contents}%
+      %
+      \let\chapentry = \shortchapentry
+      \let\unnumbchapentry = \shortunnumberedentry
+      % We want a true roman here for the page numbers.
+      \secfonts
+      \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl
+      \rm
+      \advance\baselineskip by 1pt % Open it up a little.
+      \def\secentry ##1##2##3##4{}
+      \def\unnumbsecentry ##1##2{}
+      \def\subsecentry ##1##2##3##4##5{}
+      \def\unnumbsubsecentry ##1##2{}
+      \def\subsubsecentry ##1##2##3##4##5##6{}
+      \def\unnumbsubsubsecentry ##1##2{}
+      \input \jobname.toc
+   \endgroup
+   \vfill \eject
+}
+\let\shortcontents = \summarycontents
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Chapter-level things, for both the long and short contents.
+\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}}
+\def\shortchapentry#1#2#3{%
+   \line{{#2\labelspace #1}\dotfill\doshortpageno{#3}}%
+}
+
+\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}}
+\def\shortunnumberedentry#1#2{%
+   \line{#1\dotfill\doshortpageno{#2}}%
+}
+
+% Sections.
+\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}}
+\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}}
+
+% Subsections.
+\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}}
+\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}}
+
+% And subsubsections.
+\def\subsubsecentry#1#2#3#4#5#6{%
+  \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}}
+\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}}
+
+
+% This parameter controls the indentation of the various levels.
+\newdimen\tocindent \tocindent = 3pc
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the 
+% page number.
+%
+% If the toc has to be broken over pages, we would want to be at chapters 
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+   \penalty-300 \vskip\baselineskip
+   \line{\chapentryfonts #1\dotfill \dopageno{#2}}%
+   \nobreak\vskip .25\baselineskip
+}
+
+\def\dosecentry#1#2{%
+   \line{\secentryfonts \hskip\tocindent #1\dotfill \dopageno{#2}}%
+}
+
+\def\dosubsecentry#1#2{%
+   \line{\subsecentryfonts \hskip2\tocindent #1\dotfill \dopageno{#2}}%
+}
+
+\def\dosubsubsecentry#1#2{%
+   \line{\subsubsecentryfonts \hskip3\tocindent #1\dotfill \dopageno{#2}}%
+}
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\let\subsecentryfonts = \textfonts
+\let\subsubsecentryfonts = \textfonts
+
+
+\message{environments,}
+
+% Since these characters are used in examples, it should be an even number of 
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+% Furthermore, these definitions must come after we define our fonts.
+\newbox\dblarrowbox    \newbox\longdblarrowbox
+\newbox\pushcharbox    \newbox\bullbox
+\newbox\equivbox       \newbox\errorbox
+
+\let\ptexequiv = \equiv
+
+{\tentt
+\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil}
+\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil}
+\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil}
+\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil}
+% Adapted from the manmac format (p.420 of TeXbook)
+\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex
+                                      depth .1ex\hfil}
+}
+
+\def\point{$\star$}
+
+\def\result{\leavevmode\raise.15ex\copy\dblarrowbox}
+\def\expansion{\leavevmode\raise.1ex\copy\longdblarrowbox}
+\def\print{\leavevmode\lower.1ex\copy\pushcharbox}
+
+\def\equiv{\leavevmode\lower.1ex\copy\equivbox}
+
+% Does anyone really want this?
+% \def\bull{\leavevmode\copy\bullbox}
+
+% Adapted from the TeXbook's \boxit.
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt}
+
+\global\setbox\errorbox=\hbox to \dimen0{\hfil
+   \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+   \advance\hsize by -2\dimen2 % Rules.
+   \vbox{
+      \hrule height\dimen2
+      \hbox{\vrule width\dimen2 \kern3pt          % Space to left of text.
+         \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+         \kern3pt\vrule width\dimen2}% Space to right.
+      \hrule height\dimen2}
+    \hfil}
+
+% The @error{} command.
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @tex ... @end tex    escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\def\tex{\begingroup
+\catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+\catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie
+\catcode `\%=14
+\catcode 43=12
+\catcode`\"=12
+\catcode`\==12
+\catcode`\|=12
+\catcode`\<=12
+\catcode`\>=12
+\escapechar=`\\
+%
+\let\{=\ptexlbrace
+\let\}=\ptexrbrace
+\let\.=\ptexdot
+\let\*=\ptexstar
+\let\dots=\ptexdots
+\def\@{@}%
+\let\bullet=\ptexbullet
+\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl
+\let\L=\ptexL
+%
+\let\Etex=\endgroup}
+
+% Define @lisp ... @endlisp.
+% @lisp does a \begingroup so it can rebind things,
+% including the definition of @endlisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^M gets inside @lisp
+% phr: changed space to \null, to avoid overfull hbox problems.
+{\obeyspaces%
+\gdef\lisppar{\null\endgraf}}
+
+% Cause \obeyspaces to make each Space cause a word-separation
+% rather than the default which is that it acts punctuation.
+% This is because space in tt font looks funny.
+{\obeyspaces %
+\gdef\sepspaces{\def {\ }}}
+
+\newskip\aboveenvskipamount \aboveenvskipamount= 0pt
+\def\aboveenvbreak{{\advance\aboveenvskipamount by \parskip
+\endgraf \ifdim\lastskip<\aboveenvskipamount
+\removelastskip \penalty-50 \vskip\aboveenvskipamount \fi}}
+
+\def\afterenvbreak{\endgraf \ifdim\lastskip<\aboveenvskipamount
+\removelastskip \penalty-50 \vskip\aboveenvskipamount \fi}
+
+\def\lisp{\aboveenvbreak
+\begingroup\inENV % This group ends at the end of the @lisp body
+\hfuzz=12truept % Don't be fussy
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Elisp{\endgroup\afterenvbreak}%
+\parskip=0pt
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines \tt \rawbackslash
+\def\next##1{}\next}
+
+
+\let\example=\lisp
+\def\Eexample{\Elisp}
+
+\let\smallexample=\lisp
+\def\Esmallexample{\Elisp}
+
+% Macro for 9 pt. examples, necessary to print with 5" lines.
+% From Pavel@xerox.  This is not really used unless the
+% @smallbook command is given.
+
+\def\smalllispx{\aboveenvbreak\begingroup\inENV
+%                      This group ends at the end of the @lisp body
+\hfuzz=12truept % Don't be fussy
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Esmalllisp{\endgroup\afterenvbreak}%
+\parskip=0pt
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines \ninett \indexfonts \rawbackslash
+\def\next##1{}\next}
+
+% This is @display; same as @lisp except use roman font.
+
+\def\display{\begingroup\inENV %This group ends at the end of the @display body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% Single space lines
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Edisplay{\endgroup\afterenvbreak}%
+\parskip=0pt
+\advance \leftskip by \lispnarrowing
+\parindent=0pt
+\let\exdent=\internalexdent
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% This is @format; same as @lisp except use roman font and don't narrow margins
+
+\def\format{\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+\singlespace %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+\let\par=\lisppar
+\def\Eformat{\endgroup\afterenvbreak}
+\parskip=0pt \parindent=0pt
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% @flushleft and @flushright
+
+\def\flushleft{%
+\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+% This also causes @ to work when the directive name
+% is terminated by end of line.
+\let\par=\lisppar
+\def\Eflushleft{\endgroup\afterenvbreak}%
+\parskip=0pt \parindent=0pt
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+\def\flushright{%
+\begingroup\inENV %This group ends at the end of the @format body
+\aboveenvbreak
+% Make spaces be word-separators rather than space tokens.
+\sepspaces %
+% The following causes blank lines not to be ignored
+% by adding a space to the end of each line.
+% This also causes @ to work when the directive name
+% is terminated by end of line.
+\let\par=\lisppar
+\def\Eflushright{\endgroup\afterenvbreak}%
+\parskip=0pt \parindent=0pt
+\advance \leftskip by 0pt plus 1fill
+\obeyspaces \obeylines
+\def\next##1{}\next}
+
+% @quotation - narrow the margins.
+
+\def\quotation{%
+\begingroup\inENV %This group ends at the end of the @quotation body
+{\parskip=0pt  % because we will skip by \parskip too, later
+\aboveenvbreak}%
+\singlespace
+\parindent=0pt
+\def\Equotation{\par\endgroup\afterenvbreak}%
+\advance \rightskip by \lispnarrowing 
+\advance \leftskip by \lispnarrowing}
+
+\message{defuns,}
+% Define formatter for defuns
+% First, allow user to change definition object font (\df) internally
+\def\setdeffont #1 {\csname DEF#1\endcsname}
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deftypemargin \deftypemargin=12pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+
+\newcount\parencount
+% define \functionparens, which makes ( and ) and & do special things.
+% \functionparens affects the group it is contained in.
+\def\activeparens{%
+\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active
+\catcode`\[=\active \catcode`\]=\active}
+{\activeparens % Now, smart parens don't turn on until &foo (see \amprm)
+\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 }
+\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+
+% Definitions of (, ) and & used in args for functions.
+% This is the definition of ( outside of all parentheses.
+\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested %
+\global\advance\parencount by 1 }
+%
+% This is the definition of ( when already inside a level of parens.
+\gdef\opnested{\char`\(\global\advance\parencount by 1 }
+%
+\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0.
+% also in that case restore the outer-level definition of (.
+\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi
+\global\advance \parencount by -1 }
+% If we encounter &foo, then turn on ()-hacking afterwards
+\gdef\amprm#1 {{\rm\&#1}\let(=\oprm \let)=\clrm\ }
+%
+\gdef\normalparens{\boldbrax\let&=\ampnr}
+} % End of definition inside \activeparens
+%% These parens (in \boldbrax) actually are a little bolder than the
+%% contained text.  This is especially needed for [ and ]
+\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&}
+\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}}
+
+% First, defname, which formats the header line itself.
+% #1 should be the function name.
+% #2 should be the type of definition, such as "Function".
+
+\def\defname #1#2{%
+% Get the values of \leftskip and \rightskip as they were
+% outside the @def...
+\dimen2=\leftskip
+\advance\dimen2 by -\defbodyindent
+\dimen3=\rightskip
+\advance\dimen3 by -\defbodyindent
+\noindent        %
+\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}%
+\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line
+\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations
+\parshape 2 0in \dimen0 \defargsindent \dimen1     %
+% Now output arg 2 ("Function" or some such)
+% ending at \deftypemargin from the right margin,
+% but stuck inside a box of width 0 so it does not interfere with linebreaking
+{% Adjust \hsize to exclude the ambient margins,
+% so that \rightline will obey them.
+\advance \hsize by -\dimen2 \advance \hsize by -\dimen3
+\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}%
+% Make all lines underfull and no complaints:
+\tolerance=10000 \hbadness=10000    
+{\df #1}\enskip        % Generate function name
+}
+
+% Actually process the body of a definition
+% #1 should be the terminating control sequence, such as \Edefun.
+% #2 should be the "another name" control sequence, such as \defunx.
+% #3 should be the control sequence that actually processes the header,
+%    such as \defunheader.
+
+\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2{\begingroup\obeylines\activeparens\spacesplit#3}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\begingroup %
+\catcode 61=\active %
+\obeylines\activeparens\spacesplit#3}
+
+\def\defmethparsebody #1#2#3#4 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#4}}}
+
+\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV %
+\medbreak %
+% Define the end token that this defining construct specifies
+% so that it will exit this group.
+\def#1{\endgraf\endgroup\medbreak}%
+\def#2##1 ##2 {\def#4{##1}%
+\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}%
+\parindent=0in
+\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent
+\begingroup\obeylines\activeparens\spacesplit{#3{#5}}}
+
+% Split up #2 at the first space token.
+% call #1 with two arguments:
+%  the first is all of #2 before the space token,
+%  the second is all of #2 after that space token.
+% If #2 contains no space token, all of it is passed as the first arg
+% and the second is passed as empty.
+
+{\obeylines
+\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}%
+\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{%
+\ifx\relax #3%
+#1{#2}{}\else #1{#2}{#3#4}\fi}}
+
+% So much for the things common to all kinds of definitions.
+
+% Define @defun.
+
+% First, define the processing that is wanted for arguments of \defun
+% Use this to expand the args and terminate the paragraph they make up
+
+\def\defunargs #1{\functionparens \sl
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\hyphenchar\tensl=0
+#1%
+\hyphenchar\tensl=45
+\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
+}
+
+\def\deftypefunargs #1{%
+% Expand, preventing hyphenation at `-' chars.
+% Note that groups don't affect changes in \hyphenchar.
+\functionparens
+\code{#1}%
+\interlinepenalty=10000
+\advance\rightskip by 0pt plus 1fil
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000%
+}
+
+% Do complete processing of one @defun or @defunx line already parsed.
+
+% @deffn Command forward-char nchars
+
+\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader}
+
+\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defun == @deffn Function
+
+\def\defun{\defparsebody\Edefun\defunx\defunheader}
+
+\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Function}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefun int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader}
+
+% #1 is the data type.  #2 is the name and args.
+\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax}
+% #1 is the data type, #2 the name, #3 the args.
+\def\deftypefunheaderx #1#2 #3\relax{%
+\doind {fn}{\code{#2}}% Make entry in function index
+\begingroup\defname {\code{#1} #2}{Function}%
+\deftypefunargs {#3}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar})
+
+\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader}
+
+% #1 is the classification.  #2 is the data type.  #3 is the name and args.
+\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax}
+% #1 is the classification, #2 the data type, #3 the name, #4 the args.
+\def\deftypefnheaderx #1#2#3 #4\relax{%
+\doind {fn}{\code{#3}}% Make entry in function index
+\begingroup\defname {\code{#2} #3}{#1}%
+\deftypefunargs {#4}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defmac == @deffn Macro
+
+\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader}
+
+\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Macro}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% @defspec == @deffn Special Form
+
+\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader}
+
+\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index
+\begingroup\defname {#1}{Special Form}%
+\defunargs {#2}\endgroup %
+\catcode 61=\other % Turn off change made in \defparsebody
+}
+
+% This definition is run if you use @defunx
+% anywhere other than immediately after a @defun or @defunx.
+
+\def\deffnx #1 {\errmessage{@deffnx in invalid context}}
+\def\defunx #1 {\errmessage{@defunx in invalid context}}
+\def\defmacx #1 {\errmessage{@defmacx in invalid context}}
+\def\defspecx #1 {\errmessage{@defspecx in invalid context}}
+\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}}
+\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}}
+
+% @defmethod, and so on
+
+% @defop {Funny Method} foo-class frobnicate argument
+
+\def\defop #1 {\def\defoptype{#1}%
+\defopparsebody\Edefop\defopx\defopheader\defoptype}
+
+\def\defopheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index
+\begingroup\defname {#2}{\defoptype{} on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @defmethod == @defop Method
+
+\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader}
+
+\def\defmethodheader #1#2#3{%
+\dosubind {fn}{\code{#2}}{on #1}% entry in function index
+\begingroup\defname {#2}{Method on #1}%
+\defunargs {#3}\endgroup %
+}
+
+% @deftypemethod class type frobnicate argument
+
+\def\deftypemethod{\defmethparsebody\Edeftypemethod\deftypemethodx%
+\deftypemethodheader}
+
+% #1 is the class. #2 is the data type. #3 is the name and args.
+\def\deftypemethodheader #1#2#3{\deftypemethodheaderx{#1}{#2}#3 \relax}
+% #1 is the class, #2 the data type, #3 then name , #4 the args.
+\def\deftypemethodheaderx #1#2#3 #4\relax{\dosubind {fn}{\code{#3}}{on #1}%
+\begingroup\defname {\code{#2} #3}{Method on #1}%
+\deftypefunargs {#4}\endgroup
+}
+
+% @defcv {Class Option} foo-class foo-flag
+
+\def\defcv #1 {\def\defcvtype{#1}%
+\defopparsebody\Edefcv\defcvx\defcvarheader\defcvtype}
+
+\def\defcvarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{\defcvtype{} of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% @defivar == @defcv {Instance Variable}
+
+\def\defivar{\defmethparsebody\Edefivar\defivarx\defivarheader}
+
+\def\defivarheader #1#2#3{%
+\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index
+\begingroup\defname {#2}{Instance Variable of #1}%
+\defvarargs {#3}\endgroup %
+}
+
+% These definitions are run if you use @defmethodx, etc.,
+% anywhere other than immediately after a @defmethod, etc.
+
+\def\defopx #1 {\errmessage{@defopx in invalid context}}
+\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}}
+\def\defcvx #1 {\errmessage{@defcvx in invalid context}}
+\def\defivarx #1 {\errmessage{@defivarx in invalid context}}
+
+% Now @defvar
+
+% First, define the processing that is wanted for arguments of @defvar.
+% This is actually simple: just print them in roman.
+% This must expand the args and terminate the paragraph they make up
+\def\defvarargs #1{\normalparens #1%
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000}
+
+% @defvr Counter foo-count
+
+\def\defvr{\defmethparsebody\Edefvr\defvrx\defvrheader}
+
+\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}%
+\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup}
+
+% @defvar == @defvr Variable
+
+\def\defvar{\defparsebody\Edefvar\defvarx\defvarheader}
+
+\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{Variable}%
+\defvarargs {#2}\endgroup %
+}
+
+% @defopt == @defvr {User Option}
+
+\def\defopt{\defparsebody\Edefopt\defoptx\defoptheader}
+
+\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index
+\begingroup\defname {#1}{User Option}%
+\defvarargs {#2}\endgroup %
+}
+
+% @deftypevar int foobar
+
+\def\deftypevar{\defparsebody\Edeftypevar\deftypevarx\deftypevarheader}
+
+% #1 is the data type.  #2 is the name.
+\def\deftypevarheader #1#2{%
+\doind {vr}{\code{#2}}% Make entry in variables index
+\begingroup\defname {\code{#1} #2}{Variable}%
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000
+\endgroup}
+
+% @deftypevr {Global Flag} int enable
+
+\def\deftypevr{\defmethparsebody\Edeftypevr\deftypevrx\deftypevrheader}
+
+\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}%
+\begingroup\defname {\code{#2} #3}{#1}
+\interlinepenalty=10000
+\endgraf\penalty 10000\vskip -\parskip\penalty 10000
+\endgroup}
+
+% This definition is run if you use @defvarx
+% anywhere other than immediately after a @defvar or @defvarx.
+
+\def\defvrx #1 {\errmessage{@defvrx in invalid context}}
+\def\defvarx #1 {\errmessage{@defvarx in invalid context}}
+\def\defoptx #1 {\errmessage{@defoptx in invalid context}}
+\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}}
+\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}}
+
+% Now define @deftp
+% Args are printed in bold, a slight difference from @defvar.
+
+\def\deftpargs #1{\bf \defvarargs{#1}}
+
+% @deftp Class window height width ...
+
+\def\deftp{\defmethparsebody\Edeftp\deftpx\deftpheader}
+
+\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}%
+\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup}
+
+% This definition is run if you use @deftpx, etc
+% anywhere other than immediately after a @deftp, etc.
+
+\def\deftpx #1 {\errmessage{@deftpx in invalid context}}
+
+\message{cross reference,}
+% Define cross-reference macros
+\newwrite \auxfile
+
+\newif\ifhavexrefs  % True if xref values are known.
+\newif\ifwarnedxrefs  % True if we warned once that they aren't known.
+
+% \setref{foo} defines a cross-reference point named foo.
+
+\def\setref#1{%
+%\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ysectionnumberandtype}}
+
+\def\unnumbsetref#1{%
+%\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Ynothing}}
+
+\def\appendixsetref#1{%
+%\dosetq{#1-title}{Ytitle}%
+\dosetq{#1-pg}{Ypagenumber}%
+\dosetq{#1-snt}{Yappendixletterandtype}}
+
+% \xref, \pxref, and \ref generate cross-references to specified points.
+% For \xrefX, #1 is the node name, #2 the name of the Info
+% cross-reference, #3 the printed node name, #4 the name of the Info
+% file, #5 the name of the printed manual.  All but the node name can be
+% omitted.
+% 
+\def\pxref#1{see \xrefX[#1,,,,,,,]}
+\def\xref#1{See \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup%
+\def\printedmanual{\ignorespaces #5}%
+\def\printednodename{\ignorespaces #3}%
+%
+\setbox1=\hbox{\printedmanual}%
+\setbox0=\hbox{\printednodename}%
+\ifdim \wd0=0pt%
+\def\printednodename{\ignorespaces #1}%
+%%% Uncommment the following line to make the actual chapter or section title
+%%% appear inside the square brackets.
+%\def\printednodename{#1-title}%
+\fi%
+%
+%
+% If we use \unhbox0 and \unhbox1 to print the node names, TeX does
+% not insert empty discretionaries after hyphens, which means that it
+% will not find a line break at a hyphen in a node names.  Since some
+% manuals are best written with fairly long node names, containing
+% hyphens, this is a loss.  Therefore, we simply give the text of
+% the node name again, so it is as if TeX is seeing it for the first
+% time.
+\ifdim \wd1>0pt
+section ``\printednodename'' in \cite{\printedmanual}%
+\else%
+\turnoffactive%
+\refx{#1-snt}{} [\printednodename], page\tie\refx{#1-pg}{}%
+\fi
+\endgroup}
+
+% \dosetq is the interface for calls from other macros
+
+% Use \turnoffactive so that punctuation chars such as underscore
+% work in node names.
+\def\dosetq #1#2{{\let\folio=0 \turnoffactive%
+\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}%
+\next}}
+
+% \internalsetq {foo}{page} expands into
+% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...}
+% When the aux file is read, ' is the escape character
+
+\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}}
+
+% Things to be expanded by \internalsetq
+
+\def\Ypagenumber{\folio}
+
+\def\Ytitle{\thischapter}
+
+\def\Ynothing{}
+
+\def\Ysectionnumberandtype{%
+\ifnum\secno=0 Chapter\xreftie\the\chapno %
+\else \ifnum \subsecno=0 Section\xreftie\the\chapno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+Section\xreftie\the\chapno.\the\secno.\the\subsecno %
+\else %
+Section\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\def\Yappendixletterandtype{%
+\ifnum\secno=0 Appendix\xreftie'char\the\appendixno{}%
+\else \ifnum \subsecno=0 Section\xreftie'char\the\appendixno.\the\secno %
+\else \ifnum \subsubsecno=0 %
+Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno %
+\else %
+Section\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno %
+\fi \fi \fi }
+
+\gdef\xreftie{'tie}
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+% 
+\ifx\inputlineno\thisisundefined
+  \let\linenumber = \empty % Non-3.0.
+\else
+  \def\linenumber{\the\inputlineno:\space}
+\fi
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+
+\def\refx#1#2{%
+  \expandafter\ifx\csname X#1\endcsname\relax
+    % If not defined, say something at least.
+    $\langle$un\-de\-fined$\rangle$%
+    \ifhavexrefs
+      \message{\linenumber Undefined cross reference `#1'.}%
+    \else
+      \ifwarnedxrefs\else
+        \global\warnedxrefstrue
+        \message{Cross reference values unknown; you must run TeX again.}%
+      \fi
+    \fi
+  \else
+    % It's defined, so just use it.
+    \csname X#1\endcsname
+  \fi
+  #2% Output the suffix in any case.
+}
+
+% Read the last existing aux file, if any.  No error if none exists.
+
+% This is the macro invoked by entries in the aux file.
+\def\xrdef #1#2{
+{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}}
+
+\def\readauxfile{%
+\begingroup
+\catcode `\^^@=\other
+\catcode `\\ 1=\other
+\catcode `\\ 2=\other
+\catcode `\^^C=\other
+\catcode `\^^D=\other
+\catcode `\^^E=\other
+\catcode `\^^F=\other
+\catcode `\^^G=\other
+\catcode `\^^H=\other
+\catcode `\\v=\other
+\catcode `\^^L=\other
+\catcode `\\ e=\other
+\catcode `\\ f=\other
+\catcode `\\10=\other
+\catcode `\\11=\other
+\catcode `\\12=\other
+\catcode `\\13=\other
+\catcode `\\14=\other
+\catcode `\\15=\other
+\catcode `\\16=\other
+\catcode `\\17=\other
+\catcode `\\18=\other
+\catcode `\\19=\other
+\catcode `\\1a=\other
+\catcode `\^^[=\other
+\catcode `\^^\=\other
+\catcode `\^^]=\other
+\catcode `\^^^=\other
+\catcode `\^^_=\other
+\catcode `\@=\other
+\catcode `\^=\other
+\catcode `\~=\other
+\catcode `\[=\other
+\catcode `\]=\other
+\catcode`\"=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode `\$=\other
+\catcode `\#=\other
+\catcode `\&=\other
+% the aux file uses ' as the escape.
+% Turn off \ as an escape so we do not lose on
+% entries which were dumped with control sequences in their names.
+% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^
+% Reference to such entries still does not work the way one would wish,
+% but at least they do not bomb out when the aux file is read in.
+\catcode `\{=1 \catcode `\}=2
+\catcode `\%=\other
+\catcode `\'=0
+\catcode `\\=\other
+\openin 1 \jobname.aux
+\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue
+\fi
+% Open the new aux file.  Tex will close it automatically at exit.
+\openout \auxfile=\jobname.aux
+\endgroup}
+
+
+% Footnotes.
+
+\newcount \footnoteno
+
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+\let\ptexfootnote=\footnote
+
+{\catcode `\@=11
+\long\gdef\footnote #1{\global\advance \footnoteno by \@ne
+\removelastskip
+\edef\thisfootno{$^{\the\footnoteno}$}%
+\let\@sf\empty
+\ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi
+\thisfootno\@sf \footnotezzz{#1}}
+% \parsearg\footnotezzz}
+
+\long\gdef\footnotezzz #1{\insert\footins{
+\interlinepenalty\interfootnotelinepenalty
+\splittopskip\ht\strutbox % top baseline for broken footnotes
+\splitmaxdepth\dp\strutbox \floatingpenalty\@MM
+\leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip
+\footstrut\parindent=\defaultparindent\hang\textindent{\thisfootno}#1\strut}}
+
+}%end \catcode `\@=11
+
+% End of control word definitions.
+
+\message{and turning on texinfo input format.}
+
+\def\openindices{%
+   \newindex{cp}%
+   \newcodeindex{fn}%
+   \newcodeindex{vr}%
+   \newcodeindex{tp}%
+   \newcodeindex{ky}%
+   \newcodeindex{pg}%
+}
+
+% Set some numeric style parameters, for 8.5 x 11 format.
+
+%\hsize = 6.5in
+\newdimen\defaultparindent \defaultparindent = 15pt
+\parindent = \defaultparindent
+\parskip 18pt plus 1pt
+\baselineskip 15pt
+\advance\topskip by 1.2cm
+
+% Prevent underfull vbox error messages.
+\vbadness=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything.  We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize.  This makes it come to about 9pt for the 8.5x11 format.
+% 
+\ifx\emergencystretch\thisisundefined \else
+  \emergencystretch = \hsize
+  \divide\emergencystretch by 45
+\fi
+
+% Use @smallbook to reset parameters for 7x9.5 format
+\def\smallbook{
+\global\lispnarrowing = 0.3in
+\global\baselineskip 12pt
+\global\parskip 3pt plus 1pt
+\global\hsize = 5in
+\global\doublecolumnhsize=2.4in \global\doublecolumnvsize=15.0in
+\global\vsize=7.5in
+\global\tolerance=700
+\global\hfuzz=1pt
+
+\global\pagewidth=\hsize
+\global\pageheight=\vsize
+
+\global\let\smalllisp=\smalllispx
+\global\let\smallexample=\smalllispx
+\global\def\Esmallexample{\Esmalllisp}
+}
+
+%% For a final copy, take out the rectangles
+%% that mark overfull boxes (in case you have decided
+%% that the text looks ok even though it passes the margin).
+\def\finalout{\hfuzz=\maxdimen}
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other
+\catcode`\~=\other
+\catcode`\^=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode`\+=\other
+\def\normaldoublequote{"}
+\def\normaltilde{~}
+\def\normalcaret{^}
+\def\normalunderscore{_}
+\def\normalverticalbar{|}
+\def\normalless{<}
+\def\normalgreater{>}
+\def\normalplus{+}
+
+% This macro is used to make a character print one way in ttfont
+% where it can probably just be output, and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise.  Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+% 
+\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary).
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt \char '042}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt \char '176}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+% Subroutine for the previous macro.
+\def\_{\lvvmode \kern.06em \vbox{\hrule width.3em height.1ex}}
+
+% \lvvmode is equivalent in function to \leavevmode.
+% Using \leavevmode runs into trouble when written out to
+% an index file due to the expansion of \leavevmode into ``\unhbox
+% \voidb@x'' ---which looks to TeX like ``\unhbox \voidb\x'' due to our
+% magic tricks with @.
+\def\lvvmode{\vbox to 0pt{}}
+
+\catcode`\|=\active
+\def|{{\tt \char '174}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+%\catcode 27=\active
+%\def^^[{$\diamondsuit$}
+
+% Used sometimes to turn off (effectively) the active characters
+% even after parsing them.
+\def\turnoffactive{\let"=\normaldoublequote
+\let~=\normaltilde
+\let^=\normalcaret
+\let_=\normalunderscore
+\let|=\normalverticalbar
+\let<=\normalless
+\let>=\normalgreater
+\let+=\normalplus}
+
+% Set up an active definition for =, but don't enable it most of the time.
+{\catcode`\==\active
+\global\def={{\tt \char 61}}}
+
+\catcode`\@=0
+
+% \rawbackslashxx output one backslash character in current font
+\global\chardef\rawbackslashxx=`\\
+%{\catcode`\\=\other
+%@gdef@rawbackslashxx{\}}
+
+% \rawbackslash redefines \ as input to do \rawbackslashxx.
+{\catcode`\\=\active
+@gdef@rawbackslash{@let\=@rawbackslashxx }}
+
+% \normalbackslash outputs one backslash in fixed width font.
+\def\normalbackslash{{\tt\rawbackslashxx}}
+
+% Say @foo, not \foo, in error messages.
+\escapechar=`\@
+
+% \catcode 17=0   % Define control-q
+\catcode`\\=\active
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing 
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\{ in the file would cause an error. This macro tries to fix 
+% that, assuming it is called before the first `\' could plausibly occur.
+% 
+@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi}
+
+%% These look ok in all fonts, so just make them not special.  The @rm below
+%% makes sure that the current font starts out as the newly loaded cmr10
+@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other
+
+@textfonts
+@rm
+
+@c Local variables:
+@c page-delimiter: "^\\\\message"
+@c End:
diff --git a/readline/examples/Makefile b/readline/examples/Makefile
new file mode 100644 (file)
index 0000000..3d1fc52
--- /dev/null
@@ -0,0 +1,12 @@
+# This is the Makefile for the examples subdirectory of readline. -*- text -*-
+#
+
+EXECUTABLES = fileman
+CFLAGS  = -g -I../..
+LDFLAGS = -g -L..
+
+fileman: fileman.o
+       $(CC) $(LDFLAGS) -o fileman fileman.o -lreadline -ltermcap
+
+fileman.o: fileman.c
+  
diff --git a/readline/examples/fileman.c b/readline/examples/fileman.c
new file mode 100644 (file)
index 0000000..d1e72c5
--- /dev/null
@@ -0,0 +1,395 @@
+/* fileman.c -- A tiny application which demonstrates how to use the
+   GNU Readline library.  This application interactively allows users
+   to manipulate files and their modes. */
+
+#include <stdio.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+
+/* The names of functions that actually do the manipulation. */
+int com_list (), com_view (), com_rename (), com_stat (), com_pwd ();
+int com_delete (), com_help (), com_cd (), com_quit ();
+
+/* A structure which contains information on the commands this program
+   can understand. */
+
+typedef struct {
+  char *name;                  /* User printable name of the function. */
+  Function *func;              /* Function to call to do the job. */
+  char *doc;                   /* Documentation for this function.  */
+} COMMAND;
+
+COMMAND commands[] = {
+  { "cd", com_cd, "Change to directory DIR" },
+  { "delete", com_delete, "Delete FILE" },
+  { "help", com_help, "Display this text" },
+  { "?", com_help, "Synonym for `help'" },
+  { "list", com_list, "List files in DIR" },
+  { "ls", com_list, "Synonym for `list'" },
+  { "pwd", com_pwd, "Print the current working directory" },
+  { "quit", com_quit, "Quit using Fileman" },
+  { "rename", com_rename, "Rename FILE to NEWNAME" },
+  { "stat", com_stat, "Print out statistics on FILE" },
+  { "view", com_view, "View the contents of FILE" },
+  { (char *)NULL, (Function *)NULL, (char *)NULL }
+};
+
+/* The name of this program, as taken from argv[0]. */
+char *progname;
+
+/* When non-zero, this global means the user is done using this program. */
+int done = 0;
+
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  progname = argv[0];
+
+  initialize_readline ();      /* Bind our completer. */
+
+  /* Loop reading and executing lines until the user quits. */
+  while (!done)
+    {
+      char *line;
+
+      line = readline ("FileMan: ");
+
+      if (!line)
+       {
+         done = 1;             /* Encountered EOF at top level. */
+       }
+      else
+       {
+         /* Remove leading and trailing whitespace from the line.
+            Then, if there is anything left, add it to the history list
+            and execute it. */
+         stripwhite (line);
+
+         if (*line)
+           {
+             add_history (line);
+             execute_line (line);
+           }
+       }
+
+      if (line)
+       free (line);
+    }
+  exit (0);
+}
+
+/* Execute a command line. */
+execute_line (line)
+     char *line;
+{
+  register int i;
+  COMMAND *find_command (), *command;
+  char *word;
+
+  /* Isolate the command word. */
+  i = 0;
+  while (line[i] && !whitespace (line[i]))
+    i++;
+
+  word = line;
+
+  if (line[i])
+    line[i++] = '\0';
+
+  command = find_command (word);
+
+  if (!command)
+    {
+      fprintf (stderr, "%s: No such command for FileMan.\n", word);
+      return;
+    }
+
+  /* Get argument to command, if any. */
+  while (whitespace (line[i]))
+    i++;
+
+  word = line + i;
+
+  /* Call the function. */
+  (*(command->func)) (word);
+}
+
+/* Look up NAME as the name of a command, and return a pointer to that
+   command.  Return a NULL pointer if NAME isn't a command name. */
+COMMAND *
+find_command (name)
+     char *name;
+{
+  register int i;
+
+  for (i = 0; commands[i].name; i++)
+    if (strcmp (name, commands[i].name) == 0)
+      return (&commands[i]);
+
+  return ((COMMAND *)NULL);
+}
+
+/* Strip whitespace from the start and end of STRING. */
+stripwhite (string)
+     char *string;
+{
+  register int i = 0;
+
+  while (whitespace (string[i]))
+    i++;
+
+  if (i)
+    strcpy (string, string + i);
+
+  i = strlen (string) - 1;
+
+  while (i > 0 && whitespace (string[i]))
+    i--;
+
+  string[++i] = '\0';
+}
+
+/* **************************************************************** */
+/*                                                                  */
+/*                  Interface to Readline Completion                */
+/*                                                                  */
+/* **************************************************************** */
+
+/* Tell the GNU Readline library how to complete.  We want to try to complete
+   on command names if this is the first word in the line, or on filenames
+   if not. */
+initialize_readline ()
+{
+  char **fileman_completion ();
+
+  /* Allow conditional parsing of the ~/.inputrc file. */
+  rl_readline_name = "FileMan";
+
+  /* Tell the completer that we want a crack first. */
+  rl_attempted_completion_function = (Function *)fileman_completion;
+}
+
+/* Attempt to complete on the contents of TEXT.  START and END show the
+   region of TEXT that contains the word to complete.  We can use the
+   entire line in case we want to do some simple parsing.  Return the
+   array of matches, or NULL if there aren't any. */
+char **
+fileman_completion (text, start, end)
+     char *text;
+     int start, end;
+{
+  char **matches;
+  char *command_generator ();
+
+  matches = (char **)NULL;
+
+  /* If this word is at the start of the line, then it is a command
+     to complete.  Otherwise it is the name of a file in the current
+     directory. */
+  if (start == 0)
+    matches = completion_matches (text, command_generator);
+
+  return (matches);
+}
+
+/* Generator function for command completion.  STATE lets us know whether
+   to start from scratch; without any state (i.e. STATE == 0), then we
+   start at the top of the list. */
+char *
+command_generator (text, state)
+     char *text;
+     int state;
+{
+  static int list_index, len;
+  char *name;
+
+  /* If this is a new word to complete, initialize now.  This includes
+     saving the length of TEXT for efficiency, and initializing the index
+     variable to 0. */
+  if (!state)
+    {
+      list_index = 0;
+      len = strlen (text);
+    }
+
+  /* Return the next name which partially matches from the command list. */
+  while (name = commands[list_index].name)
+    {
+      list_index++;
+
+      if (strncmp (name, text, len) == 0)
+       return (name);
+    }
+
+  /* If no names matched, then return NULL. */
+  return ((char *)NULL);
+}
+
+/* **************************************************************** */
+/*                                                                  */
+/*                       FileMan Commands                           */
+/*                                                                  */
+/* **************************************************************** */
+
+/* String to pass to system ().  This is for the LIST, VIEW and RENAME
+   commands. */
+static char syscom[1024];
+
+/* List the file(s) named in arg. */
+com_list (arg)
+     char *arg;
+{
+  if (!arg)
+    arg = "*";
+
+  sprintf (syscom, "ls -FClg %s", arg);
+  system (syscom);
+}
+
+com_view (arg)
+     char *arg;
+{
+  if (!valid_argument ("view", arg))
+    return;
+
+  sprintf (syscom, "cat %s | more", arg);
+  system (syscom);
+}
+
+com_rename (arg)
+     char *arg;
+{
+  too_dangerous ("rename");
+}
+
+com_stat (arg)
+     char *arg;
+{
+  struct stat finfo;
+
+  if (!valid_argument ("stat", arg))
+    return;
+
+  if (stat (arg, &finfo) == -1)
+    {
+      perror (arg);
+      return;
+    }
+
+  printf ("Statistics for `%s':\n", arg);
+
+  printf ("%s has %d link%s, and is %d bytes in length.\n", arg,
+         finfo.st_nlink, (finfo.st_nlink == 1) ? "" : "s",  finfo.st_size);
+  printf ("      Created on: %s", ctime (&finfo.st_ctime));
+  printf ("  Last access at: %s", ctime (&finfo.st_atime));
+  printf ("Last modified at: %s", ctime (&finfo.st_mtime));
+}
+
+com_delete (arg)
+     char *arg;
+{
+  too_dangerous ("delete");
+}
+
+/* Print out help for ARG, or for all of the commands if ARG is
+   not present. */
+com_help (arg)
+     char *arg;
+{
+  register int i;
+  int printed = 0;
+
+  for (i = 0; commands[i].name; i++)
+    {
+      if (!*arg || (strcmp (arg, commands[i].name) == 0))
+       {
+         printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
+         printed++;
+       }
+    }
+
+  if (!printed)
+    {
+      printf ("No commands match `%s'.  Possibilties are:\n", arg);
+
+      for (i = 0; commands[i].name; i++)
+       {
+         /* Print in six columns. */
+         if (printed == 6)
+           {
+             printed = 0;
+             printf ("\n");
+           }
+
+         printf ("%s\t", commands[i].name);
+         printed++;
+       }
+
+      if (printed)
+       printf ("\n");
+    }
+}
+
+/* Change to the directory ARG. */
+com_cd (arg)
+     char *arg;
+{
+  if (chdir (arg) == -1)
+    perror (arg);
+
+  com_pwd ("");
+}
+
+/* Print out the current working directory. */
+com_pwd (ignore)
+     char *ignore;
+{
+  char dir[1024];
+
+  (void) getwd (dir);
+
+  printf ("Current directory is %s\n", dir);
+}
+
+/* The user wishes to quit using this program.  Just set DONE non-zero. */
+com_quit (arg)
+     char *arg;
+{
+  done = 1;
+}
+
+/* Function which tells you that you can't do this. */
+too_dangerous (caller)
+     char *caller;
+{
+  fprintf (stderr,
+          "%s: Too dangerous for me to distribute.  Write it yourself.\n",
+          caller);
+}
+
+/* Return non-zero if ARG is a valid argument for CALLER, else print
+   an error message and return zero. */
+int
+valid_argument (caller, arg)
+     char *caller, *arg;
+{
+  if (!arg || !*arg)
+    {
+      fprintf (stderr, "%s: Argument required.\n", caller);
+      return (0);
+    }
+
+  return (1);
+}
+
+\f
+/*
+ * Local variables:
+ * compile-command: "cc -g -I../.. -L.. -o fileman fileman.c -lreadline -ltermcap"
+ * end:
+ */