1157184Sache/* 2157184Sache * 3157184Sache * Another test harness for the readline callback interface. 4157184Sache * 5157184Sache * Author: Bob Rossi <bob@brasko.net> 6157184Sache */ 7157184Sache 8157184Sache#if defined (HAVE_CONFIG_H) 9157184Sache#include <config.h> 10157184Sache#endif 11157184Sache 12157184Sache#include <stdio.h> 13157184Sache#include <sys/types.h> 14157184Sache#include <errno.h> 15157184Sache#include <curses.h> 16157184Sache 17157184Sache#include <stdlib.h> 18157184Sache#include <unistd.h> 19157184Sache 20157184Sache#include <signal.h> 21157184Sache 22157184Sache#if 0 /* LINUX */ 23157184Sache#include <pty.h> 24157184Sache#else 25157184Sache#include <util.h> 26157184Sache#endif 27157184Sache 28157184Sache#ifdef READLINE_LIBRARY 29157184Sache# include "readline.h" 30157184Sache#else 31157184Sache# include <readline/readline.h> 32157184Sache#endif 33157184Sache 34157184Sache/** 35157184Sache * Master/Slave PTY used to keep readline off of stdin/stdout. 36157184Sache */ 37157184Sachestatic int masterfd = -1; 38157184Sachestatic int slavefd; 39157184Sache 40157184Sachevoid 41157184Sachesigint (s) 42157184Sache int s; 43157184Sache{ 44157184Sache tty_reset (STDIN_FILENO); 45157184Sache close (masterfd); 46157184Sache close (slavefd); 47157184Sache printf ("\n"); 48157184Sache exit (0); 49157184Sache} 50157184Sache 51157184Sachestatic int 52157184Sacheuser_input() 53157184Sache{ 54157184Sache int size; 55157184Sache const int MAX = 1024; 56157184Sache char *buf = (char *)malloc(MAX+1); 57157184Sache 58157184Sache size = read (STDIN_FILENO, buf, MAX); 59157184Sache if (size == -1) 60157184Sache return -1; 61157184Sache 62157184Sache size = write (masterfd, buf, size); 63157184Sache if (size == -1) 64157184Sache return -1; 65157184Sache 66157184Sache return 0; 67157184Sache} 68157184Sache 69157184Sachestatic int 70157184Sachereadline_input() 71157184Sache{ 72157184Sache const int MAX = 1024; 73157184Sache char *buf = (char *)malloc(MAX+1); 74157184Sache int size; 75157184Sache 76157184Sache size = read (masterfd, buf, MAX); 77157184Sache if (size == -1) 78157184Sache { 79157184Sache free( buf ); 80157184Sache buf = NULL; 81157184Sache return -1; 82157184Sache } 83157184Sache 84157184Sache buf[size] = 0; 85157184Sache 86157184Sache /* Display output from readline */ 87157184Sache if ( size > 0 ) 88157184Sache fprintf(stderr, "%s", buf); 89157184Sache 90157184Sache free( buf ); 91157184Sache buf = NULL; 92157184Sache return 0; 93157184Sache} 94157184Sache 95157184Sachestatic void 96157184Sacherlctx_send_user_command(char *line) 97157184Sache{ 98157184Sache /* This happens when rl_callback_read_char gets EOF */ 99157184Sache if ( line == NULL ) 100157184Sache return; 101157184Sache 102157184Sache if (strcmp (line, "exit") == 0) { 103157184Sache tty_reset (STDIN_FILENO); 104157184Sache close (masterfd); 105157184Sache close (slavefd); 106157184Sache printf ("\n"); 107157184Sache exit (0); 108157184Sache } 109157184Sache 110157184Sache /* Don't add the enter command */ 111157184Sache if ( line && *line != '\0' ) 112157184Sache add_history(line); 113157184Sache} 114157184Sache 115157184Sachestatic void 116157184Sachecustom_deprep_term_function () 117157184Sache{ 118157184Sache} 119157184Sache 120157184Sachestatic int 121157184Sacheinit_readline (int inputfd, int outputfd) 122157184Sache{ 123157184Sache FILE *inputFILE, *outputFILE; 124157184Sache 125157184Sache inputFILE = fdopen (inputfd, "r"); 126157184Sache if (!inputFILE) 127157184Sache return -1; 128157184Sache 129157184Sache outputFILE = fdopen (outputfd, "w"); 130157184Sache if (!outputFILE) 131157184Sache return -1; 132157184Sache 133157184Sache rl_instream = inputFILE; 134157184Sache rl_outstream = outputFILE; 135157184Sache 136157184Sache /* Tell readline what the prompt is if it needs to put it back */ 137157184Sache rl_callback_handler_install("(rltest): ", rlctx_send_user_command); 138157184Sache 139157184Sache /* Set the terminal type to dumb so the output of readline can be 140157184Sache * understood by tgdb */ 141157184Sache if ( rl_reset_terminal("dumb") == -1 ) 142157184Sache return -1; 143157184Sache 144157184Sache /* For some reason, readline can not deprep the terminal. 145157184Sache * However, it doesn't matter because no other application is working on 146157184Sache * the terminal besides readline */ 147157184Sache rl_deprep_term_function = custom_deprep_term_function; 148157184Sache 149157184Sache using_history(); 150157184Sache read_history(".history"); 151157184Sache 152157184Sache return 0; 153157184Sache} 154157184Sache 155157184Sachestatic int 156157184Sachemain_loop(void) 157157184Sache{ 158157184Sache fd_set rset; 159157184Sache int max; 160157184Sache 161157184Sache max = (masterfd > STDIN_FILENO) ? masterfd : STDIN_FILENO; 162157184Sache max = (max > slavefd) ? max : slavefd; 163157184Sache 164157184Sache for (;;) 165157184Sache { 166157184Sache /* Reset the fd_set, and watch for input from GDB or stdin */ 167157184Sache FD_ZERO(&rset); 168157184Sache 169157184Sache FD_SET(STDIN_FILENO, &rset); 170157184Sache FD_SET(slavefd, &rset); 171157184Sache FD_SET(masterfd, &rset); 172157184Sache 173157184Sache /* Wait for input */ 174157184Sache if (select(max + 1, &rset, NULL, NULL, NULL) == -1) 175157184Sache { 176157184Sache if (errno == EINTR) 177157184Sache continue; 178157184Sache else 179157184Sache return -1; 180157184Sache } 181157184Sache 182157184Sache /* Input received through the pty: Handle it 183157184Sache * Wrote to masterfd, slave fd has that input, alert readline to read it. 184157184Sache */ 185157184Sache if (FD_ISSET(slavefd, &rset)) 186157184Sache rl_callback_read_char(); 187157184Sache 188157184Sache /* Input received through the pty. 189157184Sache * Readline read from slavefd, and it wrote to the masterfd. 190157184Sache */ 191157184Sache if (FD_ISSET(masterfd, &rset)) 192157184Sache if ( readline_input() == -1 ) 193157184Sache return -1; 194157184Sache 195157184Sache /* Input received: Handle it, write to masterfd (input to readline) */ 196157184Sache if (FD_ISSET(STDIN_FILENO, &rset)) 197157184Sache if ( user_input() == -1 ) 198157184Sache return -1; 199157184Sache } 200157184Sache 201157184Sache return 0; 202157184Sache} 203157184Sache 204157184Sache/* The terminal attributes before calling tty_cbreak */ 205157184Sachestatic struct termios save_termios; 206157184Sachestatic struct winsize size; 207157184Sachestatic enum { RESET, TCBREAK } ttystate = RESET; 208157184Sache 209157184Sache/* tty_cbreak: Sets terminal to cbreak mode. Also known as noncanonical mode. 210157184Sache * 1. Signal handling is still turned on, so the user can still type those. 211157184Sache * 2. echo is off 212157184Sache * 3. Read in one char at a time. 213157184Sache * 214157184Sache * fd - The file descriptor of the terminal 215157184Sache * 216157184Sache * Returns: 0 on sucess, -1 on error 217157184Sache */ 218157184Sacheint tty_cbreak(int fd){ 219157184Sache struct termios buf; 220157184Sache int ttysavefd = -1; 221157184Sache 222157184Sache if(tcgetattr(fd, &save_termios) < 0) 223157184Sache return -1; 224157184Sache 225157184Sache buf = save_termios; 226157184Sache buf.c_lflag &= ~(ECHO | ICANON); 227157184Sache buf.c_iflag &= ~(ICRNL | INLCR); 228157184Sache buf.c_cc[VMIN] = 1; 229157184Sache buf.c_cc[VTIME] = 0; 230157184Sache 231157184Sache#if defined (VLNEXT) && defined (_POSIX_VDISABLE) 232157184Sache buf.c_cc[VLNEXT] = _POSIX_VDISABLE; 233157184Sache#endif 234157184Sache 235157184Sache#if defined (VDSUSP) && defined (_POSIX_VDISABLE) 236157184Sache buf.c_cc[VDSUSP] = _POSIX_VDISABLE; 237157184Sache#endif 238157184Sache 239157184Sache /* enable flow control; only stty start char can restart output */ 240157184Sache#if 0 241157184Sache buf.c_iflag |= (IXON|IXOFF); 242157184Sache#ifdef IXANY 243157184Sache buf.c_iflag &= ~IXANY; 244157184Sache#endif 245157184Sache#endif 246157184Sache 247157184Sache /* disable flow control; let ^S and ^Q through to pty */ 248157184Sache buf.c_iflag &= ~(IXON|IXOFF); 249157184Sache#ifdef IXANY 250157184Sache buf.c_iflag &= ~IXANY; 251157184Sache#endif 252157184Sache 253157184Sache if(tcsetattr(fd, TCSAFLUSH, &buf) < 0) 254157184Sache return -1; 255157184Sache 256157184Sache ttystate = TCBREAK; 257157184Sache ttysavefd = fd; 258157184Sache 259157184Sache /* set size */ 260157184Sache if(ioctl(fd, TIOCGWINSZ, (char *)&size) < 0) 261157184Sache return -1; 262157184Sache 263157184Sache#ifdef DEBUG 264157184Sache err_msg("%d rows and %d cols\n", size.ws_row, size.ws_col); 265157184Sache#endif 266157184Sache 267157184Sache return (0); 268157184Sache} 269157184Sache 270157184Sacheint 271157184Sachetty_off_xon_xoff (int fd) 272157184Sache{ 273157184Sache struct termios buf; 274157184Sache int ttysavefd = -1; 275157184Sache 276157184Sache if(tcgetattr(fd, &buf) < 0) 277157184Sache return -1; 278157184Sache 279157184Sache buf.c_iflag &= ~(IXON|IXOFF); 280157184Sache 281157184Sache if(tcsetattr(fd, TCSAFLUSH, &buf) < 0) 282157184Sache return -1; 283157184Sache 284157184Sache return 0; 285157184Sache} 286157184Sache 287157184Sache/* tty_reset: Sets the terminal attributes back to their previous state. 288157184Sache * PRE: tty_cbreak must have already been called. 289157184Sache * 290157184Sache * fd - The file descrioptor of the terminal to reset. 291157184Sache * 292157184Sache * Returns: 0 on success, -1 on error 293157184Sache */ 294157184Sacheint tty_reset(int fd) 295157184Sache{ 296157184Sache if(ttystate != TCBREAK) 297157184Sache return (0); 298157184Sache 299157184Sache if(tcsetattr(fd, TCSAFLUSH, &save_termios) < 0) 300157184Sache return (-1); 301157184Sache 302157184Sache ttystate = RESET; 303157184Sache 304157184Sache return 0; 305157184Sache} 306157184Sache 307157184Sacheint 308157184Sachemain() 309157184Sache{ 310157184Sache int val; 311157184Sache val = openpty (&masterfd, &slavefd, NULL, NULL, NULL); 312157184Sache if (val == -1) 313157184Sache return -1; 314157184Sache 315157184Sache val = tty_off_xon_xoff (masterfd); 316157184Sache if (val == -1) 317157184Sache return -1; 318157184Sache 319157184Sache val = init_readline (slavefd, slavefd); 320157184Sache if (val == -1) 321157184Sache return -1; 322157184Sache 323157184Sache val = tty_cbreak (STDIN_FILENO); 324157184Sache if (val == -1) 325157184Sache return -1; 326157184Sache 327157184Sache signal (SIGINT, sigint); 328157184Sache 329157184Sache val = main_loop (); 330157184Sache 331157184Sache tty_reset (STDIN_FILENO); 332157184Sache 333157184Sache if (val == -1) 334157184Sache return -1; 335157184Sache 336157184Sache return 0; 337157184Sache} 338