./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/