./libtecla/ 0040755 0000764 0000764 00000000000 10142301753 011130 5 ustar mcs mcs ./libtecla/html/ 0040755 0000764 0000764 00000000000 10141253664 012102 5 ustar mcs mcs ./libtecla/html/cpl_complete_word.html 0100644 0000764 0000764 00000046060 10141252545 016471 0 ustar mcs mcs
cpl_complete_word cpl_complete_word
cpl_complete_word, cfc_file_start, cfc_literal_escapes,
cfc_set_check_fn, cpl_add_completion, cpl_file_completions,
cpl_last_error, cpl_list_completions, cpl_recall_matches,
cpl_record_error, del_CplFileConf, del_WordCompletion, new_CplFileConf,
new_WordCompletion - lookup possible completions for a word
#include <stdio.h>
#include <libtecla.h>
WordCompletion *new_WordCompletion(void);
WordCompletion *del_WordCompletion(WordCompletion *cpl);
#define CPL_MATCH_FN(fn) int (fn)(WordCompletion *cpl, \
void *data, \
const char *line, \
int word_end)
typedef CPL_MATCH_FN(CplMatchFn);
CPL_MATCH_FN(cpl_file_completions);
CplMatches *cpl_complete_word(WordCompletion *cpl,
const char *line,
int word_end, void *data,
CplMatchFn *match_fn);
CplMatches *cpl_recall_matches(WordCompletion *cpl);
int cpl_list_completions(CplMatches *result, FILE *fp,
int term_width);
int cpl_add_completion(WordCompletion *cpl,
const char *line, int word_start,
int word_end, const char *suffix,
const char *type_suffix,
const char *cont_suffix);
void cpl_record_error(WordCompletion *cpl,
const char *errmsg);
const char *cpl_last_error(WordCompletion *cpl);
#define CPL_CHECK_FN(fn) int (fn)(void *data, \
const char *pathname)
typedef CPL_CHECK_FN(CplCheckFn);
CPL_CHECK_FN(cpl_check_exe);
CplFileConf *new_CplFileConf(void);
CplFileConf *del_CplFileConf(CplFileConf *cfc);
void cfc_literal_escapes(CplFileConf *cfc, int literal);
void cfc_file_start(CplFileConf *cfc, int start_index);
void cfc_set_check_fn(CplFileConf *cfc, CplCheckFn *chk_fn,
void *chk_data);
The cpl_complete_word() function is part of the tecla library (see the
libtecla man page). It is usually called behind the
scenes by gl_get_line, but can also be called sepa-
rately.
Given an input line containing an incomplete word to be completed, it
calls a user-provided callback function (or the provided file-comple-
tion callback function) to look up all possible completion suffixes for
that word. The callback function is expected to look backward in the
line, starting from the specified cursor position, to find the start of
the word to be completed, then to look up all possible completions of
that word and record them, one at a time by calling cpl_add_comple-
tion().
Descriptions of the functions of this module are as follows:
WordCompletion *new_WordCompletion(void)
This function creates the resources used by the cpl_complete_word()
function. In particular, it maintains the memory that is used to return
the results of calling cpl_complete_word().
WordCompletion *del_WordCompletion(WordCompletion *cpl)
This function deletes the resources that were returned by a previous
call to new_WordCompletion(). It always returns NULL (ie. a deleted
object). It does nothing if the cpl argument is NULL.
The callback functions which lookup possible completions should be
defined with the following macro (which is defined in libtecla.h).
#define CPL_MATCH_FN(fn) int (fn)(WordCompletion *cpl, \
void *data, \
const char *line, \
int word_end)
Functions of this type are called by cpl_complete_word(), and all of
the arguments of the callback are those that were passed to said func-
tion. In particular, the line argument contains the input line contain-
ing the word to be completed, and word_end is the index of the charac-
ter that follows the last character of the incomplete word within this
string. The callback is expected to look backwards from word_end for
the start of the incomplete word. What constitutes the start of a word
clearly depends on the application, so it makes sense for the callback
to take on this responsibility. For example, the builtin filename com-
pletion function looks backwards until it hits an unescaped space, or
the start of the line. Having found the start of the word, the call-
back should then lookup all possible completions of this word, and
record each completion via separate calls to cpl_add_completion(). If
the callback needs access to an application-specific symbol table, it
can pass it and any other data that it needs, via the data argument.
This removes any need for globals.
The callback function should return 0 if no errors occur. On failure it
should return 1, and register a terse description of the error by call-
ing cpl_record_error().
void cpl_record_error(WordCompletion *cpl,
const char *errmsg);
The last error message recorded by calling cpl_record_error(), can sub-
sequently be queried by calling cpl_last_error(), as described later.
int cpl_add_completion(WordCompletion *cpl,
const char *line, int word_start,
int word_end, const char *suffix,
const char *type_suffix,
const char *cont_suffix);
The cpl_add_completion() function is called zero or more times by the
completion callback function to record each possible completion in the
specified WordCompletion object. These completions are subsequently
returned by cpl_complete_word(), as described later. The cpl, line, and
word_end arguments should be those that were passed to the callback
function. The word_start argument should be the index within the input
line string of the start of the word that is being completed. This
should equal word_end if a zero-length string is being completed. The
suffix argument is the string that would have to be appended to the
incomplete word to complete it. If this needs any quoting (eg. the
addition of backslashes before special charaters) to be valid within
the displayed input line, this should be included. A copy of the suffix
string is allocated internally, so there is no need to maintain your
copy of the string after cpl_add_completion() returns.
Note that in the array of possible completions which the cpl_com-
plete_word() function returns, the suffix recorded by cpl_add_comple-
tion() is listed along with the concatentation of this suffix with the
word that lies between word_start and word_end in the input line.
The type_suffix argument specifies an optional string to be appended to
the completion if it is displayed as part of a list of completions by
cpl_list_completions(). The intention is that this indicate to the user
the type of each completion. For example, the file completion function
places a directory separator after completions that are directories, to
indicate their nature to the user. Similary, if the completion were a
function, you could indicate this to the user by setting type_suffix to
"()". Note that the type_suffix string isn't copied, so if the argument
isn't a literal string between speech marks, be sure that the string
remains valid for at least as long as the results of cpl_com-
plete_word() are needed.
The cont_suffix is a continuation suffix to append to the completed
word in the input line if this is the only completion. This is some-
thing that isn't part of the completion itself, but that gives the user
an indication about how they might continue to extend the token. For
example, the file-completion callback function adds a directory separa-
tor if the completed word is a directory. If the completed word were a
function name, you could similarly aid the user by arranging for an
open parenthesis to be appended.
CplMatches *cpl_complete_word(WordCompletion *cpl,
const char *line,
int word_end, void *data,
CplMatchFn *match_fn);
The cpl_complete_word() is normally called behind the scenes by
gl_get_line, but can also be called separately if you
separately allocate a WordCompletion object. It performs word comple-
tion, as described at the beginning of this section. Its first argument
is a resource object previously returned by new_WordCompletion(). The
line argument is the input line string, containing the word to be com-
pleted. The word_end argument contains the index of the character in
the input line, that just follows the last character of the word to be
completed. When called by gl_get_line(), this is the character over
which the user pressed TAB. The match_fn argument is the function
pointer of the callback function which will lookup possible completions
of the word, as described above, and the data argument provides a way
for the application to pass arbitrary data to the callback function.
If no errors occur, the cpl_complete_word() function returns a pointer
to a CplMatches container, as defined below. This container is allo-
cated as part of the cpl object that was passed to cpl_complete_word(),
and will thus change on each call which uses the same cpl argument.
typedef struct {
char *completion; /* A matching completion */
/* string */
char *suffix; /* The part of the */
/* completion string which */
/* would have to be */
/* appended to complete the */
/* original word. */
const char *type_suffix; /* A suffix to be added when */
/* listing completions, to */
/* indicate the type of the */
/* completion. */
} CplMatch;
typedef struct {
char *suffix; /* The common initial part */
/* of all of the completion */
/* suffixes. */
const char *cont_suffix; /* Optional continuation */
/* string to be appended to */
/* the sole completion when */
/* nmatch==1. */
CplMatch *matches; /* The array of possible */
/* completion strings, */
/* sorted into lexical */
/* order. */
int nmatch; /* The number of elements in */
/* the above matches[] */
/* array. */
} CplMatches;
If an error occurs during completion, cpl_complete_word() returns NULL.
A description of the error can be acquired by calling the
cpl_last_error() function.
const char *cpl_last_error(WordCompletion *cpl);
The cpl_last_error() function returns a terse description of the error
which occurred on the last call to cpl_complete_word() or cpl_add_com-
pletion().
CplMatches *cpl_recall_matches(WordCompletion *cpl);
As a convenience, the return value of the last call to cpl_com-
plete_word() can be recalled at a later time by calling
cpl_recall_matches(). If cpl_complete_word() returned NULL, so will
cpl_recall_matches().
int cpl_list_completions(CplMatches *result, FILE *fp,
int terminal_width);
When the cpl_complete_word() function returns multiple possible comple-
tions, the cpl_list_completions() function can be called upon to list
them, suitably arranged across the available width of the terminal. It
arranges for the displayed columns of completions to all have the same
width, set by the longest completion. It also appends the type_suffix
strings that were recorded with each completion, thus indicating their
types to the user.
By default the gl_get_line function, passes the follow-
ing completion callback function to cpl_complete_word(). This function
can also be used separately, either by sending it to cpl_com-
plete_word(), or by calling it directly from your own completion call-
back function.
CPL_MATCH_FN(cpl_file_completions);
Certain aspects of the behavior of this callback can be changed via its
data argument. If you are happy with its default behavior you can pass
NULL in this argument. Otherwise it should be a pointer to a CplFile-
Conf object, previously allocated by calling new_CplFileConf().
CplFileConf *new_CplFileConf(void);
CplFileConf objects encapsulate the configuration parameters of
cpl_file_completions(). These parameters, which start out with default
values, can be changed by calling the accessor functions described
below.
By default, the cpl_file_completions() callback function searches back-
wards for the start of the filename being completed, looking for the
first un-escaped space or the start of the input line. If you wish to
specify a different location, call cfc_file_start() with the index at
which the filename starts in the input line. Passing start_index=-1 re-
enables the default behavior.
void cfc_file_start(CplFileConf *cfc, int start_index);
By default, when cpl_file_completions() looks at a filename in the
input line, each lone backslash in the input line is interpreted as
being a special character which removes any special significance of the
character which follows it, such as a space which should be taken as
part of the filename rather than delimiting the start of the filename.
These backslashes are thus ignored while looking for completions, and
subsequently added before spaces, tabs and literal backslashes in the
list of completions. To have unescaped backslashes treated as normal
characters, call cfc_literal_escapes() with a non-zero value in its
literal argument.
void cfc_literal_escapes(CplFileConf *cfc, int literal);
By default, cpl_file_completions() reports all files who's names start
with the prefix that is being completed. If you only want a selected
subset of these files to be reported in the list of completions, you
can arrange this by providing a callback function which takes the full
pathname of a file, and returns 0 if the file should be ignored, or 1
if the file should be included in the list of completions. To register
such a function for use by cpl_file_completions(), call
cfc_set_check_fn(), and pass it a pointer to the function, together
with a pointer to any data that you would like passed to this callback
whenever it is called. Your callback can make its decisions based on
any property of the file, such as the filename itself, whether the file
is readable, writable or executable, or even based on what the file
contains.
#define CPL_CHECK_FN(fn) int (fn)(void *data, \
const char *pathname)
typedef CPL_CHECK_FN(CplCheckFn);
void cfc_set_check_fn(CplFileConf *cfc,
CplCheckFn *chk_fn, void *chk_data);
The cpl_check_exe() function is a provided callback of the above type,
for use with cpl_file_completions(). It returns non-zero if the file-
name that it is given represents a normal file that the user has exe-
cute permission to. You could use this to have cpl_file_completions()
only list completions of executable files.
When you have finished with a CplFileConf variable, you can pass it to
the del_CplFileConf() destructor function to reclaim its memory.
CplFileConf *del_CplFileConf(CplFileConf *cfc);
In multi-threaded programs, you should use the libtecla_r.a version of
the library. This uses POSIX reentrant functions where available (hence
the _r suffix), and disables features that rely on non-reentrant system
functions. In the case of this module, the only disabled feature is
username completion in ~username/ expressions, in cpl_file_comple-
tions().
Using the libtecla_r.a version of the library, it is safe to use the
facilities of this module in multiple threads, provided that each
thread uses a separately allocated WordCompletion object. In other
words, if two threads want to do word completion, they should each call
new_WordCompletion() to allocate their own completion objects.
libtecla.a - The tecla library
libtecla.h - The tecla header file.
libtecla, gl_get_line, ef_expand_file,
pca_lookup_file
Martin Shepherd (mcs@astro.caltech.edu)
cpl_complete_word
./libtecla/html/changes.html 0100644 0000764 0000764 00000424621 10141252550 014377 0 ustar mcs mcs
In the following log, modification dates are listed using the European
convention in which the day comes before the month (ie. DD/MM/YYYY).
The most recent modifications are listed first.
31/10/2004 mcs@astro.caltech.edu (problem reported by Godfrey van der Linden)
getline.c
The gl_event_handler() function had the endif of a
conditional compilation clause in the wrong place. This
only upset the compiler on unusual systems that don't
have select(). The problem was seen under Mac OS X, due
to the configuration problem in 1.6.0 that caused the
configure script to mistakenly report that select wasn't
available.
31/10/2004 mcs@astro.caltech.edu (info provided by Ivan Rayner)
configure.in configure Makefile.in
Ivan reported that under IRIX 6.5 it is necessary to add
-D_XOPEN_SOURCE=500 to the compiler flags, when compiling
the reentrant version of the library. Thus, whereas
previously I hardwired the value of DEFINES_R in
Makefile.in, I have now made this a variable in the
configure script, which is augmented with the above
addition, within an IRIX-specific switch clause.
Also apparently configure leaves the RANLIB variable
blank, instead of setting it to ":", so I have now
explicitly set this to ":", within the new IRIX clause of
the configure script.
31/10/2004 mcs@astro.caltech.edu (info provided by Ivan Rayner)
getline.c
Under IRIX, the compiler warned that gl_read_unmasked()
was returning an int, which was then being assigned to an
enumeration type. This is techically fine, but it
highlighted the fact that I had meant to declare
gl_read_unmasked() to directly return the enumerated
type. I have now done so.
26/09/2004 mcs@astro.caltech.edu
getline.c
Users can now turn off interactive command-line editing
by setting the TERM environment variable to the word "dumb".
18/07/2004 mcs@astro.caltech.edu (problem noted by Michael MacFaden)
getline.c
Calling gl_terminal_size() on a system without support
for SIGWINCH caused a divide-by-zero error in an unintended
call to gl_erase_line(), because gl_update_size() was
incorrectly being called to query the terminal size,
instead of gl_query_size().
18/07/2004 Padraig Brady (documented here by mcs@astro.caltech.edu)
getline.c
The suspend and termination signal-handlers installed by
gl_tty_signals(), were being installed swapped.
03/06/2004 Mike Meaney (documented here by mcs@astro.caltech.edu)
getline.c
Mike pointed out the fact that the curses setupterm()
function is actually documented to exit the application
if an error occurs while its optional errret argument is
NULL. I hadn't noticed this, and because I didn't need
the extra information returned in the errret argument, I
was passing it a NULL. As suggested by Mike, I now pass
this argument a pointer to a dummy errret variable.
23/05/2004 mcs@astro.caltech.edu (problem noted by John Beck)
man/func/cpl_complete_word.in
Some of the prototypes of functions and types documented
by the cpl_complete_word man page, weren't listed in the
Synopsis section of this man page. They are now listed
there.
23/05/2004 mcs@astro.caltech.edu
getline.c man/func/gl_get_line.in
I have now added support for calling gl_normal_io() from
any callback functions that the application installs by
calling either gl_inactivity_timeout(), or gl_watch_fd().
Previously, if one of these callback functions called
gl_normal_io(), then after returning to gl_get_line(),
gl_get_line() would incorrectly assume that the terminal
was still in raw I/O mode. Now, gl_get_line() checks to
see if gl_normal_io() was called by the callback, and
if so, calls _gl_raw_io() to reinstate raw I/O mode.
21/05/2004 mcs@astro.caltech.edu
configure.in configure
On Mac OS X the code that the configure script used to
check for select() failed due to missing symbols in
sys/select.h. Moving the inclusion of sys/select.h to
after the inclusion of sys/time.h, sys/types.h and
sys/unistd.h fixed this.
11/05/2004 mcs@astro.caltech.edu
getline.c man/func/gl_get_line.in
If the line buffer returned by one call to gl_get_line()
was passed as the start_line argument of the next call to
gl_get_line(), then instead of the just-entered line
being presented back to the user for further editing, the
start_line argument was effectively ignored, because the
line buffer whose pointer was being passed back, was
being cleared before the start_line pointer was examined.
This appears to have been a case of me incorrectly
thinking that I had forgotten to initialize gl->line[]
and gl->ntotal in the gl_reset_input_line() function, and
then "fixing" this supposed omission. Removing this
erroneous fix, restored things to how they were meant to
be. To make it unlikely that I will make the same mistake
again, I have renamed the function from
gl_reset_input_line() to gl_reset_editor(), to stop it
looking as though it is meant to reset the contents of
the input line (that is what gl_truncate_buffer() is
for), explicitly stated that it doesn't clear the input
line, in the header comments of the function, and added a
prominent warning comment in the body of the function.
Also, since support for passing back the returned line
pointer via the start_line argument of the next call to
gl_get_line(), wasn't documented in the man page, but was
meant to be supported, and definitely used to work, I
have now amended the man page documentation of
gl_get_line() to explicitly state that this feature is
officially supported.
2?/04/2004 Released 1.6.0
22/04/2004 mcs@astro.caltech.edu (Fixed a bug reported by John Beck)
getline.c
When an error, signal, or other abnormal event aborted
gl_get_line(), the cleanup code that restored the
terminal to a sane state, also overwrote the value of
errno that was associated with the aborting event. An
I/O error occurring in the cleanup code would have also
overwritten the value to be returned by
gl_return_status(), and thus remove any possibility of
the caller finding out what really caused gl_get_line()
to abort. I have now written a new internal function
called, gl_record_status(), which records the completion
status to be returned by gl_return_status(), and the
value to assign to errno just before gl_get_line()
returns. This is called wherever code detects conditions
that require gl_get_line() to return early. The function
ensures that once an abnormal completion status has been
recorded for return, subsequent completions statuses
aren't recorded. This ensures that the caller sees the
original cause of the abnormal return, rather than any
error that occurs during cleaning up from this before
return.
17/04/2004 mcs@astro.caltech.edu
getline.c
If an application's callback called gl_read_char() after
calling gl_normal_io(), it would inappropriately
redisplay the input line, when it called _gl_raw_io() to
temporarily switch the terminal back into raw mode.
To fix this, _gl_raw_io() now takes a new 'redisplay'
argument, which specifies whether or not to queue a
redisplay of the input line. I also created a new
gl->postpone flag, which is set by gl_normal_io(), and
cleared by _gl_raw_io() (when its redisplay argument is
true). When this flag is set, gl_flush_output() ignores
queued redisplays, as it generally should between calls
to gl_normal_io() and gl_raw_io(). Thus its effect is to
postpone redisplays while line editing is suspended.
11/04/2004 mcs@astro.caltech.edu
history.c man/misc/tecla.in
History searches can now include the globbing operators
*, ?, []. When a search prefix is found to have at least
one of these characters, then only history lines that
completely match that pattern are returned.
11/04/2004 mcs@astro.caltech.edu (issue raised by Mark Coiley)
getline.c ioutil.c
There appears to be a bug in Solaris's terminal I/O.
When the terminal file descriptor is placed in
non-blocking I/O mode, and the terminal is switched from
canonical to raw mode, characters that were previously
entered in canonical I/O mode don't become available to
be read until the user types one character more. Select()
incorrectly says that there are no characters available,
and read() returns EAGAIN. This is only a problem for
gl_get_line() when gl_get_line() is in non-blocking
server I/O mode, so most users won't have experienced any
problems with this.
The only way that I have found to get read() to return
the characters, without the user first having to type
another character, is to turn off non-blocking I/O before
calling read(). Select() still claims that there are no
characters available to be read, but read happily returns
them anyway. Fortunately, one can perform non-blocking
terminal reads without setting the non-blocking I/O flag
of the file descriptor, simply by setting the VTIME
terminal attribute to zero (which I already was
doing). Thus, when in non-blocking server I/O, I now turn
off the non-blocking I/O flag, attempt to read one
character and only if this fails, do I then call the
select() based event handler to implement any configured
non-zero timeout, before attempting the read again. Of
course the non-blocking I/O flag is still needed for
writing, so I only turn it off temporarily while reading.
25/03/2004 mcs@astro.caltech.edu (bug reported by Gregory Harris)
Makefile.in
It appears that when in February, I patched Makefile.in
to add abolute paths to the install-sh shell-script,
I accidentally replaced install-sh with install.sh. I
corrected the name in the Makefile.
25/03/2004 Gregory Harris (documented here by mcs)
configure.in configure
Greg added the configuration parameters needed to build
the shared version of the libtecla library under FreeBSD.
25/03/2004 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man/func/gl_get_line.in
man/func/gl_read_char.in
I wrote a public function called gl_read_char(). Unlike
gl_query_char(), this function neither prompts the user
for input, nor displays the character that was entered.
In fact it doesn't write anything to the terminal, and
takes pains not to disturb any incompletely entered
input line, and can safely be called from application
callback functions.
21/03/2004 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man/func/gl_get_line.in
man/func/gl_query_char.in
I wrote a public function called gl_query_char(), which
prompts the user and awaits a single-character reply,
without the user having to hit return.
23/02/2004 mcs@astro.caltech.edu (bug reported by Gregory Harris)
configure.in configure getline.c enhance.c demo3.c
The configure script now checks for the sys/select.h
header file, and arranges for a C macro called
HAVE_SYS_SELECT_H to be set if it exists. Thus the files
that use select() now use this macro to conditionally
include sys/select.h where available. Apparently this
header is required under FreeBSD 5.1.
23/02/2004 mcs@astro.caltech.edu
getline.c libtecla.h man/func/gl_get_line.in
I wrote two new public functions, gl_append_history() and
gl_automatic_history(). Together these allow the
application to take over the responsibility of adding
lines to the history list from gl_get_line(). I then
documented their functionality in the gl_get_line man
page.
Version 1.6.0
I incremented the minor version number of the library, to
comply with the requirement to do so when additions are
made to the public interface. See libtecla.map for
details.
libtecla.map
I added a new 1.6.0 group for the new minor version, and
added the above pair of functions to it.
15/02/2004 mcs@astro.caltech.edu (fixes a bug reported by Satya Sahoo)
history.c
Calling gl_load_history() multiple times, eventually led
to a segmentation fault. This was due to the head of the
list of unused history string segments not getting
reset when the history buffer was cleared. While
debugging this problem I also noticed that the history
resizing function was way too complicated to verify, so
after fixing the above bug, I heavily simplified the
history resizing function, trading off a small reduction
in memory efficiency, for greatly improved clarity, and
thus made it much more verifiable and maintainable.
14/02/2004 mcs@astro.caltech.edu (fixes a bug reported by Tim Burress).
getline.c
If gl_change_terminal() was first used to tell
gl_get_line to read input from a file, then called later
to tell it to read subsequent input from a terminal, no
prompt would be displayed for the first line of
interactive input. The problem was that on reaching the
end of the input file, gl_get_line() should have called
gl_abandon_line(), to tell the next call to gl_get_line()
to start inputting a new line from scratch. I have added
this now.
14/02/2004 Krister Walfridsson (documented here by mcs@astro.caltech.edu)
Makefile.in
Krister noticed that I had failed to put $(srcdir)/ in front
of some invokations of install.sh. I have remedied this.
config.guess config.sub
I hadn't updated these for a long time, so apparently they
didn't recognise the BSD system that Krister was using.
I have now updated them to the versions that come with
autoconf-2.59.
22/01/2004 mcs@astro.caltech.edu
keytab.c
When parsing key-binding specifications, backslash escaped
characters following ^ characters were not being expanded.
Thus ^\\ got interpretted as a control-\ character followed
by a \ character, rather than simply as a control-\
character.
12/01/2004 mcs@astro.caltech.edu
cplfile.c cplmatch.c demo2.c demo3.c demo.c direader.c
expand.c getline.c history.c homedir.c pathutil.c pcache.c
configure.in configure INSTALL
The configuration script now takes a
"--without-file-system" argument. This is primarily for
intended for embedded systems that either don't have
filesystems, or where the file-system code in libtecla is
unwanted bloat. It sets the WITHOUT_FILE_SYSTEM
macro. This removes all code related to filesystem
access, including the entire public file-expansion,
file-completion and path-lookup facilities. Note that the
general word completion facility is still included, but
without the normally bundled file completion
callback. Actually the callback is still there, but it
reports no completions, regardless of what string you ask
it to complete.
This option is described in the INSTALL document.
12/01/2004 mcs@astro.caltech.edu
getline.c configure.in configure INSTALL
The configuration script now takes a
"--without-file-actions" argument. This allows an
application author/installer to prevent users of
gl_get_line() from accessing the filesystem from the
builtin actions of gl_get_line(). It defines a macro
called HIDE_FILE_SYSTEM. This causes the
"expand-filename", "read-from-file", "read-init-files",
and "list-glob" action functions to be completely
removed. It also changes the default behavior of actions
such as "complete-word" and "list-or-eof" to show no
completions, instead of the normal default of showing
filename completions.
This option is described in the INSTALL document.
11/01/2004 mcs@astro.caltech.edu
getline.c man/func/gl_get_line.in
In case an application's customized completion handler
needs to write to the terminal for some unforseen reason,
there needs to be a way for the it to cleanly suspend raw
line editing, before writing to the terminal, and the
caller then needs to be aware that it may need to
resurrect the input line when the callback returns. I
have now arranged that the completion callback functions
can call the gl_normal_io() function for this purpose,
and documented this in the gl_get_line() man page.
11/01/2004 mcs@astro.caltech.edu (In response to a bug report by Satya Sahoo)
getline.c
The gl_configure_getline() function makes a malloc'd copy
of the names of the configuration files that it is asked
to read. Before the bug fix, if the application made one
or more calls to this function, the memory allocated by
the final call that it made before calling del_GetLine(),
wasn't being freed. Note that memory allocated in all but
the final call was being correctly freed, so the maximum
extent of the memory leak was the length of the file
name(s) passed in the final call to
gl_configure_getline(), and an application that didn't
call gl_configure_getline() didn't suffer any leak.
20/12/2003 mcs@astro.caltech.edu
history.c
Ellen tested the history fix that I reported below, and
pointed out that it still had a problem. This turned out
to be because getline.c was making some incorrect
assumptions about the new behavior of history.c. This
problem and the previous one both revolved around how
search prefixes were stored and discarded, so I have now
re-written this part of the code. Previously the search
prefix was retained by looking for a line with that
prefix, and keeping a pointer to that line. This saved
memory, compared to storing a separate copy of the
prefix, but it led to all kinds of hairy
interdependencies, so I have now changed the code to keep
a separate copy of search prefixes. To keep the memory
requirements constant, the search prefix is stored in the
history buffer, like normal history lines, but not
referenced by the time-ordered history list. The prefix
can now be kept around indefinitely, until a new search
prefix is specified, regardless of changes to the
archived lines in the history buffer. This is actually
necessary to make the vi-mode re-search actions work
correctly. In particular, I no longer discard the search
prefix whenever a history search session ends. Also,
rather than have getline.c keep its own record of when a
history session is in progress, it now consults
history.c, so that failed assumptions can't cause the
kind of discrepancy that occurred before. For this to
work, getline.c now explicitly tells history.c to cancel
search sessions whenever it executes any non-history
action.
14/12/2003 mcs@astro.caltech.edu (bug reported by Ellen Oschmann)
history.c
If one searched backwards for a prefix, then returned to
the original line, changed that line, then started
another backwards prefix search, getline incorrectly
discarded the new search prefix in the process of
throwing away its cached copy of the previous pre-search
input line. In other words getline was belatedly
cancelling a previous search, after a new search had
already partially begun, and thus messed up the new
search. The obvious fix was to arrange for the current
search to be cancelled whenever the history pointer
returns to its starting point, rather than waiting for
the next search to begin from there.
14/12/2003 mcs@astro.caltech.edu
history.c
_glh_recall_line() was returning the last line in the
history buffer instead of the line requested by the
caller. This only affected the obscure "repeat-history"
action-function, which probably isn't used by anybody.
09/12/2003 Version 1.5.0 released.
28/09/2003 mcs@astro.caltech.edu
homedir.c
When the home directory of the login user is requested,
see if the HOME environment variable exists, and if so
return its value, rather than looking up the user's home
directory in the password file. This seems to be the
convention adopted by other unix programs that perform
tilde expansion, and it works around a strange problem,
where a third-party libtecla program, statically compiled
under an old version of RedHat, unexpectedly complained
that getpwd() returned an error when the program was run
under RedHat 9.
01/09/2003 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man/func/gl_get_line.in
man/func/gl_register_action.in.
It is now possible for an application to register
external functions as action functions. These actions are
initially bound to specified key-sequences, but if they
are registered before the user's configuration file is
loaded, they can also be re-bound by the user to
different key-sequences. The function used to register a
new action, is called gl_register_action(). Action
functions are passed a readonly copy of the input line
and the cursor position. They can display text to the
terminal, or perform other operations on the application
environment. Currently, they can't edit the input line or
move the cursor. This will require the future addition of
functions to queue the invokation of the built-in action
functions.
26/08/2003 mcs@astro.caltech.edu
getline.c
I modified gl_update_buffer() to ensure that the cursor
stays within the input line after external line
modifications, and to queue a redisplay of the
potentially modified input line.
21/07/2003 mcs@astro.caltech.edu
configure.in configure Makefile.in Makefile.stub INSTALL
By specifying --without-man-pages or --with-man-pages=no
as command-line arguments to the configure script, it is
now possible to have the configure script skip the
man-page preprocessing step, and arrange for the man-page
installation targets in the Makefile to do nothing. This
option is designed for people who embed libtecla within
other packages. It is also used by Makefile.stub when
the distclean target is specified.
21/07/2003 mcs@astro.caltech.edu
configure.in configure
The previous workaround for recent versions of gcc
placing /usr/local/include at the start of the system
inlcude-file search path, broke something else. The fix
placed /usr/include before gcc's include area, which
meant that gcc's modified version of stdarg.h was being
ignored in deference to the version in /usr/include. I
have changed the fix to have gcc report the search path,
then have awk add options to CFLAGS to reorder this path,
plaing /usr/local/include at the end.
Also, under Solaris 9, including term.h without first
including curses.h results in complaints about undefined
symbols, such as bool. As a result the configure script's
test for term.h was failing. I have now modified it to
include curses.h in the test code that it uses to check
for term.h. In the process I also improved the tests for
curses.h and term.h to prevent an ncurses version of
term.h from being used with the system-default version of
curses.h.
29/06/2003 mcs@astro.caltech.edu
Makefile.in direader.c homedir.c
On some systems (eg. linux) the _POSIX_C_SOURCE
feature-test macro is set by system headers, rather than
being an option set by a project's Makefile at
compilation time. In software, such as tecla, where the
definition of this macro is used as an indication of
whether to use the non-reentrant or reentrant versions of
system functions, this means that the reentrant functions
are always used, regardless of whether this macro is set
or not by the project Makefile. Thus, on such systems the
reentrant and non-reentrant versions of the tecla library
are essentially identical. This has a couple of
drawbacks. First, since thread-safe functions for
traversing the password file don't exist, the supposedly
non-reentrant version of the tecla library can't support
ambiguous tab-completion of usernames in ~username/
constructions. Secondly, on some systems the use of
reentrant system functions dictates the use of a shared
library that isn't needed for the non-reentrant
functions, thus making it more difficult to distribute
binary versions of the library.
To remedy this situation I have modified the DEFINES_R
variable in Makefile.in to arrange for the compiler to
define a C macro called PREFER_REENTRANT when it is
compiling the reentrant version of the tecla library.
This macro is now used in the source code to determine
when to require reentrant code. Whithin the source code,
wherever a potentially non-reentrant interface is used,
the existance of both this macro and a suitably valued
_POSIX_C_SOURCE macro, are tested for to see if a
reentrant alternative to the problem code should be used.
22/06/2003 mcs@astro.caltech.edu
getline.c
I changed the way that redisplays are requested and
performed. Redisplays are now queued by calling
gl_queue_redisplay(), and subsequently performed by
gl_flush_output(), when the queue of already pending
output has been completely dispatched. This was necessary
to prevent event handlers from filling up the output
queue with redisplays, and it also simplifies a number of
things. In the process I removed the gl_queue_display()
function. I also wrote a gl_line_erased() function, which
is now called by all functions that erase the input
line. I also split the gl_abandon_line() function into
public and private callable parts, and used the private
version internally to arrange to discard the input line
after errors.
The raw_mode flag was not being initialized by new_GetLine().
It is now initialized to zero.
I removed the zapline flag, since using the endline flag to
communicate the desire to terminate the line, did the same
thing.
gl_terminal_move_cursor() now does nothing when the input
line isn't displayed.
18/03/2003 mcs@astro.caltech.edu
getline.c
Fixed bug which was causing newlines not to be output
at the end of each newly entered line. I was
interpreting the gl->endline flag in conflicting ways in
two places. To fix this I have created a gl->displayed
flag. This flags whether an input line is currently
displayed.
17/03/2003 mcs@astro.caltech.edu
getline.c libtecla.h man/func/gl_get_line.in
man/func/gl_erase_terminal.in libtecla.map
I added a new function that programs can call to clear
the terminal between calls to gl_get_line().
11/03/2003 mcs@astro.caltech.edu
configure.in configure
Under linux when _POSIX_C_SOURCE is defined, getpwent()
and associated functions become undefined, because
_SVID_SOURCE and _BSD_SOURCE become undefined. Adding
these feature macros back to CFLAGS resolves this.
06/03/2003 mcs@astro.caltech.edu
getline.c libtecla.map man/func/gl_get_line.in
Following the lead of Edward Chien, I wrote a function
called gl_bind_keyseq(), which binds a specified
key-sequence to a given action, or unbinds the
key-sequence.
24/02/2003 mcs@astro.caltech.edu
getline.c libtecla.map man/func/cpl_complete_word.in
I implemented a simple function called
cpl_recall_matches(). This recalls the return value of
the last call to cpl_complete_word().
19/01/2003 mcs@astro.caltech.edu
getline.c
The documented signal handling, fd event-handling,
inactivity timeout handling, and server-mode non-blocking
I/O features are now implemented for non-interactive
input streams, such as pipes and files.
19/01/2003 mcs@astro.caltech.edu
getline.c libtecla.h man/func/gl_get_line.in demo3.c
I added a new return status enumerator to report
when an end-of-file condition causes gl_get_line()
to return NULL.
13/01/2003 mcs@astro.caltech.edu
history.c
I rewrote the history facility. The previous
circular buffer implementation was a nightmare to change,
and it couldn't efficiently support certain newly
requested features. The new implementation stores history
lines in linked lists of fixed sized string segments,
taken from the buffer, with each line being reference
counted and recorded in a hash table. If the user enters
a line multiple times, only one copy of the line is now
stored. Not only does this make better use of the
available buffer space, but it also makes it easy to
ensure that a line whose prefix matches the current
search prefix, isn't returned more than once in sequence,
since we can simply see if the latest search result has
the same hash-table pointer as the previous one, rather
than having to compare strings. Another plus is that due
to the use of linked lists of nodes of fixed size line
segments, there is no longer any need to continually
shuffle the contents of the buffer in order to defragment
it. As far as the user is concerned, the visible
differences are as follows:
1. If the user enters a given line multiple times in a
row, each one will be recorded in the history list,
and will thus be listed by gl_show_history(), and
saved in the history file. Previously only one line
was recorded when consecutive duplicates were entered.
This was a kludge to prevent history recall from
recalling the same line multiple times in a row. This
only achieved the desired result when not recalling by
prefix.
2. Not only simple recall, but prefix-based history line
recalls now don't return the same line multiple times
in a row. As mentioned in (1) above, previously this
only worked when performing a simple recall, without a
search prefix.
28/12/2002 mcs@astro.caltech.edu
getline.c
The one-line function, gl_buff_curpos_to_term_curpos()
was only being used by gl_place_cursor(), so I inlined it
in that function, and removed it.
28/12/2002 mcs@astro.caltech.edu
getline.c
gl_suspend_process() was calling the application-level
gl_normal_io() and gl_raw_io() functions, where it should
have been calling the internal versions _gl_normal_io()
and _gl_raw_io().
Also gl_handle_signal() was masking and unmasking just
the signals of the first element of the gl[] array
argument. It now masks and unmasks all trappable signals.
28/12/2002 mcs@astro.caltech.edu
getline.c
Now that the number of terminal characters used to
display the current input line, is recorded, the relative
line on which the last character of the input line
resides can be determined without having to call
gl_buff_curpos_to_term_curpos(). This is now used by
gl_normal_io() via gl_start_newline(), so there is now no
need for gl_buff_curpos_to_term_curpos() to be
async-signal safe. I have thus removed the annoying
gl->cwidth[] array, and gl_buff_curpos_to_term_curpos()
now calls gl_width_of_char() directly again. There is
also now no need for the gl_line_of_char_start() and
gl_line_of_char_end() functions, so I have removed them.
28/12/2002 mcs@astro.caltech.edu
getline.c
Unfortunately it turns out that the terminfo/termcap
control sequence which is defined to delete everything
from the current position to the end of the terminal, is
only defined to work when at the start of a terminal
line. In gnome terminals in RedHat 8.0, if it is used
within a terminal line, it erases the whole terminal
line, rather than just what follows the cursor. Thus to
portably truncate the displayed input line it is
necessary to first use the control sequence which deletes
from the cursor position to the end of the line, then if
there are more terminal lines, move to the start of the
next line, and use the delete to end-of-terminal control
sequence, then restore the cursor position. This requires
that one know how many physical terminal lines are used
by the current input line, so I now keep a record of the
number of characters so far displayed to the terminal
following the start of the prompt, and the new
gl_truncate_display() function uses this information to
truncate the displayed input line from the current cursor
position.
28/12/2002 mcs@astro.caltech.edu
getline.c
gl_start_newline() now moves to an empty line following
the input line, rather than just to the next line. It
also arranges for the input line to be redisplayed before
editing resumes. A major user of this is gl_print_info(),
which now need not be followed by an explicit call to
gl_redisplay(), since the terminal input loop in
gl_get_input_line() ensures that gl_redisplay() is called
after any action function that asserts gl->redisplay.
Also, all functions that erase the displayed input line
can now call the gl_erase_line() function, which is
designed to work correctly even when a terminal resize
invalidates the horizontal cursor position. Finally, the
new gl_queue_display() function is now used by functions
that need to arrange for the input line to be displayed
from scratch after the displayed line has been erased or
invalidated by other text being written to the terminal.
All of these changes are aimed at reducing the number of
places that directly modify gl->term_curpos and
gl->redisplay.
22/12/2002 Markus Gyger (logged here by mcs)
Makefile.in update_html
In places where echo and sed were being used to extract
the base names of files, Markus substituted the basename
command. He also replaced explicit cp and chmod commands
with invokations of the install-sh script.
configure.in
Use $target_os and $target_cpu, where appropriate,
instead of $target.
configure.in
The Solaris man function and library man pages should
be in sections 3lib and 3tecla respectively, only in
Solaris version 2.8 and above.
configure.in
Markus provided values for the man page configuration
variables for HPUX.
man/*/*.in
I had missed parameterizing man page section numbers in
the man page titles, Markus corrected this.
man/func/libtecla_version.in
Fixed incorrect section number in the link to the
libtecla man page.
homedir.c
When compiled to be reentrant, although one can't use the
non-reentrant getpwent() function to scan the password
file for username completions, one can at least see if
the prefix being completed is a valid username, and if
the username of the current user minimally matches the
prefix, and if so list them. I simplified Markus'
modification by adding a prefix argument to the
_hd_scan_user_home_dirs() function, and redefining the
function description accordingly, such that now it
reports only those password file entries who's usernames
minimally match the specified prefix. Without this, it
would have been necessary to peak inside the private data
argument passed in by cf_complete_username().
Markus also provided code which under Solaris uses the
non-reentrant interfaces if the reentrant version of the
library isn't linked with the threads library.
19/12/2002 mcs@astro.caltech.edu
Makefile.in
Markus pointed out that LDFLAGS was being picked up by
the configure script, but not then being interpolated
into te Makefile. I have thus added the necessary
assignment to Makefile.in and arranged for the value of
LDFLAGS to be passed on to recursive make's. I also did
the same for CPPFLAGS, which had also been omitted.
18/12/2002 mcs@astro.caltech.edu
man/* man/*/* configure.in configure Makefile.in
update_html
It turns out that the assignment of man page sections to
topics differs somewhat from system to system, so this is
another thing that needs to be configured by the main
configuration script, rather than being hardwired. All
man pages have now been moved into suitably named
topic-specific sub-directories of the top-level man
directory, and instead of having a numeric suffix, now
have the .in suffix, since they are now preprocessed by
the configure script, in the same fashion as Makefile.in.
Whithin these *.in versions of the man pages, and within
Makefile.in, the installation subdirectory (eg. man1) and
the file-name suffix (eg. 1), are written using
configuration macros, so that they get expanded to the
appropriate tokens when the configure script is run. In
principle, the man pages could also take advantage of
other configuration macros, such as the one which expands
to the library installation directory, to include full
path names to installed files in the documentation, so in
the future this feature could have more uses than just
that of parameterizing man page sections.
18/12/2002 mcs@astro.caltech.edu
man3 man3/* Makefile.in html/index.html update_html
Markus suggested splitting the gl_get_line(3) man page
into user and developer sections, and also pointed out
that the enhance man page should be in section 1, not
section 3. I have thus created a top-level man
directory in which to place the various sections, and
moved the man3 directory into it. The enhance.3 man page
is now in man/man1/enhance.1. I have extracted all
user-oriented sections from the gl_get_line(3) man page
and placed them in a new man7/tecla.7 man page.
18/12/2002 mcs@astro.caltech.edu
getline.c
Terminal resizing was broken in normal mode, due to
me forcing the terminal cursor position to zero in the
wrong place in gl_check_caught_signal().
14/12/2002 Markus Gyger (logged here by mcs)
configure.in configure
Under Solaris, recent versions of gcc search
/usr/local/include for header files before the system
directories. This caused a problem if ncurses was
installed under Solaris, since the termcap.h include file
in /usr/local/include ended up being used at compile
time, whereas the system default version of the curses
library was used at link time. Since the two libraries
declare tputs() differently, this evoked a complaint from
gcc. Markus came up with a way to force Gnu cpp to move
/usr/local/include to the end of the system-include-file
search path, where it belongs.
13/12/2002 mcs@astro.caltech.edu
man3/gl_io_mode.3
I rewrote the man page which documents the new non-blocking
server I/O mode.
12/12/2002 mcs@astro.caltech.edu
demo3.c
I wrote a new version of demo3.c, using signal handlers
that call gl_handle_signal() and gl_abandon_line(), where
previously in this demo, these functions were called from
the application code.
05/12/2002 mcs@astro.caltech.edu
getline.c
gl_normal_io(), gl_raw_io() and gl_handle_signal() and
gl_abandon_line() are now signal safe, provided that
signal handlers that call them are installed with sa_mask's
that block all other signals who's handlers call them.
This is the case if gl_tty_signals() is used to install
signal handlers that call any of these functions.
A major stumbling block that had to be overcome was that
gl_displayed_char_width() calls isprint(), which can't
safely be called from a signal handler (eg. under linux,
the is*() functions all use thread-specific data
facilities to support per-thread locales, and the
thread-specific data facilities aren't signal safe). To
work around this, all functions that modify the
input-line buffer, now do so via accessor functions which
also maintain a parallel array of character widths, for
use by gl_buff_curpos_to_term_curpos() in place of
gl_displayed_char_width(). Other minor problems were the
need to avoid tputs(), who's signal safety isn't defined.
05/12/2002 Eric Norum (logged here by mcs@astro.caltech.edu)
configure.in
Eric provided the configuration information needed
to build shared libraries under Darwin (Max OS X).
05/12/2002 Richard Mlynarik (logged here by mcs@astro.caltech.edu)
configure.in
AC_PROG_RANLIB gets the wrong version of ranlib when
cross compiling, so has now been replaced by an
invokation of AC_CHECK_TOOL. In addition, AC_CHECK_TOOL
is also now used to find an appropriate version of LD.
05/12/2002 mcs@astro.caltech.edu (based on patch by Pankaj Rathore)
getline.c libtecla.h libtecla.map man3/gl_get_line.3
The new gl_set_term_size() function provides a way
to tell gl_get_line() about changes in the size of
the terminal in cases where the values returned by
ioctl(TIOCGWINSZ) isn't correct.
05/12/2002 mcs@astro.caltech.edu
getline.c
Rather than calling sprintf() to see how much space would
be needed to print a given number in octal, I wrote a
gl_octal_width() function, for use by
gl_displayed_char_width(). This makes the latter
function async signal safe.
05/12/2002 mcs@astro.caltech.edu
chrqueue.c
Whenever the buffer is exhausted, and getting a new
buffer node would require a call to malloc(), attempt
to flush the buffer to the terminal. In blocking I/O
mode this means that the buffer never grows. In
non-blocking I/O mode, it just helps keep the buffer
size down.
05/12/2002 mcs@astro.caltech.edu
freelist.h freelist.c
The new _idle_FreeListNodes() function queries the
number of nodes in the freelist which aren't currently
in use.
05/12/2002 mcs@astro.caltech.edu
Makefile.stub
This now accepts all of the targets that the configured
makefile does, and after configuring the latter makefile,
it invokes it with the same options.
03/12/2002 mcs@astro.caltech.edu
mans3/gl_io_mode.3
I completed the man page for all of the new functions
related to non-blocking I/O.
01/12/2002 mcs@astro.caltech.edu
man3/gl_get_line.3
I wrote a long section on reliable signal handling,
explaining how gl_get_line() does this, how to make
use of this in a program, and how to handle signals
reliably when faced with other blocking functions.
This basically documents what I have learnt about
signal handling while working on this library.
01/12/2002 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
In non-blocking server mode, the gl_replace_prompt()
function can now be used between calls to gl_get_line()
if the application wants to change the prompt of the
line that is being edited.
01/12/2002 mcs@astro.caltech.edu
man3/gl_get_line.3
I documented the new gl_return_status() and
gl_error_message() functions.
01/12/2002 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
Added SIGPOLL and SIGXFSZ to the list of signals that
are trapped by default. These are process termination
signals, so the terminal needs to be restored to a
usable state before they terminate the process.
27/11/2002 mcs@astro.caltech.edu
getline.c libtecla.h
Completed the essential changes needed to support
non-blocking server-I/O mode.
The new gl_io_mode() function allows one to switch to
and from non-blocking server-I/O mode.
The new gl_raw_io() function is used in non-blocking
server-I/O mode to switch the terminal into non-blocking
raw I/O mode.
The new gl_normal_io() function is used in non-blocking
server-I/O mode to switch the restore the terminal to
a normal, blocking state. This is used to suspend line
input before suspending the process or writing messages
to the terminal.
The new gl_tty_signals() function installs specified
signals handlers for all signals that suspend, terminate
or resume processes, and also for signals that indicate
that the terminal has been resized. This not only saves
the application from having to keep its own ifdef'd list
of such signals, of which there are many, but it also
makes sure that these signal handlers are registered
correctly. This includes using the sa_mask member of each
sigaction structure to ensure that only one of these
handlers runs at a time. This is essential to avoid the
signal handlers all trying to simultaneously modify
shared global data.
The new gl_handle_signal() function is provided for
responding (from application level) to signals caught by
the application. It handles process suspension, process
termination and terminal resize signals.
The new gl_pending_io() function tells the application
what direction of I/O gl_get_line() is currently waiting
for.
In non-blocking server I/O mode, the new
gl_abandon_line() function can be called between calls to
gl_get_line() to discard an input line and force the next
call to gl_get_line() to start the input of a new line.
Also, in non-blocking server-I/O gl_get_line() doesn't
attempt to do anything but return when one of the signals
that it is configured to catch is caught. This is
necessary because when in this mode, the application is
required to handle these signals when gl_get_line() is
running, and the default configuration of most of these
signals in gl_get_line() is to restore the terminal then
call the application signal handlers. This would be a
case of too many cooks spoiling the broth, so in this
mode, gl_get_line() always defers to the application's
signal handlers.
26/11/2002 mcs@astro.caltech.edu
getline.c libtecla.h
I implemented a couple of new functions to support
reliable signal handling, as now documented
(see above) in the gl_get_line(3) man page.
The new gl_catch_blocked() function tells gl_get_line()
to unblock all configured signals around calls to
long-running functions, not only those that aren't
blocked when gl_get_line() is called. This allows
the caller to implement reliable signal handling,
since the unblocking is only done from within code
protected by sigsetjmp(), which avoids race conditions.
The new gl_list_signals() function fills a provided
sigset_t with the set of signals that gl_get_line() is
currently configured to catch. This allows callers to
block said signals, such that they are only unblocked by
gl_get_line() when it is waiting for I/O. When used in
conjunction with the gl_catch_blocked() function, this
removes the potential for race conditions.
Also, when gl_get_line() installs its signal handler,
it uses the sa_mask member of the sigaction structure
to ensure that only one instance of this signal handler
will ever be executing at a time.
25/11/2002 mcs@astro.caltech.edu (bug reported by Pankaj Rathore)
getline.c
When any history recall action was invoked when the
input line buffer was full, an error message would be
displayed complaining about the length of the string
in the line input buffer being inconsistent with the
specified allocated size. This was because instead of
sending the allocated size of the input line, I was
sending the length excluding the element that is
reserved for the '\0' terminator. Sending it the
correct size corrected the problem.
24/11/2002 mcs@astro.caltech.edu
getline.c
All public functions which take GetLine objects as
arguments now block signals on entry and restore the
signal mask on return. This was an attempt to make it
safe to call getline functions from signal handlers, but
the fact is that the functions that I really wanted this
to apply to, potentially call malloc(), so this currently
isn't the case.
23/11/2002 mcs@astro.caltech.edu
getline.c libtecla.h
The new gl_return_status() function returns an enumerated
return status which can be used to query what caused
gl_get_line() to return.
22/11/2002 mcs@astro.caltech.edu
Most existing .c and .h files, plus errmsg.c errmsg.h
Makefile.rules
Until now, many library functions would report error
messages to stderr. This isn't appropriate for library
functions, so in place of this behavior, error messages
are now recorded in internal ErrMsg objects, and passed
between modules via new module-specific error querying
functions. In addition, errno is now set appropriately.
Thus when gl_get_line() and related functions return an
error, strerror() can be used to look up system errors,
and gl_error_message() can be used to recover a higher level
error message. Note that error messages that are
responses to user actions continue to be reported to the
terminal, as before.
21/11/2002 mcs@astro.caltech.edu
getline.c keytab.h keytab.c Makefile.rules
I wrote a new version of _kt_lookup_binding() that didn't
require the caller to have access to the innards of a
KeyTab object. This then enabled me to move the definition
of KeyTab objects into keytab.c and make the typedef in
keytab.h opaque. Many nested includes were also moved from
keytab.h into keytab.c.
05/11/2002 mcs@astro.caltech.edu
getline.c libtecla.map libtecla.h demo3.c
I split the old gl_resize_terminal() function into
two parts, gl_query_size() and gl_update_size(), with
the latter calling the former to get the new terminal
size.
05/11/2002 mcs@astro.caltech.edu
getline.c
I fixed a long time bug in the terminal resizing code.
When the cursor wasn't on the last terminal line of the
input line, the resizing code would redisplay the
the line one or more lines above where it should be
restored. This was due to an error in the calculation of
the number of lines above the cursor position.
04/11/2002 mcs@astro.caltech.edu
demo.c demo2.c demo3.c
I used the new gl_display_text() function to display
introductory text at the startup of each of the demo
programs. The text is enclosed within a box of asterixes,
drawn dynamically to fit within the confines of the
available terminal width.
04/11/2002 mcs@astro.caltech.edu
libtecla.h getline.c ioutil.c ioutil.h Makefile.rules
libtecla.map man3/gl_get_line.3 man3/gl_display_text.3
Needing a way to display introductory text intelligently
in the demo programs, I wrote and documented the
gl_display_text() function. This justifies arbitrary
length text within the bounds of the terminal width,
with or without optional indentation, prefixes and
suffixes.
03/11/2002 mcs@astro.caltech.edu
demo3.c Makefile.rules
I wrote a new demonstration program. This program acts
exactly like the main demonstration program, except that
it uses an external event loop instead of using the
gl_get_line() internal event loop. This is thus an example
of the new non-blocking server I/O facility.
02/11/2002 mcs@astro.caltech.edu
getline.c keytab.c keytab.h libtecla.h man3/gl_get_line.3
man3/gl_completion_action.3
I added the ability to register additional word
completion actions via the new function
gl_completion_action(). All action functions now take a
new (void *data) argument, which is stored with the
function in the symbol table of actions. The new
gl_completion_action() function uses this feature to
record dynamically allocated objects containing the
specified completion function and callback data along
with either the gl_complete_word() action function, or
the gl_list_completions() action function. These two
actions continue to use the builtin completion functions
when their data pointer is NULL.
20/10/2002 mcs@astro.caltech.edu
The following are changes merged from the non-blocking
gl_get_line() development branch.
getline.c
I wrote a gl_start_newline() function, to replace all of
the explicit calls to output \r\n to stdout.
Informational messages are now written to the terminal
using a new variadic function called gl_print_info().
This starts a newline, writes string arguments until a
special argument, GL_END_INFO, is seen, then starts
another newline.
Changed _output_ to _print_ in the following function
names gl_output_control_sequence(), gl_output_char(),
gl_output_string() and gl_output_raw_string().
gl_print_raw_string() now has a length argument, so that
strings that aren't terminated with '\0' can be printed.
The display of the initial contents of a new line to be
edited has been moved into a new function called
gl_present_line().
The gl_get_input_line() function now takes the prompt
string as an argument so that gl_replace_prompt() can be
called from within this function instead of from
gl_get_line().
Keyboard input is now buffered in a persistent buffer in
the parent GetLine object. gl_read_character() checks
this for unprocessed characters in preference to calling
gl_read_terminal() to append characters to it. A new
function, gl_discard_chars(), removes processed
characters from this buffer. This change is in
preparation for a non-blocking version of gl_get_line(),
where partially input key-sequences must be stored
between calls to gl_get_line().
getline.c getline.h history.c history.h cplmatch.c \
cplmatch.h expand.c expand.h
All terminal output from gl_get_line() is now routed
through a GL_WRITE_FN() callback function called
gl_write_fn. Internal functions in cplmatch.c,
expand.c and history.c have been created which take
such callbacks to write output. These are used both
by functions in getline.c, to display file completions,
expansions, history etc, and as the internals of existing
public functions in these files that print to stdio
streams. In the latter case an internal stdio
GL_WRITE_FN() callback is substituted, so that the
functions behave as before.
getline.c chrqueue.c chrqueue.h
The gl_write_fn() callback used by gl_get_line() now
writes to a queue, implemented in chrqueue.c. This queue
is implemented as a list of blocks of buffer segments,
the number of which shrink and grow as
needed. The contents of the queue are flushed to the
terminal via another GL_WRITE_FN() callback passed to the
queue object. Currently gl_get_line() passes an internal
function assigned to gl->flush_fn, called
gl_flush_terminal(), which writes the contents of the
queue to the terminal, and knows how to handle both
blocking and non-blocking I/O. The output queue is
designed to be flushed to the terminal incrementally, and
thereby also facilitates non-blocking I/O.
getline.c getline.h
gl_get_line() now reads all input via the GL_READ_FN()
callback, assigned to gl->read_fn. Currently this is
set to an internal function called gl_read_terminal(),
which knows how to handle both blocking and
non-blocking I/O.
getline.c libtecla.h
The new gl_set_nonblocking() function can be used to
enable or disable non-blocking I/O. The default is still
blocking I/O. In non-blocking mode, the terminal is told
not to wait when either reading or writing would block.
gl_get_line() then returns, with a return value of NULL,
but with the terminal left in raw mode, so that the
caller's event loop can detect key presses. The caller
should call gl_return_status() to check whether the NULL
return value was due to an error, lack of input, or
inability to write to the terminal without waiting. If
either reading or writing was said to have blocked, the
user then should check for I/O readiness in the specified
direction before calling gl_get_line() again to
incrementally build up the input line.
05/08/2002 mcs@astro.caltech.edu
man3/gl_get_line.3 man3/gl_inactivity_timeout.3
I documented the new gl_inactivity_timeout() function.
08/07/2002 mcs@astro.caltech.edu
libtecla.h getline.c libtecla.map
I added a new gl_inactivity_timeout() function. On
systems that have the select system call, this provides
the option of registering a function that is then called
whenever no I/O activity has been seen for more than a
specified period of time. Like the gl_watch_fd()
facility, timeout callbacks return a code which tells
gl_get_line() how to proceed after the timeout has been
handled.
04/07/2002 mcs@astro.caltech.edu (based on a bug report from Michael MacFaden)
getline.c
The internal event handler wasn't responding to write
events on client file descriptors, due to a typo which
resulted in read events being checked for twice, and
writes not checked for at all.
pathutil.c
The amount of space to allocate for pathnames is supposed
to come from PATH_MAX in limits.h, but I had neglected to
include limits.h. This went unnoticed because on most
systems the equivalent number is deduced by calling
pathconf(). Apparently under NetBSD this function doesn't
work correctly over NFS mounts.
30/05/2002 Version 1.4.1 released.
25/05/2002 mcs@astro.caltech.edu (based on suggestions by Paul Smith)
pathutil.c
Apparently, under QNX pathconf("/",_PC_PATH_MAX) returns
EINVAL. At Paul's suggestion I have modified the code to
silently substitute the existing MAX_PATHLEN_FALLBACK
value if pathconf() returns an error of any kind.
homedir.c
Under QNX, sysconf(_SC_GETPW_R_SIZE_MAX) also apparently
returns EINVAL, so as with pathconf() I modified the code
to substitute a fallback default, rather than
complaining and failing.
enhance.c
Paul told me that the inclusion of sys/termios.h was
causing compilation of enhance.c to fail under QNX. This
line is a bug. The correct thing to do is include
termios.h without a sub-directory prefix, as I was
already doing futher up in the file, so I have just
removed the errant include line.
07/05/2002 mcs@astro.caltech.edu (async development branch only)
getline.c
gl_read_character() now caches and reads unprocessed
characters from a key-press lookahead buffer. Whenever
gl_intepret_char() receives a new character which makes
an initially promising key-sequence no longer match the
prefix of any binding, it now simply discards the first
character from the key-press buffer and resets the buffer
pointer so that the next call to gl_read_character()
returns the character that followed it, from the buffer.
getline.c
The part of gl_get_input_line() which preloads, displays
and prepares to edit a new input line, has now been moved
into a function called gl_present_line().
12/02/2002 mcs@astro.caltech.edu
getline.c configure.in configure
Mac OS X doesn't have a term.h or termcap.h, but it does
define prototypes for tputs() and setupterm(), so the
default prototypes that I was including if no headers
where available, upset it. I've removed these prototypes.
I also now conditionally include whichever is found of
curses.h and ncurses/curses.h for both termcap and
terminfo (before I wasn't including curses.h when
termcap was selected).
12/02/2002 mcs@astro.caltech.edu
Updated version number to 1.4.1, ready for a micro
release.
12/02/2002 mcs@astro.caltech.edu
html/index.html
Added Mac OS X and Cygwin to the list of systems that
can compile libtecla.
12/02/2002 mcs@astro.caltech.edu
getline.c
Under Mac OS X, the tputs() callback function returns
void, instead of the int return value used by other
systems. This declaration is now used if both __MACH__
and __APPLE__ are defined. Hopefully these are the
correct system macros to check. Thanks for Stephan
Fiedler for providing information on Mac OS X.
11/02/2002 mcs@astro.caltech.edu
configure.in configure getline.c
Some systems don't have term.h, and others have it hidden
in an ncurses sub-directory of the standard system include
directory. If term.h can't be found, simply don't include
it. If it is in an ncurses sub-directory, include
ncurses/term.h instead of term.h.
04/02/2002 mcs@astro.caltech.edu
configure.in configure Makefile.in Makefile.rules
Use ranlib on systems that need it (Mac OS X). Also,
make all components of the installation directories where
needed, instead of assuming that they exist.
04/02/2002 mcs@astro.caltech.edu
getline.c
When the tab completion binding was unbound from the tab
key, hitting the tab key caused gl_get_line() to ring the
bell instead of inserting a tab character. This is
problematic when using the 'enhance' program with
Jython, since tabs are important in Python. I have
corrected this.
10/12/2001 Version 1.4.0 released.
10/12/2001 mcs@astro.caltech.edu
getline.c
If the TIOCGWINSZ ioctl doesn't work, as is the case when
running in an emacs shell, leave the size unchanged, rather
than returning a fatal error.
07/12/2001 mcs@astro.caltech.edu
configure.in configure
Now that the configure version of CFLAGS is included in
the makefile, I noticed that the optimization flags -g
and -O2 had been added. It turns out that if CFLAGS isn't
already set, the autoconf AC_PROG_CC macro initializes it
with these two optimization flags. Since this would break
backwards compatibility in embedded distributions that
already use the OPT= makefile argument, and because
turning debugging on needlessly bloats the library, I now
make sure that CFLAGS is set before calling this macro.
07/12/2001 mcs@astro.caltech.edu
enhance.c
Use argv[0] in error reports instead of using a
hardcoded macro.
07/12/2001 mcs@astro.caltech.edu
getline.c
The cut buffer wasn't being cleared after being
used as a work buffer by gl_load_history().
06/12/2001 mcs@astro.caltech.edu
configure.in configure
I removed my now redundant definition of SUN_TPUTS from
CFLAGS. I also added "-I/usr/include" to CFLAGS under
Solaris to prevent gcc from seeing conflicting versions
of system header files in /usr/local/include.
06/12/2001 Markus Gyger (logged here by mcs)
Lots of files.
Lots of corrections to misspellings and typos in the
comments.
getline.c
Markus reverted a supposed fix that I added a day or two
ago. I had incorrectly thought that in Solaris 8, Sun had
finally brought their declaration of the callback
function of tputs() into line with other systems, but it
turned out that gcc was pulling in a GNU version of
term.h from /usr/local/include, and this was what
confused me.
05/12/2001 mcs@astro.caltech.edu
Makefile.in
I added @CFLAGS@ to the CFLAGS assignment, so that
if CFLAGS is set as an environment variable when
configure is run, the corresponding make variable
includes its values in the output makefile.
05/12/2001 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man3/gl_get_line.3
man3/gl_last_signal.3
I added a function that programs can use to find out
which signal caused gl_get_line() to return EINTR.
05/12/2001 mcs@astro.caltech.edu
getline.c
When the newline action was triggered by a printable
character, it failed to display that character. It now
does. Also, extra control codes that I had added, to
clear to the end of the display after the carriage return,
but before displaying the prompt, were confusing expect
scripts, so I have removed them. This step is now done
instead in gl_redisplay() after displaying the full input
line.
05/12/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
A user convinced me that continuing to invoke meta
keybindings for meta characters that are printable is a
bad idea, as is allowing users to ask to have setlocale()
called behind the application's back. I have thus changed
this. The setlocale configuration option has gone, and
gl_get_line() is now completely 8-bit clean, by default.
This means that if a meta character is printable, it is
treated as a literal character, rather than a potential
M-c binding. Meta bindings can still be invoked via
their Esc-c equivalents, and indeed most terminal
emulators either output such escape pairs by default when
the meta character is pressed, or can be configured to do
so. I have documented how to configure xterm to do this,
in the man page.
03/12/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
gl_get_line() by default now prints any 8-bit printable
characters that don't match keybindings. Previously
characters > 127 were only printed if preceded by the
literal-next action. Alternatively, by placing the
command literal_if_printable in the tecla configuration
file, all printable characters are treated as literal
characters, even if they are bound to action functions.
For international users of programs written by
programmers that weren't aware of the need to call
setlocale() to support alternate character sets, the
configuration file can now also contain the single-word
command "setlocale", which tells gl_get_line() to remedy
this.
27/11/2001 mcs@astro.caltech.edu
demo.c demo2.c enhance man3/gl_get_line.3
All demos and programs now call setlocale(LC_CTYPE,"").
This makes them support character sets of different
locales, where specified with the LC_CTYPE, LC_ALL, or
LANG environment variables. I also added this to the demo
in the man page, and documented its effect.
27/11/2001 mcs@astro.caltech.edu
getline.c
When displaying unsigned characters with values over
127 literally, previously it was assumed that they would
all be displayable. Now isprint() is consulted, and if it
says that a character isn't printable, the character code
is displayed in octal like \307. In non-C locales, some
characters with values > 127 are displayable, and
isprint() tells gl_get_line() which are and which aren't.
27/11/2001 mcs@astro.caltech.edu
getline.c pathutil.c history.c enhance.c demo2.c
All arguments of the ctype.h character class functions
are now cast to (int)(unsigned char). Previously they
were cast to (int), which doesn't correctly conform to
the requirements of the C standard, and could cause
problems for characters with values > 127 on systems
with signed char's.
26/11/2001 mcs@astro.caltech.edu
man3/enhance.3 man3/libtecla.3
I started writing a man page for the enhance program.
26/11/2001 mcs@astro.caltech.edu
Makefile.in Makefile.rules INSTALL
It is now possible to specify whether the demos and other
programs are to be built, by overriding the default
values of the DEMOS, PROGRAMS and PROGRAMS_R variables.
I have also documented the BINDIR variable and the
install_bin makefile target.
22/11/2001 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man3/gl_get_line.3
man3/gl_ignore_signal.3 man3/gl_trap_signal.3
Signal handling has now been modified to be customizable.
Signals that are trapped by default can be removed from
the list of trapped signals, and signals that aren't
currently trapped, can be added to the list. Applications
can also specify the signal and terminal environments in
which an application's signal handler is invoked, and
what gl_get_line() does after the signal handler returns.
13/11/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
Added half-bright, reverse-video and blinking text to the
available prompt formatting options.
getline.c
Removed ^O from the default VT100 sgr0 capability
string. Apparently it can cause problems with some
terminal emulators, and we don't need it, since it turns
off the alternative character set mode, which we don't
use.
getline.c
gl_tigetstr() and gl_tgetstr() didn't guard against the
error returns of tigetstr() and tgetstr() respectively.
They now do.
11/11/2001 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man3/gl_get_line.3
man3/gl_prompt_style.3
Although the default remains to display the prompt string
literally, the new gl_prompt_style() function can be used
to enable text attribute formatting directives in prompt
strings, such as underlining, bold font, and highlighting
directives.
09/11/2001 mcs@astro.caltech.edu
enhance.c Makefile.rules configure.in configure
I added a new program to the distribution that allows one
to run most third party programs with the tecla library
providing command-line editing.
08/11/2001 mcs@astro.caltech.edu
libtecla.h getline.c man3/gl_get_line.3 history.c history.h
I added a max_lines argument to gl_show_history() and
_glh_show_history(). This can optionally be used to
set a limit on the number of history lines displayed.
libtecla.h getline.c man3/gl_get_line.3
I added a new function called gl_replace_prompt(). This
can be used by gl_get_line() callback functions to
request that a new prompt be use when they return.
06/11/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
I implemented, bound and documented the list-history
action, used for listing historical lines of the current
history group.
getline.c man3/gl_get_line.3 man3/gl_echo_mode.3
I wrote functions to specify and query whether subsequent
lines will be visible as they are being typed.
28/10/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
For those cases where a terminal provides its own
high-level terminal editing facilities, you can now
specify an edit-mode argument of 'none'. This disables
all tecla key bindings, and by using canonical terminal
input mode instead of raw input mode, editing is left up
to the terminal driver.
21/10/2001 mcs@astro.caltech.edu
libtecla.h getline.c history.c history.h
man3/gl_get_line.3 man3/gl_history_info.3
I added the new gl_state_of_history(),
gl_range_of_history() and gl_size_of_history()
functions for querying information about the
history list.
history.c
While testing the new gl_size_of_history()
function, I noticed that when the history buffer
wrapped, any location nodes of old lines between
the most recent line and the end of the buffer
weren't being removed. This could result in bogus
entries appearing at the start of the history list.
Now fixed.
20/10/2001 mcs@astro.caltech.edu
libtecla.h getline.c history.c history.h
man3/gl_get_line.3 man3/gl_lookup_history.3
I added a function called gl_lookup_history(), that
the application can use to lookup lines in the history
list.
libtecla.h getline.c history.c history.h man3/gl_get_line.3
gl_show_history() now takes a format string argument
to control how the line is displayed, and with what
information. It also now provides the option of either
displaying all history lines or just those of the
current history group.
getline.c man3/gl_get_line.3
gl_get_line() only archives lines in the history buffer
if the newline action was invoked by a newline or
carriage return character.
16/10/2001 mcs@astro.caltech.edu
history.c history.h getline.c libtecla.h libtecla.map
man3/gl_get_line.3 man3/gl_resize_history.3
man3/gl_limit_history.3 man3/gl_clear_history.3
man3/gl_toggle_history.3
I added a number of miscellaneous history configuration
functions. You can now resize or delete the history
buffer, limit the number of lines that are allowed in the
buffer, clear either all history or just the history of
the current history group, and temporarily enable and
disable the history mechanism.
13/10/2001 mcs@astro.caltech.edu
getline.c
tputs_fp is now only declared if using termcap or
terminfo.
getline.c libtecla.map man3/gl_get_line.3
man3/gl_terminal_size.3
I added a public gl_terminal_size() function for
updating and querying the current size of the terminal.
update_version configure.in libtecla.h
A user noted that on systems where the configure script
couldn't be used, it was inconvenient to have the version
number macros set by the configure script, so they are
now specified in libtecla.h. To reduce the likelihood
that the various files where the version number now
appears might get out of sync, I have written the
update_version script, which changes the version number
in all of these files to a given value.
01/10/2001 mcs@astro.caltech.edu
getline.c history.c history.h man3/gl_get_line.3
I added a max_lines argument to gl_save_history(), to
allow people to optionally place a ceiling on the number
of history lines saved. Specifying this as -1 sets the
ceiling to infinity.
01/10/2001 mcs@astro.caltech.edu
configure.in configure
Under digital unix, getline wouldn't compile with
_POSIX_C_SOURCE set, due to type definitions needed by
select being excluded by this flag. Defining the
_OSF_SOURCE macro as well on this system, resolved this.
30/09/2001 mcs@astro.caltech.edu
getline.c libtecla.h history.c history.h man3/gl_get_line.3
man3/gl_group_history.3
I implemented history streams. History streams
effectively allow multiple history lists to be stored in
a single history buffer. Lines in the buffer are tagged
with the current stream identification number, and
lookups only consider lines that are marked with the
current stream identifier.
getline.c libtecla.h history.c history.h man3/gl_get_line.3
man3/gl_show_history.3
The new gl_show_history function displays the current
history to a given stdio output stream.
29/09/2001 mcs@astro.caltech.edu
getline.c
Previously new_GetLine() installed a persistent signal
handler to be sure to catch the SIGWINCH (terminal size
change) signal between calls to gl_get_line(). This had
the drawback that if multiple GetLine objects were
created, only the first GetLine object used after the
signal was received, would see the signal and adapt to
the new terminal size. Instead of this, a signal handler
for sigwinch is only installed while gl_get_line() is
running, and just after installing this handler,
gl_get_line() checks for terminal size changes that
might have occurred while the signal handler wasn't
installed.
getline.c
Dynamically allocated copies of capability strings looked
up in the terminfo or termcap databases are now made, so
that calls to setupterm() etc for one GetLine object
don't get trashed when another GetLine object calls
setupterm() etc. It is now safe to allocate and use
multiple GetLine objects, albeit only within a single
thread.
28/09/2001 mcs@astro.caltech.edu
version.c Makefile.rules
I added a function for querying the version number of
the library.
26/09/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
I added the new gl_watch_fd() function, which allows
applications to register callback functions to be invoked
when activity is seen on arbitrary file descriptors while
gl_get_line() is awaiting keyboard input from the user.
keytab.c
If a request is received to delete a non-existent
binding, which happens to be an ambiguous prefix of other
bindings no complaint is now generated about it being
ambiguous.
23/09/2001 mcs@astro.caltech.edu
getline.c history.c history.h man3/gl_get_line.3
libtecla.map demo.c
I added new public functions for saving and restoring the
contents of the history list. The demo program now uses
these functions to load and save history in ~/.demo_history.
23/09/2001 mcs@astro.caltech.edu
getline.c
On trying the demo for the first time on a KDE konsole
terminal, I discovered that the default M-O binding
to repeat history was hiding the arrow keys, which are
M-OA etc. I have removed this binding. The M-o (ie the
lower case version of this), is still bound.
18/09/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3 libtecla.map
Automatic reading of ~/.teclarc is now postponed until
the first call to gl_get_line(), to give the application
the chance to specify alternative configuration sources
with the new function gl_configure_getline(). The latter
function allows configuration to be done with a string, a
specified application-specific file, and/or a specified
user-specific file. I also added a read-init-files action
function, for re-reading the configuration files, if any.
This is by default bound to ^X^R. This is all documented
in gl_get_line.3.
08/09/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
It is now possible to bind actions to key-sequences
that start with printable characters. Previously
keysequences were required to start with meta or control
characters. This is documented in gl_get_line.3.
getline.c man3/gl_get_line.3
A customized completion function can now arrange for
gl_get_line() to return the current input line whenever a
successful completion has been made. This is signalled by
setting the last character of the optional continuation
suffix to a newline character. This is documented in
gl_get_line.3.
05/07/2001 Bug reported by Mike MacFaden, fixed by mcs
configure.in
There was a bug in the configure script that only
revealed itself on systems without termcap but not
terminfo (eg. NetBSD). I traced the bug back to a lack of
sufficient quoting of multi-line m4 macro arguments in
configure.in, and have now fixed this and recreated the
configure script.
05/07/2001 Bug reported and patched by Mike MacFaden (patch modified
by mcs to match original intentions).
getline.c
getline.c wouldn't compile when termcap was selected as
the terminal information database. setupterm() was being
passed a non-existent variable, in place of the term[]
argument of gl_control_strings(). Also if
gl_change_terminal() is called with term==NULL, "ansi"
is now substituted.
02/07/2001 Version 1.3.3 released.
27/06/2001 mcs@astro.caltech.edu
getline.c expand.c cplmatch.c
Added checks to fprintf() statements that write to the
terminal.
getline.c
Move the cursor to the end of the line before suspending,
so that the cursor doesn't get left in the middle of the
input line.
Makefile.in
On systems that don't support shared libraries, the
distclean target of make deleted libtecla.h. This has
now been fixed.
getline.c
gl_change_terminal() was being called by gl_change_editor(),
with the unwanted side effect that raw terminal modes were
stored as those to be restored later, if called by an
action function. gl_change_terminal() was being called in
this case to re-establish terminal-specific key bindings,
so I have just split this part of the function out into
a separate function for both gl_change_editor() and
gl_change_terminal() to call.
12/06/2001 mcs@astro.caltech.edu
getline.c
Signal handling has been improved. Many more signals are
now trapped, and instead of using a simple flag set by a
signal handler, race conditions are avoided by blocking
signals during most of the gl_get_line() code, and
unblocking them via calls to sigsetjmp(), just before
attempting to read each new character from the user.
The matching use of siglongjmp() in the signal
handlers ensures that signals are reblocked correctly
before they are handled. In most cases, signals cause
gl_get_line() to restore the terminal modes and signal
handlers of the calling application, then resend the
signal to the application. In the case of SIGINT, SIGHUP,
SIGPIPE, and SIGQUIT, if the process still exists after
the signals are resent, gl_get_line() immediately returns
with appropriate values assigned to errno. If SIGTSTP,
SIGTTIN or SIGTTOU signals are received, the process is
suspended. If any other signal is received, and the
process continues to exist after the signal is resent to
the calling application, line input is resumed after the
terminal is put back into raw mode, the gl_get_line()
signal handling is restored, and the input line redrawn.
man/gl_get_line(3)
I added a SIGNAL HANDLING section to the gl_get_line()
man page, describing the new signal handling features.
21/05/2001 Version 1.3.2 released.
21/05/2001 mcs@astro.caltech.edu
getline.c
When vi-replace-char was used to replace the character at
the end of the line, it left the cursor one character to
its right instead of on top of it. Now rememdied.
getline.c
When undoing, to properly emulate vi, the cursor is now
left at the leftmost of the saved and current cursor
positions.
getline.c man3/gl_get_line.3
Implemented find-parenthesis (%), delete-to-paren (M-d%),
vi-change-to-paren (M-c%), copy-to-paren (M-y%).
cplfile.c pcache.c
In three places I was comparing the last argument of
strncmp() to zero instead of the return value of
strncmp().
20/05/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
Implemented and documented the vi-repeat-change action,
bound to the period key. This repeats the last action
that modified the input line.
19/05/2001 mcs@astro.caltech.edu
man3/gl_get_line.3
I documented the new action functions and bindings
provided by Tim Eliseo, plus the ring-bell action and
the new "nobeep" configuration option.
getline.c
I modified gl_change_editor() to remove and reinstate the
terminal settings as well as the default bindings, since
these have editor-specific differences. I also modified
it to not abort if a key-sequence can't be bound for some
reason. This allows the new vi-mode and emacs-mode
bindings to be used safely.
getline.c
When the line was re-displayed on receipt of a SIGWINCH
signal, the result wasn't visible until the next
character was typed, since a call to fflush() was needed.
gl_redisplay_line() now calls gl_flush_output() to remedy
this.
17/05/2001 mcs@astro.catlech.edu
getline.c
Under Linux, calling fflush(gl->output_fd) hangs if
terminal output has been suspended with ^S. With the
tecla library taking responsability for reading the stop
and start characters this was a problem, because once
hung in fflush(), the keyboard input loop wasn't entered,
so the user couldn't type the start character to resume
output. To remedy this, I now have the terminal process
these characters, rather than the library.
12/05/2001 mcs@astro.caltech.edu
getline.c
The literal-next action is now implemented as a single
function which reads the next character itself.
Previously it just set a flag which effected the
interpretation of the next character read by the input
loop.
getline.c
Added a ring-bell action function. This is currently
unbound to any key by default, but it is used internally,
and can be used by users that want to disable any of the
default key-bindings.
12/05/2001 Tim Eliseo (logged here by mcs)
getline.c
Don't reset gl->number until after calling an action
function. By looking at whether gl->number is <0 or
not, action functions can then tell whether the count
that they were passed was explicitly specified by the
user, as opposed to being defaulted to 1.
getline.c
In vi, the position at which input mode is entered
acts as a barrier to backward motion for the few
backward moving actions that are enabled in input mode.
Tim added this barrier to getline.
getline.c
In gl_get_line() after reading an input line, or
having the read aborted by a signal, the sig_atomic_t
gl_pending_signal was being compared to zero instead
of -1 to see if no signals had been received.
gl_get_line() will thus have been calling raise(-1),
which luckily didn't seem to do anything. Tim also
arranged for errno to be set to EINTR when a signal
aborts gl_get_line().
getline.c
The test in gl_add_char_to_line() for detecting
when overwriting a character with a wider character,
had a < where it needed a >. Overwriting with a wider
character thus overwrote trailing characters. Tim also
removed a redundant copy of the character into the
line buffer.
getline.c
gl_cursor_left() and gl->cursor_right() were executing
a lot of redundant code, when the existing call to the
recently added gl_place_cursor() function, does all that
is necessary.
getline.c
Remove redundant code from backward_kill_line() by
re-implimenting in terms of gl_place_cursor() and
gl_delete_chars().
getline.c
gl_forward_delete_char() now records characters in cut
buffer when in vi command mode.
getline.c
In vi mode gl_backward_delete_char() now only deletes
up to the point at which input mode was entered. Also
gl_delete_chars() restores from the undo buffer when
deleting in vi insert mode.
getline.c
Added action functions, vi-delete-goto-column,
vi-change-to-bol, vi-change-line, emacs-mode, vi-mode,
vi-forward-change-find, vi-backward-change-find,
vi-forward-change-to, vi-backward-change-to,
vi-change-goto-col, forward-delete-find, backward-delete-find,
forward-delete-to, backward-delete-to,
delete-refind, delete-invert-refind, forward-copy-find,
backward-copy-find, forward-copy-to, backward-copy-to
copy-goto-column, copy-rest-of-line, copy-to-bol, copy-line,
history-re-search-forward, history-re-search-backward.
06/05/2001 Version 1.3.1 released.
03/05/2001 mcs@astro.caltech.edu
configure.in
Old versions of GNU ld don't accept version scripts.
Under Linux I thus added a test to try out ld with
the --version-script argument to see if it works.
If not, version scripts aren't used.
configure.in
My test for versions of Solaris earlier than 7
failed when confronted by a three figure version
number (2.5.1). Fixed.
30/04/2001 mcs@astro.caltech.edu
getline.c
In vi mode, history-search-backward and
history-search-forward weren't doing anything when
invoked at the start of an empty line, whereas
they should have acted like up-history and down-history.
Makefile.in Makefile.rules
When shared libraries are being created, the build
procedure now arranges for any alternate library
links to be created as well, before linking the
demos. Without this the demos always linked to the
static libraries (which was perfectly ok, but wasn't a
good example).
Makefile.in Makefile.rules
On systems on which shared libraries were being created,
if there were no alternate list of names, make would
abort due to a Bourne shell 'for' statement that didn't
have any arguments. Currently there are no systems who's
shared library configurations would trigger this
problem.
Makefile.rules
The demos now relink to take account of changes to the
library.
configure.in configure
When determining whether the reentrant version of the
library should be compiled by default, the configure
script now attempts to compile a dummy program that
includes all of the appropriate system headers and
defines _POSIX_C_SOURCE. This should now be a robust test
on systems which use C macros to alias these function
names to other internal functions.
configure.in
Under Solaris 2.6 and earlier, the curses library is in
/usr/ccs/lib. Gcc wasn't finding this. In addition to
remedying this, I had to remove "-z text" from
LINK_SHARED under Solaris to get it to successfully
compile the shared library against the static curses
library.
configure.in
Under Linux the -soname directive was being used
incorrectly, citing the fully qualified name of the
library instead of its major version alias. This will
unfortunately mean that binaries linked with the 1.2.3
and 1.2.4 versions of the shared library won't use
later versions of the library unless relinked.
30/04/2001 mcs@astro.caltech.edu
getline.c
In gl_get_input_line(), don't redundantly copy the
start_line if start_line == gl->line.
30/04/2001 Version 1.3.0 released.
28/04/2001 mcs@astro.caltech.edu
configure.in
I removed the --no-undefined directive from the Linux
LINK_SHARED command. After recent patches to our RedHat
7.0 systems ld started reporting some internal symbols of
libc as being undefined. Using nm on libc indicated that
the offending symbols are indeed defined, albeit as
"common" symbols, so there appears to be a bug in
RedHat's ld. Removing this flag allows the tecla shared
library to compile, and programs appear to function fine.
man3/gl_get_line.3
The default key-sequence used to invoke the
read-from-file action was incorrectly cited as ^Xi
instead of ^X^F.
26/04/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
A new vi-style editing mode was added. This involved
adding many new action functions, adding support for
specifying editing modes in users' ~/.teclarc files,
writing a higher level cursor motion function to support
the different line-end bounds required in vi command
mode, and a few small changes to support the fact that vi
has two modes, input mode and command mode with different
bindings.
When vi editing mode is enabled, any binding that starts
with an escape or a meta character, is interpreted as a
command-mode binding, and switches the library to vi
command mode if not already in that mode. Once in command
mode the first character of all keysequences entered
until input mode is re-enabled, are quietly coerced to
meta characters before being looked up in the key-binding
table. So, for example, in the key-binding table, the
standard vi command-mode 'w' key, which moves the cursor
one word to the right, is represented by M-w. This
emulates vi's dual sets of bindings in a natural way
without needing large changes to the library, or new
binding syntaxes. Since cursor keys normally emit
keysequences which start with escape, it also does
something sensible when a cursor key is pressed during
input mode (unlike true vi, which gets upset).
I also added a ^Xg binding for the new list-glob action
to both the emacs and vi key-binding tables. This lists
the files that match the wild-card expression that
precedes it on the command line.
The function that reads in ~/.teclarc used to tell
new_GetLine() to abort if it encountered anything that it
didn't understand in this file. It now just reports an
error and continues onto the next line.
Makefile.in:
When passing LIBS=$(LIBS) to recursive invokations of
make, quotes weren't included around the $(LIBS) part.
This would cause problems if LIBS ever contained more
than one word (with the supplied configure script this
doesn't happen currently). I added these quotes.
expand.c man3/ef_expand_file.3:
I wrote a new public function called ef_list_expansions(),
to list the matching filenames returned by
ef_expand_file().
I also fixed the example in the man page, which cited
exp->file instead of exp->files, and changed the
dangerous name 'exp' with 'expn'.
keytab.c:
Key-binding tables start with 100 elements, and are
supposedly incremented in size by 100 elements whenever
the a table runs out of space. The realloc arguments to
do this were wrong. This would have caused problems if
anybody added a lot of personal bindings in their
~/.teclarc file. I only noticed it because the number of
key bindings needed by the new vi mode exceeded this
number.
libtecla.map
ef_expand_file() is now reported as having been added in
the upcoming 1.3.0 release.
25/03/2001 Markus Gyger (logged here by mcs)
Makefile.in:
Make symbolic links to alternative shared library names
relative instead of absolute.
Makefile.rules:
The HP-UX libtecla.map.opt file should be made in the
compilation directory, to allow the source code directory
to be on a readonly filesystem.
cplmatch.c demo2.c history.c pcache.c
To allow the library to be compiled with a C++ compiler,
without generating warnings, a few casts were added where
void* return values were being assigned directly to
none void* pointer variables.
25/03/2001 mcs@astro.caltech.edu
libtecla.map:
Added comment header to explain the purpose of the file.
Also added cpl_init_FileArgs to the list of exported
symbols. This symbol is deprecated, and no longer
documented, but for backwards compatibility, it should
still be exported.
configure:
I had forgotten to run autoconf before releasing version
1.2.4, so I have just belatedly done so. This enables
Markus' changes to "configure.in" documented previously,
(see 17/03/2001).
20/03/2001 John Levon (logged here by mcs)
libtecla.h
A couple of the function prototypes in libtecla.h have
(FILE *) argument declarations, which means that stdio.h
needs to be included. The header file should be self
contained, so libtecla.h now includes stdio.h.
18/03/2001 Version 1.2.4 released.
README html/index.html configure.in
Incremented minor version from 3 to 4.
18/03/2001 mcs@astro.caltech.edu
getline.c
The fix for the end-of-line problem that I released a
couple of weeks ago, only worked for the first line,
because I was handling this case when the cursor position
was equal to the last column, rather than when the cursor
position modulo ncolumn was zero.
Makefile.in Makefile.rules
The demos are now made by default, their rules now being
int Makefile.rules instead of Makefile.in.
INSTALL
I documented how to compile the library in a different
directory than the distribution directory.
I also documented features designed to facilitate
configuring and building the library as part of another
package.
17/03/2001 Markus Gyger (logged here by mcs)
getline.c
Until now cursor motions were done one at a time. Markus
has added code to make use the of the terminfo capability
that moves the cursor by more than one position at a
time. This greatly improves performance when editing near
the start of long lines.
getline.c
To further improve performance, Markus switched from
writing one character at a time to the terminal, using
the write() system call, to using C buffered output
streams. The output buffer is only flushed when
necessary.
Makefile.rules Makefile.in configure.in
Added support for compiling for different architectures
in different directories. Simply create another directory
and run the configure script located in the original
directory.
Makefile.in configure.in libtecla.map
Under Solaris, Linux and HP-UX, symbols that are to be
exported by tecla shared libraries are explicitly specified
via symbol map files. Only publicly documented functions
are thus visible to applications.
configure.in
When linking shared libraries under Solaris SPARC,
registers that are reserved for applications are marked
as off limits to the library, using -xregs=no%appl when
compiling with Sun cc, or -mno-app-regs when compiling
with gcc. Also removed -z redlocsym for Solaris, which
caused problems under some releases of ld.
homedir.c (after minor changes by mcs)
Under ksh, ~+ expands to the current value of the ksh
PWD environment variable, which contains the path of
the current working directory, including any symbolic
links that were traversed to get there. The special
username "+" is now treated equally by tecla, except
that it substitutes the return value of getcwd() if PWD
either isn't set, or if it points at a different
directory than that reported by getcwd().
08/03/2001 Version 1.2.3 released.
08/03/2001 mcs@astro.caltech.edu
getline.c
On compiling the library under HP-UX for the first time
I encountered and fixed a couple of bugs:
1. On all systems except Solaris, the callback function
required by tputs() takes an int argument for the
character that is to be printed. Under Solaris it
takes a char argument. The callback function was
passing this argument, regardless of type, to write(),
which wrote the first byte of the argument. This was
fine under Solaris and under little-endian systems,
because the first byte contained the character to be
written, but on big-endian systems, it always wrote
the zero byte at the other end of the word. As a
result, no control characters were being written to
the terminal.
2. While attempting to start a newline after the user hit
enter, the library was outputting the control sequence
for moving the cursor down, instead of the newline
character. On many systems the control sequence for
moving the cursor down happends to be a newline
character, but under HP-UX it isn't. The result was
that no new line was being started under HP-UX.
04/03/2001 mcs@astro.caltech.edu
configure.in Makefile.in Makefile.stub configure config.guess
config.sub Makefile.rules install-sh PORTING README INSTALL
Configuration and compilation of the library is now
performed with the help of an autoconf configure
script. In addition to relieving the user of the need to
edit the Makefile, this also allows automatic compilation
of the reentrant version of the library on platforms that
can handle it, along with the creation of shared
libraries where configured. On systems that aren't known
to the configure script, just the static tecla library is
compiled. This is currently the case on all systems
except Linux, Solaris and HP-UX. In the hope that
installers will provide specific conigurations for other
systems, the configure.in script is heavily commented,
and instructions on how to use are included in a new
PORTING file.
24/02/2001 Version 1.2b released.
22/02/2001 mcs@astro.caltech.edu
getline.c
It turns out that most terminals, but not all, on writing
a character in the rightmost column, don't wrap the
cursor onto the next line until the next character is
output. This library wasn't aware of this and thus if one
tried to reposition the cursor from the last column,
gl_get_line() thought that it was moving relative to a
point on the next line, and thus moved the cursor up a
line. The fix was to write one extra character when in
the last column to force the cursor onto the next line,
then backup the cursor to the start of the new line.
getline.c
On terminal initialization, the dynamic LINES and COLUMNS
environment variables were ignored unless
terminfo/termcap didn't return sensible dimensions. In
practice, when present they should override the static
versions in the terminfo/termcap databases. This is the
new behavior. In reality this probably won't have caused
many problems, because a SIGWINCH signal which informs of
terminal size changes is sent when the terminal is
opened, so the dimensions established during
initialization quickly get updated on most systems.
18/02/2001 Version 1.2a released.
18/02/2001 mcs@astro.caltech.edu
getline.c
Three months ago I moved the point at which termios.h
was included in getline.c. Unfortunately, I didn't notice
that this moved it to after the test for TIOCGWINSZ being
defined. This resulted in SIGWINCH signals not being
trapped for, and thus terminal size changes went
unnoticed. I have now moved the test to after the
inclusion of termios.h.
12/02/2001 Markus Gyger (described here by mcs)
man3/pca_lookup_file.3 man3/gl_get_line.3
man3/ef_expand_file.3 man3/cpl_complete_word.3
In the 1.2 release of the library, all functions in the
library were given man pages. Most of these simply
include one of the above 4 man pages, which describe the
functions while describing the modules that they are in.
Markus added all of these function names to the lists in
the "NAME" headers of the respective man pages.
Previously only the primary function of each module was
named there.
11/02/2001 mcs@astro.caltech.edu
getline.c
On entering a line that wrapped over two or more
terminal, if the user pressed enter when the cursor
wasn't on the last of the wrapped lines, the text of the
wrapped lines that followed it got mixed up with the next
line written by the application, or the next input
line. Somehow this slipped through the cracks and wasn't
noticed until now. Anyway, it is fixed now.
09/02/2001 Version 1.2 released.
04/02/2001 mcs@astro.caltech.edu
pcache.c libtecla.h
With all filesystems local, demo2 was very fast to start
up, but on a Sun system with one of the target
directories being on a remote nfs mounted filesystem, the
startup time was many seconds. This was due to the
executable selection callback being applied to all files
in the path at startup. To avoid this, all files are now
included in the cache, and the application specified
file-selection callback is only called on files as they
are matched. Whether the callback rejected or accepted
them is then cached so that the next time an already
checked file is looked at, the callback doesn't have to
be called. As a result, startup is now fast on all
systems, and since usually there are only a few matching
file completions at a time, the delay during completion
is also usually small. The only exception is if the user
tries to complete an empty string, at which point all
files have to be checked. Having done this once, however,
doing it again is fast.
man3/pca_lookup_file.3
I added a man page documenting the new PathCache module.
man3/<many-new-files>.3
I have added man pages for all of the functions in each
of the modules. These 1-line pages use the .so directive
to redirect nroff to the man page of the parent module.
man Makefile update_html
I renamed man to man3 to make it easier to test man page
rediction, and updated Makefile and update_html
accordingly. I also instructed update_html to ignore
1-line man pages when making html equivalents of the man
pages.
cplmatch.c
In cpl_list_completions() the size_t return value of
strlen() was being used as the length argument of a "%*s"
printf directive. This ought to be an int, so the return
value of strlen() is now cast to int. This would have
caused problems on architectures where the size of a
size_t is not equal to the size of an int.
02/02/2001 mcs@astro.caltech.edu
getline.c
Under UNIX, certain terminal bindings are set using the
stty command. This, for example, specifies which control
key generates a user-interrupt (usually ^C or ^Y). What I
hadn't realized was that ASCII NUL is used as the way to
specify that one of these bindings is unset. I have now
modified the code to skip unset bindings, leaving the
corresponding action bound to the built-in default, or a
user provided binding.
28/01/2001 mcs@astro.caltech.edu
pcache.c libtecla.h
A new module was added which supports searching for files
in any colon separated list of directories, such as the
unix execution PATH environment variable. Files in these
directories, after being individually okayed for
inclusion via an application provided callback, are
cached in a PathCache object. You can then look up the
full pathname of a given filename, or you can use the
provided completion callback to list possible completions
in the path-list. The contents of relative directories,
such as ".", obviously can't be cached, so these
directories are read on the fly during lookups and
completions. The obvious application of this facility is
to provide Tab-completion of commands, and thus a
callback to place executable files in the cache, is
provided.
demo2.c
This new program demonstrates the new PathCache
module. It reads and processes lines of input until the
word 'exit' is entered, or C-d is pressed. The default
tab-completion callback is replaced with one which at the
start of a line, looks up completions of commands in the
user's execution path, and when invoked in other parts of
the line, reverts to normal filename completion. Whenever
a new line is entered, it extracts the first word on the
line, looks it up in the user's execution path to see if
it corresponds to a known command file, and if so,
displays the full pathname of the file, along with the
remaining arguments.
cplfile.c
I added an optional pair of callback function/data
members to the new cpl_file_completions() configuration
structure. Where provided, this callback is asked
on a file-by-file basis, which files should be included
in the list of file completions. For example, a callback
is provided for listing only completions of executable
files.
cplmatch.c
When listing completions, the length of the type suffix
of each completion wasn't being taken into account
correctly when computing the column widths. Thus the
listing appeared ragged sometimes. This is now fixed.
pathutil.c
I added a function for prepending a string to a path,
and another for testing whether a pathname referred to
an executable file.
28/01/2001 mcs@astro.caltech.edu
libtecla.h cplmatch.c man/cpl_complete_word.3
The use of a publically defined structure to configure
the cpl_file_completions() callback was flawed, so a new
approach has been designed, and the old method, albeit
still supported, is no longer documented in the man
pages. The definition of the CplFileArgs structure in
libtecla.h is now accompanied by comments warning people
not to modify it, since modifications could break
applications linked to shared versions of the tecla
library. The new method involves an opaque CplFileConf
object, instances of which are returned by a provided
constructor function, configured with provided accessor
functions, and when no longer needed, deleted with a
provided destructor function. This is documented in the
cpl_complete_word man page. The cpl_file_completions()
callback distinguishes what type of configuration
structure it has been sent by virtue of a code placed at
the beginning of the CplFileConf argument by its
constructor.
04/01/2001 mcs@astro.caltech.edu (Release of version 1.1j)
getline.c
I added upper-case bindings for the default meta-letter
keysequences such as M-b. They thus continue to work
when the user has caps-lock on.
Makefile
I re-implemented the "install" target in terms of new
install_lib, install_inc and install_man targets. When
distributing the library with other packages, these new
targets allows for finer grained control of the
installation process.
30/12/2000 mcs@astro.caltech.edu
getline.c man/gl_get_line.3
I realized that the recall-history action that I
implemented wasn't what Markus had asked me for. What he
actually wanted was for down-history to continue going
forwards through a previous history recall session if no
history recall session had been started while entering
the current line. I have thus removed the recall-history
action and modified the down-history action function
accordingly.
24/12/2000 mcs@astro.caltech.edu
getline.c
I modified gl_get_line() to allow the previously returned
line to be passed in the start_line argument.
getline.c man/gl_get_line.3
I added a recall-history action function, bound to M^P.
This recalls the last recalled history line, regardless
of whether it was from the current or previous line.
13/12/2000 mcs@astro.caltech.edu (Release of version 1.1i)
getline.c history.h history.c man/gl_get_line.3
I implemented the equivalent of the ksh Operate action. I
have named the tecla equivalent "repeat-history". This
causes the line that is to be edited to returned, and
arranges for the next most recent history line to be
preloaded on the next call to gl_get_line(). Repeated
invocations of this action thus result in successive
history lines being repeated - hence the
name. Implementing the ksh Operate action was suggested
by Markus Gyger. In ksh it is bound to ^O, but since ^O
is traditionally bound by the default terminal settings,
to stop-output, I have bound the tecla equivalent to M-o.
01/12/2000 mcs@astro.caltech.edu (Release of version 1.1h)
getline.c keytab.c keytab.h man/gl_get_line.3
I added a digit-argument action, to allow repeat
counts for actions to be entered. As in both tcsh
and readline, this is bound by default to each of
M-0, M-1 through to M-9, the number being appended
to the current repeat count. Once one of these has been
pressed, the subsequent digits of the repeat count can be
typed with or without the meta key pressed. It is also
possible to bind digit-argument to other keys, with or
without a numeric final keystroke. See man page for
details.
getline.c man/gl_get_line.3
Markus noted that my choice of M-< for the default
binding of read-from-file, could be confusing, since
readline binds this to beginning-of-history. I have
thus rebound it to ^X^F (ie. like find-file in emacs).
getline.c history.c history.h man/gl_get_line.3
I have now implemented equivalents of the readline
beginning-of-history and end-of-history actions.
These are bound to M-< and M-> respectively.
history.c history.h
I Moved the definition of the GlHistory type, and
its subordinate types from history.h to history.c.
There is no good reason for any other module to
have access to the innards of this structure.
27/11/2000 mcs@astro.caltech.edu (Release of version 1.1g)
getline.c man/gl_get_line.3
I added a "read-from-file" action function and bound it
by default to M-<. This causes gl_get_line() to
temporarily return input from the file who's name
precedes the cursor.
26/11/2000 mcs@astro.caltech.edu
getline.c keytab.c keytab.h man/gl_get_line.3
I have reworked some of the keybinding code again.
Now, within key binding strings, in addition to the
previously existing notation, you can now use M-a to
denote meta-a, and C-a to denote control-a. For example,
a key binding which triggers when the user presses the
meta key, the control key and the letter [
simultaneously, can now be denoted by M-C-[, or M-^[ or
\EC-[ or \E^[.
I also updated the man page to use M- instead of \E in
the list of default bindings, since this looks cleaner.
getline.c man/gl_get_line.3
I added a copy-region-as-kill action function and
gave it a default binding to M-w.
22/11/2000 mcs@astro.caltech.edu
*.c
Markus Gyger sent me a copy of a previous version of
the library, with const qualifiers added in appropriate
places. I have done the same for the latest version.
Among other things, this gets rid of the warnings
that are generated if one tells the compiler to
const qualify literal strings.
getline.c getline.h glconf.c
I have moved the contents of glconf.c and the declaration
of the GetLine structure into getline.c. This is cleaner,
since now only functions in getline.c can mess with the
innards of GetLine objects. It also clears up some problems
with system header inclusion order under Solaris, and also
the possibility that this might result in inconsistent
system macro definitions, which in turn could cause different
declarations of the structure to be seen in different files.
hash.c
I wrote a wrapper function to go around strcmp(), such that
when hash.c is compiled with a C++ compiler, the pointer
to the wrapper function is a C++ function pointer.
This makes it compatible with comparison function pointer
recorded in the hash table.
cplmatch.c getline.c libtecla.h
Markus noted that the Sun C++ compiler wasn't able to
match up the declaration of cpl_complete_word() in
libtecla.h, where it is surrounded by a extern "C" {}
wrapper, with the definition of this function in
cplmatch.c. My suspicion is that the compiler looks not
only at the function name, but also at the function
arguments to see if two functions match, and that the
match_fn() argument, being a fully blown function pointer
declaration, got interpetted as that of a C function in
one case, and a C++ function in the other, thus
preventing a match.
To fix this I now define a CplMatchFn typedef in libtecla.h,
and use this to declare the match_fn callback.
20/11/2000 (Changes suggested by Markus Gyger to support C++ compilers):
expand.c
Renamed a variable called "explicit" to "xplicit", to
avoid conflicts when compiling with C++ compilers.
*.c
Added explicit casts when converting from (void *) to
other pointer types. This isn't needed in C but it is
in C++.
getline.c
tputs() has a strange declaration under Solaris. I was
enabling this declaration when the SPARC feature-test
macro was set. Markus changed the test to hinge on the
__sun and __SVR4 macros.
direader.c glconf.c stringrp.c
I had omitted to include string.h in these two files.
Markus also suggested some other changes, which are still
under discussion. With the just above changes however, the
library compiles without complaint using g++.
19/11/2000 mcs@astro.caltech.edu
getline.h getline.c keytab.c keytab.h glconf.c
man/gl_get_line.3
I added support for backslash escapes (include \e
for the keyboard escape key) and literal binary
characters to the characters allowed within key sequences
of key bindings.
getline.h getline.c keytab.c keytab.h glconf.c
man/gl_get_line.3
I introduced symbolic names for the arrow keys, and
modified the library to use the cursor key sequences
reported by terminfo/termcap in addition to the default
ANSI ones. Anything bound to the symbolically named arrow
keys also gets bound to the default and terminfo/termcap
cursor key sequences. Note that under Solaris
terminfo/termcap report the properties of hardware X
terminals when TERM is xterm instead of the terminal
emulator properties, and the cursor keys on these two
systems generate different key sequences. This is an
example of why extra default sequences are needed.
getline.h getline.c keytab.c
For some reason I was using \e to represent the escape
character. This is supported by gcc, which thus doesn't
emit a warning except with the -pedantic flag, but isn't
part of standard C. I now use a macro to define escape
as \033 in getline.h, and this is now used wherever the
escape character is needed.
17/11/2000 mcs@astro.caltech.edu (Release of version 1.1d)
getline.c, man/gl_get_line(3), html/gl_get_line.html
In tcsh ^D is bound to a function which does different
things depending on where the cursor is within the input
line. I have implemented its equivalent in the tecla
library. When invoked at the end of the line this action
function displays possible completions. When invoked on
an empty line it causes gl_get_line() to return NULL,
thus signalling end of input. When invoked within a line
it invokes forward-delete-char, as before. The new action
function is called del-char-or-list-or-eof.
getline.c, man/gl_get_line(3), html/gl_get_line.html
I found that the complete-word and expand-file actions
had underscores in their names instead of hyphens. This
made them different from all other action functions, so I
have changed the underscores to hyphens.
homedir.c
On SCO UnixWare while getpwuid_r() is available, the
associated _SC_GETPW_R_SIZE_MAX macro used by sysconf()
to find out how big to make the buffer to pass to this
function to cater for any password entry, doesn't
exist. I also hadn't catered for the case where sysconf()
reports that this limit is indeterminate. I have thus
change the code to substitute a default limit of 1024 if
either the above macro isn't defined or if sysconf() says
that the associated limit is indeterminate.
17/11/2000 mcs@astro.caltech.edu (Release of version 1.1c)
getline.c, getline.h, history.c, history.h
I have modified the way that the history recall functions
operate, to make them better emulate the behavior of
tcsh. Previously the history search bindings always
searched for the prefix that preceded the cursor, then
left the cursor at the same point in the line, so that a
following search would search using the same prefix. This
isn't how tcsh operates. On finding a matching line, tcsh
puts the cursor at the end of the line, but arranges for
the followup search to continue with the same prefix,
unless the user does any cursor motion or character
insertion operations in between, in which case it changes
the search prefix to the new set of characters that are
before the cursor. There are other complications as well,
which I have attempted to emulate. As far as I can
tell, the tecla history recall facilities now fully
emulate those of tcsh.
16/11/2000 mcs@astro.caltech.edu (Release of version 1.1b)
demo.c:
One can now quit from the demo by typing exit.
keytab.c:
The first entry of the table was getting deleted
by _kt_clear_bindings() regardless of the source
of the binding. This deleted the up-arrow binding.
Symptoms noted by gazelle@yin.interaccess.com.
getline.h:
Depending on which system include files were include
before the inclusion of getline.h, SIGWINCH and
TIOCGWINSZ might or might not be defined. This resulted
in different definitions of the GetLine object in
different files, and thus some very strange bugs! I have
now added #includes for the necessary system header files
in getline.h itself. The symptom was that on creating a
~/.teclarc file, the demo program complained of a NULL
argument to kt_set_keybinding() for the first line of the
file.
15/11/2000 mcs@astro.caltech.edu (Release of version 1.1a)
demo.c:
I had neglected to check the return value of
new_GetLine() in the demo program. Oops.
getline.c libtecla.h:
I wrote gl_change_terminal(). This allows one to change to
a different terminal or I/O stream, by specifying the
stdio streams to use for input and output, along with the
type of terminal that they are connected to.
getline.c libtecla.h:
Renamed GetLine::isterm to GetLine::is_term. Standard
C reserves names that start with "is" followed by
alphanumeric characters, so this avoids potential
clashes in the future.
keytab.c keytab.h
Each key-sequence can now have different binding
functions from different sources, with the user provided
binding having the highest precedence, followed by the
default binding, followed by any terminal specific
binding. This allows gl_change_terminal() to redefine the
terminal-specific bindings each time that
gl_change_terminal() is called, without overwriting the
user specified or default bindings. In the future, it will
also allow for reconfiguration of user specified
bindings after the call to new_GetLine(). Ie. deleting a
user specified binding should reinstate any default or
terminal specific binding.
man/cpl_complete_word.3 html/cpl_complete_word.html
man/ef_expand_file.3 html/ef_expand_file.html
man/gl_get_line.3 html/gl_get_line.html
I added sections on thread safety to the man pages of the
individual modules.
man/gl_get_line.3 html/gl_get_line.html
I documented the new gl_change_terminal() function.
man/gl_get_line.3 html/gl_get_line.html
In the description of the ~/.teclarc configuration file,
I had omitted the 'bind' command word in the example
entry. I have now remedied this.
./libtecla/html/pca_lookup_file.html 0100644 0000764 0000764 00000034134 10141252547 016124 0 ustar mcs mcs
pca_lookup_file pca_lookup_file
pca_lookup_file, del_PathCache, del_PcaPathConf, new_PathCache,
new_PcaPathConf, pca_last_error, pca_path_completions, pca_scan_path,
pca_set_check_fn, ppc_file_start, ppc_literal_escapes - lookup a file
in a list of directories
#include <libtecla.h>
PathCache *new_PathCache(void);
PathCache *del_PathCache(PathCache *pc);
int pca_scan_path(PathCache *pc, const char *path);
void pca_set_check_fn(PathCache *pc, CplCheckFn *check_fn,
void *data);
char *pca_lookup_file(PathCache *pc, const char *name,
int name_len, int literal);
const char *pca_last_error(PathCache *pc);
CPL_MATCH_FN(pca_path_completions);
The PathCache object is part of the tecla library (see the libte-
cla(@LIBR_MANEXT@) man page).
PathCache objects allow an application to search for files in any colon
separated list of directories, such as the unix execution PATH environ-
ment variable. Files in absolute directories are cached in a PathCache
object, whereas relative directories are scanned as needed. Using a
PathCache object, you can look up the full pathname of a simple file-
name, or you can obtain a list of the possible completions of a given
filename prefix. By default all files in the list of directories are
targets for lookup and completion, but a versatile mechanism is pro-
vided for only selecting specific types of files. The obvious applica-
tion of this facility is to provide Tab-completion and lookup of exe-
cutable commands in the unix PATH, so an optional callback which
rejects all but executable files, is provided.
Under UNIX, the following example program looks up and displays the
full pathnames of each of the command names on the command line.
#include <stdio.h>
#include <stdlib.h>
#include <libtecla.h>
int main(int argc, char *argv[])
{
int i;
/*
* Create a cache for executable files.
*/
PathCache *pc = new_PathCache();
if(!pc)
exit(1);
/*
* Scan the user's PATH for executables.
*/
if(pca_scan_path(pc, getenv("PATH"))) {
fprintf(stderr, "%s\n", pca_last_error(pc));
exit(1);
}
/*
* Arrange to only report executable files.
*/
pca_set_check_fn(pc, cpl_check_exe, NULL);
/*
* Lookup and display the full pathname of each of the
* commands listed on the command line.
*/
for(i=1; i<argc; i++) {
char *cmd = pca_lookup_file(pc, argv[i], -1, 0);
printf("The full pathname of '%s' is %s\n", argv[i],
cmd ? cmd : "unknown");
}
pc = del_PathCache(pc); /* Clean up */
return 0;
}
The following is an example of what this does on my laptop under linux:
$ ./example less more blob
The full pathname of 'less' is /usr/bin/less
The full pathname of 'more' is /bin/more
The full pathname of 'blob' is unknown
$
In order to use the facilities of this module, you must first allocate
a PathCache object by calling the new_PathCache() constructor function.
PathCache *new_PathCache(void)
This function creates the resources needed to cache and lookup files in
a list of directories. It returns NULL on error.
Once you have created a cache, it needs to be populated with files. To
do this, call the pca_scan_path() function.
int pca_scan_path(PathCache *pc, const char *path);
Whenever this function is called, it discards the current contents of
the cache, then scans the list of directories specified in its path
argument for files. The path argument must be a string containing a
colon-separated list of directories, such as
"/usr/bin:/home/mcs/bin:.". This can include directories specified by
absolute pathnames such as "/usr/bin", as well as sub-directories spec-
ified by relative pathnames such as "." or "bin". Files in the absolute
directories are immediately cached in the specified PathCache object,
whereas sub-directories, whose identities obviously change whenever the
current working directory is changed, are marked to be scanned on the
fly whenever a file is looked up.
On success this function return 0. On error it returns 1, and a
description of the error can be obtained by calling pca_last_error(pc).
Once the cache has been populated with files, you can look up the full
pathname of a file, simply by specifying its filename to
pca_lookup_file().
char *pca_lookup_file(PathCache *pc, const char *name,
int name_len, int literal);
To make it possible to pass this function a filename which is actually
part of a longer string, the name_len argument can be used to specify
the length of the filename at the start of the name[] argument. If you
pass -1 for this length, the length of the string will be determined
with strlen(). If the name[] string might contain backslashes that
escape the special meanings of spaces and tabs within the filename,
give the literal argument, the value 0. Otherwise, if backslashes
should be treated as normal characters, pass 1 for the value of the
literal argument.
Looking up the potential completions of a filename-prefix in the file-
name cache, is achieved by passing the provided pca_path_completions()
callback function to the cpl_complete_word() function (see the cpl_com-
plete_word(@FUNC_MANEXT@) man page).
CPL_MATCH_FN(pca_path_completions);
This callback requires that its data argument be a pointer to a PcaP-
athConf object. Configuration objects of this type are allocated by
calling new_PcaPathConf().
PcaPathConf *new_PcaPathConf(PathCache *pc);
This function returns an object initialized with default configuration
parameters, which determine how the cpl_path_completions() callback
function behaves. The functions which allow you to individually change
these parameters are discussed below.
By default, the pca_path_completions() callback function searches back-
wards for the start of the filename being completed, looking for the
first un-escaped space or the start of the input line. If you wish to
specify a different location, call ppc_file_start() with the index at
which the filename starts in the input line. Passing start_index=-1 re-
enables the default behavior.
void ppc_file_start(PcaPathConf *ppc, int start_index);
By default, when pca_path_completions() looks at a filename in the
input line, each lone backslash in the input line is interpreted as
being a special character which removes any special significance of the
character which follows it, such as a space which should be taken as
part of the filename rather than delimiting the start of the filename.
These backslashes are thus ignored while looking for completions, and
subsequently added before spaces, tabs and literal backslashes in the
list of completions. To have unescaped backslashes treated as normal
characters, call ppc_literal_escapes() with a non-zero value in its
literal argument.
void ppc_literal_escapes(PcaPathConf *ppc, int literal);
When you have finished with a PcaPathConf variable, you can pass it to
the del_PcaPathConf() destructor function to reclaim its memory.
PcaPathConf *del_PcaPathConf(PcaPathConf *ppc);
If you are only interested in certain types or files, such as, for
example, executable files, or files whose names end in a particular
suffix, you can arrange for the file completion and lookup functions to
be selective in the filenames that they return. This is done by regis-
tering a callback function with your PathCache object. Thereafter,
whenever a filename is found which either matches a filename being
looked up, or matches a prefix which is being completed, your callback
function will be called with the full pathname of the file, plus any
application-specific data that you provide, and if the callback returns
1 the filename will be reported as a match, and if it returns 0, it
will be ignored. Suitable callback functions and their prototypes
should be declared with the following macro. The CplCheckFn typedef is
also provided in case you wish to declare pointers to such functions.
#define CPL_CHECK_FN(fn) int (fn)(void *data, \
const char *pathname)
typedef CPL_CHECK_FN(CplCheckFn);
Registering one of these functions involves calling the
pca_set_check_fn() function. In addition to the callback function,
passed via the check_fn argument, you can pass a pointer to anything
via the data argument. This pointer will be passed on to your callback
function, via its own data argument, whenever it is called, so this
provides a way to pass appplication specific data to your callback.
void pca_set_check_fn(PathCache *pc, CplCheckFn *check_fn,
void *data);
Note that these callbacks are passed the full pathname of each matching
file, so the decision about whether a file is of interest can be based
on any property of the file, not just its filename. As an example, the
provided cpl_check_exe() callback function looks at the executable per-
missions of the file and the permissions of its parent directories, and
only returns 1 if the user has execute permission to the file. This
callback function can thus be used to lookup or complete command names
found in the directories listed in the user's PATH environment vari-
able. The example program given earlier in this man page provides a
demonstration of this.
Beware that if somebody tries to complete an empty string, your call-
back will get called once for every file in the cache, which could num-
ber in the thousands. If your callback does anything time consuming,
this could result in an unacceptable delay for the user, so callbacks
should be kept short.
To improve performance, whenever one of these callbacks is called, the
choice that it makes is cached, and the next time the corresponding
file is looked up, instead of calling the callback again, the cached
record of whether it was accepted or rejected is used. Thus if somebody
tries to complete an empty string, and hits tab a second time when
nothing appears to happen, there will only be one long delay, since the
second pass will operate entirely from the cached dispositions of the
files. These cached dipositions are discarded whenever pca_scan_path()
is called, and whenever pca_set_check_fn() is called with changed call-
back function or data arguments.
If pca_scan_path() reports that an error occurred by returning 1, you
can obtain a terse description of the error by calling
pca_last_error(pc). This returns an internal string containing an error
message.
const char *pca_last_error(PathCache *pc);
Once you have finished using a PathCache object, you can reclaim its
resources by passing it to the del_PathCache() destructor function.
This takes a pointer to one of these objects, and always returns NULL.
PathCache *del_PathCache(PathCache *pc);
In multi-threaded programs, you should use the libtecla_r.a version of
the library. This uses POSIX reentrant functions where available (hence
the _r suffix), and disables features that rely on non-reentrant system
functions. In the case of this module, the only disabled feature is
username completion in ~username/ expressions, in cpl_path_comple-
tions().
Using the libtecla_r.a version of the library, it is safe to use the
facilities of this module in multiple threads, provided that each
thread uses a separately allocated PathCache object. In other words, if
two threads want to do path searching, they should each call new_Path-
Cache() to allocate their own caches.
libtecla.a - The tecla library
libtecla.h - The tecla header file.
libtecla, gl_get_line, ef_expand_file,
cpl_complete_word
Martin Shepherd (mcs@astro.caltech.edu)
pca_lookup_file
./libtecla/html/ef_expand_file.html 0100644 0000764 0000764 00000023336 10141252545 015721 0 ustar mcs mcs
ef_expand_file ef_expand_file
ef_expand_file, del_ExpandFile, ef_last_error, ef_list_expansions,
new_ExpandFile - expand filenames containing ~user/$envvar and wildcard
expressions
#include <libtecla.h>
ExpandFile *new_ExpandFile(void);
ExpandFile *del_ExpandFile(ExpandFile *ef);
FileExpansion *ef_expand_file(ExpandFile *ef,
const char *path,
int pathlen);
int ef_list_expansions(FileExpansion *result, FILE *fp,
int term_width);
const char *ef_last_error(ExpandFile *ef);
The ef_expand_file() function is part of the tecla library (see the
libtecla man page). It expands a specified filename,
converting ~user/ and ~/ expressions at the start of the filename to
the corresponding home directories, replacing $envvar with the value of
the corresponding environment variable, and then, if there are any
wildcards, matching these against existing filenames. Backslashes in
the input filename are interpreted as escaping any special meanings of
the characters that follow them. Only backslahes that are themselves
preceded by backslashes are preserved in the expanded filename.
In the presence of wildcards, the returned list of filenames only
includes the names of existing files which match the wildcards. Other-
wise, the original filename is returned after expansion of tilde and
dollar expressions, and the result is not checked against existing
files. This mimics the file-globbing behavior of the unix tcsh shell.
The supported wildcards and their meanings are:
* - Match any sequence of zero or more characters.
? - Match any single character.
[chars] - Match any single character that appears in
'chars'. If 'chars' contains an expression of
the form a-b, then any character between a and
b, including a and b, matches. The '-'
character looses its special meaning as a
range specifier when it appears at the start
of the sequence of characters. The ']'
character also looses its significance as the
terminator of the range expression if it
appears immediately after the opening '[', at
which point it is treated one of the
characters of the range. If you want both '-'
and ']' to be part of the range, the '-'
should come first and the ']' second.
[^chars] - The same as [chars] except that it matches any
single character that doesn't appear in
'chars'.
Note that wildcards never match the initial dot in filenames that start
with '.'. The initial '.' must be explicitly specified in the filename.
This again mimics the globbing behavior of most unix shells, and its
rational is based in the fact that in unix, files with names that start
with '.' are usually hidden configuration files, which are not listed
by default by the ls command.
The following is a complete example of how to use the file expansion
function.
#include <stdio.h>
#include <libtecla.h>
int main(int argc, char *argv[])
{
ExpandFile *ef; /* The expansion resource object */
char *filename; /* The filename being expanded */
FileExpansion *expn; /* The results of the expansion */
int i;
ef = new_ExpandFile();
if(!ef)
return 1;
for(arg = *(argv++); arg; arg = *(argv++)) {
if((expn = ef_expand_file(ef, arg, -1)) == NULL) {
fprintf(stderr, "Error expanding %s (%s).\n", arg,
ef_last_error(ef));
} else {
printf("%s matches the following files:\n", arg);
for(i=0; i<expn->nfile; i++)
printf(" %s\n", expn->files[i]);
}
}
ef = del_ExpandFile(ef);
return 0;
}
Descriptions of the functions used above are as follows:
ExpandFile *new_ExpandFile(void)
This function creates the resources used by the ef_expand_file() func-
tion. In particular, it maintains the memory that is used to record the
array of matching filenames that is returned by ef_expand_file(). This
array is expanded as needed, so there is no built in limit to the num-
ber of files that can be matched.
ExpandFile *del_ExpandFile(ExpandFile *ef)
This function deletes the resources that were returned by a previous
call to new_ExpandFile(). It always returns NULL (ie a deleted object).
It does nothing if the ef argument is NULL.
A container of the following type is returned by ef_expand_file().
typedef struct {
int exists; /* True if the files in files[] exist */
int nfile; /* The number of files in files[] */
char **files; /* An array of 'nfile' filenames. */
} FileExpansion;
FileExpansion *ef_expand_file(ExpandFile *ef,
const char *path,
int pathlen)
The ef_expand_file() function performs filename expansion, as docu-
mented at the start of this section. Its first argument is a resource
object returned by new_ExpandFile(). A pointer to the start of the
filename to be matched is passed via the path argument. This must be a
normal NUL terminated string, but unless a length of -1 is passed in
pathlen, only the first pathlen characters will be used in the filename
expansion. If the length is specified as -1, the whole of the string
will be expanded.
The function returns a pointer to a container who's contents are the
results of the expansion. If there were no wildcards in the filename,
the nfile member will be 1, and the exists member should be queried if
it is important to know if the expanded file currently exists or not.
If there were wildcards, then the contained files[] array will contain
the names of the nfile existing files that matched the wildcarded file-
name, and the exists member will have the value 1. Note that the
returned container belongs to the specified ef object, and its contents
will change on each call, so if you need to retain the results of more
than one call to ef_expand_file(), you should either make a private
copy of the returned results, or create multiple file-expansion
resource objects via multiple calls to new_ExpandFile().
On error, NULL is returned, and an explanation of the error can be
determined by calling ef_last_error(ef).
const char *ef_last_error(ExpandFile *ef)
This function returns the message which describes the error that
occurred on the last call to ef_expand_file(), for the given (Expand-
File *ef) resource object.
int ef_list_expansions(FileExpansion *result, FILE *fp,
int terminal_width);
The ef_list_expansions() function provides a convenient way to list the
filename expansions returned by ef_expand_file(). Like the unix ls com-
mand, it arranges the filenames into equal width columns, each column
having the width of the largest file. The number of columns used is
thus determined by the length of the longest filename, and the speci-
fied terminal width. Beware that filenames that are longer than the
specified terminal width are printed without being truncated, so output
longer than the specified terminal width can occur. The list is written
to the stdio stream specified by the fp argument.
In multi-threaded programs, you should use the libtecla_r.a version of
the library. This uses POSIX reentrant functions where available (hence
the _r suffix), and disables features that rely on non-reentrant system
functions. Currently there are no features disabled in this module.
Using the libtecla_r.a version of the library, it is safe to use the
facilities of this module in multiple threads, provided that each
thread uses a separately allocated ExpandFile object. In other words,
if two threads want to do file expansion, they should each call
new_ExpandFile() to allocate their own file-expansion objects.
libtecla.a - The tecla library
libtecla.h - The tecla header file.
libtecla, gl_get_line, cpl_complete_word,
pca_lookup_file
Martin Shepherd (mcs@astro.caltech.edu)
ef_expand_file
./libtecla/html/gl_get_line.html 0100644 0000764 0000764 00000301715 10141252546 015242 0 ustar mcs mcs
gl_get_line gl_get_line
gl_get_line, new_GetLine, del_GetLine, gl_customize_completion,
gl_change_terminal, gl_configure_getline, gl_load_history, gl_save_his-
tory, gl_group_history, gl_show_history, gl_watch_fd, gl_inactiv-
ity_timeout, gl_terminal_size, gl_set_term_size, gl_resize_history,
gl_limit_history, gl_clear_history, gl_toggle_history, gl_lookup_his-
tory, gl_state_of_history, gl_range_of_history, gl_size_of_history,
gl_echo_mode, gl_replace_prompt, gl_prompt_style, gl_ignore_signal,
gl_trap_signal, gl_last_signal, gl_completion_action, gl_display_text,
gl_return_status, gl_error_message, gl_catch_blocked, gl_list_signals,
gl_bind_keyseq, gl_erase_terminal, gl_automatic_history, gl_append_his-
tory, gl_query_char, gl_read_char - allow the user to compose an input
line
#include <stdio.h>
#include <libtecla.h>
GetLine *new_GetLine(size_t linelen, size_t histlen);
GetLine *del_GetLine(GetLine *gl);
char *gl_get_line(GetLine *gl, const char *prompt,
const char *start_line, int start_pos);
int gl_query_char(GetLine *gl, const char *prompt,
char defchar);
int gl_read_char(GetLine *gl);
int gl_customize_completion(GetLine *gl, void *data,
CplMatchFn *match_fn);
int gl_change_terminal(GetLine *gl, FILE *input_fp,
FILE *output_fp, const char *term);
int gl_configure_getline(GetLine *gl,
const char *app_string,
const char *app_file,
const char *user_file);
int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin,
const char *keyseq, const char *action);
int gl_save_history(GetLine *gl, const char *filename,
const char *comment, int max_lines);
int gl_load_history(GetLine *gl, const char *filename,
const char *comment);
int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
GlFdEventFn *callback, void *data);
int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *callback,
void *data, unsigned long sec,
unsigned long nsec);
int gl_group_history(GetLine *gl, unsigned stream);
int gl_show_history(GetLine *gl, FILE *fp,
const char *fmt, int all_groups,
int max_lines);
int gl_resize_history(GetLine *gl, size_t bufsize);
void gl_limit_history(GetLine *gl, int max_lines);
void gl_clear_history(GetLine *gl, int all_groups);
void gl_toggle_history(GetLine *gl, int enable);
GlTerminalSize gl_terminal_size(GetLine *gl,
int def_ncolumn,
int def_nline);
int gl_set_term_size(GetLine *gl, int ncolumn, int nline);
int gl_lookup_history(GetLine *gl, unsigned long id,
GlHistoryLine *hline);
void gl_state_of_history(GetLine *gl,
GlHistoryState *state);
void gl_range_of_history(GetLine *gl,
GlHistoryRange *range);
void gl_size_of_history(GetLine *gl, GlHistorySize *size);
void gl_echo_mode(GetLine *gl, int enable);
void gl_replace_prompt(GetLine *gl, const char *prompt);
void gl_prompt_style(GetLine *gl, GlPromptStyle style);
int gl_ignore_signal(GetLine *gl, int signo);
int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
GlAfterSignal after, int errno_value);
int gl_last_signal(GetLine *gl);
int gl_completion_action(GetLine *gl,
void *data, CplMatchFn *match_fn,
int list_only, const char *name,
const char *keyseq);
int gl_register_action(GetLine *gl, void *data,
GlActionFn *fn, const char *name,
const char *keyseq);
int gl_display_text(GetLine *gl, int indentation,
const char *prefix,
const char *suffix, int fill_char,
int def_width, int start,
const char *string);
GlReturnStatus gl_return_status(GetLine *gl);
const char *gl_error_message(GetLine *gl, char *buff,
size_t n);
void gl_catch_blocked(GetLine *gl);
int gl_list_signals(GetLine *gl, sigset_t *set);
int gl_append_history(GetLine *gl, const char *line);
int gl_automatic_history(GetLine *gl, int enable);
The gl_get_line() function is part of the tecla library (see the libte-
cla(@LIBR_MANEXT@) man page). If the user is typing at a terminal, each
call prompts them for an line of input, then provides interactive edit-
ing facilities, similar to those of the unix tcsh shell. In addition to
simple command-line editing, it supports recall of previously entered
command lines, TAB completion of file names, and in-line wild-card
expansion of filenames. Documentation of both the user-level command-
line editing features and all user configuration options, can be found
in the tecla man page. This man page concerns itself
with documentation for programmers interested in using this library in
their application.
The following shows a complete example of how to use the gl_get_line()
function to get input from the user:
#include <stdio.h>
#include <locale.h>
#include <libtecla.h>
int main(int argc, char *argv[])
{
char *line; /* The line that the user typed */
GetLine *gl; /* The gl_get_line() resource object */
setlocale(LC_CTYPE, ""); /* Adopt the user's choice */
/* of character set. */
gl = new_GetLine(1024, 2048);
if(!gl)
return 1;
while((line=gl_get_line(gl, "$ ", NULL, -1)) != NULL &&
strcmp(line, "exit\n") != 0)
printf("You typed: %s\n", line);
gl = del_GetLine(gl);
return 0;
}
In the example, first the resources needed by the gl_get_line() func-
tion are created by calling new_GetLine(). This allocates the memory
used in subsequent calls to the gl_get_line() function, including the
history buffer for recording previously entered lines. Then one or more
lines are read from the user, until either an error occurs, or the user
types exit. Then finally the resources that were allocated by new_Get-
Line(), are returned to the system by calling del_GetLine(). Note the
use of the NULL return value of del_GetLine() to make gl NULL. This is
a safety precaution. If the program subsequently attempts to pass gl to
gl_get_line(), said function will complain, and return an error,
instead of attempting to use the deleted resource object.
The descriptions of the functions used in the example are as follows:
GetLine *new_GetLine(size_t linelen, size_t histlen)
This function creates the resources used by the gl_get_line() function
and returns an opaque pointer to the object that contains them. The
maximum length of an input line is specified via the linelen argument,
and the number of bytes to allocate for storing history lines is set by
the histlen argument. History lines are stored back-to-back in a single
buffer of this size. Note that this means that the number of history
lines that can be stored at any given time, depends on the lengths of
the individual lines. If you want to place an upper limit on the num-
ber of lines that can be stored, see the gl_limit_history() function
described later. If you don't want history at all, specify histlen as
zero, and no history buffer will be allocated.
On error, a message is printed to stderr and NULL is returned.
GetLine *del_GetLine(GetLine *gl)
This function deletes the resources that were returned by a previous
call to new_GetLine(). It always returns NULL (ie a deleted object). It
does nothing if the gl argument is NULL.
char *gl_get_line(GetLine *gl, const char *prompt,
const char *start_line, int start_pos);
The gl_get_line() function can be called any number of times to read
input from the user. The gl argument must have been previously returned
by a call to new_GetLine(). The prompt argument should be a normal NUL
terminated string, specifying the prompt to present the user with. By
default prompts are displayed literally, but if enabled with the
gl_prompt_style() function (see later), prompts can contain directives
to do underlining, switch to and from bold fonts, or turn highlighting
on and off.
If you want to specify the initial contents of the line, for the user
to edit, pass the desired string via the start_line argument. You can
then specify which character of this line the cursor is initially posi-
tioned over, using the start_pos argument. This should be -1 if you
want the cursor to follow the last character of the start line. If you
don't want to preload the line in this manner, send start_line as NULL,
and set start_pos to -1. Note that the line pointer returned by one
call to gl_get_line() can be passed back to the next call to
gl_get_line() via the start_line. This allows the application to take
the last entered line, and if it contains an error, to then present it
back to the user for re-editing, with the cursor initially positioned
where the error was encountered.
The gl_get_line() function returns a pointer to the line entered by the
user, or NULL on error or at the end of the input. The returned pointer
is part of the specified gl resource object, and thus should not be
free'd by the caller, or assumed to be unchanging from one call to the
next. When reading from a user at a terminal, there will always be a
newline character at the end of the returned line. When standard input
is being taken from a pipe or a file, there will similarly be a newline
unless the input line was too long to store in the internal buffer. In
the latter case you should call gl_get_line() again to read the rest of
the line. Note that this behavior makes gl_get_line() similar to
fgets(). In fact when stdin isn't connected to a termi-
nal,gl_get_line() just calls fgets().
As described above, the gl_get_line() function has two possible return
values; a pointer to the completed input line, or NULL. Extra informa-
tion about what caused gl_get_line() to return is available both by
inspecting errno, and by calling the gl_return_status() function.
GlReturnStatus gl_return_status(GetLine *gl);
The following are the possible enumerated values that this function
returns.
GLR_NEWLINE - The last call to gl_get_line()
successfully returned a completed
input line.
GLR_BLOCKED - gl_get_line() was in non-blocking
server mode, and returned early to
avoid blocking the process while
waiting for terminal I/O. The
gl_pending_io() function can be
used to see what type of I/O
gl_get_line() was waiting for.
(see the gl_io_mode man page
for details).
GLR_SIGNAL - A signal was caught by
gl_get_line() that had an
after-signal disposition of
GLS_ABORT (See gl_trap_signal()).
GLR_TIMEOUT - The inactivity timer expired while
gl_get_line() was waiting for
input, and the timeout callback
function returned GLTO_ABORT.
See gl_inactivity_timeout() for
information about timeouts.
GLR_FDABORT - An application I/O callack returned
GLFD_ABORT (see gl_watch_fd()).
GLR_EOF - End of file reached. This can happen
when input is coming from a file or a
pipe, instead of the terminal. It also
occurs if the user invokes the
list-or-eof or del-char-or-list-or-eof
actions at the start of a new line.
GLR_ERROR - An unexpected error caused
gl_get_line() to abort (consult
errno and/or
gl_error_message() for details.
When gl_return_status() returns GLR_ERROR, and the value of errno isn't
sufficient to explain what happened, you can use the gl_error_message()
function to request a description of the last error that occurred.
const char *gl_error_message(GetLine *gl, char *buff,
size_t n);
The return value is a pointer to the message that occurred. If the buff
argument is NULL, this will be a pointer to a buffer within gl, who's
value will probably change on the next call to any function associated
with gl_get_line(). Otherwise, if a non-NULL buff argument is provided,
the error message, including a '\0' terminator, will be written within
the first n elements of this buffer, and the return value will be a
pointer to the first element of this buffer. If the message won't fit
in the provided buffer, it will be truncated to fit.
Whereas by default the prompt string that you specify is displayed lit-
erally, without any special interpretation of the characters within it,
the gl_prompt_style() function can be used to enable optional format-
ting directives within the prompt.
void gl_prompt_style(GetLine *gl, GlPromptStyle style);
The style argument, which specifies the formatting style, can take any
of the following values:
GL_FORMAT_PROMPT - In this style, the formatting
directives described below, when
included in prompt strings, are
interpreted as follows:
%B - Display subsequent
characters with a bold
font.
%b - Stop displaying characters
with the bold font.
%F - Make subsequent characters
flash.
%f - Turn off flashing
characters.
%U - Underline subsequent
characters.
%u - Stop underlining
characters.
%P - Switch to a pale (half
brightness) font.
%p - Stop using the pale font.
%S - Highlight subsequent
characters (also known as
standout mode).
%s - Stop highlighting
characters.
%V - Turn on reverse video.
%v - Turn off reverse video.
%% - Display a single %
character.
For example, in this mode, a prompt
string like "%UOK%u$ " would
display the prompt "OK$ ",
but with the OK part
underlined.
Note that although a pair of
characters that starts with a %
character, but doesn't match any of
the above directives is displayed
literally, if a new directive is
subsequently introduced which does
match, the displayed prompt will
change, so it is better to always
use %% to display a literal %.
Also note that not all terminals
support all of these text
attributes, and that some substitute
a different attribute for missing
ones.
GL_LITERAL_PROMPT - In this style, the prompt string is
printed literally. This is the
default style.
As mentioned above, by default users have the option of configuring the
behavior of gl_get_line() via a configuration file called .teclarc in
their home directories. The fact that all applications share this same
configuration file is both an advantage and a disadvantage. In most
cases it is an advantage, since it encourages uniformity, and frees the
user from having to configure each application separately. In some
applications, however, this single means of configuration is a problem.
This is particularly true of embedded software, where there's no
filesystem to read a configuration file from, and also in applications
where a radically different choice of keybindings is needed to emulate
a legacy keyboard interface. To cater for such cases, the following
function allows the application to control where configuration informa-
tion is read from.
int gl_configure_getline(GetLine *gl,
const char *app_string,
const char *app_file,
const char *user_file);
It allows the configuration commands that would normally be read from a
user's ~/.teclarc file, to be read from any or none of, a string, an
application specific configuration file, and/or a user-specific config-
uration file. If this function is called before the first call to
gl_get_line(), the default behavior of reading ~/.teclarc on the first
call to gl_get_line() is disabled, so all configuration must be
achieved using the configuration sources specified with this function.
If app_string != NULL, then it is interpreted as a string containing
one or more configuration commands, separated from each other in the
string by embedded newline characters. If app_file != NULL then it is
interpreted as the full pathname of an application-specific configura-
tion file. If user_file != NULL then it is interpreted as the full
pathname of a user-specific configuration file, such as ~/.teclarc. For
example, in the following call,
gl_configure_getline(gl, "edit-mode vi \n nobeep",
"/usr/share/myapp/teclarc",
"~/.teclarc");
the app_string argument causes the calling application to start in vi
edit-mode, instead of the default emacs mode, and turns off the use of
the terminal bell by the library. It then attempts to read system-wide
configuration commands from an optional file called
/usr/share/myapp/teclarc, then finally reads user-specific configura-
tion commands from an optional .teclarc file in the user's home direc-
tory. Note that the arguments are listed in ascending order of prior-
ity, with the contents of app_string being potentially overriden by
commands in app_file, and commands in app_file potentially being over-
riden by commands in user_file.
You can call this function as many times as needed, the results being
cumulative, but note that copies of any filenames specified via the
app_file and user_file arguments are recorded internally for subsequent
use by the read-init-files key-binding function, so if you plan to call
this function multiple times, be sure that the last call specifies the
filenames that you want re-read when the user requests that the config-
uration files be re-read.
Individual key sequences can also be bound and unbound using the
gl_bind_keyseq() function.
int gl_bind_keyseq(GetLine *gl, GlKeyOrigin origin,
const char *keyseq,
const char *action);
The origin argument specifies the priority of the binding, according to
who it is being established for, and must be one of the following two
values.
GL_USER_KEY - The user requested this key-binding.
GL_APP_KEY - This is a default binding set by the
application.
When both user and application bindings for a given key-sequence have
been specified, the user binding takes precedence. The application's
binding is subsequently reinstated if the user's binding is later
unbound via either another to this function, or a call to gl_config-
ure_getline().
The keyseq argument specifies the key-sequence to be bound or unbound,
and is expressed in the same way as in a ~/.teclarc configuration file.
The action argument must either be a string containing the name of the
action to bind the key-sequence to, or it must be NULL or "" to unbind
the key-sequence.
If in your application, you would like to have TAB completion complete
other things in addition to or instead of filenames, you can arrange
this by registering an alternate completion callback function, via a
call to the gl_customize_completion() function.
int gl_customize_completion(GetLine *gl, void *data,
CplMatchFn *match_fn);
The data argument provides a way for your application to pass arbi-
trary, application-specific information to the callback function. This
is passed to the callback every time that it is called. It might for
example, point to the symbol table from which possible completions are
to be sought. The match_fn argument specifies the callback function to
be called. The CplMatchFn function type is defined in libtecla.h, as is
a CPL_MATCH_FN() macro that you can use to declare and prototype call-
back functions. The declaration and responsibilities of callback func-
tions are described in depth in the cpl_complete_word
man page.
In brief, the callback function is responsible for looking backwards in
the input line, back from the point at which the user pressed TAB, to
find the start of the word being completed. It then must lookup possi-
ble completions of this word, and record them one by one in the Word-
Completion object that is passed to it as an argument, by calling the
cpl_add_completion() function. If the callback function wishes to pro-
vide filename completion in addition to its own specific completions,
it has the option of itself calling the builtin file-name completion
callback. This also, is documented in the cpl_com-
plete_word(@FUNC_MANEXT@) man page.
Note that if you would like gl_get_line() to return the current input
line when a successful completion is been made, you can arrange this
when you call cpl_add_completion(), by making the last character of the
continuation suffix a newline character. If you do this, the input line
will be updated to display the completion, together with any
contiuation suffix up to the newline character, then gl_get_line() will
return this input line.
If, for some reason, your callback function needs to write something to
the terminal, it must call gl_normal_io() before doing so. This will
start a new line after the input line that is currently being edited,
reinstate normal terminal I/O, and tell gl_get_line() that the input
line will need to be redrawn when the callback returns.
In the previous section the ability to customize the behavior of the
only default completion action, complete-word, was described. In this
section the ability to install additional action functions, so that
different types of word completion can be bound to different key-
sequences, is described. This is achieved by using the gl_comple-
tion_action() function.
int gl_completion_action(GetLine *gl,
void *data, CplMatchFn *match_fn,
int list_only, const char *name,
const char *keyseq);
The data and match_fn arguments are as described in the cpl_com-
plete_word man page, and specify the callback function that should be
invoked to identify possible completions. The list_only argument
determines whether the action that is being defined should attempt to
complete the word as far as possible in the input line before display-
ing any possible ambiguous completions, or whether it should simply
display the list of possible completions without touching the input
line. The former option is selected by specifying a value of 0, and the
latter by specifying a value of 1. The name argument specifies the name
by which configuration files and future invokations of this function
should refer to the action. This must either be the name of an existing
completion action to be changed, or be a new unused name for a new
action. Finally, the keyseq argument specifies the default key-sequence
to bind the action to. If this is NULL, no new keysequence will be
bound to the action.
Beware that in order for the user to be able to change the key-sequence
that is bound to actions that are installed in this manner, when you
call gl_completion_action() to install a given action for the first
time, you should do this between calling new_GetLine() and the first
call to gl_get_line(). Otherwise, when the user's configuration file
is read on the first call to gl_get_line(), the name of the your addi-
tional action won't be known, and any reference to it in the configura-
tion file will generate an error.
As discussed for gl_customize_completion(), if your callback function,
for some reason, needs to write anything to the terminal, it must call
gl_normal_io() before doing so.
Although the built-in key-binding actions are sufficient for the needs
of most applications, occasionally a specialized application may need
to define one or more custom actions, bound to application-specific
key-sequences. For example, a sales application would benefit from hav-
ing a key-sequence that displayed the part name that corresponded to a
part number preceding the cursor. Such a feature is clearly beyond the
scope of the built-in action functions. So for such special cases, the
gl_register_action() function is provided.
int gl_register_action(GetLine *gl, void *data,
GlActionFn *fn, const char *name,
const char *keyseq);
This function lets the application register an external function, fn,
that will thereafter be called whenever either the specified key-
sequence, keyseq, is entered by the user, or the user enters any other
key-sequence that the user subsequently binds to the specified action
name, name, in their configuration file. The data argument can be a
pointer to anything that the application wishes to have passed to the
action function, fn, whenever that function is invoked.
The action function, fn, should be declared using the following macro,
which is defined in libtecla.h.
#define GL_ACTION_FN(fn) GlAfterAction (fn)(GetLine *gl, \
void *data, int count, size_t curpos, \
const char *line)
The gl and data arguments are those that were previously passed to
gl_register_action() when the action function was registered. The count
argument is a numeric argument which the user has the option of enter-
ing using the digit-argument action, before invoking the action. If the
user doesn't enter a number, then the count argument is set to 1. Nomi-
nally this argument is interpreted as a repeat count, meaning that the
action should be repeated that many times. In practice however, for
some actions a repeat count makes little sense. In such cases, actions
can either simply ignore the count argument, or use its value for a
different purpose.
A copy of the current input line is passed in the read-only line argu-
ment. The current cursor position within this string is given by the
index contained in the curpos argument. Note that direct manipulation
of the input line and the cursor position is not permitted. This is
because the rules dicated by various modes, such as vi mode versus
emacs mode, no-echo mode, and insert mode versus overstrike mode etc,
make it too complex for an application writer to write a conforming
editing action, as well as constrain future changes to the internals of
gl_get_line(). A potential solution to this dilema would be to allow
the action function to edit the line using the existing editing
actions. This is currently under consideration.
If the action function wishes to write text to the terminal, without
this getting mixed up with the displayed text of the input line, or
read from the terminal without having to handle raw terminal I/O, then
before doing either of these operations, it must temporarily suspend
line editing by calling the gl_normal_io() function. This function
flushes any pending output to the terminal, moves the cursor to the
start of the line that follows the last terminal line of the input
line, then restores the terminal to a state that is suitable for use
with the C stdio facilities. The latter includes such things as restor-
ing the normal mapping of \n to \r\n, and, when in server mode, restor-
ing the normal blocking form of terminal I/O. Having called this func-
tion, the action function can read from and write to the terminal with-
out the fear of creating a mess. It isn't necessary for the action
function to restore the original editing environment before it returns.
This is done automatically by gl_get_line() after the action function
returns. The following is a simple example of an action function which
writes the sentence "Hello world" on a new terminal line after the line
being edited. When this function returns, the input line is redrawn on
the line that follows the "Hello world" line, and line editing resumes.
static GL_ACTION_FN(say_hello_fn)
{
if(gl_normal_io(gl)) /* Temporarily suspend editing */
return GLA_ABORT;
printf("Hello world\n");
return GLA_CONTINUE;
}
Action functions must return one of the following values, to tell
gl_get_line() how to procede.
GLA_ABORT - Cause gl_get_line() to return NULL.
GLA_RETURN - Cause gl_get_line() to return the
completed input line.
GLA_CONTINUE - Resume command-line editing.
Note that the name argument of gl_register_action() specifies the name
by which a user can refer to the action in their configuration file.
This allows them to re-bind the action to an alternate key-seqeunce. In
order for this to work, it is necessary to call gl_register_action()
between calling new_GetLine() and the first call to gl_get_line().
To save the contents of the history buffer before quitting your appli-
cation, and subsequently restore them when you next start the applica-
tion, the following functions are provided.
int gl_save_history(GetLine *gl, const char *filename,
const char *comment, int max_lines);
int gl_load_history(GetLine *gl, const char *filename,
const char *comment);
The filename argument specifies the name to give the history file when
saving, or the name of an existing history file, when loading. This may
contain home-directory and environment variable expressions, such as
"~/.myapp_history" or "$HOME/.myapp_history".
Along with each history line, extra information about it, such as when
it was entered by the user, and what its nesting level is, is recorded
as a comment preceding the line in the history file. Writing this as a
comment allows the history file to double as a command file, just in
case you wish to replay a whole session using it. Since comment pre-
fixes differ in different languages, the comment argument is provided
for specifying the comment prefix. For example, if your application
were a unix shell, such as the bourne shell, you would specify "#"
here. Whatever you choose for the comment character, you must specify
the same prefix to gl_load_history() that you used when you called
gl_save_history() to write the history file.
The max_lines must be either -1 to specify that all lines in the his-
tory list be saved, or a positive number specifying a ceiling on how
many of the most recent lines should be saved.
Both fuctions return non-zero on error, after writing an error message
to stderr. Note that gl_load_history() does not consider the non-exis-
tence of a file to be an error.
If your application uses a single GetLine object for entering many dif-
ferent types of input lines, you may wish gl_get_line() to distinguish
the different types of lines in the history list, and only recall lines
that match the current type of line. To support this requirement,
gl_get_line() marks lines being recorded in the history list with an
integer identifier chosen by the application. Initially this identi-
fier is set to 0 by new_GetLine(), but it can be changed subsequently
by calling gl_group_history().
int gl_group_history(GetLine *gl, unsigned id);
The integer identifier id can be any number chosen by the application,
but note that gl_save_history() and gl_load_history() preserve the
association between identifiers and historical input lines between pro-
gram invokations, so you should choose fixed identifiers for the dif-
ferent types of input line used by your application.
Whenever gl_get_line() appends a new input line to the history list,
the current history identifier is recorded with it, and when it is
asked to recall a historical input line, it only recalls lines that are
marked with the current identifier.
The history list can be displayed by calling gl_show_history().
int gl_show_history(GetLine *gl, FILE *fp,
const char *fmt,
int all_groups,
int max_lines);
This displays the current contents of the history list to the stdio
output stream fp. If the max_lines argument is greater than or equal to
zero, then no more than this number of the most recent lines will be
displayed. If the all_groups argument is non-zero, lines from all his-
tory groups are displayed. Otherwise just those of the currently
selected history group are displayed. The format string argument, fmt,
determines how the line is displayed. This can contain arbitrary char-
acters which are written verbatim, interleaved with any of the follow-
ing format directives:
%D - The date on which the line was originally
entered, formatted like 2001-11-20.
%T - The time of day when the line was entered,
formatted like 23:59:59.
%N - The sequential entry number of the line in
the history buffer.
%G - The number of the history group which the
line belongs to.
%% - A literal % character.
%H - The history line itself.
Thus a format string like "%D %T %H0 would output something like:
2001-11-20 10:23:34 Hello world
Note the inclusion of an explicit newline character in the format
string.
The gl_lookup_history() function allows the calling application to look
up lines in the history list.
typedef struct {
const char *line; /* The requested historical */
/* line. */
unsigned group; /* The history group to which */
/* the line belongs. */
time_t timestamp; /* The date and time at which */
/* the line was originally */
/* entered. */
} GlHistoryLine;
int gl_lookup_history(GetLine *gl, unsigned long id,
GlHistoryLine *hline);
The id argument indicates which line to look up, where the first line
that was entered in the history list after new_GetLine() was called, is
denoted by 0, and subsequently entered lines are denoted with succes-
sively higher numbers. Note that the range of lines currently preserved
in the history list can be queried by calling the gl_range_of_history()
function, described later. If the requested line is in the history
list, the details of the line are recorded in the variable pointed to
by the hline argument, and 1 is returned. Otherwise 0 is returned, and
the variable pointed to by hline is left unchanged.
Beware that the string returned in hline->line is part of the history
buffer, so it must not be modified by the caller, and will be recycled
on the next call to any function that takes gl as its argument. There-
fore you should make a private copy of this string if you need to keep
it around.
By default, whenever a line is entered by the user, it is automatically
appended to the history list, just before gl_get_line() returns the
line to the caller. This is convenient for the majority of applica-
tions, but there are also applications that need finer grained control
over what gets added to the history list. In such cases, the automatic
addition of entered lines to the history list can be turned off by
calling the gl_automatic_history() function.
int gl_automatic_history(GetLine *gl, int enable);
If this function is called with its enable argument set to 0,
gl_get_line() won't automatically archive subsequently entered lines.
Automatic archiving can be reenabled at a later time, by calling this
function again, with its enable argument set to 1. While automatic
history archiving is disabled, the calling application can use the
gl_append_history() to append lines to the history list as needed.
int gl_append_history(GetLine *gl, const char *line);
The line argument specifies the line to be added to the history list.
This must be a normal ' ' terminated string. If this string contains
any newline characters, the line that gets archived in the history list
will be terminated by the first of these. Otherwise it will be termi-
nated by the ' ' terminator. If the line is longer than the maximum
input line length, that was specified when new_GetLine() was called,
when the line is recalled, it will get truncated to the actual
gl_get_line() line length.
If successful, gl_append_history() returns 0. Otherwise it returns non-
zero, and sets errno to one of the following values.
EINVAL - One of the arguments passed to
gl_append_history() was NULL.
ENOMEM - The specified line was longer than the allocated
size of the history buffer (as specified when
new_GetLine() was called), so it couldn't be
archived.
A textual description of the error can optionally be obtained by call-
ing gl_error_message(). Note that after such an error, the history list
remains in a valid state to receive new history lines, so there is lit-
tle harm in simply ignoring the return status of gl_append_history().
If you wish to change the size of the history buffer that was origi-
nally specified in the call to new_GetLine(), you can do so with the
gl_resize_history() function.
int gl_resize_history(GetLine *gl, size_t histlen);
The histlen argument specifies the new size in bytes, and if you spec-
ify this as 0, the buffer will be deleted.
As mentioned in the discussion of new_GetLine(), the number of lines
that can be stored in the history buffer, depends on the lengths of the
individual lines. For example, a 1000 byte buffer could equally store
10 lines of average length 100 bytes, or 2 lines of average length 50
bytes. Although the buffer is never expanded when new lines are added,
a list of pointers into the buffer does get expanded when needed to
accomodate the number of lines currently stored in the buffer. To place
an upper limit on the number of lines in the buffer, and thus a ceiling
on the amount of memory used in this list, you can call the
gl_limit_history() function.
void gl_limit_history(GetLine *gl, int max_lines);
The max_lines should either be a positive number >= 0, specifying an
upper limit on the number of lines in the buffer, or be -1 to cancel
any previously specified limit. When a limit is in effect, only the
max_lines most recently appended lines are kept in the buffer. Older
lines are discarded.
To discard lines from the history buffer, use the gl_clear_history()
function.
void gl_clear_history(GetLine *gl, int all_groups);
The all_groups argument tells the function whether to delete just the
lines associated with the current history group (see gl_group_his-
tory()), or all historical lines in the buffer.
The gl_toggle_history() function allows you to toggle history on and
off without losing the current contents of the history list.
void gl_toggle_history(GetLine *gl, int enable);
Setting the enable argument to 0 turns off the history mechanism, and
setting it to 1 turns it back on. When history is turned off, no new
lines will be added to the history list, and history lookup key-bind-
ings will act as though there is nothing in the history buffer.
The configured state of the history list can be queried with the
gl_history_state() function.
typedef struct {
int enabled; /* True if history is enabled */
unsigned group; /* The current history group */
int max_lines; /* The current upper limit on the */
/* number of lines in the history */
/* list, or -1 if unlimited. */
} GlHistoryState;
void gl_state_of_history(GetLine *gl,
GlHistoryState *state);
On return, the status information is recorded in the variable pointed
to by the state argument.
The gl_range_of_history() function returns the number and range of
lines in the history list.
typedef struct {
unsigned long oldest; /* The sequential entry number */
/* of the oldest line in the */
/* history list. */
unsigned long newest; /* The sequential entry number */
/* of the newest line in the */
/* history list. */
int nlines; /* The number of lines in the */
/* history list. */
} GlHistoryRange;
void gl_range_of_history(GetLine *gl, GlHistoryRange *range);
The return values are recorded in the variable pointed to by the range
argument. If the nlines member of this structure is greater than zero,
then the oldest and newest members report the range of lines in the
list, and newest=oldest+nlines-1. Otherwise they are both zero.
The gl_size_of_history() function returns the total size of the history
buffer and the amount of the buffer that is currently occupied.
typedef struct {
size_t size; /* The size of the history buffer */
/* (bytes). */
size_t used; /* The number of bytes of the */
/* history buffer that are */
/* currently occupied. */
} GlHistorySize;
void gl_size_of_history(GetLine *gl, GlHistorySize *size);
On return, the size information is recorded in the variable pointed to
by the size argument.
The new_GetLine() constructor function assumes that input is to be read
from stdin, and output written to stdout. The following function allows
you to switch to different input and output streams.
int gl_change_terminal(GetLine *gl, FILE *input_fp,
FILE *output_fp, const char *term);
The gl argument is the object that was returned by new_GetLine(). The
input_fp argument specifies the stream to read from, and output_fp
specifies the stream to be written to. Only if both of these refer to a
terminal, will interactive terminal input be enabled. Otherwise
gl_get_line() will simply call fgets() to read command input. If both
streams refer to a terminal, then they must refer to the same terminal,
and the type of this terminal must be specified via the term argument.
The value of the term argument is looked up in the terminal information
database (terminfo or termcap), in order to determine which special
control sequences are needed to control various aspects of the termi-
nal. new_GetLine() for example, passes the return value of
getenv("TERM") in this argument. Note that if one or both of input_fp
and output_fp don't refer to a terminal, then it is legal to pass NULL
instead of a terminal type.
Note that if you want to pass file descriptors to gl_change_terminal(),
you can do this by creating stdio stream wrappers using the POSIX
fdopen() function.
By default, gl_get_line() doesn't return until either a complete input
line has been entered by the user, or an error occurs. In programs that
need to watch for I/O from other sources than the terminal, there are
two options.
1. Use the functions described in the
gl_io_mode man page to switch
gl_get_line() into non-blocking server mode. In this mode,
gl_get_line() becomes a non-blocking, incremental
line-editing function that can safely be called from
an external event loop. Although this is a very
versatile method, it involves taking on some
responsibilities that are normally performed behind
the scenes by gl_get_line().
2. While gl_get_line() is waiting for keyboard
input from the user, you can ask it to also watch for
activity on arbitrary file descriptors, such as
network sockets, pipes etc, and have it call functions
of your choosing when activity is seen. This works on
any system that has the select() system call,
which is most, if not all flavors of unix.
Registering a file descriptor to be watched by gl_get_line() involves
calling the gl_watch_fd() function.
int gl_watch_fd(GetLine *gl, int fd, GlFdEvent event,
GlFdEventFn *callback, void *data);
If this returns non-zero, then it means that either your arguments are
invalid, or that this facility isn't supported on the host system.
The fd argument is the file descriptor to be watched. The event argu-
ment specifies what type of activity is of interest, chosen from the
following enumerated values:
GLFD_READ - Watch for the arrival of data to be read.
GLFD_WRITE - Watch for the ability to write to the file
descriptor without blocking.
GLFD_URGENT - Watch for the arrival of urgent
out-of-band data on the file descriptor.
The callback argument is the function to call when the selected
activity is seen. It should be defined with the following macro, which
is defined in libtecla.h.
#define GL_FD_EVENT_FN(fn) GlFdStatus (fn)(GetLine *gl, \
void *data, int fd, \
GlFdEvent event)
The data argument of the gl_watch_fd() function is passed to the call-
back function for its own use, and can point to anything you like,
including NULL. The file descriptor and the event argument are also
passed to the callback function, and this potentially allows the same
callback function to be registered to more than one type of event
and/or more than one file descriptor. The return value of the callback
function should be one of the following values.
GLFD_ABORT - Tell gl_get_line() to abort. When this
happens, gl_get_line() returns
NULL, and a following call to
gl_return_status() will return
GLR_FDABORT. Note that if the
application needs errno always to
have a meaningful value when
gl_get_line() returns NULL,
the callback function should set
errno appropriately.
GLFD_REFRESH - Redraw the input line then continue
waiting for input. Return this if
your callback wrote to the terminal.
GLFD_CONTINUE - Continue to wait for input, without
redrawing the line.
Note that before calling the callback, gl_get_line() blocks most sig-
nals, and leaves its own signal handlers installed, so if you need to
catch a particular signal you will need to both temporarily install
your own signal handler, and unblock the signal. Be sure to re-block
the signal (if it was originally blocked) and reinstate the original
signal handler, if any, before returning.
If the callback function needs to read or write to the terminal, it
should ideally first call gl_normal_io(gl) to temporarily suspend line
editing. This will restore the terminal to canonical, blocking-I/O,
mode, and move the cursor to the start of a new terminal line. Later,
when the callback returns, gl_get_line() will notice that gl_nor-
mal_io() was called, redisplay the input line and resume editing. Note
that in this case the return values, GLFD_REFRESH and GLFD_CONTINUE are
equivalent.
To support cases where the callback function calls a third-party func-
tion which occasionally and u0prisicre-enabledesbeforee themicallback
automatic conversion of "0 to "
function is called. If the callack knows that the third-party function
wrote to the terminal, it should then return the GLFD_REFRESH return
value, to tell gl_get_line() to redisplay the input line.
To remove a callback function that you previously registered for a
given file descriptor and event, simply call gl_watch_fd() with the
same file descriptor and event arguments, but with a callback argument
of 0. The data argument is ignored in this case.
On systems with the select() system call, the gl_inactivity_timeout()
function can be used to set or cancel an inactivity timeout. Inactivity
in this case refers both to keyboard input, and to I/O on any file
descriptors registered by prior and subsequent calls to gl_watch_fd().
On oddball systems that don't have select(), this call has no effect.
int gl_inactivity_timeout(GetLine *gl, GlTimeoutFn *callback,
void *data, unsigned long sec,
unsigned long nsec);
The timeout is specified in the form of an integral number of seconds
and an integral number of nanoseconds, via the sec and nsec arguments
respectively. Subsequently, whenever no activity is seen for this time
period, the function specified via the callback argument is called. The
data argument of gl_inactivity_timeout() is passed verbatim to this
callback function whenever it is invoked, and can thus be used to pass
arbitrary application-specific information to the callback. The follow-
ing macro is provided in libtecla.h for applications to use to declare
and prototype timeout callback functions.
#define GL_TIMEOUT_FN(fn) \
GlAfterTimeout (fn)(GetLine *gl, void *data)
On returning, the application's callback is expected to return one of
the following enumerators to tell gl_get_line() how to procede after
the timeout has been handled by the callback.
GLTO_ABORT - Tell gl_get_line() to abort. When
this happens, gl_get_line() will
return NULL, and a following call
to gl_return_status() will return
GLR_TIMEOUT. Note that if the
application needs errno always to
have a meaningful value when
gl_get_line() returns NULL,
the callback function should set
errno appropriately.
GLTO_REFRESH - Redraw the input line, then continue
waiting for input. You should return
this value if your callback wrote to the
terminal without having first called
gl_normal_io(gl).
GLTO_CONTINUE - In normal blocking-I/O mode, continue to
wait for input, without redrawing the
user's input line.
In non-blocking server I/O mode (see
gl_io_mode), cause gl_get_line()
to act as though I/O blocked. This means
that gl_get_line() will immediately
return NULL, and a following call
to gl_return_status() will return
GLR_BLOCKED.
Note that before calling the callback, gl_get_line() blocks most sig-
nals, and leaves its own signal handlers installed, so if you need to
catch a particular signal you will need to both temporarily install
your own signal handler, and unblock the signal. Be sure to re-block
the signal (if it was originally blocked) and reinstate the original
signal handler, if any, before returning.
If the callback function needs to read or write to the terminal, it
should ideally first call gl_normal_io(gl) to temporarily suspend line
editing. This will restore the terminal to canonical, blocking-I/O,
mode, and move the cursor to the start of a new terminal line. Later,
when the callback returns, gl_get_line() will notice that gl_nor-
mal_io() was called, redisplay the input line and resume editing. Note
that in this case the return values, GLTO_REFRESH and GLTO_CONTINUE are
equivalent.
To support cases where the callback function calls a third-party func-
tion which occasionally and u0prisicre-enabledesbeforee themicallback
automatic conversion of "0 to "
function is called. If the callack knows that the third-party function
wrote to the terminal, it should then return the GLTO_REFRESH return
value, to tell gl_get_line() to redisplay the input line.
Note that although the timeout argument includes a nano-second compo-
nent, few computer clocks presently have resolutions that are finer
than a few milliseconds, so asking for less than a few milliseconds is
equivalent to requesting zero seconds on a lot of systems. If this
would be a problem, you should base your timeout selection on the
actual resolution of the host clock (eg. by calling
sysconf(_SC_CLK_TCK)).
To turn off timeouts, simply call gl_inactivity_timeout() with a call-
back argument of 0. The data argument is ignored in this case.
By default, the gl_get_line() function intercepts a number of signals.
This is particularly important for signals which would by default ter-
minate the process, since the terminal needs to be restored to a usable
state before this happens. In this section, the signals that are
trapped by default, and how gl_get_line() responds to them, is
described. Changing these defaults is the topic of the following sec-
tion.
When the following subset of signals are caught, gl_get_line() first
restores the terminal settings and signal handling to how they were
before gl_get_line() was called, resends the signal, to allow the call-
ing application's signal handlers to handle it, then if the process
still exists, gl_get_line() returns NULL and sets errno as specified
below.
SIGINT - This signal is generated both by the keyboard
interrupt key (usually ^C), and the keyboard
break key.
errno=EINTR
SIGHUP - This signal is generated when the controlling
terminal exits.
errno=ENOTTY
SIGPIPE - This signal is generated when a program attempts
to write to a pipe who's remote end isn't being
read by any process. This can happen for example
if you have called gl_change_terminal() to
redirect output to a pipe hidden under a pseudo
terminal.
errno=EPIPE
SIGQUIT - This signal is generated by the keyboard quit
key (usually ^\).
errno=EINTR
SIGABRT - This signal is generated by the standard C,
abort() function. By default it both
terminates the process and generates a core
dump.
errno=EINTR
SIGTERM - This is the default signal that the UN*X
kill command sends to processes.
errno=EINTR
Note that in the case of all of the above signals, POSIX mandates that
by default the process is terminated, with the addition of a core dump
in the case of the SIGQUIT signal. In other words, if the calling
application doesn't override the default handler by supplying its own
signal handler, receipt of the corresponding signal will terminate the
application before gl_get_line() returns.
If gl_get_line() aborts with errno set to EINTR, you can find out what
signal caused it to abort, by calling the following function.
int gl_last_signal(const GetLine *gl);
This returns the numeric code (eg. SIGINT) of the last signal that was
received during the most recent call to gl_get_line(), or -1 if no sig-
nals were received.
On systems that support it, when a SIGWINCH (window change) signal is
received, gl_get_line() queries the terminal to find out its new size,
redraws the current input line to accomodate the new size, then returns
to waiting for keyboard input from the user. Unlike other signals, this
signal isn't resent to the application.
Finally, the following signals cause gl_get_line() to first restore the
terminal and signal environment to that which prevailed before
gl_get_line() was called, then resend the signal to the application. If
the process still exists after the signal has been delivered, then
gl_get_line() then re-establishes its own signal handlers, switches the
terminal back to raw mode, redisplays the input line, and goes back to
awaiting terminal input from the user.
SIGCONT - This signal is generated when a suspended
process is resumed.
SIGPOLL - On SVR4 systems, this signal notifies the
process of an asynchronous I/O event. Note
that under 4.3+BSD, SIGIO and SIGPOLL are
the same. On other systems, SIGIO is ignored
by default, so gl_get_line() doesn't
trap it by default.
SIGPWR - This signal is generated when a power failure
occurs (presumably when the system is on a
UPS).
SIGALRM - This signal is generated when a timer
expires.
SIGUSR1 - An application specific signal.
SIGUSR2 - Another application specific signal.
SIGVTALRM - This signal is generated when a virtual
timer expires (see man setitimer(2)).
SIGXCPU - This signal is generated when a process
exceeds its soft CPU time limit.
SIGXFSZ - This signal is generated when a process
exceeds its soft file-size limit.
SIGTSTP - This signal is generated by the terminal
suspend key, which is usually ^Z, or the
delayed terminal suspend key, which is
usually ^Y.
SIGTTIN - This signal is generated if the program
attempts to read from the terminal while the
program is running in the background.
SIGTTOU - This signal is generated if the program
attempts to write to the terminal while the
program is running in the background.
Obviously not all of the above signals are supported on all systems, so
code to support them is conditionally compiled into the tecla library.
Note that if SIGKILL or SIGPOLL, which by definition can't be caught,
or any of the hardware generated exception signals, such as SIGSEGV,
SIGBUS and SIGFPE, are received and unhandled while gl_get_line() has
the terminal in raw mode, the program will be terminated without the
terminal having been restored to a usable state. In practice, job-con-
trol shells usually reset the terminal settings when a process relin-
quishes the controlling terminal, so this is only a problem with older
shells.
The previous section listed the signals that gl_get_line() traps by
default, and described how it responds to them. This section describes
how to both add and remove signals from the list of trapped signals,
and how to specify how gl_get_line() should respond to a given signal.
If you don't need gl_get_line() to do anything in response to a signal
that it normally traps, you can tell to gl_get_line() to ignore that
signal by calling gl_ignore_signal().
int gl_ignore_signal(GetLine *gl, int signo);
The signo argument is the number of the signal (eg. SIGINT) that you
want to have ignored. If the specified signal isn't currently one of
those being trapped, this function does nothing.
The gl_trap_signal() function allows you to either add a new signal to
the list that gl_get_line() traps, or modify how it responds to a sig-
nal that it already traps.
int gl_trap_signal(GetLine *gl, int signo, unsigned flags,
GlAfterSignal after, int errno_value);
The signo argument is the number of the signal that you wish to have
trapped. The flags argument is a set of flags which determine the envi-
ronment in which the application's signal handler is invoked, the after
argument tells gl_get_line() what to do after the application's signal
handler returns, and errno_value tells gl_get_line() what to set errno
to if told to abort.
The flags argument is a bitwise OR of zero or more of the following
enumerators:
GLS_RESTORE_SIG - Restore the caller's signal
environment while handling the
signal.
GLS_RESTORE_TTY - Restore the caller's terminal settings
while handling the signal.
GLS_RESTORE_LINE - Move the cursor to the start of the
line following the input line before
invoking the application's signal
handler.
GLS_REDRAW_LINE - Redraw the input line when the
application's signal handler returns.
GLS_UNBLOCK_SIG - Normally, if the calling program has
a signal blocked (man sigprocmask),
gl_get_line() does not trap that
signal. This flag tells gl_get_line()
to trap the signal and unblock it for
the duration of the call to
gl_get_line().
GLS_DONT_FORWARD - If this flag is included, the signal
will not be forwarded to the signal
handler of the calling program.
Two commonly useful flag combinations are also enumerated as follows:
GLS_RESTORE_ENV = GLS_RESTORE_SIG | GLS_RESTORE_TTY |
GLS_REDRAW_LINE
GLS_SUSPEND_INPUT = GLS_RESTORE_ENV | GLS_RESTORE_LINE
If your signal handler, or the default system signal handler for this
signal, if you haven't overridden it, never either writes to the termi-
nal, nor suspends or terminates the calling program, then you can
safely set the flags argument to 0.
If your signal handler always writes to the terminal, reads from it, or
suspends or terminates the program, you should specify the flags argu-
ment as GL_SUSPEND_INPUT, so that:
1. The cursor doesn't get left in the middle of the input
line.
2. So that the user can type in input and have it echoed.
3. So that you don't need to end each output line with
\r\n, instead of just \n.
The GL_RESTORE_ENV combination is the same as GL_SUSPEND_INPUT, except
that it doesn't move the cursor, and if your signal handler doesn't
read or write anything to the terminal, the user won't see any visible
indication that a signal was caught. This can be useful if you have a
signal handler that only occasionally writes to the terminal, where
using GL_SUSPEND_LINE would cause the input line to be unnecessarily
duplicated when nothing had been written to the terminal. Such a sig-
nal handler, when it does write to the terminal, should be sure to
start a new line at the start of its first write, by writing a new line
before returning. If the signal arrives while the user is entering a
line that only occupies a signal terminal line, or if the cursor is on
the last terminal line of a longer input line, this will have the same
effect as GL_SUSPEND_INPUT. Otherwise it will start writing on a line
that already contains part of the displayed input line. This doesn't
do any harm, but it looks a bit ugly, which is why the GL_SUSPEND_INPUT
combination is better if you know that you are always going to be writ-
ting to the terminal.
The after argument, which determines what gl_get_line() does after the
application's signal handler returns (if it returns), can take any one
of the following values:
GLS_RETURN - Return the completed input line, just as
though the user had pressed the return
key.
GLS_ABORT - Cause gl_get_line() to abort. When
this happens, gl_get_line() returns
NULL, and a following call to
gl_return_status() will return
GLR_SIGNAL. Note that if the
application needs errno always to
have a meaningful value when
gl_get_line() returns NULL,
the callback function should set
errno appropriately.
GLS_CONTINUE - Resume command line editing.
The errno_value argument is intended to be combined with the GLS_ABORT
option, telling gl_get_line() what to set the standard errno variable
to before returning NULL to the calling program. It can also, however,
be used with the GL_RETURN option, in case you wish to have a way to
distinguish between an input line that was entered using the return
key, and one that was entered by the receipt of a signal.
Signal handling is suprisingly hard to do reliably without race condi-
tions. In gl_get_line() a lot of care has been taken to allow applica-
tions to perform reliable signal handling around gl_get_line(). This
section explains how to make use of this.
As an example of the problems that can arise if the application isn't
written correctly, imagine that one's application has a SIGINT signal
handler that sets a global flag. Now suppose that the application tests
this flag just before invoking gl_get_line(). If a SIGINT signal hap-
pens to be received in the small window of time between the statement
that tests the value of this flag, and the statement that calls
gl_get_line(), then gl_get_line() will not see the signal, and will not
be interrupted. As a result, the application won't be able to respond
to the signal until the user gets around to finishing entering the
input line and gl_get_line() returns. Depending on the application,
this might or might not be a disaster, but at the very least it would
puzzle the user.
The way to avoid such problems is to do the following.
1. If needed, use the gl_trap_signal() function to
configure gl_get_line() to abort when important
signals are caught.
2. Configure gl_get_line() such that if any of the
signals that it catches are blocked when
gl_get_line() is called, they will be unblocked
automatically during times when gl_get_line() is
waiting for I/O. This can be done either
on a per signal basis, by calling the
gl_trap_signal() function, and specifying the
GLS_UNBLOCK attribute of the signal, or globally by
calling the gl_catch_blocked() function.
void gl_catch_blocked(GetLine *gl);
This function simply adds the GLS_UNBLOCK attribute
to all of the signals that it is currently configured to
trap.
3. Just before calling gl_get_line(), block delivery
of all of the signals that gl_get_line() is
configured to trap. This can be done using the POSIX
sigprocmask() function in conjunction with the
gl_list_signals() function.
int gl_list_signals(GetLine *gl, sigset_t *set);
This function returns the set of signals that it is
currently configured to catch in the set argument,
which is in the form required by sigprocmask().
4. In the example, one would now test the global flag that
the signal handler sets, knowing that there is now no
danger of this flag being set again until
gl_get_line() unblocks its signals while performing
I/O.
5. Eventually gl_get_line() returns, either because
a signal was caught, an error occurred, or the user
finished entering their input line.
6. Now one would check the global signal flag again, and if
it is set, respond to it, and zero the flag.
7. Use sigprocmask() to unblock the signals that were
blocked in step 3.
The same technique can be used around certain POSIX signal-aware func-
tions, such as sigsetjmp() and sigsuspend(), and in particular, the
former of these two functions can be used in conjunction with sig-
longjmp() to implement race-condition free signal handling around other
long-running system calls. The way to do this, is explained next, by
showing how gl_get_line() manages to reliably trap signals around calls
to functions like read() and select() without race conditions.
The first thing that gl_get_line() does, whenever it is called, is to
use the POSIX sigprocmask() function to block the delivery of all of
the signals that it is currently configured to catch. This is redundant
if the application has already blocked them, but it does no harm. It
undoes this step just before returning.
Whenever gl_get_line() needs to call read() or select() to wait for
input from the user, it first calls the POSIX sigsetjmp() function,
being sure to specify a non-zero value for its savesigs argument. The
reason for the latter argument will become clear shortly.
If sigsetjmp() returns zero, gl_get_line() then does the following.
a. It uses the POSIX sigaction() function to register
a temporary signal handler to all of the signals that it
is configured to catch. This signal handler does two
things.
1. It records the number of the signal that was received
in a file-scope variable.
2. It then calls the POSIX siglongjmp()
function using the buffer that was passed to
sigsetjmp() for its first argument, and
a non-zero value for its second argument.
When this signal handler is registered, the sa_mask
member of the struct sigaction act argument of the
call to sigaction() is configured to contain all of
the signals that gl_get_line() is catching. This
ensures that only one signal will be caught at once by
our signal handler, which in turn ensures that multiple
instances of our signal handler don't tread on each
other's toes.
b. Now that the signal handler has been set up,
gl_get_line() unblocks all of the signals that it
is configured to catch.
c. It then calls the read() or select() system
calls to wait for keyboard input.
d. If this system call returns (ie. no signal is received),
gl_get_line() blocks delivery of the signals of
interest again.
e. It then reinstates the signal handlers that were
displaced by the one that was just installed.
Alternatively, if sigsetjmp() returns non-zero, this means that one of
the signals being trapped was caught while the above steps were execut-
ing. When this happens, gl_get_line() does the following.
First, note that when a call to siglongjmp() causes sigsetjmp() to
return, provided that the savesigs argument of sigsetjmp() was non-
zero, as specified above, the signal process mask is restored to how it
was when sigsetjmp() was called. This is the important difference
between sigsetjmp() and the older problematic setjmp(), and is the
essential ingredient that makes it possible to avoid signal handling
race conditions. Because of this we are guaranteed that all of the
signals that we blocked before calling sigsetjmp() are blocked again as
soon as any signal is caught. The following statements, which are then
executed, are thus guaranteed to be executed without any further sig-
nals being caught.
1. If so instructed by the gl_get_line() configuration
attributes of the signal that was caught,
gl_get_line() restores the terminal attributes to
the state that they had when gl_get_line() was
called. This is particularly important for signals that
suspend or terminate the process, since otherwise the
terminal would be left in an unusable state.
2. It then reinstates the application's signal handlers.
3. Then it uses the C standard-library raise()
function to re-send the application the signal that
was caught.
3. Next it unblocks delivery of the signal that we just
sent. This results in the signal that was just sent
via raise(), being caught by the application's
original signal handler, which can now handle it as it
sees fit.
4. If the signal handler returns (ie. it doesn't terminate
the process), gl_get_line() blocks delivery of the
above signal again.
5. It then undoes any actions performed in the first of the
above steps, and redisplays the line, if the signal
configuration calls for this.
6. gl_get_line() then either resumes trying to
read a character, or aborts, depending on the
configuration of the signal that was caught.
What the above steps do in essence is to take asynchronously delivered
signals and handle them synchronously, one at a time, at a point in the
code where gl_get_line() has complete control over its environment.
On most systems the combination of the TIOCGWINSZ ioctl and the SIG-
WINCH signal is used to maintain an accurate idea of the terminal size.
The terminal size is newly queried every time that gl_get_line() is
called and whenever a SIGWINCH signal is received.
On the few systems where this mechanism isn't available, at startup
new_GetLine() first looks for the LINES and COLUMNS environment vari-
ables. If these aren't found, or they contain unusable values, then if
a terminal information database like terminfo or termcap is available,
the default size of the terminal is looked up in this database. If this
too fails to provide the terminal size, a default size of 80 columns by
24 lines is used.
Even on systems that do support ioctl(TIOCGWINSZ), if the terminal is
on the other end of a serial line, the terminal driver generally has no
way of detecting when a resize occurs or of querying what the current
size is. In such cases no SIGWINCH is sent to the process, and the
dimensions returned by ioctl(TIOCGWINSZ) aren't correct. The only way
to handle such instances is to provide a way for the user to enter a
command that tells the remote system what the new size is. This command
would then call the gl_set_term_size() function to tell gl_get_line()
about the change in size.
int gl_set_term_size(GetLine *gl, int ncolumn, int nline);
The ncolumn and nline arguments are used to specify the new dimensions
of the terminal, and must not be less than 1. On systems that do sup-
port ioctl(TIOCGWINSZ), this function first calls ioctl(TIOCSWINSZ) to
tell the terminal driver about the change in size. In non-blocking
server-I/O mode, if a line is currently being input, the input line is
then redrawn to accomodate the changed size. Finally the new values are
recorded in gl for future use by gl_get_line().
The gl_terminal_size() function allows you to query the current size of
the terminal, and install an alternate fallback size for cases where
the size isn't available. Beware that the terminal size won't be
available if reading from a pipe or a file, so the default values can
be important even on systems that do support ways of finding out the
terminal size.
typedef struct {
int nline; /* The terminal has nline lines */
int ncolumn; /* The terminal has ncolumn columns */
} GlTerminalSize;
GlTerminalSize gl_terminal_size(GetLine *gl,
int def_ncolumn,
int def_nline);
This function first updates gl_get_line()'s fallback terminal dimen-
sions, then records its findings in the return value.
The def_ncolumn and def_nline specify the default number of terminal
columns and lines to use if the terminal size can't be determined via
ioctl(TIOCGWINSZ) or environment variables.
When entering sensitive information, such as passwords, it is best not
to have the text that you are entering echoed on the terminal. Fur-
thermore, such text should not be recorded in the history list, since
somebody finding your terminal unattended could then recall it, or
somebody snooping through your directories could see it in your history
file. With this in mind, the gl_echo_mode() function allows you to tog-
gle on and off the display and archival of any text that is subse-
quently entered in calls to gl_get_line().
int gl_echo_mode(GetLine *gl, int enable);
The enable argument specifies whether entered text should be visible or
not. If it is 0, then subsequently entered lines will not be visible on
the terminal, and will not be recorded in the history list. If it is 1,
then subsequent input lines will be displayed as they are entered, and
provided that history hasn't been turned off via a call to gl_tog-
gle_history(), then they will also be archived in the history list.
Finally, if the enable argument is -1, then the echoing mode is left
unchanged, which allows you to non-destructively query the current set-
ting via the return value. In all cases, the return value of the func-
tion is 0 if echoing was disabled before the function was called, and 1
if it was enabled.
When echoing is turned off, note that although tab completion will
invisibly complete your prefix as far as possible, ambiguous comple-
tions will not be displayed.
Using gl_get_line() to query the user for a single character reply, is
inconvenient for the user, since they must hit the enter or return key
before the character that they typed is returned to the program. Thus
the gl_query_char() function has been provided for single character
queries like this.
int gl_query_char(GetLine *gl, const char *prompt,
char defchar);
This function displays the specified prompt at the start of a new line,
and waits for the user to type a character. When the user types a char-
acter, gl_query_char() displays it to the right of the prompt, starts a
newline, then returns the character to the calling program. The return
value of the function is the character that was typed. If the read had
to be aborted for some reason, EOF is returned instead. In the latter
case, the application can call the previously documented gl_return_sta-
tus(), to find out what went wrong. This could, for example, have been
the reception of a signal, or the optional inactivity timer going off.
If the user simply hits enter, the value of the defchar argument is
substituted. This means that when the user hits either newline or
return, the character specified in defchar, is displayed after the
prompt, as though the user had typed it, as well as being returned to
the calling application. If such a replacement is not important, simply
pass '0 as the value of defchar.
If the entered character is an unprintable character, it is displayed
symbolically. For example, control-A is displayed as ^A, and characters
beyond 127 are displayed in octal, preceded by a backslash.
As with gl_get_line(), echoing of the entered character can be disabled
using the gl_echo_mode() function.
If the calling process is suspended while waiting for the user to type
their response, the cursor is moved to the line following the prompt
line, then when the process resumes, the prompt is redisplayed, and
gl_query_char() resumes waiting for the user to type a character.
Note that in non-blocking server mode, (see gl_io_mode),
if an incomplete input line is in the process of being read when
gl_query_char() is called, the partial input line is discarded, and
erased from the terminal, before the new prompt is displayed. The next
call to gl_get_line() will thus start editing a new line.
Whereas the gl_query_char() function visibly prompts the user for a
character, and displays what they typed, the gl_read_char() function
reads a signal character from the user, without writing anything to the
terminal, or perturbing any incompletely entered input line. This means
that it can be called not only from between calls to gl_get_line(), but
also from callback functions that the application has registered to be
called by gl_get_line().
int gl_read_char(GetLine *gl);
On success, the return value of gl_read_char() is the character that
was read. On failure, EOF is returned, and the gl_return_status() func-
tion can be called to find out what went wrong. Possibilities include
the optional inactivity timer going off, the receipt of a signal that
is configured to abort gl_get_line(), or terminal I/O blocking, when in
non-blocking server-I/O mode.
Beware that certain keyboard keys, such as function keys, and cursor
keys, usually generate at least 3 characters each, so a single call to
gl_read_char() won't be enough to identify such keystrokes.
The calling program can clear the terminal by calling gl_erase_termi-
nal(). In non-blocking server-I/O mode, this function also arranges for
the current input line to be redrawn from scratch when gl_get_line() is
next called.
int gl_erase_terminal(GetLine *gl);
Between calls to gl_get_line(), the gl_display_text() function provides
a convenient way to display paragraphs of text, left-justified and
split over one or more terminal lines according to the constraints of
the current width of the terminal. Examples of the use of this function
may be found in the demo programs, where it is used to display intro-
ductions. In those examples the advanced use of optional prefixes, suf-
fixes and filled lines to draw a box around the text is also illus-
trated.
int gl_display_text(GetLine *gl, int indentation,
const char *prefix,
const char *suffix, int fill_char,
int def_width, int start,
const char *string);
If gl isn't currently connected to a terminal, for example if the out-
put of a program that uses gl_get_line() is being piped to another pro-
gram or redirected to a file, then the value of the def_width parameter
is used as the terminal width.
The indentation argument specifies the number of characters to use to
indent each line of ouput. The fill_char argument specifies the charac-
ter that will be used to perform this indentation.
The prefix argument can either be NULL, or be a string to place at the
beginning of each new line (after any indentation). Similarly, the
suffix argument can either be NULL, or be a string to place at the end
of each line. The suffix is placed flush against the right edge of the
terminal, and any space between its first character and the last word
on that line is filled with the character specified via the fill_char
argument. Normally the fill-character is a space.
The start argument tells gl_display_text() how many characters have
already been written to the current terminal line, and thus tells it
the starting column index of the cursor. Since the return value of
gl_display_text() is the ending column index of the cursor, by passing
the return value of one call to the start argument of the next call, a
paragraph that is broken between more than one string can be composed
by calling gl_display_text() for each successive portion of the para-
graph. Note that literal newline characters are necessary at the end of
each paragraph to force a new line to be started.
On error, gl_display_text() returns -1.
Unless otherwise stated, callback functions, such as tab completion
callbacks and event callbacks should not call any functions in this
module. The following functions, however, are designed specifically to
be used by callback functions.
Calling the gl_replace_prompt() function from a callback tells
gl_get_line() to display a different prompt when the callback returns.
Except in non-blocking server mode, it has no effect if used between
calls to gl_get_line(). In non-blocking server mode (see the
gl_io_mode man page, when used between two calls to
gl_get_line() that are operating on the same input line, the current
input line will be re-drawn with the new prompt on the following call
to gl_get_line().
void gl_replace_prompt(GetLine *gl, const char *prompt);
Since libtecla version 1.4.0, gl_get_line() has been 8-bit clean. This
means that all 8-bit characters that are printable in the user's cur-
rent locale are now displayed verbatim and included in the returned
input line. Assuming that the calling program correctly contains a
call like the following,
setlocale(LC_CTYPE, "");
then the current locale is determined by the first of the environment
variables LC_CTYPE, LC_ALL, and LANG, that is found to contain a valid
locale name. If none of these variables are defined, or the program
neglects to call setlocale, then the default C locale is used, which is
US 7-bit ASCII. On most unix-like platforms, you can get a list of
valid locales by typing the command:
locale -a
at the shell prompt. Further documentation on how the user can make use
of this to enter international characters can be found in the
tecla man page.
In a multi-threaded program, you should use the libtecla_r.a version of
the library. This uses reentrant versions of system functions, where
available. Unfortunately neither terminfo nor termcap were designed to
be reentrant, so you can't safely use the functions of the getline mod-
ule in multiple threads (you can use the separate file-expansion and
word-completion modules in multiple threads, see the corresponding man
pages for details). However due to the use of POSIX reentrant functions
for looking up home directories etc, it is safe to use this module from
a single thread of a multi-threaded program, provided that your other
threads don't use any termcap or terminfo functions.
libtecla.a - The tecla library
libtecla.h - The tecla header file.
~/.teclarc - The personal tecla customization file.
libtecla, gl_io_mode, tecla, ef_expand_file,
cpl_complete_word, pca_lookup_file
Martin Shepherd (mcs@astro.caltech.edu)
gl_get_line
./libtecla/html/index.html 0100644 0000764 0000764 00000011301 10141253613 014062 0 ustar mcs mcs In addition, the library includes a path-searching module. This allows an application to provide completion and lookup of files located in UNIX style paths. Although not built into the line editor by default, it can easily be called from custom tab-completion callback functions. This was originally conceived for completing the names of executables and providing a way to look up their locations in the user's PATH environment variable, but it can easily be asked to look up and complete other types of files in any list of directories.
Note that special care has been taken to allow the use of this library in threaded programs. The option to enable this is discussed in the Makefile, and specific discussions of thread safety are presented in the included man pages.
The current version is version 1.6.1. This may be obtained from:
http://www.astro.caltech.edu/~mcs/tecla/libtecla-1.6.1.tar.gz
For the sake of automated scripts, the following URL always points to the latest version. Note that the version number can be found in the README file.
http://www.astro.caltech.edu/~mcs/tecla/libtecla.tar.gz
The library is distributed under a permissive non-copyleft free software license (the X11 license with the name of the copyright holder changed). This is compatible with, but not as restrictive as the GNU GPL.
Sun Solaris 2.5,2.6,7,8,9 with any of gcc, Sun C, or g++. Mandrake Linux 7.1 etc.., gcc Red Hat Linux 7 etc.., gcc Fedora Core 1, gcc Suse Linux 6.4, gcc IBM AIX 4.3.3, gcc HP-UX 10.20, HP-UX 11, gcc, c89 FreeBSD, gcc Alpha OSF1, cc, gcc Mac OS X Cygwin (running under Windows) QNX NetBSD 1.6, 386, gcc SGI IRIX 6.5There haven't been many reports concerning the POSIX reentrant version, so the absence of any of the above from the following list of systems on which the reentrant version is known to work, shouldn't be taken as an indication that the reentrant version doesn't work.
Sun Solaris 2.5,2.6,7,8,9 with any of gcc, Sun C, or g++. Mandrake Linux, gcc RedHat Linux, gcc Fedora Core, gcc SuSE Linux, gcc HP-UX 11, gcc IBM AIX 4.3.3, gcc Alpha OSF1, cc SGI IRIX 6.5The only system that is known to have issues with the reentrant version of the library is SCO UnixWare 7.1.1. The problem is in the system provided signal.h, which breaks when POSIX_C_SOURCE is defined. It has been reported that this can be "fixed" by editing signal.h.
If you compile the library on a system that isn't mentioned above, please send E-mail to mcs@astro.caltech.edu.
libtecla libtecla
libtecla - An interactive command-line input library.
@CC@ ... -ltecla -lcurses
The tecla library provides programs with interactive command line edit-
ing facilities, similar to those of the unix tcsh shell. In addition to
simple command-line editing, it supports recall of previously entered
command lines, TAB completion of file names or other tokens, and in-
line wild-card expansion of filenames. The internal functions which
perform file-name completion and wild-card expansion are also available
externally for optional use by the calling program.
The various parts of the library are documented in the following man
pages:
tecla - Use level documentation of the
command-line editing facilities
provided by gl_get_line().
gl_get_line - The interactive line-input module.
gl_io_mode - How to use gl_get_line() in an
incremental, non-blocking fashion.
cpl_complete_word - The word completion module.
ef_expand_file - The filename expansion module.
pca_lookup_file - A directory-list based filename
lookup and completion module.
In addition there is one optional application distributed with the
library:
enhance - Add command-line editing to third
party applications.
If the library is compiled with -D_POSIX_C_SOURCE=199506L, reentrant
versions of as many functions as possible are used. This includes using
getpwuid_r() and getpwnam_r() instead of getpwuid() and getpwnam() when
looking up the home directories of specific users in the password file
(for ~user/ expansion), and readdir_r() instead of readdir() for read-
ing directory entries when doing filename completion. The reentrant
version of the library is usually called libtecla_r.a instead of libte-
cla.a, so if only the latter is available, it probably isn't the cor-
rect version to link with threaded programs.
Reentrant functions for iterating through the password file aren't
available, so when the library is compiled to be reentrant, TAB comple-
tion of incomplete usernames in ~username/ expressions is disabled.
This doesn't disable expansion of complete ~username expressions, which
can be done reentrantly, or expansion of the parts of filenames that
follow them, so this doesn't remove much functionality.
The terminfo functions setupterm(), tigetstr(), tigetnum() and tputs()
also aren't reentrant, but very few programs will want to interact with
multiple terminals, so this shouldn't prevent this library from being
used in threaded programs.
The version number of the library can be queried using the following
function.
void libtecla_version(int *major, int *minor, int *micro);
On return, this function records the three components of the libtecla
version number in *major, *minor, *micro. The formal meaning of the
three components is as follows.
major - Incrementing this number implies that a change has
been made to the library's public interface, which
makes it binary incompatible with programs that
were linked with previous shared versions of the
tecla library.
minor - This number is incremented by one whenever
additional functionality, such as new functions or
modules, are added to the library.
micro - This is incremented whenever modifications to the
library are made which make no changes to the
public interface, but which fix bugs and/or improve
the behind-the-scenes implementation.
In Spanish, a "tecla" is the key of a keyboard. Since this library cen-
ters on keyboard input, and given that I wrote much of the library
while working in Chile, this seemed like a suitable name.
libtecla.a - The tecla library.
libtecla.h - The tecla header file.
~/.teclarc - The tecla personal customization file.
gl_get_line, tecla, gl_io_mode, ef_expand_file,
cpl_complete_word, pca_lookup_file, enhance
Martin Shepherd (mcs@astro.caltech.edu)
Markus Gyger - Lots of assistance, including help with
shared libraries, configuration information,
particularly for Solaris; modifications to
support C++ compilers, improvements for ksh
users, faster cursor motion, output
buffering, and changes to make gl_get_line()
8-bit clean.
Mike MacFaden - Suggestions, feedback and testing that led
to many of the major new functions that were
added in version 1.4.0.
Tim Eliseo - Many vi-mode bindings and fixes.
libtecla
./libtecla/html/release.html 0100644 0000764 0000764 00000070370 10141252550 014405 0 ustar mcs mcs
This file lists major changes which accompany each new release.
Version 1.6.1:
This is primarily a minor bug-fix release.
One added feature is the ability to call gl_normal_io() from
callbacks registered by gl_watch_fd() and
gl_inactivity_timeout(). This allows these callbacks to cleanly
suspend line editing before either reading from the terminal, or
writing to the terminal; and then subsequently causes the input line
to be automatically redisplayed, and line-editing to be resumed by
gl_get_line(), as soon as the callback returns.
Another minor change is that if the terminal type specified in the
TERM environment variable is set to "dumb", gl_get_line() now treats
the terminal as though it were a non-interactive stream, rather than
treating it as a VT100-compatible terminal. This means that it
doesn't either prompt for input, or perform any command-line
editing, even when it really is interacting with a terminal. This is
aimed at the rare situation where a third-pary program that connects
to libtecla through an embedded pseudo-terminal, needs to be forced
to behave as though it weren't talking to a terminal, in order that
it be useable in non-interactive scripts.
Note that in the previous release, the optional configuration
function, gl_tty_signals(), was incorrectly swapping the suspend and
terminal signal handlers before installing them.
A configuration problem that prevented select() from being used
under MacOS X, has been fixed.
Although not documented in the man page, it was meant to be possible
to take the input line that one call to gl_get_line() returned, and
ask the next call to gl_get_line() to present it back to the user
for re-editing, simply by passing the pointer returned by one call
to gl_get_line() as the start_line argument of the next call to
gl_get_line(). This feature unfortunately stopped working in 1.6.0,
so this release restores it, and officially documents it in the man
page documentation of gl_get_line().
In the previous version of the library, calling gl_terminal_size()
on a system without SIGWINCH support, would crash the
application. This has been fixed.
Libtecla now apparently compiles cleanly under IRIX.
Version 1.6.0:
This release is primarily a bug-fix release. However there are also
four new functions, so the minor version number has been
incremented to reflect this.
Two of the new functions are gl_automatic_history() and
gl_append_history(). The former of these functions allows the
application to tell gl_get_line() not to automatically archive
entered lines in the history list. The second of these functions
allows the application to explicitly append a line to the history
list. Thus together, these two functions allow the calling
application to take over control of what is placed in the history
list.
The third new function is gl_query_char(), which prompts the user
for a single character reply, which the user can then type without
having to hit return to enter it. Unless echoing is disabled, the
character that is entered is then displayed after the prompt,
and a newline is started.
Finally, the 4th new function is gl_read_char(), which also reads
a single character from the user, but doesn't prompt the user, write
anything to the terminal, or disturb any partially entered input
line. It is thus safe to call this function not only from between
calls to gl_get_line(), but also from application callback
functions, even if gl_normal_io() hasn't been called.
When using the history-search-backwards or history-search-forwards
actions, if the search prefix that the user typed, contains any of
the *,? or [ globbing characters, it is now treated as a glob
pattern to be matched against historical lines, instead of a simple
prefix.
I have added a --without-file-system option to the configure
script. This is intended for use in embedded systems that either
don't have filesystems, or where the file-system code in libtecla is
seen as unwanted bloat. See the INSTALL document for details.
Similarly, I also added a --without-file-actions option to the
configure script. This allows the application author/installer to
prevent users of gl_get_line() from accessing the filesystem with
the builtin actions of gl_get_line(). It does this by removing a
number of action functions, such as expand-filename, and list-glob,
and by changing the default behavior of other actions, such as
complete-word and list-or-eof, to show no completions.
Now to the bugs that have been fixed. Version 1.5.0 had a lot of big
internal changes, so there are a number of bugs that needed to be
fixed. There was a bug which caused a crash if gl_load_history()
was called multiple times. There was another bug which caused a
prompt not to be displayed on the next line after switching from
reading input from a file to reading from the terminal. Also, in
tecla configuration files, backslash escaped characters within
key-binding key-sequences weren't being escaped. Thus ^\\ got
interpretted as a control-\ followed by a \ character instead of as
a control-\. There was a bug in the history recall mechanism which
caused the search prefix to be forgotten in certain complicated
usage scenarios. There was a minor memory leak in the
gl_configure_getline() function. Finally, if gl_get_line() was
aborted by a signal, or any other abnormal event, the value of errno
which originally indicated what had happened, got zeroed by the
code that restored the terminal to a usable state. Thus the
application couldn't figure out what had caused the error, apart
from by looking at gl_return_status(). All of these bugs have been
fixed.
In the Makefile, there were a number of places where install-sh was
invoked without a path prefix. This has now been remedied.
A fully functional workaround for a bug in Solaris' terminal I/O
code has also been implemented. This bug, which only manifested
itself in libtecla's uncommonly used non-blocking server I/O mode,
caused characters entered while in normal I/O mode, between calls to
gl_get_line() to be invisible to the next call to gl_get_line(),
until the user typed at least one more key after raw terminal mode
was restored.
The Gnu autoconf config.guess and config.sub scripts have been
updated to their latest versions. Apparently the old versions that I
was previously using were too old to know about certain BSD ports.
Version 1.5.0:
This release includes several major new features for those using
gl_get_line(), shared library support in Darwin, better cross
compilation support, and various minor bug fixes.
The biggest new feature is the option of a non-blocking I/O mode, in
which gl_get_line() can safely be called from an application's
external event-loop to incrementally read input lines from the user.
This feature is documented in the gl_io_mode(3) man page.
In addition, there is now support for the definition of additional
word-completion action functions, which can then be bound to
different keys. See the documentation of the gl_completion_action()
function in the gl_get_line(3) man page.
Externally defined action functions can also be defined, although
presently they don't have write access to the input line, so they
are restricted to operations that display information text to the
terminal, or modify the environment of the calling application in
some way. See the documentation of the gl_register_action() function
in the gl_get_line(3) man page.
Some of the non-blocking I/O support functions can also be used for
improved signal handling in the normal blocking mode. In particular,
the gl_list_signals() and gl_catch_blocked() functions make it
easier to write reliable signal handling around gl_get_line(). The
new "RELIABLE SIGNAL HANDLING" section of the gl_get_line(3) man
page is intended as an introduction to this subject.
Programs can now clear the terminal between calls to gl_get_line(),
by calling the new gl_erase_terminal() function.
The gl_display_text() function, now used in the demos to display
introductory banners, is provided for formatting text according to
the width of the terminal.
It is now possible to install inactivity timeout callbacks in
gl_get_line(), using the new gl_inactivity_timeout() function.
The new gl_set_term_size() function allows the application to
explicitly set the terminal size, for cases, such as when one is
using a terminal at the end of a serial lineq, where the terminal
driver doesn't send the process a SIGWINCH when the terminal size
changes.
The new gl_bind_keyseq() function provides a convenient
alternative to gl_configure_getline(), for binding or unbinding
one key-sequence at a time.
gl_get_line()s signal handling, file-descriptor event-handling,
inactivity-timeout handling and server-mode non-blocking I/O
features now not only work when input is coming from a terminal, but
now also work when input is coming from non-interactive streams,
such as files and pipes.
The history implementation has been re-written to make it more
efficient and easier to modify. The biggest user-level change is
that when recalling history lines using a search prefix, the same
line is no longer returned more than once in a row. Previously this
duplicate elimination only worked when one was recalling a line
without specifying a search prefix, and this was naively performed
by preventing neighboring duplicates from existing in the history
list, rather than by skipping duplicates at search time.
In previous versions of the library, when gl_get_line() and its
associated public functions detected invalid arguments, or couldn't
allocate memory, etc, error messages were written to stderr. This
isn't appropriate for library functions, so instead of writing such
messages to stderr, these messages are now recorded in buffers
within the affected GetLine object. The latest error message can
then subsequently be queried by calling gl_error_message(). The use
of errno has also been expanded, and a new function called
gl_return_status() has been provided to expand on the cause of the
last return from gl_get_line().
User level usage and configuration information has now been split
out of the gl_get_line(3) man page into a separate tecla(7) man
page. The enhance(3) man page has also been renamed to enhance(1).
When expanding "~/", gl_get_line() now checks for, and returns the
value of the HOME environment variable, if it exists, in preference
to looking up the directory of the current user in the password
file.
When the terminal was resized to a narrower width, previous versions
of gl_get_line() would redraw the line higher up the terminal. This
bug has been fixed. A bug in history recall has also been fixed, in
which an error message was being generated if one attempted to
recall a line while the cursor was at the end of the longest
possible input line. A more serious bug, in which callbacks
registered by gl_watch_fd() weren't being called for write-events,
has also been fixed. Finally, a few minor fixes have been made to
improve support under QNX and Mac OS X.
Beware that in this release, much of the underlying code has
undergone some radical re-work, so although backwards compatibility
of all documented features has been preserved, there may be some
lingering bugs that could break existing programs. So, if you plan
to use this version in production code, please test it as far as
possible within your application before releasing it to your
clients, and as always, please report any unexpected behavior.
Version 1.4.1:
This is a maintenance release. It includes minor changes to support
Mac OS X (Darwin), the QNX real-time operating system, and Cygwin
under Windows. It also fixes an oversight that was preventing the
tab key from inserting tab characters when users unbound the
complete-word action from it.
Version 1.4.0:
The contents of the history list can now be saved and restored with
the new gl_save_history() and gl_load_history() functions.
Event handlers can now be registered to watch for and respond to I/O
on arbitrary file descriptors while gl_get_line() is waiting for
terminal input from the user. See the gl_get_line(3) man page
for details on gl_watch_fd().
As an optional alternative to getting configuration information only
from ~/.teclarc, the new gl_configure_getline() function allows
configuration commands to be taken from any of, a string, a
specified application-specific file, and/or a specified
user-specific file. See the gl_get_line(3) man page for details.
The version number of the library can now be queried using the
libtecla_version() function. See the libtecla(3) man page.
The new gl_group_history() function allows applications to group
different types of input line in the history buffer, and arrange for
only members of the appropriate group to be recalled on a given call
to gl_get_line(). See the gl_get_line(3) man page.
The new gl_show_history() function displays the current history list
to a given stdio output stream. See the gl_get_line(3) man page.
new_GetLine() now allows you to specify a history buffer size of
zero, thus requesting that no history buffer be allocated. You can
subsequently resize or delete the history buffer at any time, by
calling gl_resize_history(), limit the number of lines that are
allowed in the buffer by calling gl_limit_history(), clear either
all history lines from the history list, or just the history lines
that are associated with the current history group, by calling
gl_clear_history, and toggle the history mechanism on and off by
calling gl_toggle_history().
The new gl_terminal_size() function can be used to query the
current terminal size. It can also be used to supply a default
terminal size on systems where no mechanism is available for
looking up the size.
The contents and configuration of the history list can now be
obtained by the calling application, by calling the new
gl_lookup_history(), gl_state_of_history(), gl_range_of_history()
and gl_size_of_history() functions. See the gl_get_line(3) man page.
Echoing of the input line as it is typed, can now be turned on and
off via the new gl_echo_mode() function. While echoing is disabled,
newly entered input lines are omitted from the history list. See
the gl_get_line(3) man page.
While the default remains to display the prompt string literally,
the new gl_prompt_style() function can be used to enable text
attribute formatting directives in prompt strings, such as
underlining, bold font, and highlighting directives.
Signal handling in gl_get_line() is now customizable. The default
signal handling behavior remains essentially the same, except that
the SIGTSTP, SIGTTIN and SIGTTOU are now forwarded to the
corresponding signal handler of the calling program, instead of
causing a SIGSTOP to be sent to the application. It is now possible
to remove signals from the list that are trapped by gl_get_line(),
as well as add new signals to this list. The signal and terminal
environments in which the signal handler of the calling program is
invoked, and what gl_get_line() does after the signal handler
returns, is now customizable on a per signal basis. You can now also
query the last signal that was caught by gl_get_line(). This is
useful when gl_get_line() aborts with errno=EINTR, and you need to
know which signal caused it to abort.
Key-sequences bound to action functions can now start with printable
characters. Previously only keysequences starting with control or
meta characters were permitted.
gl_get_line() is now 8-bit clean. If the calling program has
correctly called setlocale(LC_CTYPE,""), then the user can select an
alternate locale by setting the standard LC_CTYPE, LC_ALL, or LANG
environment variables, and international characters can then be
entered directly, either by using a non-US keyboard, or by using a
compose key on a standard US keyboard. Note that in locales in which
meta characters become printable, meta characters no longer match
M-c bindings, which then have to be entered using their escape-c
equivalents. Fortunately most modern terminal emulators either
output the escape-c version by default when the meta key is used, or
can be configured to do so (see the gl_get_line(3) man page), so in
most cases you can continue to use the meta key.
Completion callback functions can now tell gl_get_line() to return
the input line immediately after a successful tab completion, simply
by setting the last character of the optional continuation suffix to
a newline character (ie. in the call to cpl_add_completion()).
It is now safe to create and use multiple GetLine objects, albeit
still only from a single thread. In conjunction with the new
gl_configure_getline() function, this optionally allows multiple
GetLine objects with different bindings to be used to implement
different input modes.
The edit-mode configuration command now accepts the argument,
none. This tells gl_get_line() to revert to using just the native
line editing facilities provided by the terminal driver. This could
be used if the termcap or terminfo entry of the host terminal were
badly corrupted.
Application callback functions invoked by gl_get_line() can now
change the displayed prompt using the gl_replace_prompt() function.
Their is now an optional program distributed with the library. This
is a beta release of a program which adds tecla command-line editing
to virtually any third party application without the application
needing to be linked to the library. See the enhance(3) man page for
further details. Although built and installed by default, the
INSTALL document explains how to prevent this.
The INSTALL document now explains how you can stop the demo programs
from being built and installed.
NetBSD/termcap fixes. Mike MacFaden reported two problems that he
saw when compiling libtecla under NetBSD. Both cases were related to
the use of termcap. Most systems use terminfo, so this problem has
gone unnoticed until now, and won't have affected the grand majority
of users. The configure script had a bug which prevented the check
for CPP working properly, and getline.c wouldn't compile due to an
undeclared variable when USE_TERMCAP was defined. Both problems have
now been fixed. Note that if you successfully compiled version
1.3.3, this problem didn't affect you.
An unfortunate and undocumented binding of the key-sequence M-O was
shadowing the arrow-key bindings on systems that use ^[OA etc. I
have removed this binding (the documented lower case M-o binding
remains bound). Under the KDE konsole terminal this was causing the
arrow keys to do something other than expected.
There was a bug in the history list code which could result in
strange entries appearing at the start of the history list once
enough history lines had been added to the list to cause the
circular history buffer to wrap. This is now fixed.
Version 1.3.3:
Signal handling has been re-written, and documentation of its
behaviour has been added to the gl_get_line(3) man page. In addition
to eliminating race conditions, and appropriately setting errno for
those signals that abort gl_get_line(), many more signals are now
intercepted, making it less likely that the terminal will be left in
raw mode by a signal that isn't trapped by gl_get_line().
A bug was also fixed that was leaving the terminal in raw mode if
the editing mode was changed interactively between vi and emacs.
This was only noticeable when running programs from old shells that
don't reset terminal modes.
Version 1.3.2:
Tim Eliseo contributed a number of improvements to vi mode,
including a fuller set of vi key-bindings, implementation of the vi
constraint that the cursor can't backup past the point at which
input mode was entered, and restoration of overwritten characters
when backspacing in overwrite mode. There are also now new bindings
to allow users to toggle between vi and emacs modes interactively.
The terminal bell is now used in some circumstances, such as when an
unrecognized key sequence is entered. This can be turned off by the
new nobeep option in the tecla configuration file.
Unrelated to the above, a problem under Linux which prevented ^Q
from being used to resume terminal output after the user had pressed
^S, has been fixed.
Version 1.3.1:
In vi mode a bug was preventing the history-search-backward and
history-search-forward actions from doing anything when invoked on
empty lines. On empty lines they now act like up-history and
down-history respectively, as in emacs mode.
When creating shared libraries under Linux, the -soname directive
was being used incorrectly. The result is that Linux binaries linked
with the 1.2.3, 1.2.4 and 1.3.0 versions of the tecla shared
libraries, will refuse to see other versions of the shared library
until relinked with version 1.3.1 or higher.
The configure script can now handle the fact that under Solaris-2.6
and earlier, the only curses library is a static one that hides in
/usr/ccs/lib. Under Linux it now also caters for old versions of GNU
ld which don't accept version scripts.
The demos are now linked against the shared version of the library
if possible. Previously they were always linked with the static
version.
Version 1.3.0:
The major change in this release is the addition of an optional vi
command-line editing mode in gl_get_line(), along with lots of new
action functions to support its bindings. To enable this, first
create a ~/.teclarc file if you don't already have one, then add the
following line to it.
edit-mode vi
The default vi bindings, which are designed to mimic those of the vi
editor as closely as possible, are described in the gl_get_line(3)
man page.
A new convenience function called ef_list_expansions() has been
added for listing filename expansions. See the ef_list_expansions(3)
man page for details. This is used in a new list-glob binding, bound
to ^Xg in emacs mode, and ^G in vi input mode.
A bug has been fixed in the key-binding table expansion code. This
bug would have caused problems to anybody who defined more than
about 18 personalized key-bindings in their ~/.teclarc file.
Version 1.2.4:
Buffered I/O is now used for writing to terminals, and where
supported, cursor motion is done with move-n-positions terminfo
capabilities instead of doing lots of move-1-position requests. This
greatly improves how the library feels over slow links.
You can now optionally compile different architectures in different
directories, without having to make multiple copies of the
distribution. This is documented in the INSTALL file.
The ksh ~+ directive is now supported.
Thanks to Markus Gyger for the above improvements.
Documentation has been added to the INSTALL file describing features
designed to facilitate configuration and installation of the library
as part of larger packages. These features are intended to remove
the need to modify the tecla distribution's configuration and build
procedures when embedding the libtecla distribution in other package
distributions.
A previous fix to stop the cursor from warping when the last
character of the input line was in the last column of the terminal,
was only being used for the first terminal line of the input line.
It is now used for all subsequent lines as well, as originally
intended.
Version 1.2.3:
The installation procedure has been better automated with the
addition of an autoconf configure script. This means that installers
can now compile and install the library by typing:
./configure
make
make install
On all systems this makes at least the normal static version of the
tecla library. It also makes the reentrant version if reentrant
POSIX functions are detected. Under Solaris, Linux and HP-UX the
configuration script arranges for shared libraries to be compiled in
addition to the static libraries. It is hoped that installers will
return information about how to compile shared libraries on other
systems, for inclusion in future releases, and to this end, a new
PORTING guide has been provided.
The versioning number scheme has been changed. This release would
have been 1.2c, but instead will be refered to as 1.2.3. The
versioning scheme, based on conventions used by Sun Microsystems, is
described in configure.in.
The library was also tested under HP-UX, and this revealed two
serious bugs, both of which have now been fixed.
The first bug prevented the library from writing control codes to
terminals on big-endian machines, with the exception of those
running under Solaris. This was due to an int variable being used
where a char was needed.
The second bug had the symptom that on systems that don't use the
newline character as the control code for moving the cursor down a
line, a newline wasn't started when the user hit enter.
Version 1.2b:
Two more minor bug fixes:
Many terminals don't wrap the cursor to the next line when a
character is written to the rightmost terminal column. Instead, they
delay starting a new line until one more character is written, at
which point they move the cursor two positions. gl_get_line()
wasn't aware of this, so cursor repositionings just after writing
the last character of a column, caused it to erroneously go up a
line. This has now been remedied, using a method that should work
regardless of whether a terminal exhibits this behavior or not.
Some systems dynamically record the current terminal dimensions in
environment variables called LINES and COLUMNS. On such systems,
during the initial terminal setup, these values should override the
static values read from the terminal information databases, and now
do. Previously they were only used if the dimensions returned by
terminfo/termcap looked bogus.
Version 1.2a:
This minor release fixes the following two bugs:
The initial terminal size and subsequent changes thereto, weren't
being noticed by gl_get_line(). This was because the test for the
existence of TIOCWINSZ was erroneously placed before the inclusion
of termios.h. One of the results was that on input lines that
spanned more than one terminal line, the cursor occasionally jumped
unexpectedly to the previous terminal line.
On entering a line that wrapped over multiple terminal lines,
gl_get_line() simply output a carriage-return line-feed at the point
at which the user pressed return. Thus if one typed in such a line,
then moved back onto one of the earlier terminal lines before
hitting return, the cursor was left on a line containing part of the
line that had just been entered. This didn't do any harm, but it
looked a mess.
Version 1.2:
A new facility for looking up and completing filenames in UNIX-style
paths has now been added (eg. you can search for, or complete
commands using the UNIX PATH environment variable). See the
pca_lookup_file(3) man page.
The already existing filename completion callback can now be made
selective in what types of files it lists. See the
cpl_complete_word(3) man page.
Due to its potential to break applications when changed, the use of
the publically defined CplFileArgs structure to configure the
cpl_file_completions() callback is now deprecated. The definition
of this structure has been frozen, and its documentation has been
removed from the man pages. It will remain supported, but if you
have used it, you are recommended to switch to the new method, which
involves a new opaque configuration object, allocated via a provided
constructor function, configured via accessor functions, and
eventually deleted with a provided destructor function. The
cpl_file_completions() callback distinguishes which structure type
it has been sent by virtue of a code placed at the start of the new
structure by the constructor. It is assumed that no existing
applications set the boolean 'escaped' member of the CplFileArgs
structure to 4568. The new method is documented in the
cpl_complete_word(3) man page.
Version 1.1j
This was the initial public release on freshmeat.org.
./libtecla/html/enhance.html 0100644 0000764 0000764 00000006357 10141252544 014375 0 ustar mcs mcs
enhance enhance
enhance - A program that adds command-line editing to third party pro-
grams.
enhance command [ argument ... ]
The enhance program provides enhanced command-line editing facilities
to users of third party applications, to which one doesn't have any
source code. It does this by placing a pseudo-terminal between the
application and the real terminal. It uses the tecla command-line edit-
ing library to read input from the real terminal, then forwards each
just completed input line to the application via the pseudo-terminal.
All output from the application is forwarded back unchanged to the real
terminal.
Whenever the application stops generating output for more than a tenth
of a second, the enhance program treats the latest incomplete output
line as the prompt, and redisplays any incompleted input line that the
user has typed after it. Note that the small delay, which is impercep-
tible to the user, isn't necessary for correct operation of the pro-
gram. It is just an optimization, designed to stop the input line from
being redisplayed so often that it slows down output.
Note that the user-level command-line editing facilities provided by
the Tecla library are documented in the tecla man page
The one major problem that hasn't been solved yet, is how to deal with
applications that change whether typed input is echo'd by their con-
trolling terminal. For example, programs that ask for a password, such
as ftp and telnet, temporarily tell their controlling terminal not to
echo what the user types. Since this request goes to the application
side of the psuedo terminal, the enhance program has no way of knowing
that this has happened, and continues to echo typed input to its con-
trolling terminal, while the user types their password.
Furthermore, before executing the host application, the enhance program
initially sets the pseudo terminal to noecho mode, so that everything
that it sends to the program doesn't get redundantly echoed. If a pro-
gram that switches to noecho mode explicitly restores echoing after-
wards, rather than restoring the terminal modes that were previously in
force, then subsequently, every time that you enter a new input line, a
duplicate copy will be displayed on the next line.
libtecla.a - The tecla library.
~/.teclarc - The tecla personal customization file.
tecla, libtecla
Martin Shepherd (mcs@astro.caltech.edu)
enhance
./libtecla/html/gl_io_mode.html 0100644 0000764 0000764 00000061475 10141252547 015076 0 ustar mcs mcs
gl_io_mode gl_io_mode
gl_io_mode, gl_raw_io, gl_normal_io, gl_tty_signals, gl_abandon_line,
gl_handle_signal, gl_pending_io - How to use gl_get_line() from an
external event loop.
#include <libtecla.h>
int gl_io_mode(GetLine *gl, GlIOMode mode);
int gl_raw_io(GetLine *gl);
int gl_normal_io(GetLine *gl);
int gl_tty_signals(void (*term_handler)(int),
void (*susp_handler)(int),
void (*cont_handler)(int),
void (*size_handler)(int));
void gl_abandon_line(GetLine *gl);
void gl_handle_signal(int signo, GetLine *gl, int ngl);
GlPendingIO gl_pending_io(GetLine *gl);
The gl_get_line() function, which is documented separately in the
gl_get_line man page, supports two different I/O modes.
These are selected by calling the gl_io_mode() function.
int gl_io_mode(GetLine *gl, GlIOMode mode);
The mode argument of this function specifies the new I/O mode, and must
be one of the following.
GL_NORMAL_MODE - Select the normal blocking-I/O mode.
In this mode gl_get_line()
doesn't return until either an error
occurs of the user finishes entering a
new line. This mode is the focus of
the gl_get_line man page.
GL_SERVER_MODE - Select non-blocking server I/O mode.
In this mode, since non-blocking
terminal I/O is used, the entry of
each new input line typically requires
many calls to gl_get_line() from
an external I/O-driven event loop.
This mode is the focus of this man
page.
Newly created GetLine objects start in normal I/O mode, so to switch to
non-blocking server mode requires an initial call to gl_io_mode().
In non-blocking server I/O mode, the application is required to have an
event loop which calls gl_get_line() whenever the terminal file
descriptor can do the type I/O that gl_get_line() is waiting for. To
determine which type of I/O gl_get_line() is waiting for, the applica-
tion calls the gl_pending_io() function.
GlPendingIO gl_pending_io(GetLine *gl);
The return value of this function is one of the following two enumer-
ated values.
GLP_READ - gl_get_line() is waiting to write a
character to the terminal.
GLP_WRITE - gl_get_line() is waiting to read a
character from the keyboad.
If the application is using either the select() or poll() system calls
to watch for I/O on a group of file descriptors, then it should call
the gl_pending_io() function before each call to these functions to see
which direction of I/O it should tell them to watch for, and configure
their arguments accordingly. In the case of the select() system call,
this means using the FD_SET() macro to add the terminal file descriptor
either to the set of file descriptors to be watched for readability, or
the set to be watched for writability.
As in normal I/O mode, the return value of gl_get_line() is either a
pointer to a completed input line, or NULL. However, whereas in normal
I/O mode a NULL return value always means that an error occurred, in
non-blocking server mode, NULL is also returned when gl_get_line()
can't read or write to the terminal without blocking. Thus in non-
blocking server mode, in order to determine when a NULL return value
signifies that an error occurred or not, it is necessary to call the
gl_return_status() function. If this function returns the enumerated
value, GLR_BLOCKED, as documented in the gl_get_line man
page, this means that gl_get_line() is waiting for I/O, and no error
has occurred.
When gl_get_line() returns NULL and gl_return_status() indicates that
this is due to blocked terminal I/O, the application should call
gl_get_line() again when the type of I/O reported by gl_pending_io()
becomes possible. The prompt, start_line and start_pos arguments of
gl_get_line() will be ignored on these calls. If you need to change
the prompt of the line that is currently being edited, then you can
call the gl_replace_prompt() function (documented in the
gl_get_line man page) between calls to gl_get_line().
A complication that is unique to non-blocking server mode is that it
requires that the terminal be left in raw mode between calls to
gl_get_line(). If this weren't the case, the external event loop
wouldn't be able to detect individual key-presses, and the basic line
editing implemented by the terminal driver would clash with the editing
provided by gl_get_line(). What this means is that any time that the
terminal needs to be used for other things than entering a new input
line with gl_get_line(), it needs to be restored to a usable state. In
particular, whenever the process is suspended or terminated, the termi-
nal must be returned to a normal state. If this isn't done, then
depending on the characteristics of the shell that was used to invoke
the program, the user may end up with a hung terminal. To this end, the
gl_normal_io() function is provided for switching the terminal back to
the state that it was in when raw mode was last established.
int gl_normal_io(GetLine *gl);
What this function does is first flush any pending output to the termi-
nal, then move the cursor to the start of the terminal line which fol-
lows the end of the incompletely entered input line. At this point it
is safe to suspend or terminate the process, and it is safe for the
application to read and write to the terminal. To resume entry of the
input line, the application should call the gl_raw_io() function.
int gl_raw_io(GetLine *gl);
This function starts a new line, redisplays the partially completed
input line (if any), restores the cursor position within this line to
where it was when gl_normal_io() was called, then switches back to raw,
non-blocking terminal mode ready to continue entry of the input line
when gl_get_line() is next called.
Note that in non-blocking server mode, if gl_get_line() is called after
a call to gl_normal_io(), without an intervening call to gl_raw_io(),
gl_get_line() will call gl_raw_mode() itself, and the terminal will
remain in this mode when gl_get_line() returns.
In the previous section it was pointed out that in non-blocking server
mode, the terminal must be restored to a sane state whenever a signal
is received that either suspends or terminates the process. In normal
I/O mode, this is done for you by gl_get_line(), but in non-blocking
server mode, since the terminal is left in raw mode between calls to
gl_get_line(), this signal handling has to be done by the application.
Since there are many signals that can suspend or terminate a process,
as well as other signals that are important to gl_get_line(), such as
the SIGWINCH signal, which tells it when the terminal size has changed,
the gl_tty_signals() function is provided for installing signal han-
dlers for all pertinent signals.
int gl_tty_signals(void (*term_handler)(int),
void (*susp_handler)(int),
void (*cont_handler)(int),
void (*size_handler)(int));
What this does is use gl_get_line()'s internal list of signals to
assign specified signal handlers to groups of signals. The arguments of
this function are as follows.
term_handler - This is the signal handler that is to be
used to trap signals that by default
terminate any process that receives
them (eg. SIGINT or SIGTERM).
susp_handler - This is the signal handler that is to be
used to trap signals that by default
suspend any process that receives them,
(eg. SIGTSTP or SIGTTOU).
cont_handler - This is the signal handler that is to be
used to trap signals that are usually
sent when a process resumes after being
suspended (usually SIGCONT). Beware that there is
nothing to stop a user from sending one of these
signals at other times.
size_handler - This signal handler is used to trap
signals that are sent to processes when
their controlling terminals are resized
by the user (eg. SIGWINCH).
These arguments can all be the same, if so desired, and you can specify
SIG_IGN (ignore this signal) or SIG_DFL (use the system-provided
default signal handler) instead of a function where pertinent. In par-
ticular, it is rarely useful to trap SIGCONT, so the cont_handler argu-
ment will usually be SIG_DFL or SIG_IGN.
The gl_tty_signals() function uses the POSIX sigaction() function to
install these signal handlers, and it is careful to use the sa_mask
member of each sigaction structure to ensure that only one of these
signals is ever delivered at a time. This guards against different
instances of these signal handlers from simultaneously trying to write
to common global data, such as a shared sigsetjmp() buffer or a signal-
received flag.
The signal handlers that are installed by this function, should call
the gl_handle_signal().
void gl_handle_signal(int signo, GetLine *gl, int ngl);
The signo argument tells this function which signal it is being asked
to respond to, and the gl argument should be a pointer to the first
element of an array of ngl GetLine objects. If your application only
has one of these objects, just pass its pointer as the gl argument and
specify ngl as 1.
Depending on the signal that is being handled, this function does dif-
ferent things.
Terminal resize signals (SIGWINCH)
If the signal indicates that the terminal was resized, then it arranges
for the next call to gl_get_line() to ask the terminal for its new size
and redraw the input line accordingly. In order that gl_get_line() be
called as soon as possible to do this, gl_handle_signal() also arranges
that the next call to gl_pending_io() will return GLP_WRITE. Thus if
the application waits for I/O in select() or poll(), then the applica-
tion needs to ensure that these functions will be reliably aborted when
a signal is caught and handled by the application. More on this below.
If the signal that was caught is one of those that by default termi-
nates any process that receives it, then gl_handle_signal() does the
following steps.
1. First it blocks the delivery of all signals that can be
blocked (ie. SIGKILL and SIGSTOP can't be blocked)
2. Next it calls gl_normal_io() for each of the ngl
GetLine objects. Note that this does nothing to any of the
GetLine objects that aren't currently in raw mode.
3. Next it sets the signal handler of the signal to its default,
process-termination disposition.
4. Next it re-sends the process the signal that was caught.
5. Finally it unblocks delivery of this signal, which
results in the process being terminated.
If the default disposition of the signal is to suspend the process, the
same steps are executed as for process termination signals, except that
when the process is later resumed, gl_handle_signal() continues, and
does the following steps.
6. It re-blocks delivery of the signal.
7. It reinstates the signal handler of the signal to the one
that was displaced when its default disposition was substituted.
8. For any of the GetLine objects that were in raw mode when
gl_handle_signal() was called, gl_handle_signal() then
calls gl_raw_io(), to resume entry of the input lines on
those terminals.
9. Finally, it restores the signal process mask to how it
was when gl_handle_signal() was called.
Note that the process is suspended or terminated using the original
signal that was caught, rather than using the uncatchable SIGSTOP and
SIGKILL signals. This is important, because when a process is suspended
or terminated, the parent of the process may wish to use the status
value returned by the wait() system call to figure out which signal was
responsible. In particular, most shells use this information to print a
corresponding message to the terminal. Users would be rightly confused
if when their process received a SIGPIPE signal, the program responded
by sending itself a SIGKILL signal, and the shell then printed out the
provocative statement, "Killed!".
If a signal is caught and handled when the application's event loop is
waiting in select() or poll(), these functions will be aborted with
errno set to EINTR. When this happens the event loop should call
gl_pending_io(), before calling select() or poll() again. It should
then arrange for select() or poll() to wait for the type of I/O that
this reports. This is necessary, because any signal handler which calls
gl_handle_signal(), will frequently change the type of I/O that
gl_get_line() is waiting for.
Unfortunately, if a signal arrives between the statements which config-
ure the arguments of select() or poll() and the calls to these func-
tions, then the signal will not be seen by these functions, which will
then not be aborted. If these functions are waiting for keyboard input
from the user when the signal is received, and the signal handler
arranges to redraw the input line to accomodate a terminal resize or
the resumption of the process, then this redisplay will be end up being
delayed until the user hits the next key. Apart from puzzling the user,
this clearly isn't a serious problem. However there is a way, albeit
complicated, to completely avoid this race condition. The following
steps illustrate this.
1. Block all of the signals that gl_get_line() catches,
by passing the signal set returned by gl_list_signals() to
sigprocmask().
2. Call gl_pending_io() and set up the arguments of
select() or poll() accordingly.
3. Call sigsetjmp() with a non-zero savesigs argument.
4. Initially this sigsetjmp() statement will return zero,
indicating that control isn't resuming there after a matching
call to siglongjmp().
5. Replace all of the handlers of the signals that gl_get_line()
is configured to catch, with a signal handler that first records
the number of the signal that was caught, in a file-scope variable,
then calls siglongjmp() with a non-zero value argument, to
return execution to the above sigsetjmp()
statement. Registering these signal handlers can conveniently be
done using the gl_tty_signals() function.
6. Set the file-scope variable that the above signal handler uses to
record any signal that is caught to -1, so that we can check
whether a signal was caught by seeing if it contains a valid signal
number.
7. Now unblock the signals that were blocked in step 1. Any signal
that was received by the process in between step 1 and now will
now be delivered, and trigger our signal handler, as will any
signal that is received until we block these signals again.
8. Now call select() or poll().
9. When select() returns, again block the signals that were
unblocked in step 7.
If a signal is arrived any time during the above steps, our signal han-
dler will be triggered and cause control to return to the sigsetjmp()
statement, where this time, sigsetjmp() will return non-zero, indicat-
ing that a signal was caught. When this happens we simply skip the
above block of statements, and continue with the following statements,
which are executed regardless of whether or not a signal is caught.
Note that when sigsetjmp() returns, regardless of why it returned, the
process signal mask is returned to how it was when sigsetjmp() was
called. Thus the following statements are always executed with all of
our signals blocked.
9. Reinstate the signal handlers that were displaced in step 5.
10. Check wether a signal was caught, by checking the file-scope
variable that the signal handler records signal numbers in.
11. If a signal was caught, send this signal to the application
again, and unblock just this signal, so that it invokes the
signal handler which we just reinstated in step 10.
12. Unblock all of the signals that were blocked in step 7.
Since this is complicated, note that demo3.c includes a working example
of how to do this. The method used there however, is more general than
the above. What it provides is a wrapper function around select() which
encompasses steps 3 to 11. In this wrapper, rather than use
gl_list_signals() to figure out the signals to block, and and
gl_tty_signals() to assign and revert signal handlers, one of its argu-
ments is a sigset_t which specifies which signals to block and assign
signal handlers to. This function thus doesn't depend on gl_get_line()
and can thus be used in other situations where race-condition-free sig-
nal handling is required.
Since the application is expected to handle signals in non-blocking
server mode, gl_get_line() doesn't attempt to duplicate this when it is
being called. If one of the signals that it is configured to catch is
sent to the application while gl_get_line() is being called,
gl_get_line() reinstates the caller's signal handlers, then just before
returning, re-sends the signal to the process to let the application's
signal handler handle it. If the process isn't terminated by this sig-
nal, gl_get_line() returns NULL, and a following call to gl_return_sta-
tus() returns the enumerated value GLR_SIGNAL.
Often, rather than letting it terminate the process, applications
respond to the SIGINT user-interrupt signal by aborting the current
input line. The way to do this in non-blocking server-I/O mode is to
not call gl_handle_signal() when this signal is caught, but instead to
call the gl_abandon_line().
void gl_abandon_line(GetLine *gl);
This function arranges that when gl_get_line() is next called, it first
flushes any pending output to the terminal, then discardes the current
input line, outputs a new prompt on the next line, and finally starts
accepting input of a new input line from the user.
Provided that certain rules are followed, the following functions can
have been written to be safely callable from signal handlers. Other
functions in this library should not be called from signal handlers.
gl_normal_io()
gl_raw_io()
gl_handle_signal()
gl_abandon_line()
In order for this to be true, all signal handlers that call these func-
tions must be registered in such a way that only one instance of any
one of them can be running at one time. The way to do this is to use
the POSIX sigaction() function to register all signal handlers, and
when doing this, use the sa_mask member of the corresponding sigaction
structure, to indicate that all of the signals who's handlers invoke
the above functions, should be blocked when the current signal is being
handled. This prevents two signal handlers from operating on a GetLine
object at the same time.
To prevent signal handlers from accessing a GetLine object while
gl_get_line() or any of its associated public functions are operating
on it, all public functions associated with gl_get_line(), including
gl_get_line() itself, temporarily block the delivery of signals when
they are accessing GetLine objects. Beware that the only signals that
they block are the signals that gl_get_line() is currently configured
to catch, so be sure that if you call any of the above functions from
signal handlers, that the signals that these handlers are assigned to
are configured to be caught by gl_get_line() (see gl_trap_signal()).
If instead of using select() or poll() to wait for I/O, your applica-
tion just needs to get out of gl_get_line() periodically to briefly do
something else before returning to accept input from the user, this can
be done in non-blocking server mode by using the gl_inactivity_time-
out() function (see gl_get_line), to specify that a
callback function that returns GLTO_CONTINUE should be called whenever
gl_get_line() has been waiting for I/O for more than a specified amount
of time.
When this callback is triggered, gl_get_line() will return NULL, and a
following call to gl_return_status() will return GLR_BLOCKED.
Beware that gl_get_line() won't return until the user hasn't typed a
key for the specified interval, so if the interval is long, and the
user keeps typing, gl_get_line() may not return for a while. In other
words there is no guarantee that it will return in the time specified.
The demo3 program that is distributed with the library, provides a
working example of how to use non-blocking server I/O mode in a real
program. As far as the user is concerned, this program operates
identically to the main demo program (called demo), except that whereas
the main demo program uses the normal blocking I/O mode, demo3 using
non-blocking I/O and an external event loop. The source code can be
found in demo3.c, and the comments therein explain the various steps.
libtecla.a - The tecla library
libtecla.h - The tecla header file.
libtecla, gl_get_line, tecla, ef_expand_file,
cpl_complete_word, pca_lookup_file
Martin Shepherd (mcs@astro.caltech.edu)
gl_io_mode
./libtecla/html/tecla.html 0100644 0000764 0000764 00000162474 10141252550 014064 0 ustar mcs mcs
tecla tecla
tecla, teclarc - The user interface provided by the Tecla library.
This man page describes the command-line editing features that are
available to users of programs that read keyboard input via the Tecla
library. Users of the tcsh shell will find the default key-bindings
very familiar. Users of the bash shell will also find it quite famil-
iar, but with a few minor differences, most notably in how forward and
backward searches through the list of historical commands are per-
formed. There are two major editing modes, one with emacs-like key-
bindings and another with vi-like key-bindings. By default emacs mode
is enabled, but vi mode can alternatively be selected via the user's
configuration file. This file can also be used to change the bindings
of individual keys to suit the user's preferences. By default, tab com-
pletion is provided. If the application hasn't reconfigured this to
complete other types of symbols, then tab completion completes file-
names.
In the rest of this man page, and also in all Tecla configuration
files, key-sequences are expressed as follows.
^A or C-a
This is a control-A, entered by pressing the control key at
the same time as the A key.
\E or M-
In key-sequences, both of these notations can be entered
either by pressing the escape key, then the following key, or by
pressing the Meta key at the same time as the following key. Thus
the key sequence M-p can be typed in two ways, by pressing
the escape key, followed by pressing p, or by pressing the
Meta key at the same time as p.
up
This refers to the up-arrow key.
down
This refers to the down-arrow key.
left
This refers to the left-arrow key.
right
This refers to the right-arrow key.
a
This is just a normal A key.
By default, Tecla looks for a file called .teclarc in your home direc-
tory (ie. ~/.teclarc). If it finds this file, it reads it, interpret-
ing each line as defining a new key binding or an editing configuration
option. Since the emacs keybindings are installed by default, if you
want to use the non-default vi editing mode, the most important item to
go in this file is the following line:
edit-mode vi
This will re-configure the default bindings for vi-mode. The complete
set of arguments that this command accepts are:
vi - Install key-bindings like those of the vi
editor.
emacs - Install key-bindings like those of the emacs
editor. This is the default.
none - Use just the native line editing facilities
provided by the terminal driver.
To prevent the terminal bell from being rung, such as when an unrecog-
nized control-sequence is typed, place the following line in the con-
figuration file:
nobeep
An example of a key binding line in the configuration file is the fol-
lowing.
bind M-[2~ insert-mode
On many keyboards, the above key sequence is generated when one presses
the insert key, so with this keybinding, one can toggle between the
emacs-mode insert and overwrite modes by hitting one key. One could
also do it by typing out the above sequence of characters one by one.
As explained above, the M- part of this sequence can be typed either by
pressing the escape key before the following key, or by pressing the
Meta key at the same time as the following key. Thus if you had set the
above key binding, and the insert key on your keyboard didn't generate
the above key sequence, you could still type it in either of the fol-
lowing 2 ways.
1. Hit the escape key momentarily, then press '[', then '2', then
finally '~'.
2. Press the meta key at the same time as pressing the '[' key,
then press '2', then '~'.
If you set a keybinding for a key-sequence that is already bound to a
function, the new binding overrides the old one. If in the new binding
you omit the name of the new function to bind to the key-sequence, the
original binding becomes undefined.
Starting with versions of libtecla later than 1.3.3 it is now possible
to bind keysequences that begin with a printable character. Previously
key-sequences were required to start with a control or meta character.
Note that the special keywords "up", "down", "left" and "right" refer
to the arrow keys, and are thus not treated as keysequences. So, for
example, to rebind the up and down arrow keys to use the history search
mechanism instead of the simple history recall method, you could place
the following in your configuration file:
bind up history-search-backwards
bind down history-search-backwards
To unbind an existing binding, you can do this with the bind command by
omitting to name any action to rebind the key sequence to. For exam-
ple, by not specifying an action function, the following command
unbinds the default beginning-of-line action from the ^A key sequence:
bind ^A
If you create a ~/.teclarc configuration file, but it appears to have
no effect on the program, check the documentation of the program to see
if the author chose a different name for this file.
With the default key bindings, pressing the TAB key (aka. ^I) results
in Tecla attempting to complete the incomplete filename that precedes
the cursor. Tecla searches backwards from the cursor, looking for the
start of the filename, stopping when it hits either a space or the
start of the line. If more than one file has the specified prefix, then
Tecla completes the filename up to the point at which the ambiguous
matches start to differ, then lists the possible matches.
In addition to literally written filenames, Tecla can complete files
that start with ~/ and ~user/ expressions and that contain $envvar
expressions. In particular, if you hit TAB within an incomplete ~user,
expression, Tecla will attempt to complete the username, listing any
ambiguous matches.
The completion binding is implemented using the cpl_word_completions()
function, which is also available separately to users of this library.
See the cpl_word_completions(@LIBR_MANEXT@) man page for more details.
With the default key bindings, pressing ^X* causes Tecla to expand the
filename that precedes the cursor, replacing ~/ and ~user/ expressions
with the corresponding home directories, and replacing $envvar expres-
sions with the value of the specified environment variable, then if
there are any wildcards, replacing the so far expanded filename with a
space-separated list of the files which match the wild cards.
The expansion binding is implemented using the ef_expand_file() func-
tion. See the ef_expand_file man page for more details.
Every time that a new line is entered by the user, it is appended to a
list of historical input lines maintained within the GetLine resource
object. You can traverse up and down this list using the up and down
arrow keys. Alternatively, you can do the same with the ^P, and ^N
keys, and in vi command mode you can alternatively use the k and j
characters. Thus pressing up-arrow once, replaces the current input
line with the previously entered line. Pressing up-arrow again,
replaces this with the line that was entered before it, etc.. Having
gone back one or more lines into the history list, one can return to
newer lines by pressing down-arrow one or more times. If you do this
sufficient times, you will return to the original line that you were
entering when you first hit up-arrow.
Note that in vi mode, all of the history recall functions switch the
library into command mode.
In emacs mode the M-p and M-n keys work just like the ^P and ^N keys,
except that they skip all but those historical lines which share the
prefix that precedes the cursor. In vi command mode the upper case K
and J characters do the same thing, except that the string that they
search for includes the character under the cursor as well as what pre-
cedes it.
Thus for example, suppose that you were in emacs mode, and you had just
entered the following list of commands in the order shown:
ls ~/tecla/
cd ~/tecla
ls -l getline.c
emacs ~/tecla/getline.c
If you next typed:
ls
and then hit M-p, then rather than returning the previously typed emacs
line, which doesn't start with "ls", Tecla would recall the "ls -l get-
line.c" line. Pressing M-p again would recall the "ls ~/tecla/" line.
Note that if the string that you are searching for, contains any of the
special characters, *, ?, or '[', then it is interpretted as a pattern
to be matched. Thus, cotinuing with the above example, after typing in
the list of commands shown, if you then typed:
*tecla*
and hit M-p, then the "emacs ~/tecla/getline.c" line would be recalled
first, since it contains the word tecla somewhere in the line, Simi-
larly, hitting M-p again, would recall the "ls ~/tecla/" line, and hit-
ting it once more would recall the "ls ~/tecla/" line. The pattern syn-
tax is the same as that described for filename expansion, in the
ef_expand_file(@LIBR_MANEXT@ man page.
Authors of programs that use the Tecla library have the option of sav-
ing historical command-lines in a file before exiting, and subsequently
reading them back in from this file when the program is next started.
There is no standard name for this file, since it makes sense for each
application to use its own history file, so that commands from differ-
ent applications don't get mixed up.
Since libtecla version 1.4.0, Tecla has been 8-bit clean. This means
that all 8-bit characters that are printable in the user's current
locale are now displayed verbatim and included in the returned input
line. Assuming that the calling program correctly contains a call like
the following,
setlocale(LC_CTYPE, "");
then the current locale is determined by the first of the environment
variables LC_CTYPE, LC_ALL, and LANG, that is found to contain a valid
locale name. If none of these variables are defined, or the program
neglects to call setlocale, then the default C locale is used, which is
US 7-bit ASCII. On most unix-like platforms, you can get a list of
valid locales by typing the command:
locale -a
at the shell prompt.
Meta keys and locales
Beware that in most locales other than the default C locale, meta char-
acters become printable, and they are then no longer considered to
match M-c style key bindings. This allows international characters to
be entered with the compose key without unexpectedly triggering meta
key bindings. You can still invoke meta bindings, since there are actu-
ally two ways to do this. For example the binding M-c can also be
invoked by pressing the escape key momentarily, then pressing the c
key, and this will work regardless of locale. Moreover, many modern
terminal emulators, such as gnome's gnome-terminal's and KDE's konsole
terminals, already generate escape pairs like this when you use the
meta key, rather than a real meta character, and other emulators usu-
ally have a way to request this behavior, so you can continue to use
the meta key on most systems.
For example, although xterm terminal emulators generate real 8-bit meta
characters by default when you use the meta key, they can be configured
to output the equivalent escape pair by setting their EightBitInput X
resource to False. You can either do this by placing a line like the
following in your ~/.Xdefaults file,
XTerm*EightBitInput: False
or by starting an xterm with an -xrm '*EightBitInput: False' command-
line argument. In recent versions of xterm you can toggle this feature
on and off with the "Meta Sends Escape" option in the menu that is dis-
played when you press the left mouse button and the control key within
an xterm window. In CDE, dtterms can be similarly coerced to generate
escape pairs in place of meta characters, by setting the Dtterm*KshMode
resource to True.
Entering international characters
If you don't have a keyboard that generates all of the international
characters that you need, there is usually a compose key that will
allow you to enter special characters, or a way to create one. For
example, under X windows on unix-like systems, if your keyboard doesn't
have a compose key, you can designate a redundant key to serve this
purpose with the xmodmap command. For example, on many PC keyboards
there is a microsoft-windows key, which is otherwise useless under
Linux. On my laptop the xev program reports that pressing this key gen-
erates keycode 115, so to turn this key into a compose key, I do the
following:
xmodmap -e 'keycode 115 = Multi_key'
I can then enter an i with a umlaut over it by typing this key, fol-
lowed by ", followed by i.
The following is a list of the editing functions provided by the Tecla
library. The names in the leftmost column of the list can be used in
configuration files to specify which function a given key or combina-
tion of keys should invoke. They are also used in the next two sections
to list the default key-bindings in emacs and vi modes.
user-interrupt - Send a SIGINT signal to the
parent process.
abort - Send a SIGABRT signal to the
parent process.
suspend - Suspend the parent process.
stop-output - Pause terminal output.
start-output - Resume paused terminal output.
literal-next - Arrange for the next character
to be treated as a normal
character. This allows control
characters to be entered.
cursor-right - Move the cursor one character
right.
cursor-left - Move the cursor one character
left.
insert-mode - Toggle between insert mode and
overwrite mode.
beginning-of-line - Move the cursor to the
beginning of the line.
end-of-line - Move the cursor to the end of
the line.
delete-line - Delete the contents of the
current line.
kill-line - Delete everything that follows
the cursor.
backward-kill-line - Delete all characters between
the cursor and the start of the
line.
forward-word - Move to the end of the word
which follows the cursor.
forward-to-word - Move the cursor to the start of
the word that follows the
cursor.
backward-word - Move to the start of the word
which precedes the cursor.
goto-column - Move the cursor to the
1-relative column in the line
specified by any preceding
digit-argument sequences (see
ENTERING REPEAT COUNTS below).
find-parenthesis - If the cursor is currently
over a parenthesis character,
move it to the matching
parenthesis character. If not
over a parenthesis character
move right to the next close
parenthesis.
forward-delete-char - Delete the character under the
cursor.
backward-delete-char - Delete the character which
precedes the cursor.
list-or-eof - This is intended for binding
to ^D. When invoked when the
cursor is within the line it
displays all possible
completions then redisplays
the line unchanged. When
invoked on an empty line, it
signals end-of-input (EOF) to
the caller of gl_get_line().
del-char-or-list-or-eof - This is intended for binding
to ^D. When invoked when the
cursor is within the line it
invokes forward-delete-char.
When invoked at the end of the
line it displays all possible
completions then redisplays
the line unchanged. When
invoked on an empty line, it
signals end-of-input (EOF) to
the caller of gl_get_line().
forward-delete-word - Delete the word which follows
the cursor.
backward-delete-word - Delete the word which precedes
the cursor.
upcase-word - Convert all of the characters
of the word which follows the
cursor, to upper case.
downcase-word - Convert all of the characters
of the word which follows the
cursor, to lower case.
capitalize-word - Capitalize the word which
follows the cursor.
change-case - If the next character is upper
case, toggle it to lower case
and vice versa.
redisplay - Redisplay the line.
clear-screen - Clear the terminal, then
redisplay the current line.
transpose-chars - Swap the character under the
cursor with the character just
before the cursor.
set-mark - Set a mark at the position of
the cursor.
exchange-point-and-mark - Move the cursor to the last
mark that was set, and move
the mark to where the cursor
used to be.
kill-region - Delete the characters that lie
between the last mark that was
set, and the cursor.
copy-region-as-kill - Copy the text between the mark
and the cursor to the cut
buffer, without deleting the
original text.
yank - Insert the text that was last
deleted, just before the
current position of the cursor.
append-yank - Paste the current contents of
the cut buffer, after the
cursor.
up-history - Recall the next oldest line
that was entered. Note that
in vi mode you are left in
command mode.
down-history - Recall the next most recent
line that was entered. If no
history recall session is
currently active, the next
line from a previous recall
session is recalled. Note that
in vi mode you are left in
command mode.
history-search-backward - Recall the next oldest line
who's prefix matches the string
which currently precedes the
cursor (in vi command-mode the
character under the cursor is
also included in the search
string). Note that in vi mode
you are left in command mode.
history-search-forward - Recall the next newest line
who's prefix matches the string
which currently precedes the
cursor (in vi command-mode the
character under the cursor is
also included in the search
string). Note that in vi mode
you are left in command mode.
history-re-search-backward -Recall the next oldest line
who's prefix matches that
established by the last
invocation of either
history-search-forward or
history-search-backward.
history-re-search-forward - Recall the next newest line
who's prefix matches that
established by the last
invocation of either
history-search-forward or
history-search-backward.
complete-word - Attempt to complete the
incomplete word which
precedes the cursor. Unless
the host program has customized
word completion, filename
completion is attempted. In vi
commmand mode the character
under the cursor is also
included in the word being
completed, and you are left in
vi insert mode.
expand-filename - Within the command line, expand
wild cards, tilde expressions
and dollar expressions in the
filename which immediately
precedes the cursor. In vi
commmand mode the character
under the cursor is also
included in the filename being
expanded, and you are left in
vi insert mode.
list-glob - List any filenames which match
the wild-card, tilde and dollar
expressions in the filename
which immediately precedes the
cursor, then redraw the input
line unchanged.
list-history - Display the contents of the
history list for the current
history group. If a repeat
count of > 1 is specified,
only that many of the most
recent lines are displayed.
See the "ENTERING REPEAT
COUNTS" section.
read-from-file - Temporarily switch to reading
input from the file who's
name precedes the cursor.
read-init-files - Re-read teclarc configuration
files.
beginning-of-history - Move to the oldest line in the
history list. Note that in vi
mode you are left in command
mode.
end-of-history - Move to the newest line in the
history list (ie. the current
line). Note that in vi mode
this leaves you in command
mode.
digit-argument - Enter a repeat count for the
next key-binding function.
For details, see the ENTERING
REPEAT COUNTS section.
newline - Terminate and return the
current contents of the
line, after appending a
newline character. The newline
character is normally '\n',
but will be the first
character of the key-sequence
that invoked the newline
action, if this happens to be
a printable character. If the
action was invoked by the
'\n' newline character or the
'\r' carriage return
character, the line is
appended to the history
buffer.
repeat-history - Return the line that is being
edited, then arrange for the
next most recent entry in the
history buffer to be recalled
when Tecla is next called.
Repeatedly invoking this
action causes successive
historical input lines to be
re-executed. Note that this
action is equivalent to the
'Operate' action in ksh.
ring-bell - Ring the terminal bell, unless
the bell has been silenced via
the nobeep configuration
option (see the THE TECLA
CONFIGURATION FILE section).
forward-copy-char - Copy the next character into
the cut buffer (NB. use repeat
counts to copy more than one).
backward-copy-char - Copy the previous character
into the cut buffer.
forward-copy-word - Copy the next word into the cut
buffer.
backward-copy-word - Copy the previous word into the
cut buffer.
forward-find-char - Move the cursor to the next
occurrence of the next
character that you type.
backward-find-char - Move the cursor to the last
occurrence of the next
character that you type.
forward-to-char - Move the cursor to the
character just before the next
occurrence of the next
character that the user types.
backward-to-char - Move the cursor to the
character just after the last
occurrence before the cursor
of the next character that the
user types.
repeat-find-char - Repeat the last
backward-find-char,
forward-find-char,
backward-to-char or
forward-to-char.
invert-refind-char - Repeat the last
backward-find-char,
forward-find-char,
backward-to-char, or
forward-to-char in the
opposite direction.
delete-to-column - Delete the characters from the
cursor up to the column that
is specified by the repeat
count.
delete-to-parenthesis - Delete the characters from the
cursor up to and including
the matching parenthesis, or
next close parenthesis.
forward-delete-find - Delete the characters from the
cursor up to and including the
following occurence of the
next character typed.
backward-delete-find - Delete the characters from the
cursor up to and including the
preceding occurence of the
next character typed.
forward-delete-to - Delete the characters from the
cursor up to, but not
including, the following
occurence of the next
character typed.
backward-delete-to - Delete the characters from the
cursor up to, but not
including, the preceding
occurence of the next
character typed.
delete-refind - Repeat the last *-delete-find
or *-delete-to action.
delete-invert-refind - Repeat the last *-delete-find
or *-delete-to action, in the
opposite direction.
copy-to-column - Copy the characters from the
cursor up to the column that
is specified by the repeat
count, into the cut buffer.
copy-to-parenthesis - Copy the characters from the
cursor up to and including
the matching parenthesis, or
next close parenthesis, into
the cut buffer.
forward-copy-find - Copy the characters from the
cursor up to and including the
following occurence of the
next character typed, into the
cut buffer.
backward-copy-find - Copy the characters from the
cursor up to and including the
preceding occurence of the
next character typed, into the
cut buffer.
forward-copy-to - Copy the characters from the
cursor up to, but not
including, the following
occurence of the next
character typed, into the cut
buffer.
backward-copy-to - Copy the characters from the
cursor up to, but not
including, the preceding
occurence of the next
character typed, into the cut
buffer.
copy-refind - Repeat the last *-copy-find
or *-copy-to action.
copy-invert-refind - Repeat the last *-copy-find
or *-copy-to action, in the
opposite direction.
vi-mode - Switch to vi mode from emacs
mode.
emacs-mode - Switch to emacs mode from vi
mode.
vi-insert - From vi command mode, switch to
insert mode.
vi-overwrite - From vi command mode, switch to
overwrite mode.
vi-insert-at-bol - From vi command mode, move the
cursor to the start of the line
and switch to insert mode.
vi-append-at-eol - From vi command mode, move the
cursor to the end of the line
and switch to append mode.
vi-append - From vi command mode, move the
cursor one position right, and
switch to insert mode.
vi-replace-char - From vi command mode, replace
the character under the cursor
with the the next character
entered.
vi-forward-change-char - From vi command mode, delete
the next character then enter
insert mode.
vi-backward-change-char - From vi command mode, delete
the preceding character then
enter insert mode.
vi-forward-change-word - From vi command mode, delete
the next word then enter
insert mode.
vi-backward-change-word - From vi command mode, delete
the preceding word then
enter insert mode.
vi-change-rest-of-line - From vi command mode, delete
from the cursor to the end of
the line, then enter insert
mode.
vi-change-line - From vi command mode, delete
the current line, then enter
insert mode.
vi-change-to-bol - From vi command mode, delete
all characters between the
cursor and the beginning of
the line, then enter insert
mode.
vi-change-to-column - From vi command mode, delete
the characters from the cursor
up to the column that is
specified by the repeat count,
then enter insert mode.
vi-change-to-parenthesis - Delete the characters from the
cursor up to and including
the matching parenthesis, or
next close parenthesis, then
enter vi insert mode.
vi-forward-change-find - From vi command mode, delete
the characters from the
cursor up to and including the
following occurence of the
next character typed, then
enter insert mode.
vi-backward-change-find - From vi command mode, delete
the characters from the
cursor up to and including the
preceding occurence of the
next character typed, then
enter insert mode.
vi-forward-change-to - From vi command mode, delete
the characters from the
cursor up to, but not
including, the following
occurence of the next
character typed, then enter
insert mode.
vi-backward-change-to - From vi command mode, delete
the characters from the
cursor up to, but not
including, the preceding
occurence of the next
character typed, then enter
insert mode.
vi-change-refind - Repeat the last
vi-*-change-find or
vi-*-change-to action.
vi-change-invert-refind - Repeat the last
vi-*-change-find or
vi-*-change-to action, in the
opposite direction.
vi-undo - In vi mode, undo the last
editing operation.
vi-repeat-change - In vi command mode, repeat the
last command that modified the
line.
The following default key bindings, which can be overriden by the Tecla
configuration file, are designed to mimic most of the bindings of the
unix tcsh shell, when it is in emacs editing mode.
This is the default editing mode of the Tecla library.
Under UNIX the terminal driver sets a number of special keys for cer-
tain functions. The tecla library attempts to use the same keybindings
to maintain consistency. The key sequences shown for the following 6
bindings are thus just examples of what they will probably be set to.
If you have used the stty command to change these keys, then the
default bindings should match.
^C -> user-interrupt
^\ -> abort
^Z -> suspend
^Q -> start-output
^S -> stop-output
^V -> literal-next
The cursor keys are refered to by name, as follows. This is necessary
because different types of terminals generate different key sequences
when their cursor keys are pressed.
right -> cursor-right
left -> cursor-left
up -> up-history
down -> down-history
The remaining bindings don't depend on the terminal setttings.
^F -> cursor-right
^B -> cursor-left
M-i -> insert-mode
^A -> beginning-of-line
^E -> end-of-line
^U -> delete-line
^K -> kill-line
M-f -> forward-word
M-b -> backward-word
^D -> del-char-or-list-or-eof
^H -> backward-delete-char
^? -> backward-delete-char
M-d -> forward-delete-word
M-^H -> backward-delete-word
M-^? -> backward-delete-word
M-u -> upcase-word
M-l -> downcase-word
M-c -> capitalize-word
^R -> redisplay
^L -> clear-screen
^T -> transpose-chars
^@ -> set-mark
^X^X -> exchange-point-and-mark
^W -> kill-region
M-w -> copy-region-as-kill
^Y -> yank
^P -> up-history
^N -> down-history
M-p -> history-search-backward
M-n -> history-search-forward
^I -> complete-word
^X* -> expand-filename
^X^F -> read-from-file
^X^R -> read-init-files
^Xg -> list-glob
^Xh -> list-history
M-< -> beginning-of-history
M-> -> end-of-history
\n -> newline
\r -> newline
M-o -> repeat-history
M-^V -> vi-mode
M-0, M-1, ... M-9 -> digit-argument (see below)
Note that ^I is what the TAB key generates, and that ^@ can be gener-
ated not only by pressing the control key and the @ key simultaneously,
but also by pressing the control key and the space bar at the same
time.
The following default key bindings are designed to mimic the vi style
of editing as closely as possible. This means that very few editing
functions are provided in the initial character input mode, editing
functions instead being provided by the vi command mode. Vi command
mode is entered whenever the escape character is pressed, or whenever a
key-sequence that starts with a meta character is entered. In addition
to mimicing vi, libtecla provides bindings for tab completion, wild-
card expansion of file names, and historical line recall.
To learn how to tell the Tecla library to use vi mode instead of the
default emacs editing mode, see the earlier section entitled THE TECLA
CONFIGURATION FILE.
Under UNIX the terminal driver sets a number of special keys for cer-
tain functions. The Tecla library attempts to use the same keybindings
to maintain consistency, binding them both in input mode and in command
mode. The key sequences shown for the following 6 bindings are thus
just examples of what they will probably be set to. If you have used
the stty command to change these keys, then the default bindings should
match.
^C -> user-interrupt
^\ -> abort
^Z -> suspend
^Q -> start-output
^S -> stop-output
^V -> literal-next
M-^C -> user-interrupt
M-^\ -> abort
M-^Z -> suspend
M-^Q -> start-output
M-^S -> stop-output
Note that above, most of the bindings are defined twice, once as a raw
control code like ^C and then a second time as a meta character like
M-^C. The former is the binding for vi input mode, whereas the latter
is the binding for vi command mode. Once in command mode all key-
sequences that the user types that they don't explicitly start with an
escape or a meta key, have their first key secretly converted to a meta
character before the key sequence is looked up in the key binding ta-
ble. Thus, once in command mode, when you type the letter i, for exam-
ple, the Tecla library actually looks up the binding for M-i.
The cursor keys are refered to by name, as follows. This is necessary
because different types of terminals generate different key sequences
when their cursor keys are pressed.
right -> cursor-right
left -> cursor-left
up -> up-history
down -> down-history
The cursor keys normally generate a keysequence that start with an
escape character, so beware that using the arrow keys will put you into
command mode (if you aren't already in command mode).
The following are the terminal-independent key bindings for vi input
mode.
^D -> list-or-eof
^G -> list-glob
^H -> backward-delete-char
^I -> complete-word
\r -> newline
\n -> newline
^L -> clear-screen
^N -> down-history
^P -> up-history
^R -> redisplay
^U -> backward-kill-line
^W -> backward-delete-word
^X* -> expand-filename
^X^F -> read-from-file
^X^R -> read-init-files
^? -> backward-delete-char
The following are the key bindings that are defined in vi command mode,
this being specified by them all starting with a meta character. As
mentioned above, once in command mode the initial meta character is
optional. For example, you might enter command mode by typing Esc, and
then press h twice to move the cursor two positions to the left. Both h
characters get quietly converted to M-h before being compared to the
key-binding table, the first one because Escape followed by a character
is always converted to the equivalent meta character, and the second
because command mode was already active.
M-\ -> cursor-right (Meta-space)
M-$ -> end-of-line
M-* -> expand-filename
M-+ -> down-history
M-- -> up-history
M-< -> beginning-of-history
M-> -> end-of-history
M-^ -> beginning-of-line
M-; -> repeat-find-char
M-, -> invert-refind-char
M-| -> goto-column
M-~ -> change-case
M-. -> vi-repeat-change
M-% -> find-parenthesis
M-a -> vi-append
M-A -> vi-append-at-eol
M-b -> backward-word
M-B -> backward-word
M-C -> vi-change-rest-of-line
M-cb -> vi-backward-change-word
M-cB -> vi-backward-change-word
M-cc -> vi-change-line
M-ce -> vi-forward-change-word
M-cE -> vi-forward-change-word
M-cw -> vi-forward-change-word
M-cW -> vi-forward-change-word
M-cF -> vi-backward-change-find
M-cf -> vi-forward-change-find
M-cT -> vi-backward-change-to
M-ct -> vi-forward-change-to
M-c; -> vi-change-refind
M-c, -> vi-change-invert-refind
M-ch -> vi-backward-change-char
M-c^H -> vi-backward-change-char
M-c^? -> vi-backward-change-char
M-cl -> vi-forward-change-char
M-c\ -> vi-forward-change-char (Meta-c-space)
M-c^ -> vi-change-to-bol
M-c0 -> vi-change-to-bol
M-c$ -> vi-change-rest-of-line
M-c| -> vi-change-to-column
M-c% -> vi-change-to-parenthesis
M-dh -> backward-delete-char
M-d^H -> backward-delete-char
M-d^? -> backward-delete-char
M-dl -> forward-delete-char
M-d -> forward-delete-char (Meta-d-space)
M-dd -> delete-line
M-db -> backward-delete-word
M-dB -> backward-delete-word
M-de -> forward-delete-word
M-dE -> forward-delete-word
M-dw -> forward-delete-word
M-dW -> forward-delete-word
M-dF -> backward-delete-find
M-df -> forward-delete-find
M-dT -> backward-delete-to
M-dt -> forward-delete-to
M-d; -> delete-refind
M-d, -> delete-invert-refind
M-d^ -> backward-kill-line
M-d0 -> backward-kill-line
M-d$ -> kill-line
M-D -> kill-line
M-d| -> delete-to-column
M-d% -> delete-to-parenthesis
M-e -> forward-word
M-E -> forward-word
M-f -> forward-find-char
M-F -> backward-find-char
M-- -> up-history
M-h -> cursor-left
M-H -> beginning-of-history
M-i -> vi-insert
M-I -> vi-insert-at-bol
M-j -> down-history
M-J -> history-search-forward
M-k -> up-history
M-K -> history-search-backward
M-l -> cursor-right
M-L -> end-of-history
M-n -> history-re-search-forward
M-N -> history-re-search-backward
M-p -> append-yank
M-P -> yank
M-r -> vi-replace-char
M-R -> vi-overwrite
M-s -> vi-forward-change-char
M-S -> vi-change-line
M-t -> forward-to-char
M-T -> backward-to-char
M-u -> vi-undo
M-w -> forward-to-word
M-W -> forward-to-word
M-x -> forward-delete-char
M-X -> backward-delete-char
M-yh -> backward-copy-char
M-y^H -> backward-copy-char
M-y^? -> backward-copy-char
M-yl -> forward-copy-char
M-y\ -> forward-copy-char (Meta-y-space)
M-ye -> forward-copy-word
M-yE -> forward-copy-word
M-yw -> forward-copy-word
M-yW -> forward-copy-word
M-yb -> backward-copy-word
M-yB -> backward-copy-word
M-yf -> forward-copy-find
M-yF -> backward-copy-find
M-yt -> forward-copy-to
M-yT -> backward-copy-to
M-y; -> copy-refind
M-y, -> copy-invert-refind
M-y^ -> copy-to-bol
M-y0 -> copy-to-bol
M-y$ -> copy-rest-of-line
M-yy -> copy-line
M-Y -> copy-line
M-y| -> copy-to-column
M-y% -> copy-to-parenthesis
M-^E -> emacs-mode
M-^H -> cursor-left
M-^? -> cursor-left
M-^L -> clear-screen
M-^N -> down-history
M-^P -> up-history
M-^R -> redisplay
M-^D -> list-or-eof
M-^I -> complete-word
M-\r -> newline
M-\n -> newline
M-^X^R -> read-init-files
M-^Xh -> list-history
M-0, M-1, ... M-9 -> digit-argument (see below)
Note that ^I is what the TAB key generates.
Many of the key binding functions described previously, take an
optional count, typed in before the target keysequence. This is inter-
preted as a repeat count by most bindings. A notable exception is the
goto-column binding, which interprets the count as a column number.
By default you can specify this count argument by pressing the meta key
while typing in the numeric count. This relies on the digit-argument
action being bound to Meta-0, Meta-1 etc. Once any one of these bind-
ings has been activated, you can optionally take your finger off the
meta key to type in the rest of the number, since every numeric digit
thereafter is treated as part of the number, unless it is preceded by
the literal-next binding. As soon as a non-digit, or literal digit key
is pressed the repeat count is terminated and either causes the just
typed character to be added to the line that many times, or causes the
next key-binding function to be given that argument.
For example, in emacs mode, typing:
M-12a
causes the letter 'a' to be added to the line 12 times, whereas
M-4M-c
Capitalizes the next 4 words.
In vi command mode the Meta modifier is automatically added to all
characters typed in, so to enter a count in vi command-mode, just
involves typing in the number, just as it does in the vi editor itself.
So for example, in vi command mode, typing:
4w2x
moves the cursor four words to the right, then deletes two characters.
You can also bind digit-argument to other key sequences. If these end
in a numeric digit, that digit gets appended to the current repeat
count. If it doesn't end in a numeric digit, a new repeat count is
started with a value of zero, and can be completed by typing in the
number, after letting go of the key which triggered the digit-argument
action.
libtecla.a - The Tecla library
libtecla.h - The Tecla header file.
~/.teclarc - The personal Tecla customization file.
libtecla, gl_get_line, gl_io_mode, ef_expand_file,
cpl_complete_word, pca_lookup_file
Martin Shepherd (mcs@astro.caltech.edu)
tecla
./libtecla/LICENSE.TERMS 0100644 0000764 0000764 00000002755 10027466660 013047 0 ustar mcs mcs Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, and/or sell copies of the Software, and to permit persons
to whom the Software is furnished to do so, provided that the above
copyright notice(s) and this permission notice appear in all copies of
the Software and that both the above copyright notice(s) and this
permission notice appear in supporting documentation.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Except as contained in this notice, the name of a copyright holder
shall not be used in advertising or otherwise to promote the sale, use
or other dealings in this Software without prior written authorization
of the copyright holder.
./libtecla/CHANGES 0100644 0000764 0000764 00000424305 10141252116 012125 0 ustar mcs mcs In the following log, modification dates are listed using the European
convention in which the day comes before the month (ie. DD/MM/YYYY).
The most recent modifications are listed first.
31/10/2004 mcs@astro.caltech.edu (problem reported by Godfrey van der Linden)
getline.c
The gl_event_handler() function had the endif of a
conditional compilation clause in the wrong place. This
only upset the compiler on unusual systems that don't
have select(). The problem was seen under Mac OS X, due
to the configuration problem in 1.6.0 that caused the
configure script to mistakenly report that select wasn't
available.
31/10/2004 mcs@astro.caltech.edu (info provided by Ivan Rayner)
configure.in configure Makefile.in
Ivan reported that under IRIX 6.5 it is necessary to add
-D_XOPEN_SOURCE=500 to the compiler flags, when compiling
the reentrant version of the library. Thus, whereas
previously I hardwired the value of DEFINES_R in
Makefile.in, I have now made this a variable in the
configure script, which is augmented with the above
addition, within an IRIX-specific switch clause.
Also apparently configure leaves the RANLIB variable
blank, instead of setting it to ":", so I have now
explicitly set this to ":", within the new IRIX clause of
the configure script.
31/10/2004 mcs@astro.caltech.edu (info provided by Ivan Rayner)
getline.c
Under IRIX, the compiler warned that gl_read_unmasked()
was returning an int, which was then being assigned to an
enumeration type. This is techically fine, but it
highlighted the fact that I had meant to declare
gl_read_unmasked() to directly return the enumerated
type. I have now done so.
26/09/2004 mcs@astro.caltech.edu
getline.c
Users can now turn off interactive command-line editing
by setting the TERM environment variable to the word "dumb".
18/07/2004 mcs@astro.caltech.edu (problem noted by Michael MacFaden)
getline.c
Calling gl_terminal_size() on a system without support
for SIGWINCH caused a divide-by-zero error in an unintended
call to gl_erase_line(), because gl_update_size() was
incorrectly being called to query the terminal size,
instead of gl_query_size().
18/07/2004 Padraig Brady (documented here by mcs@astro.caltech.edu)
getline.c
The suspend and termination signal-handlers installed by
gl_tty_signals(), were being installed swapped.
03/06/2004 Mike Meaney (documented here by mcs@astro.caltech.edu)
getline.c
Mike pointed out the fact that the curses setupterm()
function is actually documented to exit the application
if an error occurs while its optional errret argument is
NULL. I hadn't noticed this, and because I didn't need
the extra information returned in the errret argument, I
was passing it a NULL. As suggested by Mike, I now pass
this argument a pointer to a dummy errret variable.
23/05/2004 mcs@astro.caltech.edu (problem noted by John Beck)
man/func/cpl_complete_word.in
Some of the prototypes of functions and types documented
by the cpl_complete_word man page, weren't listed in the
Synopsis section of this man page. They are now listed
there.
23/05/2004 mcs@astro.caltech.edu
getline.c man/func/gl_get_line.in
I have now added support for calling gl_normal_io() from
any callback functions that the application installs by
calling either gl_inactivity_timeout(), or gl_watch_fd().
Previously, if one of these callback functions called
gl_normal_io(), then after returning to gl_get_line(),
gl_get_line() would incorrectly assume that the terminal
was still in raw I/O mode. Now, gl_get_line() checks to
see if gl_normal_io() was called by the callback, and
if so, calls _gl_raw_io() to reinstate raw I/O mode.
21/05/2004 mcs@astro.caltech.edu
configure.in configure
On Mac OS X the code that the configure script used to
check for select() failed due to missing symbols in
sys/select.h. Moving the inclusion of sys/select.h to
after the inclusion of sys/time.h, sys/types.h and
sys/unistd.h fixed this.
11/05/2004 mcs@astro.caltech.edu
getline.c man/func/gl_get_line.in
If the line buffer returned by one call to gl_get_line()
was passed as the start_line argument of the next call to
gl_get_line(), then instead of the just-entered line
being presented back to the user for further editing, the
start_line argument was effectively ignored, because the
line buffer whose pointer was being passed back, was
being cleared before the start_line pointer was examined.
This appears to have been a case of me incorrectly
thinking that I had forgotten to initialize gl->line[]
and gl->ntotal in the gl_reset_input_line() function, and
then "fixing" this supposed omission. Removing this
erroneous fix, restored things to how they were meant to
be. To make it unlikely that I will make the same mistake
again, I have renamed the function from
gl_reset_input_line() to gl_reset_editor(), to stop it
looking as though it is meant to reset the contents of
the input line (that is what gl_truncate_buffer() is
for), explicitly stated that it doesn't clear the input
line, in the header comments of the function, and added a
prominent warning comment in the body of the function.
Also, since support for passing back the returned line
pointer via the start_line argument of the next call to
gl_get_line(), wasn't documented in the man page, but was
meant to be supported, and definitely used to work, I
have now amended the man page documentation of
gl_get_line() to explicitly state that this feature is
officially supported.
2?/04/2004 Released 1.6.0
22/04/2004 mcs@astro.caltech.edu (Fixed a bug reported by John Beck)
getline.c
When an error, signal, or other abnormal event aborted
gl_get_line(), the cleanup code that restored the
terminal to a sane state, also overwrote the value of
errno that was associated with the aborting event. An
I/O error occurring in the cleanup code would have also
overwritten the value to be returned by
gl_return_status(), and thus remove any possibility of
the caller finding out what really caused gl_get_line()
to abort. I have now written a new internal function
called, gl_record_status(), which records the completion
status to be returned by gl_return_status(), and the
value to assign to errno just before gl_get_line()
returns. This is called wherever code detects conditions
that require gl_get_line() to return early. The function
ensures that once an abnormal completion status has been
recorded for return, subsequent completions statuses
aren't recorded. This ensures that the caller sees the
original cause of the abnormal return, rather than any
error that occurs during cleaning up from this before
return.
17/04/2004 mcs@astro.caltech.edu
getline.c
If an application's callback called gl_read_char() after
calling gl_normal_io(), it would inappropriately
redisplay the input line, when it called _gl_raw_io() to
temporarily switch the terminal back into raw mode.
To fix this, _gl_raw_io() now takes a new 'redisplay'
argument, which specifies whether or not to queue a
redisplay of the input line. I also created a new
gl->postpone flag, which is set by gl_normal_io(), and
cleared by _gl_raw_io() (when its redisplay argument is
true). When this flag is set, gl_flush_output() ignores
queued redisplays, as it generally should between calls
to gl_normal_io() and gl_raw_io(). Thus its effect is to
postpone redisplays while line editing is suspended.
11/04/2004 mcs@astro.caltech.edu
history.c man/misc/tecla.in
History searches can now include the globbing operators
*, ?, []. When a search prefix is found to have at least
one of these characters, then only history lines that
completely match that pattern are returned.
11/04/2004 mcs@astro.caltech.edu (issue raised by Mark Coiley)
getline.c ioutil.c
There appears to be a bug in Solaris's terminal I/O.
When the terminal file descriptor is placed in
non-blocking I/O mode, and the terminal is switched from
canonical to raw mode, characters that were previously
entered in canonical I/O mode don't become available to
be read until the user types one character more. Select()
incorrectly says that there are no characters available,
and read() returns EAGAIN. This is only a problem for
gl_get_line() when gl_get_line() is in non-blocking
server I/O mode, so most users won't have experienced any
problems with this.
The only way that I have found to get read() to return
the characters, without the user first having to type
another character, is to turn off non-blocking I/O before
calling read(). Select() still claims that there are no
characters available to be read, but read happily returns
them anyway. Fortunately, one can perform non-blocking
terminal reads without setting the non-blocking I/O flag
of the file descriptor, simply by setting the VTIME
terminal attribute to zero (which I already was
doing). Thus, when in non-blocking server I/O, I now turn
off the non-blocking I/O flag, attempt to read one
character and only if this fails, do I then call the
select() based event handler to implement any configured
non-zero timeout, before attempting the read again. Of
course the non-blocking I/O flag is still needed for
writing, so I only turn it off temporarily while reading.
25/03/2004 mcs@astro.caltech.edu (bug reported by Gregory Harris)
Makefile.in
It appears that when in February, I patched Makefile.in
to add abolute paths to the install-sh shell-script,
I accidentally replaced install-sh with install.sh. I
corrected the name in the Makefile.
25/03/2004 Gregory Harris (documented here by mcs)
configure.in configure
Greg added the configuration parameters needed to build
the shared version of the libtecla library under FreeBSD.
25/03/2004 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man/func/gl_get_line.in
man/func/gl_read_char.in
I wrote a public function called gl_read_char(). Unlike
gl_query_char(), this function neither prompts the user
for input, nor displays the character that was entered.
In fact it doesn't write anything to the terminal, and
takes pains not to disturb any incompletely entered
input line, and can safely be called from application
callback functions.
21/03/2004 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man/func/gl_get_line.in
man/func/gl_query_char.in
I wrote a public function called gl_query_char(), which
prompts the user and awaits a single-character reply,
without the user having to hit return.
23/02/2004 mcs@astro.caltech.edu (bug reported by Gregory Harris)
configure.in configure getline.c enhance.c demo3.c
The configure script now checks for the sys/select.h
header file, and arranges for a C macro called
HAVE_SYS_SELECT_H to be set if it exists. Thus the files
that use select() now use this macro to conditionally
include sys/select.h where available. Apparently this
header is required under FreeBSD 5.1.
23/02/2004 mcs@astro.caltech.edu
getline.c libtecla.h man/func/gl_get_line.in
I wrote two new public functions, gl_append_history() and
gl_automatic_history(). Together these allow the
application to take over the responsibility of adding
lines to the history list from gl_get_line(). I then
documented their functionality in the gl_get_line man
page.
Version 1.6.0
I incremented the minor version number of the library, to
comply with the requirement to do so when additions are
made to the public interface. See libtecla.map for
details.
libtecla.map
I added a new 1.6.0 group for the new minor version, and
added the above pair of functions to it.
15/02/2004 mcs@astro.caltech.edu (fixes a bug reported by Satya Sahoo)
history.c
Calling gl_load_history() multiple times, eventually led
to a segmentation fault. This was due to the head of the
list of unused history string segments not getting
reset when the history buffer was cleared. While
debugging this problem I also noticed that the history
resizing function was way too complicated to verify, so
after fixing the above bug, I heavily simplified the
history resizing function, trading off a small reduction
in memory efficiency, for greatly improved clarity, and
thus made it much more verifiable and maintainable.
14/02/2004 mcs@astro.caltech.edu (fixes a bug reported by Tim Burress).
getline.c
If gl_change_terminal() was first used to tell
gl_get_line to read input from a file, then called later
to tell it to read subsequent input from a terminal, no
prompt would be displayed for the first line of
interactive input. The problem was that on reaching the
end of the input file, gl_get_line() should have called
gl_abandon_line(), to tell the next call to gl_get_line()
to start inputting a new line from scratch. I have added
this now.
14/02/2004 Krister Walfridsson (documented here by mcs@astro.caltech.edu)
Makefile.in
Krister noticed that I had failed to put $(srcdir)/ in front
of some invokations of install.sh. I have remedied this.
config.guess config.sub
I hadn't updated these for a long time, so apparently they
didn't recognise the BSD system that Krister was using.
I have now updated them to the versions that come with
autoconf-2.59.
22/01/2004 mcs@astro.caltech.edu
keytab.c
When parsing key-binding specifications, backslash escaped
characters following ^ characters were not being expanded.
Thus ^\\ got interpretted as a control-\ character followed
by a \ character, rather than simply as a control-\
character.
12/01/2004 mcs@astro.caltech.edu
cplfile.c cplmatch.c demo2.c demo3.c demo.c direader.c
expand.c getline.c history.c homedir.c pathutil.c pcache.c
configure.in configure INSTALL
The configuration script now takes a
"--without-file-system" argument. This is primarily for
intended for embedded systems that either don't have
filesystems, or where the file-system code in libtecla is
unwanted bloat. It sets the WITHOUT_FILE_SYSTEM
macro. This removes all code related to filesystem
access, including the entire public file-expansion,
file-completion and path-lookup facilities. Note that the
general word completion facility is still included, but
without the normally bundled file completion
callback. Actually the callback is still there, but it
reports no completions, regardless of what string you ask
it to complete.
This option is described in the INSTALL document.
12/01/2004 mcs@astro.caltech.edu
getline.c configure.in configure INSTALL
The configuration script now takes a
"--without-file-actions" argument. This allows an
application author/installer to prevent users of
gl_get_line() from accessing the filesystem from the
builtin actions of gl_get_line(). It defines a macro
called HIDE_FILE_SYSTEM. This causes the
"expand-filename", "read-from-file", "read-init-files",
and "list-glob" action functions to be completely
removed. It also changes the default behavior of actions
such as "complete-word" and "list-or-eof" to show no
completions, instead of the normal default of showing
filename completions.
This option is described in the INSTALL document.
11/01/2004 mcs@astro.caltech.edu
getline.c man/func/gl_get_line.in
In case an application's customized completion handler
needs to write to the terminal for some unforseen reason,
there needs to be a way for the it to cleanly suspend raw
line editing, before writing to the terminal, and the
caller then needs to be aware that it may need to
resurrect the input line when the callback returns. I
have now arranged that the completion callback functions
can call the gl_normal_io() function for this purpose,
and documented this in the gl_get_line() man page.
11/01/2004 mcs@astro.caltech.edu (In response to a bug report by Satya Sahoo)
getline.c
The gl_configure_getline() function makes a malloc'd copy
of the names of the configuration files that it is asked
to read. Before the bug fix, if the application made one
or more calls to this function, the memory allocated by
the final call that it made before calling del_GetLine(),
wasn't being freed. Note that memory allocated in all but
the final call was being correctly freed, so the maximum
extent of the memory leak was the length of the file
name(s) passed in the final call to
gl_configure_getline(), and an application that didn't
call gl_configure_getline() didn't suffer any leak.
20/12/2003 mcs@astro.caltech.edu
history.c
Ellen tested the history fix that I reported below, and
pointed out that it still had a problem. This turned out
to be because getline.c was making some incorrect
assumptions about the new behavior of history.c. This
problem and the previous one both revolved around how
search prefixes were stored and discarded, so I have now
re-written this part of the code. Previously the search
prefix was retained by looking for a line with that
prefix, and keeping a pointer to that line. This saved
memory, compared to storing a separate copy of the
prefix, but it led to all kinds of hairy
interdependencies, so I have now changed the code to keep
a separate copy of search prefixes. To keep the memory
requirements constant, the search prefix is stored in the
history buffer, like normal history lines, but not
referenced by the time-ordered history list. The prefix
can now be kept around indefinitely, until a new search
prefix is specified, regardless of changes to the
archived lines in the history buffer. This is actually
necessary to make the vi-mode re-search actions work
correctly. In particular, I no longer discard the search
prefix whenever a history search session ends. Also,
rather than have getline.c keep its own record of when a
history session is in progress, it now consults
history.c, so that failed assumptions can't cause the
kind of discrepancy that occurred before. For this to
work, getline.c now explicitly tells history.c to cancel
search sessions whenever it executes any non-history
action.
14/12/2003 mcs@astro.caltech.edu (bug reported by Ellen Oschmann)
history.c
If one searched backwards for a prefix, then returned to
the original line, changed that line, then started
another backwards prefix search, getline incorrectly
discarded the new search prefix in the process of
throwing away its cached copy of the previous pre-search
input line. In other words getline was belatedly
cancelling a previous search, after a new search had
already partially begun, and thus messed up the new
search. The obvious fix was to arrange for the current
search to be cancelled whenever the history pointer
returns to its starting point, rather than waiting for
the next search to begin from there.
14/12/2003 mcs@astro.caltech.edu
history.c
_glh_recall_line() was returning the last line in the
history buffer instead of the line requested by the
caller. This only affected the obscure "repeat-history"
action-function, which probably isn't used by anybody.
09/12/2003 Version 1.5.0 released.
28/09/2003 mcs@astro.caltech.edu
homedir.c
When the home directory of the login user is requested,
see if the HOME environment variable exists, and if so
return its value, rather than looking up the user's home
directory in the password file. This seems to be the
convention adopted by other unix programs that perform
tilde expansion, and it works around a strange problem,
where a third-party libtecla program, statically compiled
under an old version of RedHat, unexpectedly complained
that getpwd() returned an error when the program was run
under RedHat 9.
01/09/2003 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man/func/gl_get_line.in
man/func/gl_register_action.in.
It is now possible for an application to register
external functions as action functions. These actions are
initially bound to specified key-sequences, but if they
are registered before the user's configuration file is
loaded, they can also be re-bound by the user to
different key-sequences. The function used to register a
new action, is called gl_register_action(). Action
functions are passed a readonly copy of the input line
and the cursor position. They can display text to the
terminal, or perform other operations on the application
environment. Currently, they can't edit the input line or
move the cursor. This will require the future addition of
functions to queue the invokation of the built-in action
functions.
26/08/2003 mcs@astro.caltech.edu
getline.c
I modified gl_update_buffer() to ensure that the cursor
stays within the input line after external line
modifications, and to queue a redisplay of the
potentially modified input line.
21/07/2003 mcs@astro.caltech.edu
configure.in configure Makefile.in Makefile.stub INSTALL
By specifying --without-man-pages or --with-man-pages=no
as command-line arguments to the configure script, it is
now possible to have the configure script skip the
man-page preprocessing step, and arrange for the man-page
installation targets in the Makefile to do nothing. This
option is designed for people who embed libtecla within
other packages. It is also used by Makefile.stub when
the distclean target is specified.
21/07/2003 mcs@astro.caltech.edu
configure.in configure
The previous workaround for recent versions of gcc
placing /usr/local/include at the start of the system
inlcude-file search path, broke something else. The fix
placed /usr/include before gcc's include area, which
meant that gcc's modified version of stdarg.h was being
ignored in deference to the version in /usr/include. I
have changed the fix to have gcc report the search path,
then have awk add options to CFLAGS to reorder this path,
plaing /usr/local/include at the end.
Also, under Solaris 9, including term.h without first
including curses.h results in complaints about undefined
symbols, such as bool. As a result the configure script's
test for term.h was failing. I have now modified it to
include curses.h in the test code that it uses to check
for term.h. In the process I also improved the tests for
curses.h and term.h to prevent an ncurses version of
term.h from being used with the system-default version of
curses.h.
29/06/2003 mcs@astro.caltech.edu
Makefile.in direader.c homedir.c
On some systems (eg. linux) the _POSIX_C_SOURCE
feature-test macro is set by system headers, rather than
being an option set by a project's Makefile at
compilation time. In software, such as tecla, where the
definition of this macro is used as an indication of
whether to use the non-reentrant or reentrant versions of
system functions, this means that the reentrant functions
are always used, regardless of whether this macro is set
or not by the project Makefile. Thus, on such systems the
reentrant and non-reentrant versions of the tecla library
are essentially identical. This has a couple of
drawbacks. First, since thread-safe functions for
traversing the password file don't exist, the supposedly
non-reentrant version of the tecla library can't support
ambiguous tab-completion of usernames in ~username/
constructions. Secondly, on some systems the use of
reentrant system functions dictates the use of a shared
library that isn't needed for the non-reentrant
functions, thus making it more difficult to distribute
binary versions of the library.
To remedy this situation I have modified the DEFINES_R
variable in Makefile.in to arrange for the compiler to
define a C macro called PREFER_REENTRANT when it is
compiling the reentrant version of the tecla library.
This macro is now used in the source code to determine
when to require reentrant code. Whithin the source code,
wherever a potentially non-reentrant interface is used,
the existance of both this macro and a suitably valued
_POSIX_C_SOURCE macro, are tested for to see if a
reentrant alternative to the problem code should be used.
22/06/2003 mcs@astro.caltech.edu
getline.c
I changed the way that redisplays are requested and
performed. Redisplays are now queued by calling
gl_queue_redisplay(), and subsequently performed by
gl_flush_output(), when the queue of already pending
output has been completely dispatched. This was necessary
to prevent event handlers from filling up the output
queue with redisplays, and it also simplifies a number of
things. In the process I removed the gl_queue_display()
function. I also wrote a gl_line_erased() function, which
is now called by all functions that erase the input
line. I also split the gl_abandon_line() function into
public and private callable parts, and used the private
version internally to arrange to discard the input line
after errors.
The raw_mode flag was not being initialized by new_GetLine().
It is now initialized to zero.
I removed the zapline flag, since using the endline flag to
communicate the desire to terminate the line, did the same
thing.
gl_terminal_move_cursor() now does nothing when the input
line isn't displayed.
18/03/2003 mcs@astro.caltech.edu
getline.c
Fixed bug which was causing newlines not to be output
at the end of each newly entered line. I was
interpreting the gl->endline flag in conflicting ways in
two places. To fix this I have created a gl->displayed
flag. This flags whether an input line is currently
displayed.
17/03/2003 mcs@astro.caltech.edu
getline.c libtecla.h man/func/gl_get_line.in
man/func/gl_erase_terminal.in libtecla.map
I added a new function that programs can call to clear
the terminal between calls to gl_get_line().
11/03/2003 mcs@astro.caltech.edu
configure.in configure
Under linux when _POSIX_C_SOURCE is defined, getpwent()
and associated functions become undefined, because
_SVID_SOURCE and _BSD_SOURCE become undefined. Adding
these feature macros back to CFLAGS resolves this.
06/03/2003 mcs@astro.caltech.edu
getline.c libtecla.map man/func/gl_get_line.in
Following the lead of Edward Chien, I wrote a function
called gl_bind_keyseq(), which binds a specified
key-sequence to a given action, or unbinds the
key-sequence.
24/02/2003 mcs@astro.caltech.edu
getline.c libtecla.map man/func/cpl_complete_word.in
I implemented a simple function called
cpl_recall_matches(). This recalls the return value of
the last call to cpl_complete_word().
19/01/2003 mcs@astro.caltech.edu
getline.c
The documented signal handling, fd event-handling,
inactivity timeout handling, and server-mode non-blocking
I/O features are now implemented for non-interactive
input streams, such as pipes and files.
19/01/2003 mcs@astro.caltech.edu
getline.c libtecla.h man/func/gl_get_line.in demo3.c
I added a new return status enumerator to report
when an end-of-file condition causes gl_get_line()
to return NULL.
13/01/2003 mcs@astro.caltech.edu
history.c
I rewrote the history facility. The previous
circular buffer implementation was a nightmare to change,
and it couldn't efficiently support certain newly
requested features. The new implementation stores history
lines in linked lists of fixed sized string segments,
taken from the buffer, with each line being reference
counted and recorded in a hash table. If the user enters
a line multiple times, only one copy of the line is now
stored. Not only does this make better use of the
available buffer space, but it also makes it easy to
ensure that a line whose prefix matches the current
search prefix, isn't returned more than once in sequence,
since we can simply see if the latest search result has
the same hash-table pointer as the previous one, rather
than having to compare strings. Another plus is that due
to the use of linked lists of nodes of fixed size line
segments, there is no longer any need to continually
shuffle the contents of the buffer in order to defragment
it. As far as the user is concerned, the visible
differences are as follows:
1. If the user enters a given line multiple times in a
row, each one will be recorded in the history list,
and will thus be listed by gl_show_history(), and
saved in the history file. Previously only one line
was recorded when consecutive duplicates were entered.
This was a kludge to prevent history recall from
recalling the same line multiple times in a row. This
only achieved the desired result when not recalling by
prefix.
2. Not only simple recall, but prefix-based history line
recalls now don't return the same line multiple times
in a row. As mentioned in (1) above, previously this
only worked when performing a simple recall, without a
search prefix.
28/12/2002 mcs@astro.caltech.edu
getline.c
The one-line function, gl_buff_curpos_to_term_curpos()
was only being used by gl_place_cursor(), so I inlined it
in that function, and removed it.
28/12/2002 mcs@astro.caltech.edu
getline.c
gl_suspend_process() was calling the application-level
gl_normal_io() and gl_raw_io() functions, where it should
have been calling the internal versions _gl_normal_io()
and _gl_raw_io().
Also gl_handle_signal() was masking and unmasking just
the signals of the first element of the gl[] array
argument. It now masks and unmasks all trappable signals.
28/12/2002 mcs@astro.caltech.edu
getline.c
Now that the number of terminal characters used to
display the current input line, is recorded, the relative
line on which the last character of the input line
resides can be determined without having to call
gl_buff_curpos_to_term_curpos(). This is now used by
gl_normal_io() via gl_start_newline(), so there is now no
need for gl_buff_curpos_to_term_curpos() to be
async-signal safe. I have thus removed the annoying
gl->cwidth[] array, and gl_buff_curpos_to_term_curpos()
now calls gl_width_of_char() directly again. There is
also now no need for the gl_line_of_char_start() and
gl_line_of_char_end() functions, so I have removed them.
28/12/2002 mcs@astro.caltech.edu
getline.c
Unfortunately it turns out that the terminfo/termcap
control sequence which is defined to delete everything
from the current position to the end of the terminal, is
only defined to work when at the start of a terminal
line. In gnome terminals in RedHat 8.0, if it is used
within a terminal line, it erases the whole terminal
line, rather than just what follows the cursor. Thus to
portably truncate the displayed input line it is
necessary to first use the control sequence which deletes
from the cursor position to the end of the line, then if
there are more terminal lines, move to the start of the
next line, and use the delete to end-of-terminal control
sequence, then restore the cursor position. This requires
that one know how many physical terminal lines are used
by the current input line, so I now keep a record of the
number of characters so far displayed to the terminal
following the start of the prompt, and the new
gl_truncate_display() function uses this information to
truncate the displayed input line from the current cursor
position.
28/12/2002 mcs@astro.caltech.edu
getline.c
gl_start_newline() now moves to an empty line following
the input line, rather than just to the next line. It
also arranges for the input line to be redisplayed before
editing resumes. A major user of this is gl_print_info(),
which now need not be followed by an explicit call to
gl_redisplay(), since the terminal input loop in
gl_get_input_line() ensures that gl_redisplay() is called
after any action function that asserts gl->redisplay.
Also, all functions that erase the displayed input line
can now call the gl_erase_line() function, which is
designed to work correctly even when a terminal resize
invalidates the horizontal cursor position. Finally, the
new gl_queue_display() function is now used by functions
that need to arrange for the input line to be displayed
from scratch after the displayed line has been erased or
invalidated by other text being written to the terminal.
All of these changes are aimed at reducing the number of
places that directly modify gl->term_curpos and
gl->redisplay.
22/12/2002 Markus Gyger (logged here by mcs)
Makefile.in update_html
In places where echo and sed were being used to extract
the base names of files, Markus substituted the basename
command. He also replaced explicit cp and chmod commands
with invokations of the install-sh script.
configure.in
Use $target_os and $target_cpu, where appropriate,
instead of $target.
configure.in
The Solaris man function and library man pages should
be in sections 3lib and 3tecla respectively, only in
Solaris version 2.8 and above.
configure.in
Markus provided values for the man page configuration
variables for HPUX.
man/*/*.in
I had missed parameterizing man page section numbers in
the man page titles, Markus corrected this.
man/func/libtecla_version.in
Fixed incorrect section number in the link to the
libtecla man page.
homedir.c
When compiled to be reentrant, although one can't use the
non-reentrant getpwent() function to scan the password
file for username completions, one can at least see if
the prefix being completed is a valid username, and if
the username of the current user minimally matches the
prefix, and if so list them. I simplified Markus'
modification by adding a prefix argument to the
_hd_scan_user_home_dirs() function, and redefining the
function description accordingly, such that now it
reports only those password file entries who's usernames
minimally match the specified prefix. Without this, it
would have been necessary to peak inside the private data
argument passed in by cf_complete_username().
Markus also provided code which under Solaris uses the
non-reentrant interfaces if the reentrant version of the
library isn't linked with the threads library.
19/12/2002 mcs@astro.caltech.edu
Makefile.in
Markus pointed out that LDFLAGS was being picked up by
the configure script, but not then being interpolated
into te Makefile. I have thus added the necessary
assignment to Makefile.in and arranged for the value of
LDFLAGS to be passed on to recursive make's. I also did
the same for CPPFLAGS, which had also been omitted.
18/12/2002 mcs@astro.caltech.edu
man/* man/*/* configure.in configure Makefile.in
update_html
It turns out that the assignment of man page sections to
topics differs somewhat from system to system, so this is
another thing that needs to be configured by the main
configuration script, rather than being hardwired. All
man pages have now been moved into suitably named
topic-specific sub-directories of the top-level man
directory, and instead of having a numeric suffix, now
have the .in suffix, since they are now preprocessed by
the configure script, in the same fashion as Makefile.in.
Whithin these *.in versions of the man pages, and within
Makefile.in, the installation subdirectory (eg. man1) and
the file-name suffix (eg. 1), are written using
configuration macros, so that they get expanded to the
appropriate tokens when the configure script is run. In
principle, the man pages could also take advantage of
other configuration macros, such as the one which expands
to the library installation directory, to include full
path names to installed files in the documentation, so in
the future this feature could have more uses than just
that of parameterizing man page sections.
18/12/2002 mcs@astro.caltech.edu
man3 man3/* Makefile.in html/index.html update_html
Markus suggested splitting the gl_get_line(3) man page
into user and developer sections, and also pointed out
that the enhance man page should be in section 1, not
section 3. I have thus created a top-level man
directory in which to place the various sections, and
moved the man3 directory into it. The enhance.3 man page
is now in man/man1/enhance.1. I have extracted all
user-oriented sections from the gl_get_line(3) man page
and placed them in a new man7/tecla.7 man page.
18/12/2002 mcs@astro.caltech.edu
getline.c
Terminal resizing was broken in normal mode, due to
me forcing the terminal cursor position to zero in the
wrong place in gl_check_caught_signal().
14/12/2002 Markus Gyger (logged here by mcs)
configure.in configure
Under Solaris, recent versions of gcc search
/usr/local/include for header files before the system
directories. This caused a problem if ncurses was
installed under Solaris, since the termcap.h include file
in /usr/local/include ended up being used at compile
time, whereas the system default version of the curses
library was used at link time. Since the two libraries
declare tputs() differently, this evoked a complaint from
gcc. Markus came up with a way to force Gnu cpp to move
/usr/local/include to the end of the system-include-file
search path, where it belongs.
13/12/2002 mcs@astro.caltech.edu
man3/gl_io_mode.3
I rewrote the man page which documents the new non-blocking
server I/O mode.
12/12/2002 mcs@astro.caltech.edu
demo3.c
I wrote a new version of demo3.c, using signal handlers
that call gl_handle_signal() and gl_abandon_line(), where
previously in this demo, these functions were called from
the application code.
05/12/2002 mcs@astro.caltech.edu
getline.c
gl_normal_io(), gl_raw_io() and gl_handle_signal() and
gl_abandon_line() are now signal safe, provided that
signal handlers that call them are installed with sa_mask's
that block all other signals who's handlers call them.
This is the case if gl_tty_signals() is used to install
signal handlers that call any of these functions.
A major stumbling block that had to be overcome was that
gl_displayed_char_width() calls isprint(), which can't
safely be called from a signal handler (eg. under linux,
the is*() functions all use thread-specific data
facilities to support per-thread locales, and the
thread-specific data facilities aren't signal safe). To
work around this, all functions that modify the
input-line buffer, now do so via accessor functions which
also maintain a parallel array of character widths, for
use by gl_buff_curpos_to_term_curpos() in place of
gl_displayed_char_width(). Other minor problems were the
need to avoid tputs(), who's signal safety isn't defined.
05/12/2002 Eric Norum (logged here by mcs@astro.caltech.edu)
configure.in
Eric provided the configuration information needed
to build shared libraries under Darwin (Max OS X).
05/12/2002 Richard Mlynarik (logged here by mcs@astro.caltech.edu)
configure.in
AC_PROG_RANLIB gets the wrong version of ranlib when
cross compiling, so has now been replaced by an
invokation of AC_CHECK_TOOL. In addition, AC_CHECK_TOOL
is also now used to find an appropriate version of LD.
05/12/2002 mcs@astro.caltech.edu (based on patch by Pankaj Rathore)
getline.c libtecla.h libtecla.map man3/gl_get_line.3
The new gl_set_term_size() function provides a way
to tell gl_get_line() about changes in the size of
the terminal in cases where the values returned by
ioctl(TIOCGWINSZ) isn't correct.
05/12/2002 mcs@astro.caltech.edu
getline.c
Rather than calling sprintf() to see how much space would
be needed to print a given number in octal, I wrote a
gl_octal_width() function, for use by
gl_displayed_char_width(). This makes the latter
function async signal safe.
05/12/2002 mcs@astro.caltech.edu
chrqueue.c
Whenever the buffer is exhausted, and getting a new
buffer node would require a call to malloc(), attempt
to flush the buffer to the terminal. In blocking I/O
mode this means that the buffer never grows. In
non-blocking I/O mode, it just helps keep the buffer
size down.
05/12/2002 mcs@astro.caltech.edu
freelist.h freelist.c
The new _idle_FreeListNodes() function queries the
number of nodes in the freelist which aren't currently
in use.
05/12/2002 mcs@astro.caltech.edu
Makefile.stub
This now accepts all of the targets that the configured
makefile does, and after configuring the latter makefile,
it invokes it with the same options.
03/12/2002 mcs@astro.caltech.edu
mans3/gl_io_mode.3
I completed the man page for all of the new functions
related to non-blocking I/O.
01/12/2002 mcs@astro.caltech.edu
man3/gl_get_line.3
I wrote a long section on reliable signal handling,
explaining how gl_get_line() does this, how to make
use of this in a program, and how to handle signals
reliably when faced with other blocking functions.
This basically documents what I have learnt about
signal handling while working on this library.
01/12/2002 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
In non-blocking server mode, the gl_replace_prompt()
function can now be used between calls to gl_get_line()
if the application wants to change the prompt of the
line that is being edited.
01/12/2002 mcs@astro.caltech.edu
man3/gl_get_line.3
I documented the new gl_return_status() and
gl_error_message() functions.
01/12/2002 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
Added SIGPOLL and SIGXFSZ to the list of signals that
are trapped by default. These are process termination
signals, so the terminal needs to be restored to a
usable state before they terminate the process.
27/11/2002 mcs@astro.caltech.edu
getline.c libtecla.h
Completed the essential changes needed to support
non-blocking server-I/O mode.
The new gl_io_mode() function allows one to switch to
and from non-blocking server-I/O mode.
The new gl_raw_io() function is used in non-blocking
server-I/O mode to switch the terminal into non-blocking
raw I/O mode.
The new gl_normal_io() function is used in non-blocking
server-I/O mode to switch the restore the terminal to
a normal, blocking state. This is used to suspend line
input before suspending the process or writing messages
to the terminal.
The new gl_tty_signals() function installs specified
signals handlers for all signals that suspend, terminate
or resume processes, and also for signals that indicate
that the terminal has been resized. This not only saves
the application from having to keep its own ifdef'd list
of such signals, of which there are many, but it also
makes sure that these signal handlers are registered
correctly. This includes using the sa_mask member of each
sigaction structure to ensure that only one of these
handlers runs at a time. This is essential to avoid the
signal handlers all trying to simultaneously modify
shared global data.
The new gl_handle_signal() function is provided for
responding (from application level) to signals caught by
the application. It handles process suspension, process
termination and terminal resize signals.
The new gl_pending_io() function tells the application
what direction of I/O gl_get_line() is currently waiting
for.
In non-blocking server I/O mode, the new
gl_abandon_line() function can be called between calls to
gl_get_line() to discard an input line and force the next
call to gl_get_line() to start the input of a new line.
Also, in non-blocking server-I/O gl_get_line() doesn't
attempt to do anything but return when one of the signals
that it is configured to catch is caught. This is
necessary because when in this mode, the application is
required to handle these signals when gl_get_line() is
running, and the default configuration of most of these
signals in gl_get_line() is to restore the terminal then
call the application signal handlers. This would be a
case of too many cooks spoiling the broth, so in this
mode, gl_get_line() always defers to the application's
signal handlers.
26/11/2002 mcs@astro.caltech.edu
getline.c libtecla.h
I implemented a couple of new functions to support
reliable signal handling, as now documented
(see above) in the gl_get_line(3) man page.
The new gl_catch_blocked() function tells gl_get_line()
to unblock all configured signals around calls to
long-running functions, not only those that aren't
blocked when gl_get_line() is called. This allows
the caller to implement reliable signal handling,
since the unblocking is only done from within code
protected by sigsetjmp(), which avoids race conditions.
The new gl_list_signals() function fills a provided
sigset_t with the set of signals that gl_get_line() is
currently configured to catch. This allows callers to
block said signals, such that they are only unblocked by
gl_get_line() when it is waiting for I/O. When used in
conjunction with the gl_catch_blocked() function, this
removes the potential for race conditions.
Also, when gl_get_line() installs its signal handler,
it uses the sa_mask member of the sigaction structure
to ensure that only one instance of this signal handler
will ever be executing at a time.
25/11/2002 mcs@astro.caltech.edu (bug reported by Pankaj Rathore)
getline.c
When any history recall action was invoked when the
input line buffer was full, an error message would be
displayed complaining about the length of the string
in the line input buffer being inconsistent with the
specified allocated size. This was because instead of
sending the allocated size of the input line, I was
sending the length excluding the element that is
reserved for the '\0' terminator. Sending it the
correct size corrected the problem.
24/11/2002 mcs@astro.caltech.edu
getline.c
All public functions which take GetLine objects as
arguments now block signals on entry and restore the
signal mask on return. This was an attempt to make it
safe to call getline functions from signal handlers, but
the fact is that the functions that I really wanted this
to apply to, potentially call malloc(), so this currently
isn't the case.
23/11/2002 mcs@astro.caltech.edu
getline.c libtecla.h
The new gl_return_status() function returns an enumerated
return status which can be used to query what caused
gl_get_line() to return.
22/11/2002 mcs@astro.caltech.edu
Most existing .c and .h files, plus errmsg.c errmsg.h
Makefile.rules
Until now, many library functions would report error
messages to stderr. This isn't appropriate for library
functions, so in place of this behavior, error messages
are now recorded in internal ErrMsg objects, and passed
between modules via new module-specific error querying
functions. In addition, errno is now set appropriately.
Thus when gl_get_line() and related functions return an
error, strerror() can be used to look up system errors,
and gl_error_message() can be used to recover a higher level
error message. Note that error messages that are
responses to user actions continue to be reported to the
terminal, as before.
21/11/2002 mcs@astro.caltech.edu
getline.c keytab.h keytab.c Makefile.rules
I wrote a new version of _kt_lookup_binding() that didn't
require the caller to have access to the innards of a
KeyTab object. This then enabled me to move the definition
of KeyTab objects into keytab.c and make the typedef in
keytab.h opaque. Many nested includes were also moved from
keytab.h into keytab.c.
05/11/2002 mcs@astro.caltech.edu
getline.c libtecla.map libtecla.h demo3.c
I split the old gl_resize_terminal() function into
two parts, gl_query_size() and gl_update_size(), with
the latter calling the former to get the new terminal
size.
05/11/2002 mcs@astro.caltech.edu
getline.c
I fixed a long time bug in the terminal resizing code.
When the cursor wasn't on the last terminal line of the
input line, the resizing code would redisplay the
the line one or more lines above where it should be
restored. This was due to an error in the calculation of
the number of lines above the cursor position.
04/11/2002 mcs@astro.caltech.edu
demo.c demo2.c demo3.c
I used the new gl_display_text() function to display
introductory text at the startup of each of the demo
programs. The text is enclosed within a box of asterixes,
drawn dynamically to fit within the confines of the
available terminal width.
04/11/2002 mcs@astro.caltech.edu
libtecla.h getline.c ioutil.c ioutil.h Makefile.rules
libtecla.map man3/gl_get_line.3 man3/gl_display_text.3
Needing a way to display introductory text intelligently
in the demo programs, I wrote and documented the
gl_display_text() function. This justifies arbitrary
length text within the bounds of the terminal width,
with or without optional indentation, prefixes and
suffixes.
03/11/2002 mcs@astro.caltech.edu
demo3.c Makefile.rules
I wrote a new demonstration program. This program acts
exactly like the main demonstration program, except that
it uses an external event loop instead of using the
gl_get_line() internal event loop. This is thus an example
of the new non-blocking server I/O facility.
02/11/2002 mcs@astro.caltech.edu
getline.c keytab.c keytab.h libtecla.h man3/gl_get_line.3
man3/gl_completion_action.3
I added the ability to register additional word
completion actions via the new function
gl_completion_action(). All action functions now take a
new (void *data) argument, which is stored with the
function in the symbol table of actions. The new
gl_completion_action() function uses this feature to
record dynamically allocated objects containing the
specified completion function and callback data along
with either the gl_complete_word() action function, or
the gl_list_completions() action function. These two
actions continue to use the builtin completion functions
when their data pointer is NULL.
20/10/2002 mcs@astro.caltech.edu
The following are changes merged from the non-blocking
gl_get_line() development branch.
getline.c
I wrote a gl_start_newline() function, to replace all of
the explicit calls to output \r\n to stdout.
Informational messages are now written to the terminal
using a new variadic function called gl_print_info().
This starts a newline, writes string arguments until a
special argument, GL_END_INFO, is seen, then starts
another newline.
Changed _output_ to _print_ in the following function
names gl_output_control_sequence(), gl_output_char(),
gl_output_string() and gl_output_raw_string().
gl_print_raw_string() now has a length argument, so that
strings that aren't terminated with '\0' can be printed.
The display of the initial contents of a new line to be
edited has been moved into a new function called
gl_present_line().
The gl_get_input_line() function now takes the prompt
string as an argument so that gl_replace_prompt() can be
called from within this function instead of from
gl_get_line().
Keyboard input is now buffered in a persistent buffer in
the parent GetLine object. gl_read_character() checks
this for unprocessed characters in preference to calling
gl_read_terminal() to append characters to it. A new
function, gl_discard_chars(), removes processed
characters from this buffer. This change is in
preparation for a non-blocking version of gl_get_line(),
where partially input key-sequences must be stored
between calls to gl_get_line().
getline.c getline.h history.c history.h cplmatch.c \
cplmatch.h expand.c expand.h
All terminal output from gl_get_line() is now routed
through a GL_WRITE_FN() callback function called
gl_write_fn. Internal functions in cplmatch.c,
expand.c and history.c have been created which take
such callbacks to write output. These are used both
by functions in getline.c, to display file completions,
expansions, history etc, and as the internals of existing
public functions in these files that print to stdio
streams. In the latter case an internal stdio
GL_WRITE_FN() callback is substituted, so that the
functions behave as before.
getline.c chrqueue.c chrqueue.h
The gl_write_fn() callback used by gl_get_line() now
writes to a queue, implemented in chrqueue.c. This queue
is implemented as a list of blocks of buffer segments,
the number of which shrink and grow as
needed. The contents of the queue are flushed to the
terminal via another GL_WRITE_FN() callback passed to the
queue object. Currently gl_get_line() passes an internal
function assigned to gl->flush_fn, called
gl_flush_terminal(), which writes the contents of the
queue to the terminal, and knows how to handle both
blocking and non-blocking I/O. The output queue is
designed to be flushed to the terminal incrementally, and
thereby also facilitates non-blocking I/O.
getline.c getline.h
gl_get_line() now reads all input via the GL_READ_FN()
callback, assigned to gl->read_fn. Currently this is
set to an internal function called gl_read_terminal(),
which knows how to handle both blocking and
non-blocking I/O.
getline.c libtecla.h
The new gl_set_nonblocking() function can be used to
enable or disable non-blocking I/O. The default is still
blocking I/O. In non-blocking mode, the terminal is told
not to wait when either reading or writing would block.
gl_get_line() then returns, with a return value of NULL,
but with the terminal left in raw mode, so that the
caller's event loop can detect key presses. The caller
should call gl_return_status() to check whether the NULL
return value was due to an error, lack of input, or
inability to write to the terminal without waiting. If
either reading or writing was said to have blocked, the
user then should check for I/O readiness in the specified
direction before calling gl_get_line() again to
incrementally build up the input line.
05/08/2002 mcs@astro.caltech.edu
man3/gl_get_line.3 man3/gl_inactivity_timeout.3
I documented the new gl_inactivity_timeout() function.
08/07/2002 mcs@astro.caltech.edu
libtecla.h getline.c libtecla.map
I added a new gl_inactivity_timeout() function. On
systems that have the select system call, this provides
the option of registering a function that is then called
whenever no I/O activity has been seen for more than a
specified period of time. Like the gl_watch_fd()
facility, timeout callbacks return a code which tells
gl_get_line() how to proceed after the timeout has been
handled.
04/07/2002 mcs@astro.caltech.edu (based on a bug report from Michael MacFaden)
getline.c
The internal event handler wasn't responding to write
events on client file descriptors, due to a typo which
resulted in read events being checked for twice, and
writes not checked for at all.
pathutil.c
The amount of space to allocate for pathnames is supposed
to come from PATH_MAX in limits.h, but I had neglected to
include limits.h. This went unnoticed because on most
systems the equivalent number is deduced by calling
pathconf(). Apparently under NetBSD this function doesn't
work correctly over NFS mounts.
30/05/2002 Version 1.4.1 released.
25/05/2002 mcs@astro.caltech.edu (based on suggestions by Paul Smith)
pathutil.c
Apparently, under QNX pathconf("/",_PC_PATH_MAX) returns
EINVAL. At Paul's suggestion I have modified the code to
silently substitute the existing MAX_PATHLEN_FALLBACK
value if pathconf() returns an error of any kind.
homedir.c
Under QNX, sysconf(_SC_GETPW_R_SIZE_MAX) also apparently
returns EINVAL, so as with pathconf() I modified the code
to substitute a fallback default, rather than
complaining and failing.
enhance.c
Paul told me that the inclusion of sys/termios.h was
causing compilation of enhance.c to fail under QNX. This
line is a bug. The correct thing to do is include
termios.h without a sub-directory prefix, as I was
already doing futher up in the file, so I have just
removed the errant include line.
07/05/2002 mcs@astro.caltech.edu (async development branch only)
getline.c
gl_read_character() now caches and reads unprocessed
characters from a key-press lookahead buffer. Whenever
gl_intepret_char() receives a new character which makes
an initially promising key-sequence no longer match the
prefix of any binding, it now simply discards the first
character from the key-press buffer and resets the buffer
pointer so that the next call to gl_read_character()
returns the character that followed it, from the buffer.
getline.c
The part of gl_get_input_line() which preloads, displays
and prepares to edit a new input line, has now been moved
into a function called gl_present_line().
12/02/2002 mcs@astro.caltech.edu
getline.c configure.in configure
Mac OS X doesn't have a term.h or termcap.h, but it does
define prototypes for tputs() and setupterm(), so the
default prototypes that I was including if no headers
where available, upset it. I've removed these prototypes.
I also now conditionally include whichever is found of
curses.h and ncurses/curses.h for both termcap and
terminfo (before I wasn't including curses.h when
termcap was selected).
12/02/2002 mcs@astro.caltech.edu
Updated version number to 1.4.1, ready for a micro
release.
12/02/2002 mcs@astro.caltech.edu
html/index.html
Added Mac OS X and Cygwin to the list of systems that
can compile libtecla.
12/02/2002 mcs@astro.caltech.edu
getline.c
Under Mac OS X, the tputs() callback function returns
void, instead of the int return value used by other
systems. This declaration is now used if both __MACH__
and __APPLE__ are defined. Hopefully these are the
correct system macros to check. Thanks for Stephan
Fiedler for providing information on Mac OS X.
11/02/2002 mcs@astro.caltech.edu
configure.in configure getline.c
Some systems don't have term.h, and others have it hidden
in an ncurses sub-directory of the standard system include
directory. If term.h can't be found, simply don't include
it. If it is in an ncurses sub-directory, include
ncurses/term.h instead of term.h.
04/02/2002 mcs@astro.caltech.edu
configure.in configure Makefile.in Makefile.rules
Use ranlib on systems that need it (Mac OS X). Also,
make all components of the installation directories where
needed, instead of assuming that they exist.
04/02/2002 mcs@astro.caltech.edu
getline.c
When the tab completion binding was unbound from the tab
key, hitting the tab key caused gl_get_line() to ring the
bell instead of inserting a tab character. This is
problematic when using the 'enhance' program with
Jython, since tabs are important in Python. I have
corrected this.
10/12/2001 Version 1.4.0 released.
10/12/2001 mcs@astro.caltech.edu
getline.c
If the TIOCGWINSZ ioctl doesn't work, as is the case when
running in an emacs shell, leave the size unchanged, rather
than returning a fatal error.
07/12/2001 mcs@astro.caltech.edu
configure.in configure
Now that the configure version of CFLAGS is included in
the makefile, I noticed that the optimization flags -g
and -O2 had been added. It turns out that if CFLAGS isn't
already set, the autoconf AC_PROG_CC macro initializes it
with these two optimization flags. Since this would break
backwards compatibility in embedded distributions that
already use the OPT= makefile argument, and because
turning debugging on needlessly bloats the library, I now
make sure that CFLAGS is set before calling this macro.
07/12/2001 mcs@astro.caltech.edu
enhance.c
Use argv[0] in error reports instead of using a
hardcoded macro.
07/12/2001 mcs@astro.caltech.edu
getline.c
The cut buffer wasn't being cleared after being
used as a work buffer by gl_load_history().
06/12/2001 mcs@astro.caltech.edu
configure.in configure
I removed my now redundant definition of SUN_TPUTS from
CFLAGS. I also added "-I/usr/include" to CFLAGS under
Solaris to prevent gcc from seeing conflicting versions
of system header files in /usr/local/include.
06/12/2001 Markus Gyger (logged here by mcs)
Lots of files.
Lots of corrections to misspellings and typos in the
comments.
getline.c
Markus reverted a supposed fix that I added a day or two
ago. I had incorrectly thought that in Solaris 8, Sun had
finally brought their declaration of the callback
function of tputs() into line with other systems, but it
turned out that gcc was pulling in a GNU version of
term.h from /usr/local/include, and this was what
confused me.
05/12/2001 mcs@astro.caltech.edu
Makefile.in
I added @CFLAGS@ to the CFLAGS assignment, so that
if CFLAGS is set as an environment variable when
configure is run, the corresponding make variable
includes its values in the output makefile.
05/12/2001 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man3/gl_get_line.3
man3/gl_last_signal.3
I added a function that programs can use to find out
which signal caused gl_get_line() to return EINTR.
05/12/2001 mcs@astro.caltech.edu
getline.c
When the newline action was triggered by a printable
character, it failed to display that character. It now
does. Also, extra control codes that I had added, to
clear to the end of the display after the carriage return,
but before displaying the prompt, were confusing expect
scripts, so I have removed them. This step is now done
instead in gl_redisplay() after displaying the full input
line.
05/12/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
A user convinced me that continuing to invoke meta
keybindings for meta characters that are printable is a
bad idea, as is allowing users to ask to have setlocale()
called behind the application's back. I have thus changed
this. The setlocale configuration option has gone, and
gl_get_line() is now completely 8-bit clean, by default.
This means that if a meta character is printable, it is
treated as a literal character, rather than a potential
M-c binding. Meta bindings can still be invoked via
their Esc-c equivalents, and indeed most terminal
emulators either output such escape pairs by default when
the meta character is pressed, or can be configured to do
so. I have documented how to configure xterm to do this,
in the man page.
03/12/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
gl_get_line() by default now prints any 8-bit printable
characters that don't match keybindings. Previously
characters > 127 were only printed if preceded by the
literal-next action. Alternatively, by placing the
command literal_if_printable in the tecla configuration
file, all printable characters are treated as literal
characters, even if they are bound to action functions.
For international users of programs written by
programmers that weren't aware of the need to call
setlocale() to support alternate character sets, the
configuration file can now also contain the single-word
command "setlocale", which tells gl_get_line() to remedy
this.
27/11/2001 mcs@astro.caltech.edu
demo.c demo2.c enhance man3/gl_get_line.3
All demos and programs now call setlocale(LC_CTYPE,"").
This makes them support character sets of different
locales, where specified with the LC_CTYPE, LC_ALL, or
LANG environment variables. I also added this to the demo
in the man page, and documented its effect.
27/11/2001 mcs@astro.caltech.edu
getline.c
When displaying unsigned characters with values over
127 literally, previously it was assumed that they would
all be displayable. Now isprint() is consulted, and if it
says that a character isn't printable, the character code
is displayed in octal like \307. In non-C locales, some
characters with values > 127 are displayable, and
isprint() tells gl_get_line() which are and which aren't.
27/11/2001 mcs@astro.caltech.edu
getline.c pathutil.c history.c enhance.c demo2.c
All arguments of the ctype.h character class functions
are now cast to (int)(unsigned char). Previously they
were cast to (int), which doesn't correctly conform to
the requirements of the C standard, and could cause
problems for characters with values > 127 on systems
with signed char's.
26/11/2001 mcs@astro.caltech.edu
man3/enhance.3 man3/libtecla.3
I started writing a man page for the enhance program.
26/11/2001 mcs@astro.caltech.edu
Makefile.in Makefile.rules INSTALL
It is now possible to specify whether the demos and other
programs are to be built, by overriding the default
values of the DEMOS, PROGRAMS and PROGRAMS_R variables.
I have also documented the BINDIR variable and the
install_bin makefile target.
22/11/2001 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man3/gl_get_line.3
man3/gl_ignore_signal.3 man3/gl_trap_signal.3
Signal handling has now been modified to be customizable.
Signals that are trapped by default can be removed from
the list of trapped signals, and signals that aren't
currently trapped, can be added to the list. Applications
can also specify the signal and terminal environments in
which an application's signal handler is invoked, and
what gl_get_line() does after the signal handler returns.
13/11/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
Added half-bright, reverse-video and blinking text to the
available prompt formatting options.
getline.c
Removed ^O from the default VT100 sgr0 capability
string. Apparently it can cause problems with some
terminal emulators, and we don't need it, since it turns
off the alternative character set mode, which we don't
use.
getline.c
gl_tigetstr() and gl_tgetstr() didn't guard against the
error returns of tigetstr() and tgetstr() respectively.
They now do.
11/11/2001 mcs@astro.caltech.edu
getline.c libtecla.h libtecla.map man3/gl_get_line.3
man3/gl_prompt_style.3
Although the default remains to display the prompt string
literally, the new gl_prompt_style() function can be used
to enable text attribute formatting directives in prompt
strings, such as underlining, bold font, and highlighting
directives.
09/11/2001 mcs@astro.caltech.edu
enhance.c Makefile.rules configure.in configure
I added a new program to the distribution that allows one
to run most third party programs with the tecla library
providing command-line editing.
08/11/2001 mcs@astro.caltech.edu
libtecla.h getline.c man3/gl_get_line.3 history.c history.h
I added a max_lines argument to gl_show_history() and
_glh_show_history(). This can optionally be used to
set a limit on the number of history lines displayed.
libtecla.h getline.c man3/gl_get_line.3
I added a new function called gl_replace_prompt(). This
can be used by gl_get_line() callback functions to
request that a new prompt be use when they return.
06/11/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
I implemented, bound and documented the list-history
action, used for listing historical lines of the current
history group.
getline.c man3/gl_get_line.3 man3/gl_echo_mode.3
I wrote functions to specify and query whether subsequent
lines will be visible as they are being typed.
28/10/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
For those cases where a terminal provides its own
high-level terminal editing facilities, you can now
specify an edit-mode argument of 'none'. This disables
all tecla key bindings, and by using canonical terminal
input mode instead of raw input mode, editing is left up
to the terminal driver.
21/10/2001 mcs@astro.caltech.edu
libtecla.h getline.c history.c history.h
man3/gl_get_line.3 man3/gl_history_info.3
I added the new gl_state_of_history(),
gl_range_of_history() and gl_size_of_history()
functions for querying information about the
history list.
history.c
While testing the new gl_size_of_history()
function, I noticed that when the history buffer
wrapped, any location nodes of old lines between
the most recent line and the end of the buffer
weren't being removed. This could result in bogus
entries appearing at the start of the history list.
Now fixed.
20/10/2001 mcs@astro.caltech.edu
libtecla.h getline.c history.c history.h
man3/gl_get_line.3 man3/gl_lookup_history.3
I added a function called gl_lookup_history(), that
the application can use to lookup lines in the history
list.
libtecla.h getline.c history.c history.h man3/gl_get_line.3
gl_show_history() now takes a format string argument
to control how the line is displayed, and with what
information. It also now provides the option of either
displaying all history lines or just those of the
current history group.
getline.c man3/gl_get_line.3
gl_get_line() only archives lines in the history buffer
if the newline action was invoked by a newline or
carriage return character.
16/10/2001 mcs@astro.caltech.edu
history.c history.h getline.c libtecla.h libtecla.map
man3/gl_get_line.3 man3/gl_resize_history.3
man3/gl_limit_history.3 man3/gl_clear_history.3
man3/gl_toggle_history.3
I added a number of miscellaneous history configuration
functions. You can now resize or delete the history
buffer, limit the number of lines that are allowed in the
buffer, clear either all history or just the history of
the current history group, and temporarily enable and
disable the history mechanism.
13/10/2001 mcs@astro.caltech.edu
getline.c
tputs_fp is now only declared if using termcap or
terminfo.
getline.c libtecla.map man3/gl_get_line.3
man3/gl_terminal_size.3
I added a public gl_terminal_size() function for
updating and querying the current size of the terminal.
update_version configure.in libtecla.h
A user noted that on systems where the configure script
couldn't be used, it was inconvenient to have the version
number macros set by the configure script, so they are
now specified in libtecla.h. To reduce the likelihood
that the various files where the version number now
appears might get out of sync, I have written the
update_version script, which changes the version number
in all of these files to a given value.
01/10/2001 mcs@astro.caltech.edu
getline.c history.c history.h man3/gl_get_line.3
I added a max_lines argument to gl_save_history(), to
allow people to optionally place a ceiling on the number
of history lines saved. Specifying this as -1 sets the
ceiling to infinity.
01/10/2001 mcs@astro.caltech.edu
configure.in configure
Under digital unix, getline wouldn't compile with
_POSIX_C_SOURCE set, due to type definitions needed by
select being excluded by this flag. Defining the
_OSF_SOURCE macro as well on this system, resolved this.
30/09/2001 mcs@astro.caltech.edu
getline.c libtecla.h history.c history.h man3/gl_get_line.3
man3/gl_group_history.3
I implemented history streams. History streams
effectively allow multiple history lists to be stored in
a single history buffer. Lines in the buffer are tagged
with the current stream identification number, and
lookups only consider lines that are marked with the
current stream identifier.
getline.c libtecla.h history.c history.h man3/gl_get_line.3
man3/gl_show_history.3
The new gl_show_history function displays the current
history to a given stdio output stream.
29/09/2001 mcs@astro.caltech.edu
getline.c
Previously new_GetLine() installed a persistent signal
handler to be sure to catch the SIGWINCH (terminal size
change) signal between calls to gl_get_line(). This had
the drawback that if multiple GetLine objects were
created, only the first GetLine object used after the
signal was received, would see the signal and adapt to
the new terminal size. Instead of this, a signal handler
for sigwinch is only installed while gl_get_line() is
running, and just after installing this handler,
gl_get_line() checks for terminal size changes that
might have occurred while the signal handler wasn't
installed.
getline.c
Dynamically allocated copies of capability strings looked
up in the terminfo or termcap databases are now made, so
that calls to setupterm() etc for one GetLine object
don't get trashed when another GetLine object calls
setupterm() etc. It is now safe to allocate and use
multiple GetLine objects, albeit only within a single
thread.
28/09/2001 mcs@astro.caltech.edu
version.c Makefile.rules
I added a function for querying the version number of
the library.
26/09/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
I added the new gl_watch_fd() function, which allows
applications to register callback functions to be invoked
when activity is seen on arbitrary file descriptors while
gl_get_line() is awaiting keyboard input from the user.
keytab.c
If a request is received to delete a non-existent
binding, which happens to be an ambiguous prefix of other
bindings no complaint is now generated about it being
ambiguous.
23/09/2001 mcs@astro.caltech.edu
getline.c history.c history.h man3/gl_get_line.3
libtecla.map demo.c
I added new public functions for saving and restoring the
contents of the history list. The demo program now uses
these functions to load and save history in ~/.demo_history.
23/09/2001 mcs@astro.caltech.edu
getline.c
On trying the demo for the first time on a KDE konsole
terminal, I discovered that the default M-O binding
to repeat history was hiding the arrow keys, which are
M-OA etc. I have removed this binding. The M-o (ie the
lower case version of this), is still bound.
18/09/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3 libtecla.map
Automatic reading of ~/.teclarc is now postponed until
the first call to gl_get_line(), to give the application
the chance to specify alternative configuration sources
with the new function gl_configure_getline(). The latter
function allows configuration to be done with a string, a
specified application-specific file, and/or a specified
user-specific file. I also added a read-init-files action
function, for re-reading the configuration files, if any.
This is by default bound to ^X^R. This is all documented
in gl_get_line.3.
08/09/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
It is now possible to bind actions to key-sequences
that start with printable characters. Previously
keysequences were required to start with meta or control
characters. This is documented in gl_get_line.3.
getline.c man3/gl_get_line.3
A customized completion function can now arrange for
gl_get_line() to return the current input line whenever a
successful completion has been made. This is signalled by
setting the last character of the optional continuation
suffix to a newline character. This is documented in
gl_get_line.3.
05/07/2001 Bug reported by Mike MacFaden, fixed by mcs
configure.in
There was a bug in the configure script that only
revealed itself on systems without termcap but not
terminfo (eg. NetBSD). I traced the bug back to a lack of
sufficient quoting of multi-line m4 macro arguments in
configure.in, and have now fixed this and recreated the
configure script.
05/07/2001 Bug reported and patched by Mike MacFaden (patch modified
by mcs to match original intentions).
getline.c
getline.c wouldn't compile when termcap was selected as
the terminal information database. setupterm() was being
passed a non-existent variable, in place of the term[]
argument of gl_control_strings(). Also if
gl_change_terminal() is called with term==NULL, "ansi"
is now substituted.
02/07/2001 Version 1.3.3 released.
27/06/2001 mcs@astro.caltech.edu
getline.c expand.c cplmatch.c
Added checks to fprintf() statements that write to the
terminal.
getline.c
Move the cursor to the end of the line before suspending,
so that the cursor doesn't get left in the middle of the
input line.
Makefile.in
On systems that don't support shared libraries, the
distclean target of make deleted libtecla.h. This has
now been fixed.
getline.c
gl_change_terminal() was being called by gl_change_editor(),
with the unwanted side effect that raw terminal modes were
stored as those to be restored later, if called by an
action function. gl_change_terminal() was being called in
this case to re-establish terminal-specific key bindings,
so I have just split this part of the function out into
a separate function for both gl_change_editor() and
gl_change_terminal() to call.
12/06/2001 mcs@astro.caltech.edu
getline.c
Signal handling has been improved. Many more signals are
now trapped, and instead of using a simple flag set by a
signal handler, race conditions are avoided by blocking
signals during most of the gl_get_line() code, and
unblocking them via calls to sigsetjmp(), just before
attempting to read each new character from the user.
The matching use of siglongjmp() in the signal
handlers ensures that signals are reblocked correctly
before they are handled. In most cases, signals cause
gl_get_line() to restore the terminal modes and signal
handlers of the calling application, then resend the
signal to the application. In the case of SIGINT, SIGHUP,
SIGPIPE, and SIGQUIT, if the process still exists after
the signals are resent, gl_get_line() immediately returns
with appropriate values assigned to errno. If SIGTSTP,
SIGTTIN or SIGTTOU signals are received, the process is
suspended. If any other signal is received, and the
process continues to exist after the signal is resent to
the calling application, line input is resumed after the
terminal is put back into raw mode, the gl_get_line()
signal handling is restored, and the input line redrawn.
man/gl_get_line(3)
I added a SIGNAL HANDLING section to the gl_get_line()
man page, describing the new signal handling features.
21/05/2001 Version 1.3.2 released.
21/05/2001 mcs@astro.caltech.edu
getline.c
When vi-replace-char was used to replace the character at
the end of the line, it left the cursor one character to
its right instead of on top of it. Now rememdied.
getline.c
When undoing, to properly emulate vi, the cursor is now
left at the leftmost of the saved and current cursor
positions.
getline.c man3/gl_get_line.3
Implemented find-parenthesis (%), delete-to-paren (M-d%),
vi-change-to-paren (M-c%), copy-to-paren (M-y%).
cplfile.c pcache.c
In three places I was comparing the last argument of
strncmp() to zero instead of the return value of
strncmp().
20/05/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
Implemented and documented the vi-repeat-change action,
bound to the period key. This repeats the last action
that modified the input line.
19/05/2001 mcs@astro.caltech.edu
man3/gl_get_line.3
I documented the new action functions and bindings
provided by Tim Eliseo, plus the ring-bell action and
the new "nobeep" configuration option.
getline.c
I modified gl_change_editor() to remove and reinstate the
terminal settings as well as the default bindings, since
these have editor-specific differences. I also modified
it to not abort if a key-sequence can't be bound for some
reason. This allows the new vi-mode and emacs-mode
bindings to be used safely.
getline.c
When the line was re-displayed on receipt of a SIGWINCH
signal, the result wasn't visible until the next
character was typed, since a call to fflush() was needed.
gl_redisplay_line() now calls gl_flush_output() to remedy
this.
17/05/2001 mcs@astro.catlech.edu
getline.c
Under Linux, calling fflush(gl->output_fd) hangs if
terminal output has been suspended with ^S. With the
tecla library taking responsability for reading the stop
and start characters this was a problem, because once
hung in fflush(), the keyboard input loop wasn't entered,
so the user couldn't type the start character to resume
output. To remedy this, I now have the terminal process
these characters, rather than the library.
12/05/2001 mcs@astro.caltech.edu
getline.c
The literal-next action is now implemented as a single
function which reads the next character itself.
Previously it just set a flag which effected the
interpretation of the next character read by the input
loop.
getline.c
Added a ring-bell action function. This is currently
unbound to any key by default, but it is used internally,
and can be used by users that want to disable any of the
default key-bindings.
12/05/2001 Tim Eliseo (logged here by mcs)
getline.c
Don't reset gl->number until after calling an action
function. By looking at whether gl->number is <0 or
not, action functions can then tell whether the count
that they were passed was explicitly specified by the
user, as opposed to being defaulted to 1.
getline.c
In vi, the position at which input mode is entered
acts as a barrier to backward motion for the few
backward moving actions that are enabled in input mode.
Tim added this barrier to getline.
getline.c
In gl_get_line() after reading an input line, or
having the read aborted by a signal, the sig_atomic_t
gl_pending_signal was being compared to zero instead
of -1 to see if no signals had been received.
gl_get_line() will thus have been calling raise(-1),
which luckily didn't seem to do anything. Tim also
arranged for errno to be set to EINTR when a signal
aborts gl_get_line().
getline.c
The test in gl_add_char_to_line() for detecting
when overwriting a character with a wider character,
had a < where it needed a >. Overwriting with a wider
character thus overwrote trailing characters. Tim also
removed a redundant copy of the character into the
line buffer.
getline.c
gl_cursor_left() and gl->cursor_right() were executing
a lot of redundant code, when the existing call to the
recently added gl_place_cursor() function, does all that
is necessary.
getline.c
Remove redundant code from backward_kill_line() by
re-implimenting in terms of gl_place_cursor() and
gl_delete_chars().
getline.c
gl_forward_delete_char() now records characters in cut
buffer when in vi command mode.
getline.c
In vi mode gl_backward_delete_char() now only deletes
up to the point at which input mode was entered. Also
gl_delete_chars() restores from the undo buffer when
deleting in vi insert mode.
getline.c
Added action functions, vi-delete-goto-column,
vi-change-to-bol, vi-change-line, emacs-mode, vi-mode,
vi-forward-change-find, vi-backward-change-find,
vi-forward-change-to, vi-backward-change-to,
vi-change-goto-col, forward-delete-find, backward-delete-find,
forward-delete-to, backward-delete-to,
delete-refind, delete-invert-refind, forward-copy-find,
backward-copy-find, forward-copy-to, backward-copy-to
copy-goto-column, copy-rest-of-line, copy-to-bol, copy-line,
history-re-search-forward, history-re-search-backward.
06/05/2001 Version 1.3.1 released.
03/05/2001 mcs@astro.caltech.edu
configure.in
Old versions of GNU ld don't accept version scripts.
Under Linux I thus added a test to try out ld with
the --version-script argument to see if it works.
If not, version scripts aren't used.
configure.in
My test for versions of Solaris earlier than 7
failed when confronted by a three figure version
number (2.5.1). Fixed.
30/04/2001 mcs@astro.caltech.edu
getline.c
In vi mode, history-search-backward and
history-search-forward weren't doing anything when
invoked at the start of an empty line, whereas
they should have acted like up-history and down-history.
Makefile.in Makefile.rules
When shared libraries are being created, the build
procedure now arranges for any alternate library
links to be created as well, before linking the
demos. Without this the demos always linked to the
static libraries (which was perfectly ok, but wasn't a
good example).
Makefile.in Makefile.rules
On systems on which shared libraries were being created,
if there were no alternate list of names, make would
abort due to a Bourne shell 'for' statement that didn't
have any arguments. Currently there are no systems who's
shared library configurations would trigger this
problem.
Makefile.rules
The demos now relink to take account of changes to the
library.
configure.in configure
When determining whether the reentrant version of the
library should be compiled by default, the configure
script now attempts to compile a dummy program that
includes all of the appropriate system headers and
defines _POSIX_C_SOURCE. This should now be a robust test
on systems which use C macros to alias these function
names to other internal functions.
configure.in
Under Solaris 2.6 and earlier, the curses library is in
/usr/ccs/lib. Gcc wasn't finding this. In addition to
remedying this, I had to remove "-z text" from
LINK_SHARED under Solaris to get it to successfully
compile the shared library against the static curses
library.
configure.in
Under Linux the -soname directive was being used
incorrectly, citing the fully qualified name of the
library instead of its major version alias. This will
unfortunately mean that binaries linked with the 1.2.3
and 1.2.4 versions of the shared library won't use
later versions of the library unless relinked.
30/04/2001 mcs@astro.caltech.edu
getline.c
In gl_get_input_line(), don't redundantly copy the
start_line if start_line == gl->line.
30/04/2001 Version 1.3.0 released.
28/04/2001 mcs@astro.caltech.edu
configure.in
I removed the --no-undefined directive from the Linux
LINK_SHARED command. After recent patches to our RedHat
7.0 systems ld started reporting some internal symbols of
libc as being undefined. Using nm on libc indicated that
the offending symbols are indeed defined, albeit as
"common" symbols, so there appears to be a bug in
RedHat's ld. Removing this flag allows the tecla shared
library to compile, and programs appear to function fine.
man3/gl_get_line.3
The default key-sequence used to invoke the
read-from-file action was incorrectly cited as ^Xi
instead of ^X^F.
26/04/2001 mcs@astro.caltech.edu
getline.c man3/gl_get_line.3
A new vi-style editing mode was added. This involved
adding many new action functions, adding support for
specifying editing modes in users' ~/.teclarc files,
writing a higher level cursor motion function to support
the different line-end bounds required in vi command
mode, and a few small changes to support the fact that vi
has two modes, input mode and command mode with different
bindings.
When vi editing mode is enabled, any binding that starts
with an escape or a meta character, is interpreted as a
command-mode binding, and switches the library to vi
command mode if not already in that mode. Once in command
mode the first character of all keysequences entered
until input mode is re-enabled, are quietly coerced to
meta characters before being looked up in the key-binding
table. So, for example, in the key-binding table, the
standard vi command-mode 'w' key, which moves the cursor
one word to the right, is represented by M-w. This
emulates vi's dual sets of bindings in a natural way
without needing large changes to the library, or new
binding syntaxes. Since cursor keys normally emit
keysequences which start with escape, it also does
something sensible when a cursor key is pressed during
input mode (unlike true vi, which gets upset).
I also added a ^Xg binding for the new list-glob action
to both the emacs and vi key-binding tables. This lists
the files that match the wild-card expression that
precedes it on the command line.
The function that reads in ~/.teclarc used to tell
new_GetLine() to abort if it encountered anything that it
didn't understand in this file. It now just reports an
error and continues onto the next line.
Makefile.in:
When passing LIBS=$(LIBS) to recursive invokations of
make, quotes weren't included around the $(LIBS) part.
This would cause problems if LIBS ever contained more
than one word (with the supplied configure script this
doesn't happen currently). I added these quotes.
expand.c man3/ef_expand_file.3:
I wrote a new public function called ef_list_expansions(),
to list the matching filenames returned by
ef_expand_file().
I also fixed the example in the man page, which cited
exp->file instead of exp->files, and changed the
dangerous name 'exp' with 'expn'.
keytab.c:
Key-binding tables start with 100 elements, and are
supposedly incremented in size by 100 elements whenever
the a table runs out of space. The realloc arguments to
do this were wrong. This would have caused problems if
anybody added a lot of personal bindings in their
~/.teclarc file. I only noticed it because the number of
key bindings needed by the new vi mode exceeded this
number.
libtecla.map
ef_expand_file() is now reported as having been added in
the upcoming 1.3.0 release.
25/03/2001 Markus Gyger (logged here by mcs)
Makefile.in:
Make symbolic links to alternative shared library names
relative instead of absolute.
Makefile.rules:
The HP-UX libtecla.map.opt file should be made in the
compilation directory, to allow the source code directory
to be on a readonly filesystem.
cplmatch.c demo2.c history.c pcache.c
To allow the library to be compiled with a C++ compiler,
without generating warnings, a few casts were added where
void* return values were being assigned directly to
none void* pointer variables.
25/03/2001 mcs@astro.caltech.edu
libtecla.map:
Added comment header to explain the purpose of the file.
Also added cpl_init_FileArgs to the list of exported
symbols. This symbol is deprecated, and no longer
documented, but for backwards compatibility, it should
still be exported.
configure:
I had forgotten to run autoconf before releasing version
1.2.4, so I have just belatedly done so. This enables
Markus' changes to "configure.in" documented previously,
(see 17/03/2001).
20/03/2001 John Levon (logged here by mcs)
libtecla.h
A couple of the function prototypes in libtecla.h have
(FILE *) argument declarations, which means that stdio.h
needs to be included. The header file should be self
contained, so libtecla.h now includes stdio.h.
18/03/2001 Version 1.2.4 released.
README html/index.html configure.in
Incremented minor version from 3 to 4.
18/03/2001 mcs@astro.caltech.edu
getline.c
The fix for the end-of-line problem that I released a
couple of weeks ago, only worked for the first line,
because I was handling this case when the cursor position
was equal to the last column, rather than when the cursor
position modulo ncolumn was zero.
Makefile.in Makefile.rules
The demos are now made by default, their rules now being
int Makefile.rules instead of Makefile.in.
INSTALL
I documented how to compile the library in a different
directory than the distribution directory.
I also documented features designed to facilitate
configuring and building the library as part of another
package.
17/03/2001 Markus Gyger (logged here by mcs)
getline.c
Until now cursor motions were done one at a time. Markus
has added code to make use the of the terminfo capability
that moves the cursor by more than one position at a
time. This greatly improves performance when editing near
the start of long lines.
getline.c
To further improve performance, Markus switched from
writing one character at a time to the terminal, using
the write() system call, to using C buffered output
streams. The output buffer is only flushed when
necessary.
Makefile.rules Makefile.in configure.in
Added support for compiling for different architectures
in different directories. Simply create another directory
and run the configure script located in the original
directory.
Makefile.in configure.in libtecla.map
Under Solaris, Linux and HP-UX, symbols that are to be
exported by tecla shared libraries are explicitly specified
via symbol map files. Only publicly documented functions
are thus visible to applications.
configure.in
When linking shared libraries under Solaris SPARC,
registers that are reserved for applications are marked
as off limits to the library, using -xregs=no%appl when
compiling with Sun cc, or -mno-app-regs when compiling
with gcc. Also removed -z redlocsym for Solaris, which
caused problems under some releases of ld.
homedir.c (after minor changes by mcs)
Under ksh, ~+ expands to the current value of the ksh
PWD environment variable, which contains the path of
the current working directory, including any symbolic
links that were traversed to get there. The special
username "+" is now treated equally by tecla, except
that it substitutes the return value of getcwd() if PWD
either isn't set, or if it points at a different
directory than that reported by getcwd().
08/03/2001 Version 1.2.3 released.
08/03/2001 mcs@astro.caltech.edu
getline.c
On compiling the library under HP-UX for the first time
I encountered and fixed a couple of bugs:
1. On all systems except Solaris, the callback function
required by tputs() takes an int argument for the
character that is to be printed. Under Solaris it
takes a char argument. The callback function was
passing this argument, regardless of type, to write(),
which wrote the first byte of the argument. This was
fine under Solaris and under little-endian systems,
because the first byte contained the character to be
written, but on big-endian systems, it always wrote
the zero byte at the other end of the word. As a
result, no control characters were being written to
the terminal.
2. While attempting to start a newline after the user hit
enter, the library was outputting the control sequence
for moving the cursor down, instead of the newline
character. On many systems the control sequence for
moving the cursor down happends to be a newline
character, but under HP-UX it isn't. The result was
that no new line was being started under HP-UX.
04/03/2001 mcs@astro.caltech.edu
configure.in Makefile.in Makefile.stub configure config.guess
config.sub Makefile.rules install-sh PORTING README INSTALL
Configuration and compilation of the library is now
performed with the help of an autoconf configure
script. In addition to relieving the user of the need to
edit the Makefile, this also allows automatic compilation
of the reentrant version of the library on platforms that
can handle it, along with the creation of shared
libraries where configured. On systems that aren't known
to the configure script, just the static tecla library is
compiled. This is currently the case on all systems
except Linux, Solaris and HP-UX. In the hope that
installers will provide specific conigurations for other
systems, the configure.in script is heavily commented,
and instructions on how to use are included in a new
PORTING file.
24/02/2001 Version 1.2b released.
22/02/2001 mcs@astro.caltech.edu
getline.c
It turns out that most terminals, but not all, on writing
a character in the rightmost column, don't wrap the
cursor onto the next line until the next character is
output. This library wasn't aware of this and thus if one
tried to reposition the cursor from the last column,
gl_get_line() thought that it was moving relative to a
point on the next line, and thus moved the cursor up a
line. The fix was to write one extra character when in
the last column to force the cursor onto the next line,
then backup the cursor to the start of the new line.
getline.c
On terminal initialization, the dynamic LINES and COLUMNS
environment variables were ignored unless
terminfo/termcap didn't return sensible dimensions. In
practice, when present they should override the static
versions in the terminfo/termcap databases. This is the
new behavior. In reality this probably won't have caused
many problems, because a SIGWINCH signal which informs of
terminal size changes is sent when the terminal is
opened, so the dimensions established during
initialization quickly get updated on most systems.
18/02/2001 Version 1.2a released.
18/02/2001 mcs@astro.caltech.edu
getline.c
Three months ago I moved the point at which termios.h
was included in getline.c. Unfortunately, I didn't notice
that this moved it to after the test for TIOCGWINSZ being
defined. This resulted in SIGWINCH signals not being
trapped for, and thus terminal size changes went
unnoticed. I have now moved the test to after the
inclusion of termios.h.
12/02/2001 Markus Gyger (described here by mcs)
man3/pca_lookup_file.3 man3/gl_get_line.3
man3/ef_expand_file.3 man3/cpl_complete_word.3
In the 1.2 release of the library, all functions in the
library were given man pages. Most of these simply
include one of the above 4 man pages, which describe the
functions while describing the modules that they are in.
Markus added all of these function names to the lists in
the "NAME" headers of the respective man pages.
Previously only the primary function of each module was
named there.
11/02/2001 mcs@astro.caltech.edu
getline.c
On entering a line that wrapped over two or more
terminal, if the user pressed enter when the cursor
wasn't on the last of the wrapped lines, the text of the
wrapped lines that followed it got mixed up with the next
line written by the application, or the next input
line. Somehow this slipped through the cracks and wasn't
noticed until now. Anyway, it is fixed now.
09/02/2001 Version 1.2 released.
04/02/2001 mcs@astro.caltech.edu
pcache.c libtecla.h
With all filesystems local, demo2 was very fast to start
up, but on a Sun system with one of the target
directories being on a remote nfs mounted filesystem, the
startup time was many seconds. This was due to the
executable selection callback being applied to all files
in the path at startup. To avoid this, all files are now
included in the cache, and the application specified
file-selection callback is only called on files as they
are matched. Whether the callback rejected or accepted
them is then cached so that the next time an already
checked file is looked at, the callback doesn't have to
be called. As a result, startup is now fast on all
systems, and since usually there are only a few matching
file completions at a time, the delay during completion
is also usually small. The only exception is if the user
tries to complete an empty string, at which point all
files have to be checked. Having done this once, however,
doing it again is fast.
man3/pca_lookup_file.3
I added a man page documenting the new PathCache module.
man3/