Annotation of embedaddon/readline/examples/excallback.c, revision 1.1.1.1

1.1       misho       1: /*
                      2: From: Jeff Solomon <jsolomon@stanford.edu>
                      3: Date: Fri,  9 Apr 1999 10:13:27 -0700 (PDT)
                      4: To: chet@po.cwru.edu
                      5: Subject: new readline example
                      6: Message-ID: <14094.12094.527305.199695@mrclean.Stanford.EDU>
                      7: 
                      8: Chet,
                      9: 
                     10: I've been using readline 4.0. Specifically, I've been using the perl
                     11: version Term::ReadLine::Gnu. It works great.
                     12: 
                     13: Anyway, I've been playing around the alternate interface and I wanted
                     14: to contribute a little C program, callback.c, to you that you could
                     15: use as an example of the alternate interface in the /examples
                     16: directory of the readline distribution.
                     17: 
                     18: My example shows how, using the alternate interface, you can
                     19: interactively change the prompt (which is very nice imo). Also, I
                     20: point out that you must roll your own terminal setting when using the
                     21: alternate interface because readline depreps (using your parlance) the
                     22: terminal while in the user callback. I try to demostrate what I mean
                     23: with an example. I've included the program below.
                     24: 
                     25: To compile, I just put the program in the examples directory and made
                     26: the appropriate changes to the EXECUTABLES and OBJECTS line and added
                     27: an additional target 'callback'.
                     28: 
                     29: I compiled on my Sun Solaris2.6 box using Sun's cc.
                     30: 
                     31: Let me know what you think.
                     32: 
                     33: Jeff
                     34: */
                     35: /*
                     36: Copyright (C) 1999 Jeff Solomon
                     37: */
                     38: 
                     39: #if defined (HAVE_CONFIG_H)
                     40: #include <config.h>
                     41: #endif
                     42: 
                     43: #include <sys/types.h>
                     44: 
                     45: #ifdef HAVE_UNISTD_H
                     46: #include <unistd.h>
                     47: #endif
                     48: #include <stdlib.h>
                     49: 
                     50: #include <stdio.h>
                     51: #include <termios.h>   /* xxx - should make this more general */
                     52: 
                     53: #ifdef READLINE_LIBRARY
                     54: #  include "readline.h"
                     55: #else
                     56: #  include <readline/readline.h>
                     57: #endif
                     58: 
                     59: #ifndef STDIN_FILENO
                     60: #  define STDIN_FILENO 0
                     61: #endif
                     62: 
                     63: /* This little examples demonstrates the alternate interface to using readline.
                     64:  * In the alternate interface, the user maintains control over program flow and
                     65:  * only calls readline when STDIN is readable. Using the alternate interface,
                     66:  * you can do anything else while still using readline (like talking to a
                     67:  * network or another program) without blocking.
                     68:  *
                     69:  * Specifically, this program highlights two importants features of the
                     70:  * alternate interface. The first is the ability to interactively change the
                     71:  * prompt, which can't be done using the regular interface since rl_prompt is
                     72:  * read-only.
                     73:  * 
                     74:  * The second feature really highlights a subtle point when using the alternate
                     75:  * interface. That is, readline will not alter the terminal when inside your
                     76:  * callback handler. So let's so, your callback executes a user command that
                     77:  * takes a non-trivial amount of time to complete (seconds). While your
                     78:  * executing the command, the user continues to type keystrokes and expects them
                     79:  * to be re-echoed on the new prompt when it returns. Unfortunately, the default
                     80:  * terminal configuration doesn't do this. After the prompt returns, the user
                     81:  * must hit one additional keystroke and then will see all of his previous
                     82:  * keystrokes. To illustrate this, compile and run this program. Type "sleep" at
                     83:  * the prompt and then type "bar" before the prompt returns (you have 3
                     84:  * seconds). Notice how "bar" is re-echoed on the prompt after the prompt
                     85:  * returns? This is what you expect to happen. Now comment out the 4 lines below
                     86:  * the line that says COMMENT LINE BELOW. Recompile and rerun the program and do
                     87:  * the same thing. When the prompt returns, you should not see "bar". Now type
                     88:  * "f", see how "barf" magically appears? This behavior is un-expected and not
                     89:  * desired.
                     90:  */
                     91: 
                     92: void process_line(char *line);
                     93: int  change_prompt(void);
                     94: char *get_prompt(void);
                     95: 
                     96: int prompt = 1;
                     97: char prompt_buf[40], line_buf[256];
                     98: tcflag_t old_lflag;
                     99: cc_t     old_vtime;
                    100: struct termios term;
                    101: 
                    102: int 
                    103: main()
                    104: {
                    105:     fd_set fds;
                    106: 
                    107:     /* Adjust the terminal slightly before the handler is installed. Disable
                    108:      * canonical mode processing and set the input character time flag to be
                    109:      * non-blocking.
                    110:      */
                    111:     if( tcgetattr(STDIN_FILENO, &term) < 0 ) {
                    112:         perror("tcgetattr");
                    113:         exit(1);
                    114:     }
                    115:     old_lflag = term.c_lflag;
                    116:     old_vtime = term.c_cc[VTIME];
                    117:     term.c_lflag &= ~ICANON;
                    118:     term.c_cc[VTIME] = 1;
                    119:     /* COMMENT LINE BELOW - see above */
                    120:     if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) {
                    121:         perror("tcsetattr");
                    122:         exit(1);
                    123:     }
                    124: 
                    125:     rl_add_defun("change-prompt", change_prompt, CTRL('t'));
                    126:     rl_callback_handler_install(get_prompt(), process_line);
                    127: 
                    128:     while(1) {
                    129:       FD_ZERO(&fds);
                    130:       FD_SET(fileno(stdin), &fds);
                    131: 
                    132:       if( select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0) {
                    133:         perror("select");
                    134:         exit(1);
                    135:       }
                    136: 
                    137:       if( FD_ISSET(fileno(stdin), &fds) ) {
                    138:         rl_callback_read_char();
                    139:       }
                    140:     }
                    141: }
                    142: 
                    143: void
                    144: process_line(char *line)
                    145: {
                    146:   if( line == NULL ) {
                    147:     fprintf(stderr, "\n", line);
                    148: 
                    149:     /* reset the old terminal setting before exiting */
                    150:     term.c_lflag     = old_lflag;
                    151:     term.c_cc[VTIME] = old_vtime;
                    152:     if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) {
                    153:         perror("tcsetattr");
                    154:         exit(1);
                    155:     }
                    156:     exit(0);
                    157:   }
                    158: 
                    159:   if( strcmp(line, "sleep") == 0 ) {
                    160:     sleep(3);
                    161:   } else {
                    162:     fprintf(stderr, "|%s|\n", line);
                    163:   }
                    164: 
                    165:   free (line);
                    166: }
                    167: 
                    168: int
                    169: change_prompt(void)
                    170: {
                    171:   /* toggle the prompt variable */
                    172:   prompt = !prompt;
                    173: 
                    174:   /* save away the current contents of the line */
                    175:   strcpy(line_buf, rl_line_buffer);
                    176: 
                    177:   /* install a new handler which will change the prompt and erase the current line */
                    178:   rl_callback_handler_install(get_prompt(), process_line);
                    179: 
                    180:   /* insert the old text on the new line */
                    181:   rl_insert_text(line_buf);
                    182: 
                    183:   /* redraw the current line - this is an undocumented function. It invokes the
                    184:    * redraw-current-line command.
                    185:    */
                    186:   rl_refresh_line(0, 0);
                    187: }
                    188: 
                    189: char *
                    190: get_prompt(void)
                    191: {
                    192:   /* The prompts can even be different lengths! */
                    193:   sprintf(prompt_buf, "%s", 
                    194:     prompt ? "Hit ctrl-t to toggle prompt> " : "Pretty cool huh?> ");
                    195:   return prompt_buf;
                    196: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>