File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / readline / examples / rlptytest.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 01:01:01 2021 UTC (4 years ago) by misho
Branches: readline, MAIN
CVS tags: v8_2p0, v8_1p0, HEAD
readline 8.1

    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: void
   52: sigwinch (s)
   53:      int s;
   54: {
   55:   rl_resize_terminal ();
   56: }
   57: 
   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: 
  326:   signal (SIGWINCH, sigwinch);
  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>