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>