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>