mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-07-04 02:40:49 +02:00
commit bash-20140625 snapshot
This commit is contained in:
@@ -6,9 +6,9 @@
|
||||
.\" Case Western Reserve University
|
||||
.\" chet.ramey@case.edu
|
||||
.\"
|
||||
.\" Last Change: Thu Thu Jun 27 10:34:44 EDT 2013
|
||||
.\" Last Change: Tue Jul 1 16:38:38 PDT 2014
|
||||
.\"
|
||||
.TH HISTORY 3 "2013 June 27" "GNU History 6.3"
|
||||
.TH HISTORY 3 "2014 July 1" "GNU History 6.3"
|
||||
.\"
|
||||
.\" File Name macro. This used to be `.PN', for Path Name,
|
||||
.\" but Sun doesn't seem to like that very much.
|
||||
@@ -613,8 +613,8 @@ string, in addition to space, tab, \fI:\fP and \fI?\fP in the case of
|
||||
a substring search. The default is empty.
|
||||
|
||||
.Vb int history_quotes_inhibit_expansion
|
||||
If non-zero, single-quoted words are not scanned for the history expansion
|
||||
character. The default value is 0.
|
||||
If non-zero, double-quoted words are not scanned for the history expansion
|
||||
character or the history comment character. The default value is 0.
|
||||
|
||||
.Vb "rl_linebuf_func_t *" history_inhibit_expansion_function
|
||||
This should be set to the address of a function that takes two arguments:
|
||||
|
||||
@@ -0,0 +1,673 @@
|
||||
.\"
|
||||
.\" MAN PAGE COMMENTS to
|
||||
.\"
|
||||
.\" Chet Ramey
|
||||
.\" Information Network Services
|
||||
.\" Case Western Reserve University
|
||||
.\" chet.ramey@case.edu
|
||||
.\"
|
||||
.\" Last Change: Thu Thu Jun 27 10:34:44 EDT 2013
|
||||
.\"
|
||||
.TH HISTORY 3 "2013 June 27" "GNU History 6.3"
|
||||
.\"
|
||||
.\" File Name macro. This used to be `.PN', for Path Name,
|
||||
.\" but Sun doesn't seem to like that very much.
|
||||
.\"
|
||||
.de FN
|
||||
\fI\|\\$1\|\fP
|
||||
..
|
||||
.ds lp \fR\|(\fP
|
||||
.ds rp \fR\|)\fP
|
||||
.\" FnN return-value fun-name N arguments
|
||||
.de Fn1
|
||||
\fI\\$1\fP \fB\\$2\fP \\*(lp\fI\\$3\fP\\*(rp
|
||||
.br
|
||||
..
|
||||
.de Fn2
|
||||
.if t \fI\\$1\fP \fB\\$2\fP \\*(lp\fI\\$3,\|\\$4\fP\\*(rp
|
||||
.if n \fI\\$1\fP \fB\\$2\fP \\*(lp\fI\\$3, \\$4\fP\\*(rp
|
||||
.br
|
||||
..
|
||||
.de Fn3
|
||||
.if t \fI\\$1\fP \fB\\$2\fP \\*(lp\fI\\$3,\|\\$4,\|\\$5\fP\|\\*(rp
|
||||
.if n \fI\\$1\fP \fB\\$2\fP \\*(lp\fI\\$3, \\$4, \\$5\fP\\*(rp
|
||||
.br
|
||||
..
|
||||
.de Vb
|
||||
\fI\\$1\fP \fB\\$2\fP
|
||||
.br
|
||||
..
|
||||
.SH NAME
|
||||
history \- GNU History Library
|
||||
.SH COPYRIGHT
|
||||
.if t The GNU History Library is Copyright \(co 1989-2011 by the Free Software Foundation, Inc.
|
||||
.if n The GNU History Library is Copyright (C) 1989-2011 by the Free Software Foundation, Inc.
|
||||
.SH DESCRIPTION
|
||||
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
|
||||
composing new ones.
|
||||
.PP
|
||||
.SH "HISTORY EXPANSION"
|
||||
.PP
|
||||
The history library supports a history expansion feature that
|
||||
is identical to the history expansion in
|
||||
.BR bash.
|
||||
This section describes what syntax features are available.
|
||||
.PP
|
||||
History expansions introduce words from the history list into
|
||||
the input stream, making it easy to repeat commands, insert the
|
||||
arguments to a previous command into the current input line, or
|
||||
fix errors in previous commands quickly.
|
||||
.PP
|
||||
History expansion is usually performed immediately after a complete line
|
||||
is read.
|
||||
It takes place in two parts.
|
||||
The first is to determine which line from the history list
|
||||
to use during substitution.
|
||||
The second is to select portions of that line for inclusion into
|
||||
the current one.
|
||||
The line selected from the history is the \fIevent\fP,
|
||||
and the portions of that line that are acted upon are \fIwords\fP.
|
||||
Various \fImodifiers\fP are available to manipulate the selected words.
|
||||
The line is broken into words in the same fashion as \fBbash\fP
|
||||
does when reading input,
|
||||
so that several words that would otherwise be separated
|
||||
are considered one word when surrounded by quotes (see the
|
||||
description of \fBhistory_tokenize()\fP below).
|
||||
History expansions are introduced by the appearance of the
|
||||
history expansion character, which is \^\fB!\fP\^ by default.
|
||||
Only backslash (\^\fB\e\fP\^) and single quotes can quote
|
||||
the history expansion character.
|
||||
.SS Event Designators
|
||||
.PP
|
||||
An event designator is a reference to a command line entry in the
|
||||
history list.
|
||||
Unless the reference is absolute, events are relative to the current
|
||||
position in the history list.
|
||||
.PP
|
||||
.PD 0
|
||||
.TP
|
||||
.B !
|
||||
Start a history substitution, except when followed by a
|
||||
.BR blank ,
|
||||
newline, = or (.
|
||||
.TP
|
||||
.B !\fIn\fR
|
||||
Refer to command line
|
||||
.IR n .
|
||||
.TP
|
||||
.B !\-\fIn\fR
|
||||
Refer to the current command minus
|
||||
.IR n .
|
||||
.TP
|
||||
.B !!
|
||||
Refer to the previous command. This is a synonym for `!\-1'.
|
||||
.TP
|
||||
.B !\fIstring\fR
|
||||
Refer to the most recent command
|
||||
preceding the current position in the history list
|
||||
starting with
|
||||
.IR string .
|
||||
.TP
|
||||
.B !?\fIstring\fR\fB[?]\fR
|
||||
Refer to the most recent command
|
||||
preceding the current position in the history list
|
||||
containing
|
||||
.IR string .
|
||||
The trailing \fB?\fP may be omitted if
|
||||
.I string
|
||||
is followed immediately by a newline.
|
||||
.TP
|
||||
.B \d\s+2^\s-2\u\fIstring1\fP\d\s+2^\s-2\u\fIstring2\fP\d\s+2^\s-2\u
|
||||
Quick substitution. Repeat the last command, replacing
|
||||
.I string1
|
||||
with
|
||||
.IR string2 .
|
||||
Equivalent to
|
||||
``!!:s/\fIstring1\fP/\fIstring2\fP/''
|
||||
(see \fBModifiers\fP below).
|
||||
.TP
|
||||
.B !#
|
||||
The entire command line typed so far.
|
||||
.PD
|
||||
.SS Word Designators
|
||||
.PP
|
||||
Word designators are used to select desired words from the event.
|
||||
A
|
||||
.B :
|
||||
separates the event specification from the word designator.
|
||||
It may be omitted if the word designator begins with a
|
||||
.BR ^ ,
|
||||
.BR $ ,
|
||||
.BR * ,
|
||||
.BR \- ,
|
||||
or
|
||||
.BR % .
|
||||
Words are numbered from the beginning of the line,
|
||||
with the first word being denoted by 0 (zero).
|
||||
Words are inserted into the current line separated by single spaces.
|
||||
.PP
|
||||
.PD 0
|
||||
.TP
|
||||
.B 0 (zero)
|
||||
The zeroth word. For the shell, this is the command
|
||||
word.
|
||||
.TP
|
||||
.I n
|
||||
The \fIn\fRth word.
|
||||
.TP
|
||||
.B ^
|
||||
The first argument. That is, word 1.
|
||||
.TP
|
||||
.B $
|
||||
The last word. This is usually the last argument, but will expand to the
|
||||
zeroth word if there is only one word in the line.
|
||||
.TP
|
||||
.B %
|
||||
The word matched by the most recent `?\fIstring\fR?' search.
|
||||
.TP
|
||||
.I x\fB\-\fPy
|
||||
A range of words; `\-\fIy\fR' abbreviates `0\-\fIy\fR'.
|
||||
.TP
|
||||
.B *
|
||||
All of the words but the zeroth. This is a synonym
|
||||
for `\fI1\-$\fP'. It is not an error to use
|
||||
.B *
|
||||
if there is just one
|
||||
word in the event; the empty string is returned in that case.
|
||||
.TP
|
||||
.B x*
|
||||
Abbreviates \fIx\-$\fP.
|
||||
.TP
|
||||
.B x\-
|
||||
Abbreviates \fIx\-$\fP like \fBx*\fP, but omits the last word.
|
||||
.PD
|
||||
.PP
|
||||
If a word designator is supplied without an event specification, the
|
||||
previous command is used as the event.
|
||||
.SS Modifiers
|
||||
.PP
|
||||
After the optional word designator, there may appear a sequence of
|
||||
one or more of the following modifiers, each preceded by a `:'.
|
||||
.PP
|
||||
.PD 0
|
||||
.PP
|
||||
.TP
|
||||
.B h
|
||||
Remove a trailing file name component, leaving only the head.
|
||||
.TP
|
||||
.B t
|
||||
Remove all leading file name components, leaving the tail.
|
||||
.TP
|
||||
.B r
|
||||
Remove a trailing suffix of the form \fI.xxx\fP, leaving the
|
||||
basename.
|
||||
.TP
|
||||
.B e
|
||||
Remove all but the trailing suffix.
|
||||
.TP
|
||||
.B p
|
||||
Print the new command but do not execute it.
|
||||
.TP
|
||||
.B q
|
||||
Quote the substituted words, escaping further substitutions.
|
||||
.TP
|
||||
.B x
|
||||
Quote the substituted words as with
|
||||
.BR q ,
|
||||
but break into words at
|
||||
.B blanks
|
||||
and newlines.
|
||||
.TP
|
||||
.B s/\fIold\fP/\fInew\fP/
|
||||
Substitute
|
||||
.I new
|
||||
for the first occurrence of
|
||||
.I old
|
||||
in the event line. Any delimiter can be used in place of /. The
|
||||
final delimiter is optional if it is the last character of the
|
||||
event line. The delimiter may be quoted in
|
||||
.I old
|
||||
and
|
||||
.I new
|
||||
with a single backslash. If & appears in
|
||||
.IR new ,
|
||||
it is replaced by
|
||||
.IR old .
|
||||
A single backslash will quote the &. If
|
||||
.I old
|
||||
is null, it is set to the last
|
||||
.I old
|
||||
substituted, or, if no previous history substitutions took place,
|
||||
the last
|
||||
.I string
|
||||
in a
|
||||
.B !?\fIstring\fR\fB[?]\fR
|
||||
search.
|
||||
.TP
|
||||
.B &
|
||||
Repeat the previous substitution.
|
||||
.TP
|
||||
.B g
|
||||
Cause changes to be applied over the entire event line. This is
|
||||
used in conjunction with `\fB:s\fP' (e.g., `\fB:gs/\fIold\fP/\fInew\fP/\fR')
|
||||
or `\fB:&\fP'. If used with
|
||||
`\fB:s\fP', any delimiter can be used
|
||||
in place of /, and the final delimiter is optional
|
||||
if it is the last character of the event line.
|
||||
An \fBa\fP may be used as a synonym for \fBg\fP.
|
||||
.TP
|
||||
.B G
|
||||
Apply the following `\fBs\fP' modifier once to each word in the event line.
|
||||
.PD
|
||||
.SH "PROGRAMMING WITH HISTORY FUNCTIONS"
|
||||
This section describes how to use the History library in other programs.
|
||||
.SS Introduction to History
|
||||
.PP
|
||||
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 \fIexpansion\fP function
|
||||
is available which provides for a consistent user interface across
|
||||
different programs.
|
||||
.PP
|
||||
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
|
||||
identical to
|
||||
the history substitution provided by \fBbash\fP.
|
||||
.PP
|
||||
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.
|
||||
.PP
|
||||
Before declaring any functions using any functionality the History
|
||||
library provides in other code, an application writer should include
|
||||
the file
|
||||
.FN <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.
|
||||
|
||||
.SS History Storage
|
||||
.PP
|
||||
The history list is an array of history entries. A history entry is
|
||||
declared as follows:
|
||||
.PP
|
||||
.Vb "typedef void *" histdata_t;
|
||||
.PP
|
||||
.nf
|
||||
typedef struct _hist_entry {
|
||||
char *line;
|
||||
char *timestamp;
|
||||
histdata_t data;
|
||||
} HIST_ENTRY;
|
||||
.fi
|
||||
.PP
|
||||
The history list itself might therefore be declared as
|
||||
.PP
|
||||
.Vb "HIST_ENTRY **" the_history_list;
|
||||
.PP
|
||||
The state of the History library is encapsulated into a single structure:
|
||||
.PP
|
||||
.nf
|
||||
/*
|
||||
* 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;
|
||||
.fi
|
||||
.PP
|
||||
If the flags member includes \fBHS_STIFLED\fP, the history has been
|
||||
stifled.
|
||||
.SH "History Functions"
|
||||
.PP
|
||||
This section describes the calling sequence for the various functions
|
||||
exported by the GNU History library.
|
||||
.SS 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.
|
||||
|
||||
.Fn1 void using_history void
|
||||
Begin a session in which the history functions might be used. This
|
||||
initializes the interactive variables.
|
||||
|
||||
.Fn1 "HISTORY_STATE *" history_get_history_state void
|
||||
Return a structure describing the current state of the input history.
|
||||
|
||||
.Fn1 void history_set_history_state "HISTORY_STATE *state"
|
||||
Set the state of the history list according to \fIstate\fP.
|
||||
|
||||
.SS History List Management
|
||||
|
||||
These functions manage individual entries on the history list, or set
|
||||
parameters managing the list itself.
|
||||
|
||||
.Fn1 void add_history "const char *string"
|
||||
Place \fIstring\fP at the end of the history list. The associated data
|
||||
field (if any) is set to \fBNULL\fP.
|
||||
|
||||
.Fn1 void add_history_time "const char *string"
|
||||
Change the time stamp associated with the most recent history entry to
|
||||
\fIstring\fP.
|
||||
|
||||
.Fn1 "HIST_ENTRY *" remove_history "int which"
|
||||
Remove history entry at offset \fIwhich\fP from the history. The
|
||||
removed element is returned so you can free the line, data,
|
||||
and containing structure.
|
||||
|
||||
.Fn1 "histdata_t" free_history_entry "HIST_ENTRY *histent"
|
||||
Free the history entry \fIhistent\fP and any history library private
|
||||
data associated with it. Returns the application-specific data
|
||||
so the caller can dispose of it.
|
||||
|
||||
.Fn3 "HIST_ENTRY *" replace_history_entry "int which" "const char *line" "histdata_t data"
|
||||
Make the history entry at offset \fIwhich\fP have \fIline\fP and \fIdata\fP.
|
||||
This returns the old entry so the caller can dispose of any
|
||||
application-specific data. In the case
|
||||
of an invalid \fIwhich\fP, a \fBNULL\fP pointer is returned.
|
||||
|
||||
.Fn1 void clear_history "void"
|
||||
Clear the history list by deleting all the entries.
|
||||
|
||||
.Fn1 void stifle_history "int max"
|
||||
Stifle the history list, remembering only the last \fImax\fP entries.
|
||||
|
||||
.Fn1 int unstifle_history "void"
|
||||
Stop stifling the history. This returns the previously-set
|
||||
maximum number of history entries (as set by \fBstifle_history()\fP).
|
||||
history was stifled. The value is positive if the history was
|
||||
stifled, negative if it wasn't.
|
||||
|
||||
.Fn1 int history_is_stifled "void"
|
||||
Returns non-zero if the history is stifled, zero if it is not.
|
||||
|
||||
.SS Information About the History List
|
||||
|
||||
These functions return information about the entire history list or
|
||||
individual list entries.
|
||||
|
||||
.Fn1 "HIST_ENTRY **" history_list "void"
|
||||
Return a \fBNULL\fP terminated array of \fIHIST_ENTRY *\fP which is the
|
||||
current input history. Element 0 of this list is the beginning of time.
|
||||
If there is no history, return \fBNULL\fP.
|
||||
|
||||
.Fn1 int where_history "void"
|
||||
Returns the offset of the current history element.
|
||||
|
||||
.Fn1 "HIST_ENTRY *" current_history "void"
|
||||
Return the history entry at the current position, as determined by
|
||||
\fBwhere_history()\fP. If there is no entry there, return a \fBNULL\fP
|
||||
pointer.
|
||||
|
||||
.Fn1 "HIST_ENTRY *" history_get "int offset"
|
||||
Return the history entry at position \fIoffset\fP, starting from
|
||||
\fBhistory_base\fP.
|
||||
If there is no entry there, or if \fIoffset\fP
|
||||
is greater than the history length, return a \fBNULL\fP pointer.
|
||||
|
||||
.Fn1 "time_t" history_get_time "HIST_ENTRY *"
|
||||
Return the time stamp associated with the history entry passed as the argument.
|
||||
|
||||
.Fn1 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.
|
||||
|
||||
.SS Moving Around the History List
|
||||
|
||||
These functions allow the current index into the history list to be
|
||||
set or changed.
|
||||
|
||||
.Fn1 int history_set_pos "int pos"
|
||||
Set the current history offset to \fIpos\fP, an absolute index
|
||||
into the list.
|
||||
Returns 1 on success, 0 if \fIpos\fP is less than zero or greater
|
||||
than the number of history entries.
|
||||
|
||||
.Fn1 "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 \fBNULL\fP pointer.
|
||||
|
||||
.Fn1 "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 \fBNULL\fP pointer.
|
||||
|
||||
.SS Searching the History List
|
||||
|
||||
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 \fIanchored\fP,
|
||||
meaning that the string must match at the beginning of the history entry.
|
||||
|
||||
.Fn2 int history_search "const char *string" "int direction"
|
||||
Search the history for \fIstring\fP, starting at the current history offset.
|
||||
If \fIdirection\fP is less than 0, then the search is through
|
||||
previous entries, otherwise through subsequent entries.
|
||||
If \fIstring\fP 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
|
||||
\fIstring\fP was found. Otherwise, nothing is changed, and a -1 is
|
||||
returned.
|
||||
|
||||
.Fn2 int history_search_prefix "const char *string" "int direction"
|
||||
Search the history for \fIstring\fP, starting at the current history
|
||||
offset. The search is anchored: matching lines must begin with
|
||||
\fIstring\fP. If \fIdirection\fP is less than 0, then the search is
|
||||
through previous entries, otherwise through subsequent entries.
|
||||
If \fIstring\fP 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.
|
||||
|
||||
.Fn3 int history_search_pos "const char *string" "int direction" "int pos"
|
||||
Search for \fIstring\fP in the history list, starting at \fIpos\fP, an
|
||||
absolute index into the list. If \fIdirection\fP is negative, the search
|
||||
proceeds backward from \fIpos\fP, otherwise forward. Returns the absolute
|
||||
index of the history element where \fIstring\fP was found, or -1 otherwise.
|
||||
|
||||
.SS 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.
|
||||
|
||||
.Fn1 int read_history "const char *filename"
|
||||
Add the contents of \fIfilename\fP to the history list, a line at a time.
|
||||
If \fIfilename\fP is \fBNULL\fP, then read from \fI~/.history\fP.
|
||||
Returns 0 if successful, or \fBerrno\fP if not.
|
||||
|
||||
.Fn3 int read_history_range "const char *filename" "int from" "int to"
|
||||
Read a range of lines from \fIfilename\fP, adding them to the history list.
|
||||
Start reading at line \fIfrom\fP and end at \fIto\fP.
|
||||
If \fIfrom\fP is zero, start at the beginning. If \fIto\fP is less than
|
||||
\fIfrom\fP, then read until the end of the file. If \fIfilename\fP is
|
||||
\fBNULL\fP, then read from \fI~/.history\fP. Returns 0 if successful,
|
||||
or \fBerrno\fP if not.
|
||||
|
||||
.Fn1 int write_history "const char *filename"
|
||||
Write the current history to \fIfilename\fP, overwriting \fIfilename\fP
|
||||
if necessary.
|
||||
If \fIfilename\fP is \fBNULL\fP, then write the history list to \fI~/.history\fP.
|
||||
Returns 0 on success, or \fBerrno\fP on a read or write error.
|
||||
|
||||
|
||||
.Fn2 int append_history "int nelements" "const char *filename"
|
||||
Append the last \fInelements\fP of the history list to \fIfilename\fP.
|
||||
If \fIfilename\fP is \fBNULL\fP, then append to \fI~/.history\fP.
|
||||
Returns 0 on success, or \fBerrno\fP on a read or write error.
|
||||
|
||||
.Fn2 int history_truncate_file "const char *filename" "int nlines"
|
||||
Truncate the history file \fIfilename\fP, leaving only the last
|
||||
\fInlines\fP lines.
|
||||
If \fIfilename\fP is \fBNULL\fP, then \fI~/.history\fP is truncated.
|
||||
Returns 0 on success, or \fBerrno\fP on failure.
|
||||
|
||||
.SS History Expansion
|
||||
|
||||
These functions implement history expansion.
|
||||
|
||||
.Fn2 int history_expand "char *string" "char **output"
|
||||
Expand \fIstring\fP, placing the result into \fIoutput\fP, a pointer
|
||||
to a string. Returns:
|
||||
.RS
|
||||
.PD 0
|
||||
.TP
|
||||
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);
|
||||
.TP
|
||||
1
|
||||
if expansions did take place;
|
||||
.TP
|
||||
-1
|
||||
if there was an error in expansion;
|
||||
.TP
|
||||
2
|
||||
if the returned line should be displayed, but not executed,
|
||||
as with the \fB:p\fP modifier.
|
||||
.PD
|
||||
.RE
|
||||
If an error ocurred in expansion, then \fIoutput\fP contains a descriptive
|
||||
error message.
|
||||
|
||||
.Fn3 "char *" get_history_event "const char *string" "int *cindex" "int qchar"
|
||||
Returns the text of the history event beginning at \fIstring\fP +
|
||||
\fI*cindex\fP. \fI*cindex\fP is modified to point to after the event
|
||||
specifier. At function entry, \fIcindex\fP points to the index into
|
||||
\fIstring\fP where the history event specification begins. \fIqchar\fP
|
||||
is a character that is allowed to end the event specification in addition
|
||||
to the ``normal'' terminating characters.
|
||||
|
||||
.Fn1 "char **" history_tokenize "const char *string"
|
||||
Return an array of tokens parsed out of \fIstring\fP, much as the
|
||||
shell might.
|
||||
The tokens are split on the characters in the
|
||||
\fBhistory_word_delimiters\fP variable,
|
||||
and shell quoting conventions are obeyed.
|
||||
|
||||
.Fn3 "char *" history_arg_extract "int first" "int last" "const char *string"
|
||||
Extract a string segment consisting of the \fIfirst\fP through \fIlast\fP
|
||||
arguments present in \fIstring\fP. Arguments are split using
|
||||
\fBhistory_tokenize()\fP.
|
||||
|
||||
.SS History Variables
|
||||
|
||||
This section describes the externally-visible variables exported by
|
||||
the GNU History Library.
|
||||
|
||||
.Vb int history_base
|
||||
The logical offset of the first entry in the history list.
|
||||
|
||||
.Vb int history_length
|
||||
The number of entries currently stored in the history list.
|
||||
|
||||
.Vb int history_max_entries
|
||||
The maximum number of history entries. This must be changed using
|
||||
\fBstifle_history()\fP.
|
||||
|
||||
.Vb int history_wite_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.
|
||||
The current timestamp format uses the value of \fIhistory_comment_char\fP
|
||||
to delimit timestamp entries in the history file. If that variable does
|
||||
not have a value (the default), timestamps will not be written.
|
||||
|
||||
.Vb char history_expansion_char
|
||||
The character that introduces a history event. The default is \fB!\fP.
|
||||
Setting this to 0 inhibits history expansion.
|
||||
|
||||
.Vb char history_subst_char
|
||||
The character that invokes word substitution if found at the start of
|
||||
a line. The default is \fB^\fP.
|
||||
|
||||
.Vb 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.
|
||||
|
||||
.Vb "char *" history_word_delimiters
|
||||
The characters that separate tokens for \fBhistory_tokenize()\fP.
|
||||
The default value is \fB"\ \et\en()<>;&|"\fP.
|
||||
|
||||
.Vb "char *" history_no_expand_chars
|
||||
The list of characters which inhibit history expansion if found immediately
|
||||
following \fBhistory_expansion_char\fP. The default is space, tab, newline,
|
||||
\fB\er\fP, and \fB=\fP.
|
||||
|
||||
.Vb "char *" history_search_delimiter_chars
|
||||
The list of additional characters which can delimit a history search
|
||||
string, in addition to space, tab, \fI:\fP and \fI?\fP in the case of
|
||||
a substring search. The default is empty.
|
||||
|
||||
.Vb int history_quotes_inhibit_expansion
|
||||
If non-zero, double-quoted words are not scanned for the history expansion
|
||||
character or the history comment character. The default value is 0.
|
||||
|
||||
.Vb "rl_linebuf_func_t *" history_inhibit_expansion_function
|
||||
This should be set to the address of a function that takes two arguments:
|
||||
a \fBchar *\fP (\fIstring\fP)
|
||||
and an \fBint\fP index into that string (\fIi\fP).
|
||||
It should return a non-zero value if the history expansion starting at
|
||||
\fIstring[i]\fP should not be performed; zero if the expansion should
|
||||
be done.
|
||||
It is intended for use by applications like \fBbash\fP that use the history
|
||||
expansion character for additional purposes.
|
||||
By default, this variable is set to \fBNULL\fP.
|
||||
.SH FILES
|
||||
.PD 0
|
||||
.TP
|
||||
.FN ~/.history
|
||||
Default filename for reading and writing saved history
|
||||
.PD
|
||||
.SH "SEE ALSO"
|
||||
.PD 0
|
||||
.TP
|
||||
\fIThe Gnu Readline Library\fP, Brian Fox and Chet Ramey
|
||||
.TP
|
||||
\fIThe Gnu History Library\fP, Brian Fox and Chet Ramey
|
||||
.TP
|
||||
\fIbash\fP(1)
|
||||
.TP
|
||||
\fIreadline\fP(3)
|
||||
.PD
|
||||
.SH AUTHORS
|
||||
Brian Fox, Free Software Foundation
|
||||
.br
|
||||
bfox@gnu.org
|
||||
.PP
|
||||
Chet Ramey, Case Western Reserve University
|
||||
.br
|
||||
chet.ramey@case.edu
|
||||
.SH BUG REPORTS
|
||||
If you find a bug in the
|
||||
.B history
|
||||
library, you should report it. But first, you should
|
||||
make sure that it really is a bug, and that it appears in the latest
|
||||
version of the
|
||||
.B history
|
||||
library that you have.
|
||||
.PP
|
||||
Once you have determined that a bug actually exists, mail a
|
||||
bug report to \fIbug\-readline\fP@\fIgnu.org\fP.
|
||||
If you have a fix, you are welcome to mail that
|
||||
as well! Suggestions and `philosophical' bug reports may be mailed
|
||||
to \fPbug-readline\fP@\fIgnu.org\fP or posted to the Usenet
|
||||
newsgroup
|
||||
.BR gnu.bash.bug .
|
||||
.PP
|
||||
Comments and bug reports concerning
|
||||
this manual page should be directed to
|
||||
.IR chet.ramey@case.edu .
|
||||
@@ -467,8 +467,8 @@ 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.
|
||||
If non-zero, double-quoted words are not scanned for the history expansion
|
||||
character or the history comment character. The default value is 0.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar {rl_linebuf_func_t *} history_inhibit_expansion_function
|
||||
|
||||
@@ -0,0 +1,577 @@
|
||||
@ignore
|
||||
This file documents the user interface to the GNU History library.
|
||||
|
||||
Copyright (C) 1988-2014 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 occurred 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.
|
||||
|
||||
The current timestamp format uses the value of @var{history_comment_char}
|
||||
to delimit timestamp entries in the history file. If that variable does
|
||||
not have a value (the default), timestamps will not be written.
|
||||
@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
|
||||
@@ -4,7 +4,7 @@ Copyright (C) 1988-2014 Free Software Foundation, Inc.
|
||||
|
||||
@set EDITION 6.3
|
||||
@set VERSION 6.3
|
||||
@set UPDATED 16 May 2014
|
||||
@set UPDATED-MONTH May 2014
|
||||
@set UPDATED 1 July 2014
|
||||
@set UPDATED-MONTH Julyy 2014
|
||||
|
||||
@set LASTCHANGE Fri May 16 09:36:19 EDT 2014
|
||||
@set LASTCHANGE Tue Jul 1 16:37:33 PDT 2014
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
@ignore
|
||||
Copyright (C) 1988-2014 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set EDITION 6.3
|
||||
@set VERSION 6.3
|
||||
@set UPDATED 16 May 2014
|
||||
@set UPDATED-MONTH May 2014
|
||||
|
||||
@set LASTCHANGE Fri May 16 09:36:19 EDT 2014
|
||||
@@ -991,6 +991,7 @@ history_expand (hstring, output)
|
||||
history expansion performed on it.
|
||||
Skip the rest of the line and break out of the loop. */
|
||||
if (history_comment_char && string[i] == history_comment_char &&
|
||||
dquote == 0 &&
|
||||
(i == 0 || member (string[i - 1], history_word_delimiters)))
|
||||
{
|
||||
while (string[i])
|
||||
@@ -1149,7 +1150,8 @@ history_expand (hstring, output)
|
||||
}
|
||||
|
||||
case -2: /* history_comment_char */
|
||||
if (i == 0 || member (string[i - 1], history_word_delimiters))
|
||||
if ((dquote == 0 || history_quotes_inhibit_expansion == 0) &&
|
||||
(i == 0 || member (string[i - 1], history_word_delimiters)))
|
||||
{
|
||||
temp = (char *)xmalloc (l - i + 1);
|
||||
strcpy (temp, string + i);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+22
-3
@@ -319,13 +319,14 @@ history_truncate_file (fname, lines)
|
||||
const char *fname;
|
||||
int lines;
|
||||
{
|
||||
char *buffer, *filename, *bp, *bp1; /* bp1 == bp+1 */
|
||||
char *buffer, *filename, *bakname, *bp, *bp1; /* bp1 == bp+1 */
|
||||
int file, chars_read, rv;
|
||||
struct stat finfo;
|
||||
size_t file_size;
|
||||
|
||||
buffer = (char *)NULL;
|
||||
filename = history_filename (fname);
|
||||
bakname = 0;
|
||||
file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1;
|
||||
rv = 0;
|
||||
|
||||
@@ -410,7 +411,17 @@ history_truncate_file (fname, lines)
|
||||
|
||||
/* Write only if there are more lines in the file than we want to
|
||||
truncate to. */
|
||||
if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
|
||||
if (bp <= buffer)
|
||||
{
|
||||
rv = 0;
|
||||
goto truncate_exit;
|
||||
}
|
||||
|
||||
bakname = history_backupfile (filename);
|
||||
if (filename && bakname)
|
||||
rename (filename, bakname);
|
||||
|
||||
if ((file = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600)) != -1)
|
||||
{
|
||||
if (write (file, bp, chars_read - (bp - buffer)) < 0)
|
||||
rv = errno;
|
||||
@@ -423,12 +434,20 @@ history_truncate_file (fname, lines)
|
||||
if (close (file) < 0 && rv == 0)
|
||||
rv = errno;
|
||||
}
|
||||
else
|
||||
rv = errno;
|
||||
|
||||
truncate_exit:
|
||||
|
||||
FREE (buffer);
|
||||
|
||||
if (rv != 0 && filename && bakname)
|
||||
rename (bakname, filename);
|
||||
else if (rv == 0 && bakname)
|
||||
unlink (bakname);
|
||||
|
||||
xfree (filename);
|
||||
FREE (bakname);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -319,13 +319,14 @@ history_truncate_file (fname, lines)
|
||||
const char *fname;
|
||||
int lines;
|
||||
{
|
||||
char *buffer, *filename, *bp, *bp1; /* bp1 == bp+1 */
|
||||
char *buffer, *filename, *bakname, *bp, *bp1; /* bp1 == bp+1 */
|
||||
int file, chars_read, rv;
|
||||
struct stat finfo;
|
||||
size_t file_size;
|
||||
|
||||
buffer = (char *)NULL;
|
||||
filename = history_filename (fname);
|
||||
bakname = 0;
|
||||
file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1;
|
||||
rv = 0;
|
||||
|
||||
@@ -368,6 +369,7 @@ history_truncate_file (fname, lines)
|
||||
buffer = (char *)malloc (file_size + 1);
|
||||
if (buffer == 0)
|
||||
{
|
||||
rv = errno;
|
||||
close (file);
|
||||
goto truncate_exit;
|
||||
}
|
||||
@@ -409,10 +411,23 @@ history_truncate_file (fname, lines)
|
||||
|
||||
/* Write only if there are more lines in the file than we want to
|
||||
truncate to. */
|
||||
if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
|
||||
if (bp <= buffer)
|
||||
{
|
||||
rv = 0;
|
||||
goto truncate_exit;
|
||||
}
|
||||
|
||||
bakname = history_backupfile (filename);
|
||||
if (filename && bakname)
|
||||
rename (filename, bakname);
|
||||
|
||||
if ((file = open (filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600)) != -1)
|
||||
{
|
||||
if (write (file, bp, chars_read - (bp - buffer)) < 0)
|
||||
rv = errno;
|
||||
{
|
||||
rv = errno;
|
||||
rename (bakname, filename);
|
||||
}
|
||||
|
||||
#if defined (__BEOS__)
|
||||
/* BeOS ignores O_TRUNC. */
|
||||
@@ -420,7 +435,15 @@ history_truncate_file (fname, lines)
|
||||
#endif
|
||||
|
||||
if (close (file) < 0 && rv == 0)
|
||||
rv = errno;
|
||||
{
|
||||
rv = errno;
|
||||
rename (bakname, filename);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = errno;
|
||||
rename (bakname, filename);
|
||||
}
|
||||
|
||||
truncate_exit:
|
||||
@@ -428,6 +451,8 @@ history_truncate_file (fname, lines)
|
||||
FREE (buffer);
|
||||
|
||||
xfree (filename);
|
||||
FREE (bakname);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -461,6 +461,7 @@ _rl_revert_all_lines ()
|
||||
saved_undo_list = 0;
|
||||
/* Set up rl_line_buffer and other variables from history entry */
|
||||
rl_replace_from_history (entry, 0); /* entry->line is now current */
|
||||
entry->data = 0; /* entry->data is now current undo list */
|
||||
/* Undo all changes to this history entry */
|
||||
while (rl_undo_list)
|
||||
rl_do_undo ();
|
||||
@@ -468,7 +469,6 @@ _rl_revert_all_lines ()
|
||||
the timestamp. */
|
||||
FREE (entry->line);
|
||||
entry->line = savestring (rl_line_buffer);
|
||||
entry->data = 0;
|
||||
}
|
||||
entry = previous_history ();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,693 @@
|
||||
/* misc.c -- miscellaneous bindable readline functions. */
|
||||
|
||||
/* Copyright (C) 1987-2012 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library (Readline), a library
|
||||
for reading lines of text with interactive input and history editing.
|
||||
|
||||
Readline 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Readline 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 Readline. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define READLINE_LIBRARY
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# include "ansi_stdlib.h"
|
||||
#endif /* HAVE_STDLIB_H */
|
||||
|
||||
#if defined (HAVE_LOCALE_H)
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
#include "history.h"
|
||||
|
||||
#include "rlprivate.h"
|
||||
#include "rlshell.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
static int rl_digit_loop PARAMS((void));
|
||||
static void _rl_history_set_point PARAMS((void));
|
||||
|
||||
extern int history_offset;
|
||||
|
||||
/* Forward declarations used in this file */
|
||||
void _rl_free_history_entry PARAMS((HIST_ENTRY *));
|
||||
|
||||
/* If non-zero, rl_get_previous_history and rl_get_next_history attempt
|
||||
to preserve the value of rl_point from line to line. */
|
||||
int _rl_history_preserve_point = 0;
|
||||
|
||||
_rl_arg_cxt _rl_argcxt;
|
||||
|
||||
/* Saved target point for when _rl_history_preserve_point is set. Special
|
||||
value of -1 means that point is at the end of the line. */
|
||||
int _rl_history_saved_point = -1;
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Numeric Arguments */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
int
|
||||
_rl_arg_overflow ()
|
||||
{
|
||||
if (rl_numeric_arg > 1000000)
|
||||
{
|
||||
_rl_argcxt = 0;
|
||||
rl_explicit_arg = rl_numeric_arg = 0;
|
||||
rl_ding ();
|
||||
rl_restore_prompt ();
|
||||
rl_clear_message ();
|
||||
RL_UNSETSTATE(RL_STATE_NUMERICARG);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
_rl_arg_init ()
|
||||
{
|
||||
rl_save_prompt ();
|
||||
_rl_argcxt = 0;
|
||||
RL_SETSTATE(RL_STATE_NUMERICARG);
|
||||
}
|
||||
|
||||
int
|
||||
_rl_arg_getchar ()
|
||||
{
|
||||
int c;
|
||||
|
||||
rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
|
||||
RL_SETSTATE(RL_STATE_MOREINPUT);
|
||||
c = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Process C as part of the current numeric argument. Return -1 if the
|
||||
argument should be aborted, 0 if we should not read any more chars, and
|
||||
1 if we should continue to read chars. */
|
||||
int
|
||||
_rl_arg_dispatch (cxt, c)
|
||||
_rl_arg_cxt cxt;
|
||||
int c;
|
||||
{
|
||||
int key, r;
|
||||
|
||||
key = c;
|
||||
|
||||
/* If we see a key bound to `universal-argument' after seeing digits,
|
||||
it ends the argument but is otherwise ignored. */
|
||||
if (_rl_keymap[c].type == ISFUNC && _rl_keymap[c].function == rl_universal_argument)
|
||||
{
|
||||
if ((cxt & NUM_SAWDIGITS) == 0)
|
||||
{
|
||||
rl_numeric_arg *= 4;
|
||||
return 1;
|
||||
}
|
||||
else if (RL_ISSTATE (RL_STATE_CALLBACK))
|
||||
{
|
||||
_rl_argcxt |= NUM_READONE;
|
||||
return 0; /* XXX */
|
||||
}
|
||||
else
|
||||
{
|
||||
RL_SETSTATE(RL_STATE_MOREINPUT);
|
||||
key = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
rl_restore_prompt ();
|
||||
rl_clear_message ();
|
||||
RL_UNSETSTATE(RL_STATE_NUMERICARG);
|
||||
if (key < 0)
|
||||
return -1;
|
||||
return (_rl_dispatch (key, _rl_keymap));
|
||||
}
|
||||
}
|
||||
|
||||
c = UNMETA (c);
|
||||
|
||||
if (_rl_digit_p (c))
|
||||
{
|
||||
r = _rl_digit_value (c);
|
||||
rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + r : r;
|
||||
rl_explicit_arg = 1;
|
||||
_rl_argcxt |= NUM_SAWDIGITS;
|
||||
}
|
||||
else if (c == '-' && rl_explicit_arg == 0)
|
||||
{
|
||||
rl_numeric_arg = 1;
|
||||
_rl_argcxt |= NUM_SAWMINUS;
|
||||
rl_arg_sign = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make M-- command equivalent to M--1 command. */
|
||||
if ((_rl_argcxt & NUM_SAWMINUS) && rl_numeric_arg == 1 && rl_explicit_arg == 0)
|
||||
rl_explicit_arg = 1;
|
||||
rl_restore_prompt ();
|
||||
rl_clear_message ();
|
||||
RL_UNSETSTATE(RL_STATE_NUMERICARG);
|
||||
|
||||
r = _rl_dispatch (key, _rl_keymap);
|
||||
if (RL_ISSTATE (RL_STATE_CALLBACK))
|
||||
{
|
||||
/* At worst, this will cause an extra redisplay. Otherwise,
|
||||
we have to wait until the next character comes in. */
|
||||
if (rl_done == 0)
|
||||
(*rl_redisplay_function) ();
|
||||
r = 0;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Handle C-u style numeric args, as well as M--, and M-digits. */
|
||||
static int
|
||||
rl_digit_loop ()
|
||||
{
|
||||
int c, r;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (_rl_arg_overflow ())
|
||||
return 1;
|
||||
|
||||
c = _rl_arg_getchar ();
|
||||
|
||||
if (c < 0)
|
||||
{
|
||||
_rl_abort_internal ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = _rl_arg_dispatch (_rl_argcxt, c);
|
||||
if (r <= 0 || (RL_ISSTATE (RL_STATE_NUMERICARG) == 0))
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Create a default argument. */
|
||||
void
|
||||
_rl_reset_argument ()
|
||||
{
|
||||
rl_numeric_arg = rl_arg_sign = 1;
|
||||
rl_explicit_arg = 0;
|
||||
_rl_argcxt = 0;
|
||||
}
|
||||
|
||||
/* Start a numeric argument with initial value KEY */
|
||||
int
|
||||
rl_digit_argument (ignore, key)
|
||||
int ignore, key;
|
||||
{
|
||||
_rl_arg_init ();
|
||||
if (RL_ISSTATE (RL_STATE_CALLBACK))
|
||||
{
|
||||
_rl_arg_dispatch (_rl_argcxt, key);
|
||||
rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rl_execute_next (key);
|
||||
return (rl_digit_loop ());
|
||||
}
|
||||
}
|
||||
|
||||
/* C-u, universal argument. Multiply the current argument by 4.
|
||||
Read a key. If the key has nothing to do with arguments, then
|
||||
dispatch on it. If the key is the abort character then abort. */
|
||||
int
|
||||
rl_universal_argument (count, key)
|
||||
int count, key;
|
||||
{
|
||||
_rl_arg_init ();
|
||||
rl_numeric_arg *= 4;
|
||||
|
||||
return (RL_ISSTATE (RL_STATE_CALLBACK) ? 0 : rl_digit_loop ());
|
||||
}
|
||||
|
||||
int
|
||||
_rl_arg_callback (cxt)
|
||||
_rl_arg_cxt cxt;
|
||||
{
|
||||
int c, r;
|
||||
|
||||
c = _rl_arg_getchar ();
|
||||
|
||||
if (_rl_argcxt & NUM_READONE)
|
||||
{
|
||||
_rl_argcxt &= ~NUM_READONE;
|
||||
rl_restore_prompt ();
|
||||
rl_clear_message ();
|
||||
RL_UNSETSTATE(RL_STATE_NUMERICARG);
|
||||
rl_execute_next (c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = _rl_arg_dispatch (cxt, c);
|
||||
return (r != 1);
|
||||
}
|
||||
|
||||
/* What to do when you abort reading an argument. */
|
||||
int
|
||||
rl_discard_argument ()
|
||||
{
|
||||
rl_ding ();
|
||||
rl_clear_message ();
|
||||
_rl_reset_argument ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* History Utilities */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* We already have a history library, and that is what we use to control
|
||||
the history features of readline. This is our local interface to
|
||||
the history mechanism. */
|
||||
|
||||
/* While we are editing the history, this is the saved
|
||||
version of the original line. */
|
||||
HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
|
||||
/* Set the history pointer back to the last entry in the history. */
|
||||
void
|
||||
_rl_start_using_history ()
|
||||
{
|
||||
using_history ();
|
||||
if (_rl_saved_line_for_history)
|
||||
_rl_free_history_entry (_rl_saved_line_for_history);
|
||||
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
}
|
||||
|
||||
/* Free the contents (and containing structure) of a HIST_ENTRY. */
|
||||
void
|
||||
_rl_free_history_entry (entry)
|
||||
HIST_ENTRY *entry;
|
||||
{
|
||||
if (entry == 0)
|
||||
return;
|
||||
|
||||
FREE (entry->line);
|
||||
FREE (entry->timestamp);
|
||||
|
||||
xfree (entry);
|
||||
}
|
||||
|
||||
/* Perhaps put back the current line if it has changed. */
|
||||
int
|
||||
rl_maybe_replace_line ()
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
|
||||
temp = current_history ();
|
||||
/* If the current line has changed, save the changes. */
|
||||
if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list))
|
||||
{
|
||||
temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
|
||||
xfree (temp->line);
|
||||
FREE (temp->timestamp);
|
||||
xfree (temp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Restore the _rl_saved_line_for_history if there is one. */
|
||||
int
|
||||
rl_maybe_unsave_line ()
|
||||
{
|
||||
if (_rl_saved_line_for_history)
|
||||
{
|
||||
/* Can't call with `1' because rl_undo_list might point to an undo
|
||||
list from a history entry, as in rl_replace_from_history() below. */
|
||||
rl_replace_line (_rl_saved_line_for_history->line, 0);
|
||||
rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data;
|
||||
_rl_free_history_entry (_rl_saved_line_for_history);
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
rl_point = rl_end; /* rl_replace_line sets rl_end */
|
||||
}
|
||||
else
|
||||
rl_ding ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the current line in _rl_saved_line_for_history. */
|
||||
int
|
||||
rl_maybe_save_line ()
|
||||
{
|
||||
if (_rl_saved_line_for_history == 0)
|
||||
{
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
|
||||
_rl_saved_line_for_history->line = savestring (rl_line_buffer);
|
||||
_rl_saved_line_for_history->timestamp = (char *)NULL;
|
||||
_rl_saved_line_for_history->data = (char *)rl_undo_list;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_rl_free_saved_history_line ()
|
||||
{
|
||||
if (_rl_saved_line_for_history)
|
||||
{
|
||||
_rl_free_history_entry (_rl_saved_line_for_history);
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_rl_history_set_point ()
|
||||
{
|
||||
rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1)
|
||||
? _rl_history_saved_point
|
||||
: rl_end;
|
||||
if (rl_point > rl_end)
|
||||
rl_point = rl_end;
|
||||
|
||||
#if defined (VI_MODE)
|
||||
if (rl_editing_mode == vi_mode && _rl_keymap != vi_insertion_keymap)
|
||||
rl_point = 0;
|
||||
#endif /* VI_MODE */
|
||||
|
||||
if (rl_editing_mode == emacs_mode)
|
||||
rl_mark = (rl_point == rl_end ? 0 : rl_end);
|
||||
}
|
||||
|
||||
void
|
||||
rl_replace_from_history (entry, flags)
|
||||
HIST_ENTRY *entry;
|
||||
int flags; /* currently unused */
|
||||
{
|
||||
/* Can't call with `1' because rl_undo_list might point to an undo list
|
||||
from a history entry, just like we're setting up here. */
|
||||
rl_replace_line (entry->line, 0);
|
||||
rl_undo_list = (UNDO_LIST *)entry->data;
|
||||
rl_point = rl_end;
|
||||
rl_mark = 0;
|
||||
|
||||
#if defined (VI_MODE)
|
||||
if (rl_editing_mode == vi_mode)
|
||||
{
|
||||
rl_point = 0;
|
||||
rl_mark = rl_end;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Process and free undo lists attached to each history entry prior to the
|
||||
current entry, inclusive, reverting each line to its saved state. This
|
||||
is destructive, and state about the current line is lost. This is not
|
||||
intended to be called while actively editing, and the current line is
|
||||
not assumed to have been added to the history list. */
|
||||
void
|
||||
_rl_revert_all_lines ()
|
||||
{
|
||||
int hpos;
|
||||
HIST_ENTRY *entry;
|
||||
UNDO_LIST *ul, *saved_undo_list;
|
||||
char *lbuf;
|
||||
|
||||
lbuf = savestring (rl_line_buffer);
|
||||
saved_undo_list = rl_undo_list;
|
||||
hpos = where_history ();
|
||||
|
||||
entry = (hpos == history_length) ? previous_history () : current_history ();
|
||||
while (entry)
|
||||
{
|
||||
if (ul = (UNDO_LIST *)entry->data)
|
||||
{
|
||||
if (ul == saved_undo_list)
|
||||
saved_undo_list = 0;
|
||||
/* Set up rl_line_buffer and other variables from history entry */
|
||||
rl_replace_from_history (entry, 0); /* entry->line is now current */
|
||||
/* entry->data = 0; /* entry->data is now current undo list */
|
||||
/* Undo all changes to this history entry */
|
||||
while (rl_undo_list)
|
||||
rl_do_undo ();
|
||||
/* And copy the reverted line back to the history entry, preserving
|
||||
the timestamp. */
|
||||
FREE (entry->line);
|
||||
entry->line = savestring (rl_line_buffer);
|
||||
entry->data = 0;
|
||||
}
|
||||
entry = previous_history ();
|
||||
}
|
||||
|
||||
/* Restore history state */
|
||||
rl_undo_list = saved_undo_list; /* may have been set to null */
|
||||
history_set_pos (hpos);
|
||||
|
||||
/* reset the line buffer */
|
||||
rl_replace_line (lbuf, 0);
|
||||
_rl_set_the_line ();
|
||||
|
||||
/* and clean up */
|
||||
xfree (lbuf);
|
||||
}
|
||||
|
||||
/* Free the history list, including private readline data and take care
|
||||
of pointer aliases to history data. Resets rl_undo_list if it points
|
||||
to an UNDO_LIST * saved as some history entry's data member. This
|
||||
should not be called while editing is active. */
|
||||
void
|
||||
rl_clear_history ()
|
||||
{
|
||||
HIST_ENTRY **hlist, *hent;
|
||||
register int i;
|
||||
UNDO_LIST *ul, *saved_undo_list;
|
||||
|
||||
saved_undo_list = rl_undo_list;
|
||||
hlist = history_list (); /* direct pointer, not copy */
|
||||
|
||||
for (i = 0; i < history_length; i++)
|
||||
{
|
||||
hent = hlist[i];
|
||||
if (ul = (UNDO_LIST *)hent->data)
|
||||
{
|
||||
if (ul == saved_undo_list)
|
||||
saved_undo_list = 0;
|
||||
_rl_free_undo_list (ul);
|
||||
hent->data = 0;
|
||||
}
|
||||
_rl_free_history_entry (hent);
|
||||
}
|
||||
|
||||
history_offset = history_length = 0;
|
||||
rl_undo_list = saved_undo_list; /* should be NULL */
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* History Commands */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Meta-< goes to the start of the history. */
|
||||
int
|
||||
rl_beginning_of_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
return (rl_get_previous_history (1 + where_history (), key));
|
||||
}
|
||||
|
||||
/* Meta-> goes to the end of the history. (The current line). */
|
||||
int
|
||||
rl_end_of_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
rl_maybe_replace_line ();
|
||||
using_history ();
|
||||
rl_maybe_unsave_line ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move down to the next history line. */
|
||||
int
|
||||
rl_get_next_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
|
||||
if (count < 0)
|
||||
return (rl_get_previous_history (-count, key));
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
rl_maybe_replace_line ();
|
||||
|
||||
/* either not saved by rl_newline or at end of line, so set appropriately. */
|
||||
if (_rl_history_saved_point == -1 && (rl_point || rl_end))
|
||||
_rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
|
||||
|
||||
temp = (HIST_ENTRY *)NULL;
|
||||
while (count)
|
||||
{
|
||||
temp = next_history ();
|
||||
if (!temp)
|
||||
break;
|
||||
--count;
|
||||
}
|
||||
|
||||
if (temp == 0)
|
||||
rl_maybe_unsave_line ();
|
||||
else
|
||||
{
|
||||
rl_replace_from_history (temp, 0);
|
||||
_rl_history_set_point ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the previous item out of our interactive history, making it the current
|
||||
line. If there is no previous history, just ding. */
|
||||
int
|
||||
rl_get_previous_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
HIST_ENTRY *old_temp, *temp;
|
||||
|
||||
if (count < 0)
|
||||
return (rl_get_next_history (-count, key));
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
/* either not saved by rl_newline or at end of line, so set appropriately. */
|
||||
if (_rl_history_saved_point == -1 && (rl_point || rl_end))
|
||||
_rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
|
||||
|
||||
/* If we don't have a line saved, then save this one. */
|
||||
rl_maybe_save_line ();
|
||||
|
||||
/* If the current line has changed, save the changes. */
|
||||
rl_maybe_replace_line ();
|
||||
|
||||
temp = old_temp = (HIST_ENTRY *)NULL;
|
||||
while (count)
|
||||
{
|
||||
temp = previous_history ();
|
||||
if (temp == 0)
|
||||
break;
|
||||
|
||||
old_temp = temp;
|
||||
--count;
|
||||
}
|
||||
|
||||
/* If there was a large argument, and we moved back to the start of the
|
||||
history, that is not an error. So use the last value found. */
|
||||
if (!temp && old_temp)
|
||||
temp = old_temp;
|
||||
|
||||
if (temp == 0)
|
||||
rl_ding ();
|
||||
else
|
||||
{
|
||||
rl_replace_from_history (temp, 0);
|
||||
_rl_history_set_point ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Editing Modes */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
/* How to toggle back and forth between editing modes. */
|
||||
int
|
||||
rl_vi_editing_mode (count, key)
|
||||
int count, key;
|
||||
{
|
||||
#if defined (VI_MODE)
|
||||
_rl_set_insert_mode (RL_IM_INSERT, 1); /* vi mode ignores insert mode */
|
||||
rl_editing_mode = vi_mode;
|
||||
rl_vi_insert_mode (1, key);
|
||||
#endif /* VI_MODE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rl_emacs_editing_mode (count, key)
|
||||
int count, key;
|
||||
{
|
||||
rl_editing_mode = emacs_mode;
|
||||
_rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */
|
||||
_rl_keymap = emacs_standard_keymap;
|
||||
|
||||
if (_rl_show_mode_in_prompt)
|
||||
_rl_reset_prompt ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Function for the rest of the library to use to set insert/overwrite mode. */
|
||||
void
|
||||
_rl_set_insert_mode (im, force)
|
||||
int im, force;
|
||||
{
|
||||
#ifdef CURSOR_MODE
|
||||
_rl_set_cursor (im, force);
|
||||
#endif
|
||||
|
||||
rl_insert_mode = im;
|
||||
}
|
||||
|
||||
/* Toggle overwrite mode. A positive explicit argument selects overwrite
|
||||
mode. A negative or zero explicit argument selects insert mode. */
|
||||
int
|
||||
rl_overwrite_mode (count, key)
|
||||
int count, key;
|
||||
{
|
||||
if (rl_explicit_arg == 0)
|
||||
_rl_set_insert_mode (rl_insert_mode ^ 1, 0);
|
||||
else if (count > 0)
|
||||
_rl_set_insert_mode (RL_IM_OVERWRITE, 0);
|
||||
else
|
||||
_rl_set_insert_mode (RL_IM_INSERT, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+9
-5
@@ -48,9 +48,12 @@ typedef ssize_t creadfunc_t __P((int, char *));
|
||||
/* Derived from GNU libc's getline.
|
||||
The behavior is almost the same as getline. See man getline.
|
||||
The differences are
|
||||
(1) using file descriptor instead of FILE *,
|
||||
(2) the order of arguments; the file descriptor comes the first, and
|
||||
(3) the addition of third argument, UNBUFFERED_READ; this argument
|
||||
(1) using file descriptor instead of FILE *;
|
||||
(2) the order of arguments: the file descriptor comes first;
|
||||
(3) the addition of a fourth argument, DELIM; sets the delimiter to
|
||||
be something other than newline if desired. If setting DELIM,
|
||||
the next argument should be 1; and
|
||||
(4) the addition of a fifth argument, UNBUFFERED_READ; this argument
|
||||
controls whether get_line uses buffering or not to get a byte data
|
||||
from FD. get_line uses zreadc if UNBUFFERED_READ is zero; and
|
||||
uses zread if UNBUFFERED_READ is non-zero.
|
||||
@@ -58,10 +61,11 @@ typedef ssize_t creadfunc_t __P((int, char *));
|
||||
Returns number of bytes read or -1 on error. */
|
||||
|
||||
ssize_t
|
||||
zgetline (fd, lineptr, n, unbuffered_read)
|
||||
zgetline (fd, lineptr, n, delim, unbuffered_read)
|
||||
int fd;
|
||||
char **lineptr;
|
||||
size_t *n;
|
||||
int delim;
|
||||
int unbuffered_read;
|
||||
{
|
||||
int nr, retval;
|
||||
@@ -110,7 +114,7 @@ zgetline (fd, lineptr, n, unbuffered_read)
|
||||
line[nr] = c;
|
||||
nr++;
|
||||
|
||||
if (c == '\n')
|
||||
if (c == delim)
|
||||
{
|
||||
line[nr] = '\0';
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/* zgetline - read a line of input from a specified file descriptor and return
|
||||
a pointer to a newly-allocated buffer containing the data. */
|
||||
|
||||
/* Copyright (C) 2008,2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include "xmalloc.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern ssize_t zread __P((int, char *, size_t));
|
||||
extern ssize_t zreadc __P((int, char *));
|
||||
extern ssize_t zreadintr __P((int, char *, size_t));
|
||||
extern ssize_t zreadcintr __P((int, char *));
|
||||
|
||||
typedef ssize_t breadfunc_t __P((int, char *, size_t));
|
||||
typedef ssize_t creadfunc_t __P((int, char *));
|
||||
|
||||
/* Initial memory allocation for automatic growing buffer in zreadlinec */
|
||||
#define GET_LINE_INITIAL_ALLOCATION 16
|
||||
|
||||
/* Derived from GNU libc's getline.
|
||||
The behavior is almost the same as getline. See man getline.
|
||||
The differences are
|
||||
(1) using file descriptor instead of FILE *;
|
||||
(2) the order of arguments: the file descriptor comes first;
|
||||
(3) the addition of a third argument, DELIM; sets the delimiter to
|
||||
be something other than newline if desired. If setting DELIM,
|
||||
the next argument should be 1; and
|
||||
(4) the addition of a fourth argument, UNBUFFERED_READ; this argument
|
||||
controls whether get_line uses buffering or not to get a byte data
|
||||
from FD. get_line uses zreadc if UNBUFFERED_READ is zero; and
|
||||
uses zread if UNBUFFERED_READ is non-zero.
|
||||
|
||||
Returns number of bytes read or -1 on error. */
|
||||
|
||||
ssize_t
|
||||
zgetline (fd, lineptr, n, delim, unbuffered_read)
|
||||
int fd;
|
||||
char **lineptr;
|
||||
size_t *n;
|
||||
int delim;
|
||||
int unbuffered_read;
|
||||
{
|
||||
int nr, retval;
|
||||
char *line, c;
|
||||
|
||||
if (lineptr == 0 || n == 0 || (*lineptr == 0 && *n != 0))
|
||||
return -1;
|
||||
|
||||
nr = 0;
|
||||
line = *lineptr;
|
||||
|
||||
while (1)
|
||||
{
|
||||
retval = unbuffered_read ? zread (fd, &c, 1) : zreadc(fd, &c);
|
||||
|
||||
if (retval <= 0)
|
||||
{
|
||||
if (line && nr > 0)
|
||||
line[nr] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
if (nr + 2 >= *n)
|
||||
{
|
||||
size_t new_size;
|
||||
|
||||
new_size = (*n == 0) ? GET_LINE_INITIAL_ALLOCATION : *n * 2;
|
||||
line = (*n >= new_size) ? NULL : xrealloc (*lineptr, new_size);
|
||||
|
||||
if (line)
|
||||
{
|
||||
*lineptr = line;
|
||||
*n = new_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*n > 0)
|
||||
{
|
||||
(*lineptr)[*n - 1] = '\0';
|
||||
nr = *n - 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
line[nr] = c;
|
||||
nr++;
|
||||
|
||||
if (c == delim)
|
||||
{
|
||||
line[nr] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nr - 1;
|
||||
}
|
||||
Reference in New Issue
Block a user