Interactive Command-line Input Library Functions
glgetline(3TECLA)
NAME
glgetline, newGetLine, delGetLine,
glcustomizecompletion, glchangeterminal,
glconfiguregetline, glloadhistory, glsavehistory,
glgrouphistory, glshowhistory, glwatchfd,
glinactivitytimeout, glterminalsize, glsettermsize,
glresizehistory, gllimithistory, glclearhistory,
gltogglehistory, gllookuphistory, glstateofhistory,
glrangeofhistory, glsizeofhistory, glechomode,
glreplaceprompt, glpromptstyle, glignoresignal,
gltrapsignal, gllastsignal, glcompletionaction,
glregisteraction, gldisplaytext, glreturnstatus,
glerrormessage, glcatchblocked, gllistsignals,
glbindkeyseq, gleraseterminal, glautomatichistory,
glappendhistory, glquerychar, glreadchar - allow the
user to compose an input line
SYNOPSIS
cc [ flag... ] file... -ltecla [ library... ]
#include
#include
GetLine *newGetLine(sizet linelen, sizet histlen);
GetLine *delGetLine(GetLine *gl);
char *glgetline(GetLine *gl, const char *prompt,
const char *startline, int startpos);
int glquerychar(GetLine *gl, const char *prompt, char defchar);
int glreadchar(GetLine *gl);
int glcustomizecompletion(GetLine *gl, void *data,
CplMatchFn *matchfn);
int glchangeterminal(GetLine *gl, FILE *inputfp,
FILE *outputfp, const char *term);
int glconfiguregetline(GetLine *gl, const char *appstring,
const char *appfile, const char *userfile);
SunOS 5.11 Last change: 28 Nov 2007 1
Interactive Command-line Input Library Functions
glgetline(3TECLA)
int glbindkeyseq(GetLine *gl, GlKeyOrigin origin,
const char *keyseq, const char *action);
int glsavehistory(GetLine *gl, const char *filename,
const char *comment, int maxlines);
int glloadhistory(GetLine *gl, const char *filename,
const char *comment);
int glwatchfd(GetLine *gl, int fd, GlFdEvent event,
GlFdEventFn *callback, void *data);
int glinactivitytimeout(GetLine *gl, GlTimeoutFn *callback,
void *data, unsigned long sec, unsigned long nsec);
int glgrouphistory(GetLine *gl, unsigned stream);
int glshowhistory(GetLine *gl, FILE *fp, const char *fmt,
int allgroups, int maxlines);
int glresizehistory(GetLine *gl, sizet bufsize);
void gllimithistory(GetLine *gl, int maxlines);
void glclearhistory(GetLine *gl, int allgroups);
void gltogglehistory(GetLine *gl, int enable);
GlTerminalSize glterminalsize(GetLine *gl, int defncolumn,
int defnline);
int glsettermsize(GetLine *gl, int ncolumn, int nline);
int gllookuphistory(GetLine *gl, unsigned long id,
GlHistoryLine *hline);
SunOS 5.11 Last change: 28 Nov 2007 2
Interactive Command-line Input Library Functions
glgetline(3TECLA)
void glstateofhistory(GetLine *gl, GlHistoryState *state);
void glrangeofhistory(GetLine *gl, GlHistoryRange *range);
void glsizeofhistory(GetLine *gl, GlHistorySize *size);
void glechomode(GetLine *gl, int enable);
void glreplaceprompt(GetLine *gl, const char *prompt);
void glpromptstyle(GetLine *gl, GlPromptStyle style);
int glignoresignal(GetLine *gl, int signo);
int gltrapsignal(GetLine *gl, int signo, unsigned flags,
GlAfterSignal after, int errnovalue);
int gllastsignal(GetLine *gl);
int glcompletionaction(GetLine *gl, void *data,
CplMatchFn *matchfn, int listonly, const char *name,
const char *keyseq);
int glregisteraction(GetLine *gl, void *data, GlActionFn *fn,
const char *name, const char *keyseq);
int gldisplaytext(GetLine *gl, int indentation,
const char *prefix, const char *suffix, int fillchar,
int defwidth, int start, const char *string);
GlReturnStatus glreturnstatus(GetLine *gl);
const char *glerrormessage(GetLine *gl, char *buff, sizet n);
void glcatchblocked(GetLine *gl);
SunOS 5.11 Last change: 28 Nov 2007 3
Interactive Command-line Input Library Functions
glgetline(3TECLA)
int gllistsignals(GetLine *gl, sigsett *set);
int glappendhistory(GetLine *gl, const char *line);
int glautomatichistory(GetLine *gl, int enable);
int gleraseterminal(GetLine *gl);
DESCRIPTION
The glgetline() function is part of the libtecla(3LIB)
library. If the user is typing at a terminal, each call
prompts them for an line of input, then provides interactive
editing 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 on
the tecla(5) manual page.
An Example
The following shows a complete example of how to use the
glgetline() function to get input from the user:
#include
#include
#include
int main(int argc, char *argv[])
{
char *line; /* The line that the user typed */
GetLine *gl; /* The glgetline() resource object */
setlocale(LCTYPE, ""); /* Adopt the user's choice */
/* of character set. */
gl = newGetLine(1024, 2048);
if(!gl)
return 1;
while((line=glgetline(gl, "$ ", NUL, -1)) != NUL &&
strcmp(line, "exit\n") != 0)
printf("You typed: %s\n", line);
gl = delGetLine(gl);
return 0;
}
SunOS 5.11 Last change: 28 Nov 2007 4
Interactive Command-line Input Library Functions
glgetline(3TECLA)
In the example, first the resources needed by the
glgetline() function are created by calling newGetLine().
This allocates the memory used in subsequent calls to the
glgetline() 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 allo-
cated by newGetLine(), are returned to the system by cal-
ling delGetLine(). Note the use of the NUL return value of
delGetLine() to make gl NUL. This is a safety precaution.
If the program subsequently attempts to pass gl to
glgetline(), said function will complain, and return an
error, instead of attempting to use the deleted resource
object.
The Functions Used In The Example
The newGetLine() function creates the resources used by the
glgetline() function and returns an opaque pointer to the
object that contains them. The maximum length of an input
line is specified by 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 number of lines that can
be stored, see the description of the gllimithistory()
function. If you do not want history at all, specify histlen
as zero, and no history buffer will be allocated.
On error, a message is printed to stderr and NUL is
returned.
The delGetLine() function deletes the resources that were
returned by a previous call to newGetLine(). It always
returns NUL (for example, a deleted object). It does noth-
ing if the gl argument is NUL.
The glgetline() 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 newGetLine(). The prompt
argument should be a normal null-terminated string, specify-
ing the prompt to present the user with. By default prompts
are displayed literally, but if enabled with the
glpromptstyle() function, prompts can contain directives
to do underlining, switch to and from bold fonts, or turn
highlighting on and off.
SunOS 5.11 Last change: 28 Nov 2007 5
Interactive Command-line Input Library Functions
glgetline(3TECLA)
If you want to specify the initial contents of the line for
the user to edit, pass the desired string with the
startline argument. You can then specify which character of
this line the cursor is initially positioned over by using
the startpos argument. This should be -1 if you want the
cursor to follow the last character of the start line. If
you do not want to preload the line in this manner, send
startline as NUL, and set startpos to -1.
The glgetline() function returns a pointer to the line
entered by the user, or NUL 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 freed 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 glgetline() again to read the rest of the
line. Note that this behavior makes glgetline() similar to
fgets(3C). When stdin is not connected to a terminal,
glgetline() simply calls fgets().
The Return Status Of glgetline()
The glgetline() function has two possible return values: a
pointer to the completed input line, or NUL. Additional
information about what caused glgetline() to return is
available both by inspecting errno and by calling the
glreturnstatus() function.
The following are the possible enumerated values returned by
glreturnstatus():
GLRNEWLINE The last call to glgetline() successfully
returned a completed input line.
GLRBLOCKED The glgetline() function was in non-
blocking server mode, and returned early to
avoid blocking the process while waiting for
terminal I/O. The glpendingio() function
can be used to see what type of I/O
glgetline() was waiting for. See the
gliomode(3TECLA).
GLRSIGNAL A signal was caught by glgetline() that had
an after-signal disposition of GLSABORT. See
SunOS 5.11 Last change: 28 Nov 2007 6
Interactive Command-line Input Library Functions
glgetline(3TECLA)
gltrapsignal().
GLRTIMEOUT The inactivity timer expired while
glgetline() was waiting for input, and the
timeout callback function returned
GLTOABORT. See glinactivitytimeout() for
information about timeouts.
GLRFDABORT An application I/O callback returned
GLFDABORT. Ssee glwatchfd().
GLREOF 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.
GLREROR An unexpected error caused glgetline() to
abort (consult errno and/or
glerrormessage() for details.
When glreturnstatus() returns GLREROR and the value of
errno is not sufficient to explain what happened, you can
use the glerrormessage() function to request a description
of the last error that occurred.
The return value of glerrormessage() is a pointer to the
message that occurred. If the buff argument is NUL, this
will be a pointer to a buffer within gl whose value will
probably change on the next call to any function associated
with glgetline(). 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 will not fit in the provided
buffer, it will be truncated to fit.
Optional Prompt Formatting
Whereas by default the prompt string that you specify is
displayed literally without any special interpretation of
the characters within it, the glpromptstyle() function can
be used to enable optional formatting directives within the
prompt.
SunOS 5.11 Last change: 28 Nov 2007 7
Interactive Command-line Input Library Functions
glgetline(3TECLA)
The style argument, which specifies the formatting style,
can take any of the following values:
GLFORMATPROMPT In this style, the formatting direc-
tives described below, when included in
prompt strings, are interpreted as fol-
lows:
%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 bright-
ness) 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
SunOS 5.11 Last change: 28 Nov 2007 8
Interactive Command-line Input Library Functions
glgetline(3TECLA)
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
does not match any of the above direc-
tives 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 sup-
port all of these text attributes, and
that some substitute a different attri-
bute for missing ones.
GLITERALPROMPT In this style, the prompt string is
printed literally. This is the default
style.
Alternate Configuration Sources
By default users have the option of configuring the behavior
of glgetline() with 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 inter-
face. To cater for such cases, the glconfiguregetline()
function allows the application to control where configura-
tion information is read from.
The glconfiguregetline() function 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 configuration file. If this function is called
before the first call to glgetline(), the default behavior
of reading ~/.teclarc on the first call to glgetline() is
disabled, so all configurations must be achieved using the
configuration sources specified with this function.
SunOS 5.11 Last change: 28 Nov 2007 9
Interactive Command-line Input Library Functions
glgetline(3TECLA)
If appstring != NUL, then it is interpreted as a string
containing one or more configuration commands, separated
from each other in the string by embedded newline charac-
ters. If appfile != NUL then it is interpreted as the full
pathname of an application-specific configuration file. If
userfile != NUL then it is interpreted as the full path
name of a user-specific configuration file, such as
~/.teclarc. For example, in the call
glconfiguregetline(gl, "edit-mode vi 0obeep",
"/usr/share/myapp/teclarc", "~/.teclarc");
The appstring argument causes the calling application to
start in vi(1) 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 configuration commands from an
optional .teclarc file in the user's home directory. Note
that the arguments are listed in ascending order of prior-
ity, with the contents of appstring being potentially over
riden by commands in appfile, and commands in appfile
potentially being overriden by commands in userfile.
You can call this function as many times as needed, the
results being cumulative, but note that copies of any file
names specified with the appfile and userfile 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 speci-
fies the filenames that you want re-read when the user
requests that the configuration files be re-read.
Individual key sequences can also be bound and unbound using
the glbindkeyseq() function. The origin argument specifies
the priority of the binding, according to whom it is being
established for, and must be one of the following two
values.
GLUSERKEY The user requested this key-binding.
GLAPKEY This is a default binding set by the applica-
tion.
SunOS 5.11 Last change: 28 Nov 2007 10
Interactive Command-line Input Library Functions
glgetline(3TECLA)
When both user and application bindings for a given key
sequence have been specified, the user binding takes pre-
cedence. The application's binding is subsequently rein-
stated if the user's binding is later unbound with either
another call to this function, or a call to
glconfiguregetline().
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 NUL or "" to unbind the
key sequence.
Customized Word Completion
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 with a call to the
glcustomizecompletion() function.
The data argument provides a way for your application to
pass arbitrary, 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
matchfn argument specifies the callback function to be
called. The CplMatchFn function type is defined in
, as is a CPLMATCHFN() macro that you can use
to declare and prototype callback functions. The declaration
and responsibilities of callback functions are described in
depth on the cplcompleteword(3TECLA) manual page.
The callback function is responsible for looking backwards
in the input line from the point at which the user pressed
TAB, to find the start of the word being completed. It then
must lookup possible completions of this word, and record
them one by one in the WordCompletion object that is passed
to it as an argument, by calling the cpladdcompletion()
function. If the callback function wants to provide filename
completion in addition to its own specific completions, it
has the option of itself calling the builtin filename com-
pletion callback. This also is documented on the
cplcompleteword(3TECLA) manual page.
If you would like glgetline() to return the current input
line when a successful completion is been made, you can
SunOS 5.11 Last change: 28 Nov 2007 11
Interactive Command-line Input Library Functions
glgetline(3TECLA)
arrange this when you call cpladdcompletion() by making
the last character of the continuation suffix a newline
character. The input line will be updated to display the
completion, together with any contiuation suffix up to the
newline character, and glgetline() will return this input
line.
If your callback function needs to write something to the
terminal, it must call glnormalio() before doing so. This
will start a new line after the input line that is currently
being edited, reinstate normal terminal I/O, and notify
glgetline() that the input line will need to be redrawn
when the callback returns.
Adding Completion Actions
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
glcompletionaction() function.
The data and matchfn arguments are as described on the
cplcompleteword(3TECLA) manual page, and specify the call-
back function that should be invoked to identify possible
completions. The listonly argument determines whether the
action that is being defined should attempt to complete the
word as far as possible in the input line before displaying
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 invocations 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 NUL, no new key sequence 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, you shouldcall glcompletionaction() to
install a given action for the first time between calling
newGetLine() and the first call to glgetline(). Other-
wise, when the user's configuration file is read on the
SunOS 5.11 Last change: 28 Nov 2007 12
Interactive Command-line Input Library Functions
glgetline(3TECLA)
first call to glgetline(), the name of the your additional
action will not be known, and any reference to it in the
configuration file will generate an error.
As discussed for glcustomizecompletion(), if your callback
function needs to write anything to the terminal, it must
call glnormalio() before doing so.
Defining Custom Actions
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 having 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 glregisteraction() function is
provided.
The glregisteraction() 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
wants to have passed to the action function, fn, whenever
that function is invoked.
The action function, fn, should be declared using the
GLACTIONFN() macro, which is defined in .
#define GLACTIONFN(fn) GlAfterAction (fn)(GetLine *gl, \
void *data, int count, sizet curpos, \
const char *line)
The gl and data arguments are those that were previously
passed to glregisteraction() when the action function was
registered. The count argument is a numeric argument which
the user has the option of entering using the digit-argument
action, before invoking the action. If the user does not
enter a number, then the count argument is set to 1. Nomi-
nally this argument is interpreted as a repeat count, mean-
ing that the action should be repeated that many times. In
practice however, for some actions a repeat count makes
SunOS 5.11 Last change: 28 Nov 2007 13
Interactive Command-line Input Library Functions
glgetline(3TECLA)
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 argument. The current cursor position within this
string is given by the index contained in the curpos argu-
ment. Note that direct manipulation of the input line and
the cursor position is not permitted because the rules dic-
tated by various modes (such as vi mode versus emacs mode,
no-echo mode, and insert mode versus overstrike mode) make
it too complex for an application writer to write a conform-
ing editing action, as well as constrain future changes to
the internals of glgetline(). A potential solution to this
dilemma 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 han-
dle raw terminal I/O, then before doing either of these
operations, it must temporarily suspend line editing by cal-
ling the glnormalio() 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 restoring the normal mapping of \n
to \r\n, and, when in server mode, restoring the normal
blocking form of terminal I/O. Having called this function,
the action function can read from and write to the terminal
without the fear of creating a mess. It is not necessary for
the action function to restore the original editing environ-
ment before it returns. This is done automatically by
glgetline() after the action function returns. The follow-
ing 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 GLACTIONFN(sayhellofn)
{
if(glnormalio(gl)) /* Temporarily suspend editing */
return GLABORT;
printf("Hello world\n");
return GLACONTINUE;
}
SunOS 5.11 Last change: 28 Nov 2007 14
Interactive Command-line Input Library Functions
glgetline(3TECLA)
Action functions must return one of the following values, to
tell glgetline() how to proceed.
GLABORT Cause glgetline() to return NUL.
GLARETURN Cause glgetline() to return the completed
input line
GLACONTINUE Resume command-line editing.
Note that the name argument of glregisteraction() speci-
fies 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 glregisteraction() between
calling newGetLine() and the first call to glgetline().
History Files
To save the contents of the history buffer before quitting
your application and subsequently restore them when you next
start the application, the glsavehistory() and
glloadhistory() functions are provided.
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 environ-
ment variable expressions, such as ~/.myapphistory or
$HOME/.myapphistory.
Along with each history line, additional information about
it, such as its nesting level and when it was entered by the
user, 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 prefixes
differ in different languages, the comment argument is pro-
vided 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
glloadhistory() that you used when you called
glsavehistory() to write the history file.
SunOS 5.11 Last change: 28 Nov 2007 15
Interactive Command-line Input Library Functions
glgetline(3TECLA)
The maxlines argument must be either -1 to specify that all
lines in the history 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 glloadhistory() does
not consider the non-existence of a file to be an error.
Multiple History Lists
If your application uses a single GetLine object for enter-
ing many different types of input lines, you might want
glgetline() 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,
glgetline() marks lines being recorded in the history list
with an integer identifier chosen by the application. Ini-
tially this identifier is set to 0 by newGetLine(), but it
can be changed subsequently by calling glgrouphistory().
The integer identifier ID can be any number chosen by the
application, but note that glsavehistory() and
glloadhistory() preserve the association between identif-
iers and historical input lines between program invocations,
so you should choose fixed identifiers for the different
types of input line used by your application.
Whenever glgetline() appends a new input line to the his-
tory 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 iden-
tifier.
Displaying History
The history list can be displayed by calling
glshowhistory(). This function displays the current con-
tents of the history list to the stdio output stream fp. If
the maxlines argument is greater than or equal to zero,
then no more than this number of the most recent lines will
be displayed. If the allgroups argument is non-zero, lines
from all history groups are displayed. Otherwise only those
of the currently selected history group are displayed. The
format string argument, fmt, determines how the line is
displayed. This can contain arbitrary characters which are
written verbatim, interleaved with any of the following for-
mat directives:
SunOS 5.11 Last change: 28 Nov 2007 16
Interactive Command-line Input Library Functions
glgetline(3TECLA)
%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.
Looking Up History
The gllookuphistory() function allows the calling applica-
tion to look up lines in the history list.
The id argument indicates which line to look up, where the
first line that was entered in the history list after
newGetLine() was called is denoted by 0, and subsequently
entered lines are denoted with successively higher numbers.
Note that the range of lines currently preserved in the his-
tory list can be queried by calling the
glrangeofhistory() function. 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.
SunOS 5.11 Last change: 28 Nov 2007 17
Interactive Command-line Input Library Functions
glgetline(3TECLA)
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 func-
tion that takes gl as its argument. Therefore you should
make a private copy of this string if you need to keep it.
Manual History Archival
By default, whenever a line is entered by the user, it is
automatically appended to the history list, just before
glgetline() returns the line to the caller. This is con-
venient for the majority of applications, 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 glautomatichistory() function.
If this function is called with its enable argument set to
0, glgetline() will not 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 dis-
abled, the calling application can use the
glappendhistory() to append lines to the history list as
needed.
The line argument specifies the line to be added to the his-
tory list. This must be a normal '\0 ' 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 terminated by the '\0 '
terminator. If the line is longer than the maximum input
line length that was specified when newGetLine() was
called, it will be truncated to the actual glgetline()
line length when the line is recalled.
If successful, glappendhistory() returns 0. Otherwise it
returns non-zero and sets errno to one of the following
values.
EINVAL One of the arguments passed to glappendhistory()
was NUL.
ENOMEM The specified line was longer than the allocated
size of the history buffer (as specified when
newGetLine() was called), so it could not be
archived.
SunOS 5.11 Last change: 28 Nov 2007 18
Interactive Command-line Input Library Functions
glgetline(3TECLA)
A textual description of the error can optionally be
obtained by calling glerrormessage(). Note that after such
an error, the history list remains in a valid state to
receive new history lines, so there is little harm in simply
ignoring the return status of glappendhistory().
Miscellaneous History Configuration
If you wish to change the size of the history buffer that
was originally specified in the call to newGetLine(), you
can do so with the glresizehistory() function.
The histlen argument specifies the new size in bytes, and if
you specify this as 0, the buffer will be deleted.
As mentioned in the discussion of newGetLine(), 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 20 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 gllimithistory() func-
tion.
The maxlines 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 maxlines most recently
appended lines are kept in the buffer. Older lines are dis-
carded.
To discard lines from the history buffer, use the
glclearhistory() function.
The allgroups argument tells the function whether to delete
just the lines associated with the current history group
(see glgrouphistory()) or all historical lines in the
buffer.
The gltogglehistory() function allows you to toggle his-
tory on and off without losing the current contents of the
history list.
SunOS 5.11 Last change: 28 Nov 2007 19
Interactive Command-line Input Library Functions
glgetline(3TECLA)
Setting the enable argument to 0 turns off the history
mechanism, and setting it to 1 turns it back on. When his-
tory is turned off, no new lines will be added to the his-
tory list, and history lookup key-bindings will act as
though there is nothing in the history buffer.
Querying History Information
The configured state of the history list can be queried with
the glhistorystate() function. On return, the status
information is recorded in the variable pointed to by the
state argument.
The glrangeofhistory() function returns the number and
range of lines in the history list. 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 glsizeofhistory() function returns the total size of
the history buffer and the amount of the buffer that is
currently occupied.
On return, the size information is recorded in the variable
pointed to by the size argument.
Changing Terminals
The newGetLine() constructor function assumes that input is
to be read from stdin and output written to stdout. The fol-
lowing function allows you to switch to different input and
output streams.
The gl argument is the object that was returned by
newGetLine(). The inputfp argument specifies the stream to
read from, and outputfp specifies the stream to be written
to. Only if both of these refer to a terminal, will interac-
tive terminal input be enabled. Otherwise glgetline() will
simply call fgets() to read command input. If both streams
refer to a terminal, then they must refer to the same termi-
nal, and the type of this terminal must be specified with
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 ter-
minal. newGetLine() for example, passes the return value of
getenv("TERM") in this argument. Note that if one or both of
SunOS 5.11 Last change: 28 Nov 2007 20
Interactive Command-line Input Library Functions
glgetline(3TECLA)
inputfp and outputfp do not refer to a terminal, then it
is legal to pass NUL instead of a terminal type.
Note that if you want to pass file descriptors to
glchangeterminal(), you can do this by creating stdio
stream wrappers using the POSIX fdopen(3C) function.
External Event Handling
By default, glgetline() does not 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.
o Use the functions described in the
gliomode(3TECLA) manual page to switch
glgetline() into non-blocking server mode. In
this mode, glgetline() 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 per-
formed behind the scenes by glgetline().
o While glgetline() 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 or pipes, and have it call func-
tions 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 glgetline()
involves calling the glwatchfd() function. If this returns
non-zero, then it means that either your arguments are
invalid, or that this facility is not supported on the host
system.
The fd argument is the file descriptor to be watched. The
event argument specifies what type of activity is of
interest, chosen from the following enumerated values:
GLFDREAD Watch for the arrival of data to be read.
GLFDWRITE Watch for the ability to write to the file
descriptor without blocking.
SunOS 5.11 Last change: 28 Nov 2007 21
Interactive Command-line Input Library Functions
glgetline(3TECLA)
GLFDURGENT 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 GLFDEVENTFN(fn) GlFdStatus (fn)(GetLine *gl, void *data, int fd, GlFdEvent event)
The data argument of the glwatchfd() function is passed to
the callback function for its own use, and can point to any-
thing you like, including NUL. 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 func-
tion should be one of the following values.
GLFDABORT Tell glgetline() to abort. When this hap-
pens, glgetline() returns NUL, and a
following call to glreturnstatus() will
return GLRFDABORT. Note that if the appli-
cation needs errno always to have a mean-
ingful value when glgetline() returns
NUL, the callback function should set
errno appropriately.
GLFDREFRESH Redraw the input line then continue wait-
ing for input. Return this if your callback
wrote to the terminal.
GLFDCONTINUE Continue to wait for input, without redraw-
ing the line.
Note that before calling the callback, glgetline() blocks
most signals 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.
SunOS 5.11 Last change: 28 Nov 2007 22
Interactive Command-line Input Library Functions
glgetline(3TECLA)
Your callback should not try to read from the terminal,
which is left in raw mode as far as input is concerned. You
can write to the terminal as usual, since features like
conversion of newline to carriage-return/linefeed are re-
enabled while the callback is running. If your callback
function does write to the terminal, be sure to output a
newline first, and when your callback returns, tell
glgetline() that the input line needs to be redrawn, by
returning the GLFDREFRESH status code.
To remove a callback function that you previously registered
for a given file descriptor and event, simply call
glwatchfd() with the same fd and event arguments, but with
a callback argument of 0. The data argument is ignored in
this case.
Setting An Inactivity Timeout
The glinactivitytimeout() 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 glwatchfd().
The timeout is specified in the form of an integral number
of seconds and an integral number of nanoseconds, specified
by the sec and nsec arguments, respectively. Subsequently,
whenever no activity is seen for this time period, the func-
tion specified by the callback argument is called. The data
argument of glinactivitytimeout() is passed to this call-
back function whenever it is invoked, and can thus be used
to pass arbitrary application-specific information to the
callback. The following macro is provided in
for applications to use to declare and prototype timeout
callback functions.
#define GLTIMEOUTFN(fn) GlAfterTimeout (fn)(GetLine *gl, void *data)
On returning, the application's callback is expected to
return one of the following enumerators to tell
glgetline() how to procede after the timeout has been han-
dled by the callback.
GLTOABORT Tell glgetline() to abort. When this hap-
pens, glgetline() will return NUL, and a
following call to glreturnstatus() will
return GLRTIMEOUT. Note that if the appli-
cation needs errno always to have a mean-
ingful value when glgetline() returns
SunOS 5.11 Last change: 28 Nov 2007 23
Interactive Command-line Input Library Functions
glgetline(3TECLA)
NUL, the callback function should set
errno appropriately.
GLTOREFRESH Redraw the input line, then continue wait-
ing for input. You should return this value
if your callback wrote to the terminal.
GLTOCONTINUE 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 gliomode(3TECLA)),
glgetline() acts as though I/O blocked.
This means that glgetline() will immedi-
ately return NUL, and a following call to
glreturnstatus() will return GLRBLOCKED.
Note that before calling the callback, glgetline() blocks
most signals 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 origi-
nally blocked) and reinstate the original signal handler, if
any, before returning.
Your callback should not try to read from the terminal,
which is left in raw mode as far as input is concerned. You
can however write to the terminal as usual, since features
like conversion of newline to carriage-return/linefeed are
re-enabled while the callback is running. If your callback
function does write to the terminal, be sure to output a
newline first, and when your callback returns, tell
glgetline() that the input line needs to be redrawn, by
returning the GLTOREFRESH status code.
Finally, note that although the timeout arguments include a
nanosecond component, few computer clocks presently have
resolutions that are finer than a few milliseconds, so ask-
ing for less than a few milliseconds is equivalent to
requesting zero seconds on many systems. If this would be a
problem, you should base your timeout selection on the
actual resolution of the host clock (for example, by calling
sysconf(SCLKTCK)).
SunOS 5.11 Last change: 28 Nov 2007 24
Interactive Command-line Input Library Functions
glgetline(3TECLA)
To turn off timeouts, simply call glinactivitytimeout()
with a callback argument of 0. The data argument is ignored
in this case.
Signal Handling Defaults
By default, the glgetline() function intercepts a number
of signals. This is particularly important for signals that
would by default terminate the process, since the terminal
needs to be restored to a usable state before this happens.
This section describes the signals that are trapped by
default and how glgetline() responds to them. Changing
these defaults is the topic of the following section.
When the following subset of signals are caught,
glgetline() first restores the terminal settings and sig-
nal handling to how they were before glgetline() was
called, resends the signal to allow the calling
application's signal handlers to handle it, then, if the
process still exists, returns NUL and sets errno as speci-
fied below.
SIGINT This signal is generated both by the keyboard
interrupt key (usually ^C), and the keyboard
break key. The errno value is EINTR.
SIGHUP This signal is generated when the controlling
terminal exits. The errno value is ENOTY.
SIGPIPE This signal is generated when a program attempts
to write to a pipe whose remote end is not being
read by any process. This can happen for example
if you have called glchangeterminal() to
redirect output to a pipe hidden under a pseudo
terminal. The errno value is EPIPE.
SIGQUIT This signal is generated by the keyboard quit key
(usually ^\fR). The errno value is EINTR.
SIGABRT This signal is generated by the standard C, abort
function. By default it both terminates the pro-
cess and generates a core dump. The errno value
is EINTR.
SIGTERM This is the default signal that the UNIX kill
command sends to processes. The errno value is
SunOS 5.11 Last change: 28 Nov 2007 25
Interactive Command-line Input Library Functions
glgetline(3TECLA)
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 does not override
the default handler by supplying its own signal handler,
receipt of the corresponding signal will terminate the
application before glgetline() returns.
If glgetline() aborts with errno set to EINTR, you can
find out what signal caused it to abort, by calling the
gllastsignal() function. This returns the numeric code
(for example, SIGINT) of the last signal that was received
during the most recent call to glgetline(), or -1 if no
signals were received.
On systems that support it, when a SIGWINCH (window change)
signal is received, glgetline() queries the terminal to
find out its new size, redraws the current input line to
accomodate the new size, then returns to waiting for key-
board input from the user. Unlike other signals, this signal
is not resent to the application.
Finally, the following signals cause glgetline() to first
restore the terminal and signal environment to that which
prevailed before glgetline() was called, then resend the
signal to the application. If the process still exists after
the signal has been delivered, then glgetline() 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 pro-
cess is resumed.
SIGPOL On SVR4 systems, this signal notifies the pro-
cess of an asynchronous I/O event. Note that
under 4.3]BSD, SIGIO and SIGPOL are the same.
On other systems, SIGIO is ignored by default,
so glgetline() does not trap it by default.
SIGPWR This signal is generated when a power failure
occurs (presumably when the system is on a
SunOS 5.11 Last change: 28 Nov 2007 26
Interactive Command-line Input Library Functions
glgetline(3TECLA)
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 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.
SIGTIN This signal is generated if the program
attempts to read from the terminal while the
program is running in the background.
SIGTOU 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 SIGKIL or SIGPOL, which by definition cannot
be caught, or any of the hardware generated exception sig-
nals, such as SIGSEGV, SIGBUS, and SIGFPE, are received and
unhandled while glgetline() has the terminal in raw mode,
the program will be terminated without the terminal having
SunOS 5.11 Last change: 28 Nov 2007 27
Interactive Command-line Input Library Functions
glgetline(3TECLA)
been restored to a usable state. In practice, job-control
shells usually reset the terminal settings when a process
relinquishes the controlling terminal, so this is only a
problem with older shells.
Customized Signal Handling
The previous section listed the signals that glgetline()
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
glgetline() should respond to a given signal.
If you do not need glgetline() to do anything in response
to a signal that it normally traps, you can tell to
glgetline() to ignore that signal by calling
glignoresignal().
The signo argument is the number of the signal (for example,
SIGINT) that you want to have ignored. If the specified sig-
nal is not currently one of those being trapped, this func-
tion does nothing.
The gltrapsignal() function allows you to either add a new
signal to the list that glgetline() traps or modify how it
responds to a signal that it already traps.
The signo argument is the number of the signal that you want
to have trapped. The flags argument is a set of flags that
determine the environment in which the application's signal
handler is invoked. The after argument tells glgetline()
what to do after the application's signal handler returns.
The errnovalue tells glgetline() what to set errno to if
told to abort.
The flags argument is a bitwise OR of zero or more of the
following enumerators:
GLSRESTORESIG Restore the caller's signal environment
while handling the signal.
GLSRESTORETY Restore the caller's terminal settings
while handling the signal.
SunOS 5.11 Last change: 28 Nov 2007 28
Interactive Command-line Input Library Functions
glgetline(3TECLA)
GLSRESTORELINE Move the cursor to the start of the line
following the input line before invoking
the application's signal handler.
GLSREDRAWLINE Redraw the input line when the
application's signal handler returns.
GLSUNBLOCKSIG Normally, if the calling program has a
signal blocked (see sigprocmask(2)),
glgetline() does not trap that signal.
This flag tells glgetline() to trap
the signal and unblock it for the dura-
tion of the call to glgetline().
GLSDONTFORWARD 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:
GLSRESTORENV GLSRESTORESIG GLSRESTORETY
GLSREDRAWLINE
GLSUSPENDINPUT GLSRESTORENV GLSRESTORELINE
If your signal handler, or the default system signal handler
for this signal, if you have not overridden it, never either
writes to the terminal, nor suspends or terminates the cal-
ling program, then you can safely set the flags argument to
0.
o The cursor does not get left in the middle of the
input line.
o So that the user can type in input and have it
echoed.
o So that you do not need to end each output line
with \r\n, instead of just \n.
SunOS 5.11 Last change: 28 Nov 2007 29
Interactive Command-line Input Library Functions
glgetline(3TECLA)
The GLRESTORENV combination is the same as
GLSUSPENDINPUT, except that it does not move the cursor.
If your signal handler does not read or write anything to
the terminal, the user will not 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 termi-
nal, where using GLSUSPENDLINE would cause the input line
to be unnecessarily duplicated when nothing had been written
to the terminal. Such a signal 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 GLSUSPENDINPUT. Other-
wise it will start writing on a line that already contains
part of the displayed input line. This does not do any harm,
but it looks a bit ugly, which is why the GLSUSPENDINPUT
combination is better if you know that you are always going
to be writting to the terminal.
The after argument, which determines what glgetline() does
after the application's signal handler returns (if it
returns), can take any one of the following values:
GLSRETURN Return the completed input line, just as
though the user had pressed the return key.
GLSABORT Cause glgetline() to abort. When this hap-
pens, glgetline() returns NUL, and a fol-
lowing call to glreturnstatus() will
return GLRSIGNAL. Note that if the applica-
tion needs errno always to have a meaningful
value when glgetline() returns NUL, the
callback function should set errno appropri-
ately.
GLSCONTINUE Resume command line editing.
The errnovalue argument is intended to be combined with the
GLSABORT option, telling glgetline() what to set the
standard errno variable to before returning NUL to the cal-
ling program. It can also, however, be used with the
GLRETURN option, in case you want to have a way to distin-
guish between an input line that was entered using the
return key, and one that was entered by the receipt of a
SunOS 5.11 Last change: 28 Nov 2007 30
Interactive Command-line Input Library Functions
glgetline(3TECLA)
signal.
Reliable Signal Handling
Signal handling is suprisingly hard to do reliably without
race conditions. In glgetline() a lot of care has been
taken to allow applications to perform reliable signal han-
dling around glgetline(). This section explains how to
make use of this.
As an example of the problems that can arise if the applica-
tion is not written correctly, imagine that one's applica-
tion has a SIGINT signal handler that sets a global flag.
Now suppose that the application tests this flag just before
invoking glgetline(). If a SIGINT signal happens to be
received in the small window of time between the statement
that tests the value of this flag, and the statement that
calls glgetline(), then glgetline() will not see the
signal, and will not be interrupted. As a result, the appli-
cation will not be able to respond to the signal until the
user gets around to finishing entering the input line and
glgetline() 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 gltrapsignal() function to
configure glgetline() to abort when important
signals are caught.
2. Configure glgetline() such that if any of the
signals that it catches are blocked when
glgetline() is called, they will be unblocked
automatically during times when glgetline() is
waiting for I/O. This can be done either on a per
signal basis, by calling the gltrapsignal() func-
tion, and specifying the GLSUNBLOCK attribute of
the signal, or globally by calling the
glcatchblocked() function. This function simply
adds the GLSUNBLOCK attribute to all of the sig-
nals that it is currently configured to trap.
3. Just before calling glgetline(), block delivery
of all of the signals that glgetline() is config-
ured to trap. This can be done using the POSIX sig-
procmask function in conjunction with the
gllistsignals() function. This function returns
the set of signals that it is currently configured
to catch in the set argument, which is in the form
SunOS 5.11 Last change: 28 Nov 2007 31
Interactive Command-line Input Library Functions
glgetline(3TECLA)
required by sigprocmask(2).
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
glgetline() unblocks its signals while performing
I/O.
5. Eventually glgetline() 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 functions, such as sigsetjmp(3C) and sigsuspend(2),
and in particular, the former of these two functions can be
used in conjunction with siglongjmp(3C) to implement race-
condition free signal handling around other long-running
system calls. The glgetline() function manages to reliably
trap signals around calls to functions like read(2) and
select(3C) without race conditions.
The glgetline() function first uses the POSIX sigproc-
mask() 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 glgetline() needs to call read or select to wait
for input from the user, it first calls the POSIX sig-
setjmp() function, being sure to specify a non-zero value
for its savemask argument.
If sigsetjmp() returns zero, glgetline() then does the
following.
1. It uses the POSIX sigaction(2) function to register
a temporary signal handler to all of the signals
that it is configured to catch. This signal handler
does two things.
a. It records the number of the signal that was
SunOS 5.11 Last change: 28 Nov 2007 32
Interactive Command-line Input Library Functions
glgetline(3TECLA)
received in a file-scope variable.
b. 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 samask
member of the struct sigaction act argument of the call
to sigaction() is configured to contain all of the sig-
nals that glgetline() 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 do not tread on each other's toes.
2. Now that the signal handler has been set up,
glgetline() unblocks all of the signals that it
is configured to catch.
3. It then calls the read() or select() function to
wait for keyboard input.
4. If this function returns (that is, no signal is
received), glgetline() blocks delivery of the
signals of interest again.
5. 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 executing. When this happens, glgetline()
does the following.
First, note that when a call to siglongjmp() causes sig-
setjmp() to return, provided that the savemask argument of
sigsetjmp() was non-zero, 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(3C), 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 signals being caught.
1. If so instructed by the glgetline() configuration
attributes of the signal that was caught,
glgetline() restores the terminal attributes to
SunOS 5.11 Last change: 28 Nov 2007 33
Interactive Command-line Input Library Functions
glgetline(3TECLA)
the state that they had when glgetline() was
called. This is particularly important for signals
that suspend or terminate the process, since other-
wise 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(3C) func-
tion to re-send the application the signal that was
caught.
4. Next it unblocks delivery of the signal that we
just sent. This results in the signal that was just
sent by raise() being caught by the application's
original signal handler, which can now handle it as
it sees fit.
5. If the signal handler returns (that is, it does not
terminate the process), glgetline() blocks
delivery of the above signal again.
6. It then undoes any actions performed in the first
of the above steps and redisplays the line, if the
signal configuration calls for this.
7. glgetline() then either resumes trying to read a
character, or aborts, depending on the configura-
tion 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 glgetline() has com-
plete control over its environment.
The Terminal Size
On most systems the combination of the TIOCGWINSZ ioctl and
the SIGWINCH signal is used to maintain an accurate idea of
the terminal size. The terminal size is newly queried every
time that glgetline() is called and whenever a SIGWINCH
signal is received.
On the few systems where this mechanism is not available, at
startup newGetLine() first looks for the LINES and COLUMNS
environment variables. If these are not found, or they con-
tain unusable values, then if a terminal information data-
base like terminfo or termcap is available, the default size
SunOS 5.11 Last change: 28 Nov 2007 34
Interactive Command-line Input Library Functions
glgetline(3TECLA)
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) are not 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 glsettermsize()
function to tell glgetline() about the change in size.
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 support 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 glgetline().
The glterminalsize() function allows you to query the
current size of the terminal, and install an alternate fall-
back size for cases where the size is not available. Beware
that the terminal size will not 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 ter-
minal size.
This function first updates glgetline()'s fallback termi-
nal dimensions, then records its findings in the return
value.
The defncolumn and defnline arguments specify the default
number of terminal columns and lines to use if the terminal
size cannot be determined by ioctl(TIOCGWINSZ) or environ-
ment variables.
Hiding What You Type
When entering sensitive information, such as passwords, it
is best not to have the text that you are entering echoed on
the terminal. Furthermore, such text should not be recorded
in the history list, since somebody finding your terminal
SunOS 5.11 Last change: 28 Nov 2007 35
Interactive Command-line Input Library Functions
glgetline(3TECLA)
unattended could then recall it, or somebody snooping
through your directories could see it in your history file.
With this in mind, the glechomode() function allows you to
toggle on and off the display and archival of any text that
is subsequently entered in calls to glgetline().
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 pro-
vided that history has not been turned off with a call to
gltogglehistory(), 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 setting through the
return value. In all cases, the return value of the function
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 comple-
tion will invisibly complete your prefix as far as possible,
ambiguous completions will not be displayed.
Single Character Queries
Using glgetline() 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 glquerychar() function
has been provided for single character queries like this.
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 character, glquerychar() 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 docu-
mented glreturnstatus(), 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
SunOS 5.11 Last change: 28 Nov 2007 36
Interactive Command-line Input Library Functions
glgetline(3TECLA)
had typed it, as well as being returned to the calling
application. If such a replacement is not important, simply
pass '\n' 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 glgetline(), echoing of the entered character can
be disabled using the glechomode() 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 glquerychar() resumes wait-
ing for the user to type a character.
Note that in non-blocking server mode, if an incomplete
input line is in the process of being read when
glquerychar() is called, the partial input line is dis-
carded, and erased from the terminal, before the new prompt
is displayed. The next call to glgetline() will thus start
editing a new line.
Reading Raw Characters
Whereas the glquerychar() function visibly prompts the
user for a character, and displays what they typed, the
glreadchar() function reads a signal character from the
user, without writing anything to the terminal, or perturb-
ing any incompletely entered input line. This means that it
can be called not only from between calls to glgetline(),
but also from callback functions that the application has
registered to be called by glgetline().
On success, the return value of glreadchar() is the char-
acter that was read. On failure, EOF is returned, and the
glreturnstatus() function 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 glgetline(), 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 three characters
SunOS 5.11 Last change: 28 Nov 2007 37
Interactive Command-line Input Library Functions
glgetline(3TECLA)
each, so a single call to glreadchar() will not be enough
to identify such keystrokes.
Clearing The Terminal
The calling program can clear the terminal by calling
gleraseterminal(). In non-blocking server-I/O mode, this
function also arranges for the current input line to be
redrawn from scratch when glgetline() is next called.
Displaying Text Dynamically
Between calls to glgetline(), the gldisplaytext() func-
tion 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
introductions. In those examples the advanced use of
optional prefixes, suffixes and filled lines to draw a box
around the text is also illustrated.
If gl is not currently connected to a terminal, for example
if the output of a program that uses glgetline() is being
piped to another program or redirected to a file, then the
value of the defwidth parameter is used as the terminal
width.
The indentation argument specifies the number of characters
to use to indent each line of ouput. The fillchar argument
specifies the character that will be used to perform this
indentation.
The prefix argument can be either NUL or a string to place
at the beginning of each new line (after any indentation).
Similarly, the suffix argument can be either NUL or 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 by the fillchar
argument. Normally the fill-character is a space.
The start argument tells gldisplaytext() how many charac-
ters 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 gldisplaytext() 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
SunOS 5.11 Last change: 28 Nov 2007 38
Interactive Command-line Input Library Functions
glgetline(3TECLA)
by calling gldisplaytext() for each successive portion of
the paragraph. Note that literal newline characters are
necessary at the end of each paragraph to force a new line
to be started.
On error, gldisplaytext() returns -1.
Callback Function Facilities
Unless otherwise stated, callback functions such as tab com-
pletion 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 glreplaceprompt() function from a callback
tells glgetline() to display a different prompt when the
callback returns. Except in non-blocking server mode, it has
no effect if used between calls to glgetline(). In non-
blocking server mode, when used between two calls to
glgetline() 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 glgetline().
International Character Sets
Since libtecla(3LIB) version 1.4.0, glgetline() 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(LCTYPE, "")
then the current locale is determined by the first of the
environment variables LCTYPE, LCAL, and LANG that is
found to contain a valid locale name. If none of these vari-
ables are defined, or the program neglects to call
setlocale(3C), then the default C locale is used, which is
US 7-bit ASCI. 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
SunOS 5.11 Last change: 28 Nov 2007 39
Interactive Command-line Input Library Functions
glgetline(3TECLA)
be found in the tecla(5) man page.
Thread Safety
Unfortunately neither terminfo nor termcap were designed to
be reentrant, so you cannot safely use the functions of the
getline module in multiple threads (you can use the separate
file-expansion and word-completion modules in multiple
threads, see the corresponding man pages for details). How-
ever due to the use of POSIX reentrant functions for looking
up home directories, it is safe to use this module from a
single thread of a multi-threaded program, provided that
your other threads do not use any termcap or terminfo func-
tions.
ATRIBUTES
See attributes(5) for descriptions of the following attri-
butes:
ATRIBUTE TYPE ATRIBUTE VALUE
Interface Stability Committed
MT-Level MT-Safe
SEE ALSO
cplcompleteword(3TECLA), efexpandfile(3TECLA),
gliomode(3TECLA), libtecla(3LIB), pcalookupfile(3TECLA),
attributes(5), tecla(5)
SunOS 5.11 Last change: 28 Nov 2007 40
Interactive Command-line Input Library Functions
glgetline(3TECLA)
SunOS 5.11 Last change: 28 Nov 2007 41
|