123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- /*
- *
- * Another test harness for the readline callback interface.
- *
- * Author: Bob Rossi <bob@brasko.net>
- */
- #if defined (HAVE_CONFIG_H)
- #include <config.h>
- #endif
- #include <stdio.h>
- #include <sys/types.h>
- #include <errno.h>
- #include <curses.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <signal.h>
- #if 0 /* LINUX */
- #include <pty.h>
- #else
- #include <util.h>
- #endif
- #ifdef READLINE_LIBRARY
- # include "readline.h"
- #else
- # include <readline/readline.h>
- #endif
- /**
- * Master/Slave PTY used to keep readline off of stdin/stdout.
- */
- static int masterfd = -1;
- static int slavefd;
- void
- sigint (s)
- int s;
- {
- tty_reset (STDIN_FILENO);
- close (masterfd);
- close (slavefd);
- printf ("\n");
- exit (0);
- }
- static int
- user_input()
- {
- int size;
- const int MAX = 1024;
- char *buf = (char *)malloc(MAX+1);
- size = read (STDIN_FILENO, buf, MAX);
- if (size == -1)
- return -1;
- size = write (masterfd, buf, size);
- if (size == -1)
- return -1;
- return 0;
- }
- static int
- readline_input()
- {
- const int MAX = 1024;
- char *buf = (char *)malloc(MAX+1);
- int size;
- size = read (masterfd, buf, MAX);
- if (size == -1)
- {
- free( buf );
- buf = NULL;
- return -1;
- }
- buf[size] = 0;
- /* Display output from readline */
- if ( size > 0 )
- fprintf(stderr, "%s", buf);
- free( buf );
- buf = NULL;
- return 0;
- }
- static void
- rlctx_send_user_command(char *line)
- {
- /* This happens when rl_callback_read_char gets EOF */
- if ( line == NULL )
- return;
-
- if (strcmp (line, "exit") == 0) {
- tty_reset (STDIN_FILENO);
- close (masterfd);
- close (slavefd);
- printf ("\n");
- exit (0);
- }
-
- /* Don't add the enter command */
- if ( line && *line != '\0' )
- add_history(line);
- }
- static void
- custom_deprep_term_function ()
- {
- }
- static int
- init_readline (int inputfd, int outputfd)
- {
- FILE *inputFILE, *outputFILE;
- inputFILE = fdopen (inputfd, "r");
- if (!inputFILE)
- return -1;
- outputFILE = fdopen (outputfd, "w");
- if (!outputFILE)
- return -1;
- rl_instream = inputFILE;
- rl_outstream = outputFILE;
- /* Tell readline what the prompt is if it needs to put it back */
- rl_callback_handler_install("(rltest): ", rlctx_send_user_command);
- /* Set the terminal type to dumb so the output of readline can be
- * understood by tgdb */
- if ( rl_reset_terminal("dumb") == -1 )
- return -1;
- /* For some reason, readline can not deprep the terminal.
- * However, it doesn't matter because no other application is working on
- * the terminal besides readline */
- rl_deprep_term_function = custom_deprep_term_function;
- using_history();
- read_history(".history");
- return 0;
- }
- static int
- main_loop(void)
- {
- fd_set rset;
- int max;
-
- max = (masterfd > STDIN_FILENO) ? masterfd : STDIN_FILENO;
- max = (max > slavefd) ? max : slavefd;
- for (;;)
- {
- /* Reset the fd_set, and watch for input from GDB or stdin */
- FD_ZERO(&rset);
-
- FD_SET(STDIN_FILENO, &rset);
- FD_SET(slavefd, &rset);
- FD_SET(masterfd, &rset);
- /* Wait for input */
- if (select(max + 1, &rset, NULL, NULL, NULL) == -1)
- {
- if (errno == EINTR)
- continue;
- else
- return -1;
- }
- /* Input received through the pty: Handle it
- * Wrote to masterfd, slave fd has that input, alert readline to read it.
- */
- if (FD_ISSET(slavefd, &rset))
- rl_callback_read_char();
- /* Input received through the pty.
- * Readline read from slavefd, and it wrote to the masterfd.
- */
- if (FD_ISSET(masterfd, &rset))
- if ( readline_input() == -1 )
- return -1;
- /* Input received: Handle it, write to masterfd (input to readline) */
- if (FD_ISSET(STDIN_FILENO, &rset))
- if ( user_input() == -1 )
- return -1;
- }
- return 0;
- }
- /* The terminal attributes before calling tty_cbreak */
- static struct termios save_termios;
- static struct winsize size;
- static enum { RESET, TCBREAK } ttystate = RESET;
- /* tty_cbreak: Sets terminal to cbreak mode. Also known as noncanonical mode.
- * 1. Signal handling is still turned on, so the user can still type those.
- * 2. echo is off
- * 3. Read in one char at a time.
- *
- * fd - The file descriptor of the terminal
- *
- * Returns: 0 on sucess, -1 on error
- */
- int tty_cbreak(int fd){
- struct termios buf;
- int ttysavefd = -1;
-
- if(tcgetattr(fd, &save_termios) < 0)
- return -1;
-
- buf = save_termios;
- buf.c_lflag &= ~(ECHO | ICANON);
- buf.c_iflag &= ~(ICRNL | INLCR);
- buf.c_cc[VMIN] = 1;
- buf.c_cc[VTIME] = 0;
- #if defined (VLNEXT) && defined (_POSIX_VDISABLE)
- buf.c_cc[VLNEXT] = _POSIX_VDISABLE;
- #endif
- #if defined (VDSUSP) && defined (_POSIX_VDISABLE)
- buf.c_cc[VDSUSP] = _POSIX_VDISABLE;
- #endif
- /* enable flow control; only stty start char can restart output */
- #if 0
- buf.c_iflag |= (IXON|IXOFF);
- #ifdef IXANY
- buf.c_iflag &= ~IXANY;
- #endif
- #endif
- /* disable flow control; let ^S and ^Q through to pty */
- buf.c_iflag &= ~(IXON|IXOFF);
- #ifdef IXANY
- buf.c_iflag &= ~IXANY;
- #endif
- if(tcsetattr(fd, TCSAFLUSH, &buf) < 0)
- return -1;
- ttystate = TCBREAK;
- ttysavefd = fd;
- /* set size */
- if(ioctl(fd, TIOCGWINSZ, (char *)&size) < 0)
- return -1;
- #ifdef DEBUG
- err_msg("%d rows and %d cols\n", size.ws_row, size.ws_col);
- #endif
-
- return (0);
- }
- int
- tty_off_xon_xoff (int fd)
- {
- struct termios buf;
- int ttysavefd = -1;
- if(tcgetattr(fd, &buf) < 0)
- return -1;
-
- buf.c_iflag &= ~(IXON|IXOFF);
- if(tcsetattr(fd, TCSAFLUSH, &buf) < 0)
- return -1;
- return 0;
- }
- /* tty_reset: Sets the terminal attributes back to their previous state.
- * PRE: tty_cbreak must have already been called.
- *
- * fd - The file descrioptor of the terminal to reset.
- *
- * Returns: 0 on success, -1 on error
- */
- int tty_reset(int fd)
- {
- if(ttystate != TCBREAK)
- return (0);
- if(tcsetattr(fd, TCSAFLUSH, &save_termios) < 0)
- return (-1);
-
- ttystate = RESET;
-
- return 0;
- }
- int
- main()
- {
- int val;
- val = openpty (&masterfd, &slavefd, NULL, NULL, NULL);
- if (val == -1)
- return -1;
- val = tty_off_xon_xoff (masterfd);
- if (val == -1)
- return -1;
- val = init_readline (slavefd, slavefd);
- if (val == -1)
- return -1;
- val = tty_cbreak (STDIN_FILENO);
- if (val == -1)
- return -1;
- signal (SIGINT, sigint);
- val = main_loop ();
- tty_reset (STDIN_FILENO);
- if (val == -1)
- return -1;
- return 0;
- }
|