Annotation of embedaddon/readline/examples/rlptytest.c, revision 1.1.1.1
1.1 misho 1: /*
2: *
3: * Another test harness for the readline callback interface.
4: *
5: * Author: Bob Rossi <bob@brasko.net>
6: */
7:
8: #if defined (HAVE_CONFIG_H)
9: #include <config.h>
10: #endif
11:
12: #include <stdio.h>
13: #include <sys/types.h>
14: #include <errno.h>
15: #include <curses.h>
16:
17: #include <stdlib.h>
18: #include <unistd.h>
19:
20: #include <signal.h>
21:
22: #if 1 /* LINUX */
23: #include <pty.h>
24: #else
25: #include <util.h>
26: #endif
27:
28: #ifdef READLINE_LIBRARY
29: # include "readline.h"
30: #else
31: # include <readline/readline.h>
32: #endif
33:
34: /**
35: * Master/Slave PTY used to keep readline off of stdin/stdout.
36: */
37: static int masterfd = -1;
38: static int slavefd;
39:
40: void
41: sigint (s)
42: int s;
43: {
44: tty_reset (STDIN_FILENO);
45: close (masterfd);
46: close (slavefd);
47: printf ("\n");
48: exit (0);
49: }
50:
51: static int
52: user_input()
53: {
54: int size;
55: const int MAX = 1024;
56: char *buf = (char *)malloc(MAX+1);
57:
58: size = read (STDIN_FILENO, buf, MAX);
59: if (size == -1)
60: return -1;
61:
62: size = write (masterfd, buf, size);
63: if (size == -1)
64: return -1;
65:
66: return 0;
67: }
68:
69: static int
70: readline_input()
71: {
72: const int MAX = 1024;
73: char *buf = (char *)malloc(MAX+1);
74: int size;
75:
76: size = read (masterfd, buf, MAX);
77: if (size == -1)
78: {
79: free( buf );
80: buf = NULL;
81: return -1;
82: }
83:
84: buf[size] = 0;
85:
86: /* Display output from readline */
87: if ( size > 0 )
88: fprintf(stderr, "%s", buf);
89:
90: free( buf );
91: buf = NULL;
92: return 0;
93: }
94:
95: static void
96: rlctx_send_user_command(char *line)
97: {
98: /* This happens when rl_callback_read_char gets EOF */
99: if ( line == NULL )
100: return;
101:
102: if (strcmp (line, "exit") == 0) {
103: tty_reset (STDIN_FILENO);
104: close (masterfd);
105: close (slavefd);
106: printf ("\n");
107: exit (0);
108: }
109:
110: /* Don't add the enter command */
111: if ( line && *line != '\0' )
112: add_history(line);
113: }
114:
115: static void
116: custom_deprep_term_function ()
117: {
118: }
119:
120: static int
121: init_readline (int inputfd, int outputfd)
122: {
123: FILE *inputFILE, *outputFILE;
124:
125: inputFILE = fdopen (inputfd, "r");
126: if (!inputFILE)
127: return -1;
128:
129: outputFILE = fdopen (outputfd, "w");
130: if (!outputFILE)
131: return -1;
132:
133: rl_instream = inputFILE;
134: rl_outstream = outputFILE;
135:
136: /* Tell readline what the prompt is if it needs to put it back */
137: rl_callback_handler_install("(rltest): ", rlctx_send_user_command);
138:
139: /* Set the terminal type to dumb so the output of readline can be
140: * understood by tgdb */
141: if ( rl_reset_terminal("dumb") == -1 )
142: return -1;
143:
144: /* For some reason, readline can not deprep the terminal.
145: * However, it doesn't matter because no other application is working on
146: * the terminal besides readline */
147: rl_deprep_term_function = custom_deprep_term_function;
148:
149: using_history();
150: read_history(".history");
151:
152: return 0;
153: }
154:
155: static int
156: main_loop(void)
157: {
158: fd_set rset;
159: int max;
160:
161: max = (masterfd > STDIN_FILENO) ? masterfd : STDIN_FILENO;
162: max = (max > slavefd) ? max : slavefd;
163:
164: for (;;)
165: {
166: /* Reset the fd_set, and watch for input from GDB or stdin */
167: FD_ZERO(&rset);
168:
169: FD_SET(STDIN_FILENO, &rset);
170: FD_SET(slavefd, &rset);
171: FD_SET(masterfd, &rset);
172:
173: /* Wait for input */
174: if (select(max + 1, &rset, NULL, NULL, NULL) == -1)
175: {
176: if (errno == EINTR)
177: continue;
178: else
179: return -1;
180: }
181:
182: /* Input received through the pty: Handle it
183: * Wrote to masterfd, slave fd has that input, alert readline to read it.
184: */
185: if (FD_ISSET(slavefd, &rset))
186: rl_callback_read_char();
187:
188: /* Input received through the pty.
189: * Readline read from slavefd, and it wrote to the masterfd.
190: */
191: if (FD_ISSET(masterfd, &rset))
192: if ( readline_input() == -1 )
193: return -1;
194:
195: /* Input received: Handle it, write to masterfd (input to readline) */
196: if (FD_ISSET(STDIN_FILENO, &rset))
197: if ( user_input() == -1 )
198: return -1;
199: }
200:
201: return 0;
202: }
203:
204: /* The terminal attributes before calling tty_cbreak */
205: static struct termios save_termios;
206: static struct winsize size;
207: static enum { RESET, TCBREAK } ttystate = RESET;
208:
209: /* tty_cbreak: Sets terminal to cbreak mode. Also known as noncanonical mode.
210: * 1. Signal handling is still turned on, so the user can still type those.
211: * 2. echo is off
212: * 3. Read in one char at a time.
213: *
214: * fd - The file descriptor of the terminal
215: *
216: * Returns: 0 on sucess, -1 on error
217: */
218: int tty_cbreak(int fd){
219: struct termios buf;
220: int ttysavefd = -1;
221:
222: if(tcgetattr(fd, &save_termios) < 0)
223: return -1;
224:
225: buf = save_termios;
226: buf.c_lflag &= ~(ECHO | ICANON);
227: buf.c_iflag &= ~(ICRNL | INLCR);
228: buf.c_cc[VMIN] = 1;
229: buf.c_cc[VTIME] = 0;
230:
231: #if defined (VLNEXT) && defined (_POSIX_VDISABLE)
232: buf.c_cc[VLNEXT] = _POSIX_VDISABLE;
233: #endif
234:
235: #if defined (VDSUSP) && defined (_POSIX_VDISABLE)
236: buf.c_cc[VDSUSP] = _POSIX_VDISABLE;
237: #endif
238:
239: /* enable flow control; only stty start char can restart output */
240: #if 0
241: buf.c_iflag |= (IXON|IXOFF);
242: #ifdef IXANY
243: buf.c_iflag &= ~IXANY;
244: #endif
245: #endif
246:
247: /* disable flow control; let ^S and ^Q through to pty */
248: buf.c_iflag &= ~(IXON|IXOFF);
249: #ifdef IXANY
250: buf.c_iflag &= ~IXANY;
251: #endif
252:
253: if(tcsetattr(fd, TCSAFLUSH, &buf) < 0)
254: return -1;
255:
256: ttystate = TCBREAK;
257: ttysavefd = fd;
258:
259: /* set size */
260: if(ioctl(fd, TIOCGWINSZ, (char *)&size) < 0)
261: return -1;
262:
263: #ifdef DEBUG
264: err_msg("%d rows and %d cols\n", size.ws_row, size.ws_col);
265: #endif
266:
267: return (0);
268: }
269:
270: int
271: tty_off_xon_xoff (int fd)
272: {
273: struct termios buf;
274: int ttysavefd = -1;
275:
276: if(tcgetattr(fd, &buf) < 0)
277: return -1;
278:
279: buf.c_iflag &= ~(IXON|IXOFF);
280:
281: if(tcsetattr(fd, TCSAFLUSH, &buf) < 0)
282: return -1;
283:
284: return 0;
285: }
286:
287: /* tty_reset: Sets the terminal attributes back to their previous state.
288: * PRE: tty_cbreak must have already been called.
289: *
290: * fd - The file descrioptor of the terminal to reset.
291: *
292: * Returns: 0 on success, -1 on error
293: */
294: int tty_reset(int fd)
295: {
296: if(ttystate != TCBREAK)
297: return (0);
298:
299: if(tcsetattr(fd, TCSAFLUSH, &save_termios) < 0)
300: return (-1);
301:
302: ttystate = RESET;
303:
304: return 0;
305: }
306:
307: int
308: main()
309: {
310: int val;
311: val = openpty (&masterfd, &slavefd, NULL, NULL, NULL);
312: if (val == -1)
313: return -1;
314:
315: val = tty_off_xon_xoff (masterfd);
316: if (val == -1)
317: return -1;
318:
319: signal (SIGINT, sigint);
320:
321: val = init_readline (slavefd, slavefd);
322: if (val == -1)
323: return -1;
324:
325: val = tty_cbreak (STDIN_FILENO);
326: if (val == -1)
327: return -1;
328:
329: val = main_loop ();
330:
331: tty_reset (STDIN_FILENO);
332:
333: if (val == -1)
334: return -1;
335:
336: return 0;
337: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>