Annotation of embedaddon/readline/examples/rlptytest.c, revision 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>