5836a818ec
This reverts commitb558ff043d
. This reverts commit4a11f20659
. The initial import commit failed to retain local changes made to readline's configure.in (and the commit message erroneously stated that there were no local changes that needed to be reapplied). Also the import caused a couple of build errors and a scattering of testsuite regressions throughout many arches. It's probably better to start over with this import, hopefully more carefully next time.
191 lines
5.6 KiB
C
191 lines
5.6 KiB
C
/*
|
|
From: Jeff Solomon <jsolomon@stanford.edu>
|
|
Date: Fri, 9 Apr 1999 10:13:27 -0700 (PDT)
|
|
To: chet@po.cwru.edu
|
|
Subject: new readline example
|
|
Message-ID: <14094.12094.527305.199695@mrclean.Stanford.EDU>
|
|
|
|
Chet,
|
|
|
|
I've been using readline 4.0. Specifically, I've been using the perl
|
|
version Term::ReadLine::Gnu. It works great.
|
|
|
|
Anyway, I've been playing around the alternate interface and I wanted
|
|
to contribute a little C program, callback.c, to you that you could
|
|
use as an example of the alternate interface in the /examples
|
|
directory of the readline distribution.
|
|
|
|
My example shows how, using the alternate interface, you can
|
|
interactively change the prompt (which is very nice imo). Also, I
|
|
point out that you must roll your own terminal setting when using the
|
|
alternate interface because readline depreps (using your parlance) the
|
|
terminal while in the user callback. I try to demostrate what I mean
|
|
with an example. I've included the program below.
|
|
|
|
To compile, I just put the program in the examples directory and made
|
|
the appropriate changes to the EXECUTABLES and OBJECTS line and added
|
|
an additional target 'callback'.
|
|
|
|
I compiled on my Sun Solaris2.6 box using Sun's cc.
|
|
|
|
Let me know what you think.
|
|
|
|
Jeff
|
|
*/
|
|
/*
|
|
Copyright (C) 1999 Jeff Solomon
|
|
*/
|
|
|
|
#if defined (HAVE_CONFIG_H)
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include <termios.h> /* xxx - should make this more general */
|
|
|
|
#ifdef READLINE_LIBRARY
|
|
# include "readline.h"
|
|
#else
|
|
# include <readline/readline.h>
|
|
#endif
|
|
|
|
/* This little examples demonstrates the alternate interface to using readline.
|
|
* In the alternate interface, the user maintains control over program flow and
|
|
* only calls readline when STDIN is readable. Using the alternate interface,
|
|
* you can do anything else while still using readline (like talking to a
|
|
* network or another program) without blocking.
|
|
*
|
|
* Specifically, this program highlights two importants features of the
|
|
* alternate interface. The first is the ability to interactively change the
|
|
* prompt, which can't be done using the regular interface since rl_prompt is
|
|
* read-only.
|
|
*
|
|
* The second feature really highlights a subtle point when using the alternate
|
|
* interface. That is, readline will not alter the terminal when inside your
|
|
* callback handler. So let's so, your callback executes a user command that
|
|
* takes a non-trivial amount of time to complete (seconds). While your
|
|
* executing the command, the user continues to type keystrokes and expects them
|
|
* to be re-echoed on the new prompt when it returns. Unfortunately, the default
|
|
* terminal configuration doesn't do this. After the prompt returns, the user
|
|
* must hit one additional keystroke and then will see all of his previous
|
|
* keystrokes. To illustrate this, compile and run this program. Type "sleep" at
|
|
* the prompt and then type "bar" before the prompt returns (you have 3
|
|
* seconds). Notice how "bar" is re-echoed on the prompt after the prompt
|
|
* returns? This is what you expect to happen. Now comment out the 4 lines below
|
|
* the line that says COMMENT LINE BELOW. Recompile and rerun the program and do
|
|
* the same thing. When the prompt returns, you should not see "bar". Now type
|
|
* "f", see how "barf" magically appears? This behavior is un-expected and not
|
|
* desired.
|
|
*/
|
|
|
|
void process_line(char *line);
|
|
int change_prompt(void);
|
|
char *get_prompt(void);
|
|
|
|
int prompt = 1;
|
|
char prompt_buf[40], line_buf[256];
|
|
tcflag_t old_lflag;
|
|
cc_t old_vtime;
|
|
struct termios term;
|
|
|
|
int
|
|
main()
|
|
{
|
|
fd_set fds;
|
|
|
|
/* Adjust the terminal slightly before the handler is installed. Disable
|
|
* canonical mode processing and set the input character time flag to be
|
|
* non-blocking.
|
|
*/
|
|
if( tcgetattr(STDIN_FILENO, &term) < 0 ) {
|
|
perror("tcgetattr");
|
|
exit(1);
|
|
}
|
|
old_lflag = term.c_lflag;
|
|
old_vtime = term.c_cc[VTIME];
|
|
term.c_lflag &= ~ICANON;
|
|
term.c_cc[VTIME] = 1;
|
|
/* COMMENT LINE BELOW - see above */
|
|
if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) {
|
|
perror("tcsetattr");
|
|
exit(1);
|
|
}
|
|
|
|
rl_add_defun("change-prompt", change_prompt, CTRL('t'));
|
|
rl_callback_handler_install(get_prompt(), process_line);
|
|
|
|
while(1) {
|
|
FD_ZERO(&fds);
|
|
FD_SET(fileno(stdin), &fds);
|
|
|
|
if( select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0) {
|
|
perror("select");
|
|
exit(1);
|
|
}
|
|
|
|
if( FD_ISSET(fileno(stdin), &fds) ) {
|
|
rl_callback_read_char();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
process_line(char *line)
|
|
{
|
|
if( line == NULL ) {
|
|
fprintf(stderr, "\n", line);
|
|
|
|
/* reset the old terminal setting before exiting */
|
|
term.c_lflag = old_lflag;
|
|
term.c_cc[VTIME] = old_vtime;
|
|
if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) {
|
|
perror("tcsetattr");
|
|
exit(1);
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
if( strcmp(line, "sleep") == 0 ) {
|
|
sleep(3);
|
|
} else {
|
|
fprintf(stderr, "|%s|\n", line);
|
|
}
|
|
|
|
free (line);
|
|
}
|
|
|
|
int
|
|
change_prompt(void)
|
|
{
|
|
/* toggle the prompt variable */
|
|
prompt = !prompt;
|
|
|
|
/* save away the current contents of the line */
|
|
strcpy(line_buf, rl_line_buffer);
|
|
|
|
/* install a new handler which will change the prompt and erase the current line */
|
|
rl_callback_handler_install(get_prompt(), process_line);
|
|
|
|
/* insert the old text on the new line */
|
|
rl_insert_text(line_buf);
|
|
|
|
/* redraw the current line - this is an undocumented function. It invokes the
|
|
* redraw-current-line command.
|
|
*/
|
|
rl_refresh_line(0, 0);
|
|
}
|
|
|
|
char *
|
|
get_prompt(void)
|
|
{
|
|
/* The prompts can even be different lengths! */
|
|
sprintf(prompt_buf, "%s",
|
|
prompt ? "Hit ctrl-t to toggle prompt> " : "Pretty cool huh?> ");
|
|
return prompt_buf;
|
|
}
|