573 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			573 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
@ignore
 | 
						|
This file documents the user interface to the GNU History library.
 | 
						|
 | 
						|
Copyright (C) 1988-2007 Free Software Foundation, Inc.
 | 
						|
Authored by Brian Fox and Chet Ramey.
 | 
						|
 | 
						|
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 programs that you write
 | 
						|
with the @sc{gnu} History Library.
 | 
						|
It should be considered a technical guide.
 | 
						|
For information on the interactive use of @sc{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 @sc{gnu}
 | 
						|
History library is able to keep track of those lines, associate arbitrary
 | 
						|
data with each line, and utilize information from previous lines in
 | 
						|
composing new ones. 
 | 
						|
 | 
						|
The programmer using the History library has available functions
 | 
						|
for remembering lines on a history list, associating arbitrary data
 | 
						|
with a line, removing lines from the list, searching through the list
 | 
						|
for a line containing an arbitrary text string, and referencing any line
 | 
						|
in the list directly.  In addition, a history @dfn{expansion} function
 | 
						|
is available which provides for a consistent user interface across
 | 
						|
different programs.
 | 
						|
 | 
						|
The user using programs written with the History library has the
 | 
						|
benefit 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 provided 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 command line editing.
 | 
						|
 | 
						|
Before declaring any functions using any functionality the History
 | 
						|
library provides in other code, an application writer should include
 | 
						|
the file @code{<readline/history.h>} in any file that uses the
 | 
						|
History library's features.  It supplies extern declarations for all
 | 
						|
of the library's public functions and variables, and declares all of
 | 
						|
the public data structures.
 | 
						|
 | 
						|
@node History Storage
 | 
						|
@section History Storage
 | 
						|
 | 
						|
The history list is an array of history entries.  A history entry is
 | 
						|
declared as follows:
 | 
						|
 | 
						|
@example
 | 
						|
typedef void *histdata_t;
 | 
						|
 | 
						|
typedef struct _hist_entry @{
 | 
						|
  char *line;
 | 
						|
  char *timestamp;
 | 
						|
  histdata_t data;
 | 
						|
@} HIST_ENTRY;
 | 
						|
@end example
 | 
						|
 | 
						|
The history list itself might therefore be declared as
 | 
						|
 | 
						|
@example
 | 
						|
HIST_ENTRY **the_history_list;
 | 
						|
@end example
 | 
						|
 | 
						|
The state of the History library is encapsulated into a single structure:
 | 
						|
 | 
						|
@example
 | 
						|
/*
 | 
						|
 * A structure used to pass around the current state of the history.
 | 
						|
 */
 | 
						|
typedef struct _hist_state @{
 | 
						|
  HIST_ENTRY **entries; /* Pointer to the entries themselves. */
 | 
						|
  int offset;           /* The location pointer within this array. */
 | 
						|
  int length;           /* Number of elements within this array. */
 | 
						|
  int size;             /* Number of slots allocated to this array. */
 | 
						|
  int flags;
 | 
						|
@} HISTORY_STATE;
 | 
						|
@end example
 | 
						|
 | 
						|
If the flags member includes @code{HS_STIFLED}, the history has been
 | 
						|
stifled.
 | 
						|
 | 
						|
@node History Functions
 | 
						|
@section History Functions
 | 
						|
 | 
						|
This section describes the calling sequence for the various functions
 | 
						|
exported by the @sc{gnu} History library.
 | 
						|
 | 
						|
@menu
 | 
						|
* Initializing History and State Management::	Functions to call when you
 | 
						|
						want to use history in a
 | 
						|
						program.
 | 
						|
* History List Management::		Functions used to manage the list
 | 
						|
					of history entries.
 | 
						|
* Information About the History List::	Functions returning information about
 | 
						|
					the history list.
 | 
						|
* Moving Around the History List::	Functions used to change the position
 | 
						|
					in the history list.
 | 
						|
* Searching the History List::		Functions to search the history list
 | 
						|
					for entries containing a string.
 | 
						|
* Managing the History File::		Functions that read and write a file
 | 
						|
					containing the history list.
 | 
						|
* History Expansion::			Functions to perform csh-like history
 | 
						|
					expansion.
 | 
						|
@end menu
 | 
						|
 | 
						|
@node Initializing History and State Management
 | 
						|
@subsection Initializing History and State Management
 | 
						|
 | 
						|
This section describes functions used to initialize and manage
 | 
						|
the state of the History library when you want to use the history
 | 
						|
functions in your program.
 | 
						|
 | 
						|
@deftypefun void using_history (void)
 | 
						|
Begin a session in which the history functions might be used.  This
 | 
						|
initializes the interactive variables.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun {HISTORY_STATE *} history_get_history_state (void)
 | 
						|
Return a structure describing the current state of the input history.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun void history_set_history_state (HISTORY_STATE *state)
 | 
						|
Set the state of the history list according to @var{state}.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@node History List Management
 | 
						|
@subsection History List Management
 | 
						|
 | 
						|
These functions manage individual entries on the history list, or set
 | 
						|
parameters managing the list itself.
 | 
						|
 | 
						|
@deftypefun void add_history (const char *string)
 | 
						|
Place @var{string} at the end of the history list.  The associated data
 | 
						|
field (if any) is set to @code{NULL}.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun void add_history_time (const char *string)
 | 
						|
Change the time stamp associated with the most recent history entry to
 | 
						|
@var{string}.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun {HIST_ENTRY *} remove_history (int which)
 | 
						|
Remove history entry at offset @var{which} from the history.  The
 | 
						|
removed element is returned so you can free the line, data,
 | 
						|
and containing structure.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun {histdata_t} free_history_entry (HIST_ENTRY *histent)
 | 
						|
Free the history entry @var{histent} and any history library private
 | 
						|
data associated with it.  Returns the application-specific data
 | 
						|
so the caller can dispose of it.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun {HIST_ENTRY *} replace_history_entry (int which, const char *line, histdata_t data)
 | 
						|
Make the history entry at offset @var{which} have @var{line} and @var{data}.
 | 
						|
This returns the old entry so the caller can dispose of any
 | 
						|
application-specific data.  In the case
 | 
						|
of an invalid @var{which}, a @code{NULL} pointer is returned.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun void clear_history (void)
 | 
						|
Clear the history list by deleting all the entries.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun void stifle_history (int max)
 | 
						|
Stifle the history list, remembering only the last @var{max} entries.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun int unstifle_history (void)
 | 
						|
Stop stifling the history.  This returns the previously-set
 | 
						|
maximum number of history entries (as set by @code{stifle_history()}).
 | 
						|
The value is positive if the history was
 | 
						|
stifled, negative if it wasn't.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun int history_is_stifled (void)
 | 
						|
Returns non-zero if the history is stifled, zero if it is not.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@node Information About the History List
 | 
						|
@subsection Information About the History List
 | 
						|
 | 
						|
These functions return information about the entire history list or
 | 
						|
individual list entries.
 | 
						|
 | 
						|
@deftypefun {HIST_ENTRY **} history_list (void)
 | 
						|
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 deftypefun
 | 
						|
 | 
						|
@deftypefun int where_history (void)
 | 
						|
Returns the offset of the current history element.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun {HIST_ENTRY *} current_history (void)
 | 
						|
Return the history entry at the current position, as determined by
 | 
						|
@code{where_history()}.  If there is no entry there, return a @code{NULL}
 | 
						|
pointer.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun {HIST_ENTRY *} history_get (int offset)
 | 
						|
Return the history entry at position @var{offset}, starting from
 | 
						|
@code{history_base} (@pxref{History Variables}).
 | 
						|
If there is no entry there, or if @var{offset}
 | 
						|
is greater than the history length, return a @code{NULL} pointer.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun time_t history_get_time (HIST_ENTRY *entry)
 | 
						|
Return the time stamp associated with the history entry @var{entry}.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun int history_total_bytes (void)
 | 
						|
Return the number of bytes that the primary history entries are using.
 | 
						|
This function returns the sum of the lengths of all the lines in the
 | 
						|
history.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@node Moving Around the History List
 | 
						|
@subsection Moving Around the History List
 | 
						|
 | 
						|
These functions allow the current index into the history list to be
 | 
						|
set or changed.
 | 
						|
 | 
						|
@deftypefun int history_set_pos (int pos)
 | 
						|
Set the current history offset to @var{pos}, an absolute index
 | 
						|
into the list.
 | 
						|
Returns 1 on success, 0 if @var{pos} is less than zero or greater
 | 
						|
than the number of history entries.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun {HIST_ENTRY *} previous_history (void)
 | 
						|
Back up the current 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 deftypefun
 | 
						|
 | 
						|
@deftypefun {HIST_ENTRY *} next_history (void)
 | 
						|
Move the current 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 deftypefun
 | 
						|
 | 
						|
@node Searching the History List
 | 
						|
@subsection Searching the History List
 | 
						|
@cindex History Searching
 | 
						|
 | 
						|
These functions allow searching of the history list for entries containing
 | 
						|
a specific string.  Searching may be performed both forward and backward
 | 
						|
from the current history position.  The search may be @dfn{anchored},
 | 
						|
meaning that the string must match at the beginning of the history entry.
 | 
						|
@cindex anchored search
 | 
						|
 | 
						|
@deftypefun int history_search (const char *string, int direction)
 | 
						|
Search the history for @var{string}, starting at the current history offset.
 | 
						|
If @var{direction} is less than 0, then the search is through
 | 
						|
previous entries, otherwise through subsequent entries.
 | 
						|
If @var{string} is found, then
 | 
						|
the current history index is set to that history entry, and the value
 | 
						|
returned is the offset in the line of the entry where
 | 
						|
@var{string} was found.  Otherwise, nothing is changed, and a -1 is
 | 
						|
returned.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun int history_search_prefix (const char *string, int direction)
 | 
						|
Search the history for @var{string}, starting at the current history
 | 
						|
offset.  The search is anchored: matching lines must begin with
 | 
						|
@var{string}.  If @var{direction} is less than 0, then the search is
 | 
						|
through previous entries, otherwise through subsequent entries.
 | 
						|
If @var{string} is found, then the
 | 
						|
current history index is set to that entry, and the return value is 0. 
 | 
						|
Otherwise, nothing is changed, and a -1 is returned. 
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun int history_search_pos (const char *string, int direction, int pos)
 | 
						|
Search for @var{string} in the history list, starting at @var{pos}, an
 | 
						|
absolute index into the list.  If @var{direction} is negative, the search
 | 
						|
proceeds backward from @var{pos}, otherwise forward.  Returns the absolute
 | 
						|
index of the history element where @var{string} was found, or -1 otherwise.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@node Managing the History File
 | 
						|
@subsection Managing the History File
 | 
						|
 | 
						|
The History library can read the history from and write it to a file.
 | 
						|
This section documents the functions for managing a history file.
 | 
						|
 | 
						|
@deftypefun int read_history (const 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 @code{errno} if not.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun int read_history_range (const char *filename, int from, int to)
 | 
						|
Read a range of lines from @var{filename}, adding them to the history list.
 | 
						|
Start reading at line @var{from} and end at @var{to}.
 | 
						|
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 deftypefun
 | 
						|
 | 
						|
@deftypefun int write_history (const char *filename)
 | 
						|
Write the current history to @var{filename}, overwriting @var{filename}
 | 
						|
if necessary.
 | 
						|
If @var{filename} is @code{NULL}, then write the history list to
 | 
						|
@file{~/.history}.
 | 
						|
Returns 0 on success, or @code{errno} on a read or write error.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun int append_history (int nelements, const char *filename)
 | 
						|
Append the last @var{nelements} of the history list to @var{filename}.
 | 
						|
If @var{filename} is @code{NULL}, then append to @file{~/.history}.
 | 
						|
Returns 0 on success, or @code{errno} on a read or write error.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun int history_truncate_file (const char *filename, int nlines)
 | 
						|
Truncate the history file @var{filename}, leaving only the last
 | 
						|
@var{nlines} lines.
 | 
						|
If @var{filename} is @code{NULL}, then @file{~/.history} is truncated.
 | 
						|
Returns 0 on success, or @code{errno} on failure.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@node History Expansion
 | 
						|
@subsection History Expansion
 | 
						|
 | 
						|
These functions implement history expansion.
 | 
						|
 | 
						|
@deftypefun int history_expand (char *string, char **output)
 | 
						|
Expand @var{string}, placing the result into @var{output}, a pointer
 | 
						|
to a string (@pxref{History Interaction}).  Returns:
 | 
						|
@table @code
 | 
						|
@item 0
 | 
						|
If no expansions took place (or, if the only change in
 | 
						|
the text was the removal of escape characters preceding the history expansion
 | 
						|
character);
 | 
						|
@item 1
 | 
						|
if expansions did take place;
 | 
						|
@item -1
 | 
						|
if there was an error in expansion;
 | 
						|
@item 2
 | 
						|
if the returned line should be displayed, but not executed,
 | 
						|
as with the @code{:p} modifier (@pxref{Modifiers}).
 | 
						|
@end table
 | 
						|
 | 
						|
If an error ocurred in expansion, then @var{output} contains a descriptive
 | 
						|
error message.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun {char *} get_history_event (const char *string, int *cindex, int qchar)
 | 
						|
Returns the text of the history event beginning at @var{string} +
 | 
						|
@var{*cindex}.  @var{*cindex} is modified to point to after the event
 | 
						|
specifier.  At function entry, @var{cindex} points to the index into
 | 
						|
@var{string} where the history event specification begins.  @var{qchar}
 | 
						|
is a character that is allowed to end the event specification in addition
 | 
						|
to the ``normal'' terminating characters.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun {char **} history_tokenize (const char *string)
 | 
						|
Return an array of tokens parsed out of @var{string}, much as the
 | 
						|
shell might.  The tokens are split on the characters in the
 | 
						|
@var{history_word_delimiters} variable,
 | 
						|
and shell quoting conventions are obeyed.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@deftypefun {char *} history_arg_extract (int first, int last, const char *string)
 | 
						|
Extract a string segment consisting of the @var{first} through @var{last}
 | 
						|
arguments present in @var{string}.  Arguments are split using
 | 
						|
@code{history_tokenize}.
 | 
						|
@end deftypefun
 | 
						|
 | 
						|
@node History Variables
 | 
						|
@section History Variables
 | 
						|
 | 
						|
This section describes the externally-visible variables exported by
 | 
						|
the @sc{gnu} History Library.
 | 
						|
 | 
						|
@deftypevar int history_base
 | 
						|
The logical offset of the first entry in the history list.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@deftypevar int history_length
 | 
						|
The number of entries currently stored in the history list.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@deftypevar int history_max_entries
 | 
						|
The maximum number of history entries.  This must be changed using
 | 
						|
@code{stifle_history()}.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@deftypevar int history_write_timestamps
 | 
						|
If non-zero, timestamps are written to the history file, so they can be
 | 
						|
preserved between sessions.  The default value is 0, meaning that
 | 
						|
timestamps are not saved.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@deftypevar char history_expansion_char
 | 
						|
The character that introduces a history event.  The default is @samp{!}.
 | 
						|
Setting this to 0 inhibits history expansion.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@deftypevar char history_subst_char
 | 
						|
The character that invokes word substitution if found at the start of
 | 
						|
a line.  The default is @samp{^}.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@deftypevar char history_comment_char
 | 
						|
During tokenization, if this character is seen as the first character
 | 
						|
of a word, then it and all subsequent characters up to a newline are
 | 
						|
ignored, suppressing history expansion for the remainder of the line.
 | 
						|
This is disabled by default.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@deftypevar {char *} history_word_delimiters
 | 
						|
The characters that separate tokens for @code{history_tokenize()}.
 | 
						|
The default value is @code{" \t\n()<>;&|"}.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@deftypevar {char *} history_search_delimiter_chars
 | 
						|
The list of additional characters which can delimit a history search
 | 
						|
string, in addition to space, TAB, @samp{:} and @samp{?} in the case of
 | 
						|
a substring search.  The default is empty.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@deftypevar {char *} history_no_expand_chars
 | 
						|
The list of characters which inhibit history expansion if found immediately
 | 
						|
following @var{history_expansion_char}.  The default is space, tab, newline,
 | 
						|
carriage return, and @samp{=}.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@deftypevar int history_quotes_inhibit_expansion
 | 
						|
If non-zero, single-quoted words are not scanned for the history expansion
 | 
						|
character.  The default value is 0.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@deftypevar {rl_linebuf_func_t *} history_inhibit_expansion_function
 | 
						|
This should be set to the address of a function that takes two arguments:
 | 
						|
a @code{char *} (@var{string})
 | 
						|
and an @code{int} index into that string (@var{i}).
 | 
						|
It should return a non-zero value if the history expansion starting at
 | 
						|
@var{string[i]} should not be performed; zero if the expansion should
 | 
						|
be done.
 | 
						|
It is intended for use by applications like Bash that use the history
 | 
						|
expansion character for additional purposes.
 | 
						|
By default, this variable is set to @code{NULL}.
 | 
						|
@end deftypevar
 | 
						|
 | 
						|
@node History Programming Example
 | 
						|
@section History Programming Example
 | 
						|
 | 
						|
The following program demonstrates simple use of the @sc{gnu} History Library.
 | 
						|
 | 
						|
@smallexample
 | 
						|
#include <stdio.h>
 | 
						|
#include <readline/history.h>
 | 
						|
 | 
						|
main (argc, argv)
 | 
						|
     int argc;
 | 
						|
     char **argv;
 | 
						|
@{
 | 
						|
  char line[1024], *t;
 | 
						|
  int len, done = 0;
 | 
						|
 | 
						|
  line[0] = 0;
 | 
						|
 | 
						|
  using_history ();
 | 
						|
  while (!done)
 | 
						|
    @{
 | 
						|
      printf ("history$ ");
 | 
						|
      fflush (stdout);
 | 
						|
      t = fgets (line, sizeof (line) - 1, stdin);
 | 
						|
      if (t && *t)
 | 
						|
        @{
 | 
						|
          len = strlen (t);
 | 
						|
          if (t[len - 1] == '\n')
 | 
						|
            t[len - 1] = '\0';
 | 
						|
        @}
 | 
						|
 | 
						|
      if (!t)
 | 
						|
        strcpy (line, "quit");
 | 
						|
 | 
						|
      if (line[0])
 | 
						|
        @{
 | 
						|
          char *expansion;
 | 
						|
          int result;
 | 
						|
 | 
						|
          result = history_expand (line, &expansion);
 | 
						|
          if (result)
 | 
						|
            fprintf (stderr, "%s\n", expansion);
 | 
						|
 | 
						|
          if (result < 0 || result == 2)
 | 
						|
            @{
 | 
						|
              free (expansion);
 | 
						|
              continue;
 | 
						|
            @}
 | 
						|
 | 
						|
          add_history (expansion);
 | 
						|
          strncpy (line, expansion, sizeof (line) - 1);
 | 
						|
          free (expansion);
 | 
						|
        @}
 | 
						|
 | 
						|
      if (strcmp (line, "quit") == 0)
 | 
						|
        done = 1;
 | 
						|
      else if (strcmp (line, "save") == 0)
 | 
						|
        write_history ("history_file");
 | 
						|
      else if (strcmp (line, "read") == 0)
 | 
						|
        read_history ("history_file");
 | 
						|
      else if (strcmp (line, "list") == 0)
 | 
						|
        @{
 | 
						|
          register HIST_ENTRY **the_list;
 | 
						|
          register int i;
 | 
						|
 | 
						|
          the_list = history_list ();
 | 
						|
          if (the_list)
 | 
						|
            for (i = 0; the_list[i]; i++)
 | 
						|
              printf ("%d: %s\n", i + history_base, the_list[i]->line);
 | 
						|
        @}
 | 
						|
      else if (strncmp (line, "delete", 6) == 0)
 | 
						|
        @{
 | 
						|
          int which;
 | 
						|
          if ((sscanf (line + 6, "%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
 |