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