]> git.ipfire.org Git - thirdparty/bash.git/blame - lib/readline/examples/excallback.c
Imported from ../bash-2.05.tar.gz.
[thirdparty/bash.git] / lib / readline / examples / excallback.c
CommitLineData
bb70624e
JA
1/*
2From: Jeff Solomon <jsolomon@stanford.edu>
3Date: Fri, 9 Apr 1999 10:13:27 -0700 (PDT)
4To: chet@po.cwru.edu
5Subject: new readline example
6Message-ID: <14094.12094.527305.199695@mrclean.Stanford.EDU>
7
8Chet,
9
10I've been using readline 4.0. Specifically, I've been using the perl
11version Term::ReadLine::Gnu. It works great.
12
13Anyway, I've been playing around the alternate interface and I wanted
14to contribute a little C program, callback.c, to you that you could
15use as an example of the alternate interface in the /examples
16directory of the readline distribution.
17
18My example shows how, using the alternate interface, you can
19interactively change the prompt (which is very nice imo). Also, I
20point out that you must roll your own terminal setting when using the
21alternate interface because readline depreps (using your parlance) the
22terminal while in the user callback. I try to demostrate what I mean
23with an example. I've included the program below.
24
25To compile, I just put the program in the examples directory and made
26the appropriate changes to the EXECUTABLES and OBJECTS line and added
27an additional target 'callback'.
28
29I compiled on my Sun Solaris2.6 box using Sun's cc.
30
31Let me know what you think.
32
33Jeff
34*/
35
36#if defined (HAVE_CONFIG_H)
37#include <config.h>
38#endif
39
40#include <stdio.h>
41#include <sys/types.h>
42
43#ifdef HAVE_UNISTD_H
44#include <unistd.h>
45#endif
46
47#include <termios.h> /* xxx - should make this more general */
48
49#ifdef READLINE_LIBRARY
50# include "readline.h"
51#else
52# include <readline/readline.h>
53#endif
54
55/* This little examples demonstrates the alternate interface to using readline.
56 * In the alternate interface, the user maintains control over program flow and
57 * only calls readline when STDIN is readable. Using the alternate interface,
58 * you can do anything else while still using readline (like talking to a
59 * network or another program) without blocking.
60 *
61 * Specifically, this program highlights two importants features of the
62 * alternate interface. The first is the ability to interactively change the
63 * prompt, which can't be done using the regular interface since rl_prompt is
64 * read-only.
65 *
66 * The second feature really highlights a subtle point when using the alternate
67 * interface. That is, readline will not alter the terminal when inside your
68 * callback handler. So let's so, your callback executes a user command that
69 * takes a non-trivial amount of time to complete (seconds). While your
70 * executing the command, the user continues to type keystrokes and expects them
71 * to be re-echoed on the new prompt when it returns. Unfortunately, the default
72 * terminal configuration doesn't do this. After the prompt returns, the user
73 * must hit one additional keystroke and then will see all of his previous
74 * keystrokes. To illustrate this, compile and run this program. Type "sleep" at
75 * the prompt and then type "bar" before the prompt returns (you have 3
76 * seconds). Notice how "bar" is re-echoed on the prompt after the prompt
77 * returns? This is what you expect to happen. Now comment out the 4 lines below
78 * the line that says COMMENT LINE BELOW. Recompile and rerun the program and do
79 * the same thing. When the prompt returns, you should not see "bar". Now type
80 * "f", see how "barf" magically appears? This behavior is un-expected and not
81 * desired.
82 */
83
84void process_line(char *line);
85int change_prompt(void);
86char *get_prompt(void);
87
88int prompt = 1;
89char prompt_buf[40], line_buf[256];
90tcflag_t old_lflag;
91cc_t old_vtime;
92struct termios term;
93
94int
95main()
96{
97 fd_set fds;
98
99 /* Adjust the terminal slightly before the handler is installed. Disable
100 * canonical mode processing and set the input character time flag to be
101 * non-blocking.
102 */
103 if( tcgetattr(STDIN_FILENO, &term) < 0 ) {
104 perror("tcgetattr");
105 exit(1);
106 }
107 old_lflag = term.c_lflag;
108 old_vtime = term.c_cc[VTIME];
109 term.c_lflag &= ~ICANON;
110 term.c_cc[VTIME] = 1;
111 /* COMMENT LINE BELOW - see above */
112 if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) {
113 perror("tcsetattr");
114 exit(1);
115 }
116
117 rl_add_defun("change-prompt", change_prompt, CTRL('t'));
118 rl_callback_handler_install(get_prompt(), process_line);
119
120 while(1) {
121 FD_ZERO(&fds);
122 FD_SET(fileno(stdin), &fds);
123
124 if( select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0) {
125 perror("select");
126 exit(1);
127 }
128
129 if( FD_ISSET(fileno(stdin), &fds) ) {
130 rl_callback_read_char();
131 }
132 }
133}
134
135void
136process_line(char *line)
137{
138 if( line == NULL ) {
139 fprintf(stderr, "\n", line);
140
141 /* reset the old terminal setting before exiting */
142 term.c_lflag = old_lflag;
143 term.c_cc[VTIME] = old_vtime;
144 if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) {
145 perror("tcsetattr");
146 exit(1);
147 }
148 exit(0);
149 }
150
151 if( strcmp(line, "sleep") == 0 ) {
152 sleep(3);
153 } else {
154 fprintf(stderr, "|%s|\n", line);
155 }
28ef6c31
JA
156
157 free (line);
bb70624e
JA
158}
159
160int
161change_prompt(void)
162{
163 /* toggle the prompt variable */
164 prompt = !prompt;
165
166 /* save away the current contents of the line */
167 strcpy(line_buf, rl_line_buffer);
168
169 /* install a new handler which will change the prompt and erase the current line */
170 rl_callback_handler_install(get_prompt(), process_line);
171
172 /* insert the old text on the new line */
173 rl_insert_text(line_buf);
174
175 /* redraw the current line - this is an undocumented function. It invokes the
176 * redraw-current-line command.
177 */
178 rl_refresh_line(0, 0);
179}
180
181char *
182get_prompt(void)
183{
184 /* The prompts can even be different lengths! */
185 sprintf(prompt_buf, "%s",
186 prompt ? "Hit ctrl-t to toggle prompt> " : "Pretty cool huh?> ");
187 return prompt_buf;
188}