kbdterm.c

Go to the documentation of this file.
00001 
00002 #include <stdio.h>
00003 #include <stdlib.h>
00004 #include <string.h>
00005 #include <ctype.h>
00006 #include <signal.h>
00007 #include <errno.h>
00008 #include <fcntl.h>
00009 #ifndef WIN32
00010 #include <unistd.h>
00011 #include <sys/time.h>
00012 #else
00013 #include "win32.h"
00014 #include <conio.h>
00015 #endif
00016 #include <sys/types.h>
00017 #include <sys/stat.h>
00018 
00019 #include "sic_command_line.h"
00020 #include "kbdtermio.h"
00021 
00022 #include "kbdterm.h"
00023 
00024 /* This code is taken (with many thanks but no money) from the GNUPLOT package
00025  * printable characters print as themselves (insert not overwrite)
00026  * ^A moves to the beginning of the line
00027  * ^B or Left Arrow moves back a single character
00028  * ^E moves to the end of the line
00029  * ^F or Right Arrow moves forward a single character
00030  * ^K kills from current position to the end of line
00031  * ^P or Up Arrow moves back through stack if enabled
00032  * ^N or Down Arrow moves forward through stack if enabled
00033  * ^H and DEL delete the previous character
00034  * ^D deletes the current character, or EOF if line is empty
00035  * ^L/^R redraw line in case it gets trashed
00036  * ^U kills the entire line
00037  * ^W kills last word
00038  * LF and CR return the entire line regardless of the cursor postition
00039  * EOF with an empty line returns
00040  * all other characters are ignored
00041  */
00042 
00043 #define BACKSPACE 0x08                  /* ^H */
00044 #define SPACE   ' '
00045 
00046 static char cur_line[MAXBUF];   /* current contents of the line */
00047 static char sav_line[MAXBUF];   /* current contents of the line */
00048 static int cur_pos = 0;                 /* current position of the cursor */
00049 static int max_pos = 0;                 /* maximum character position */
00050 
00051 static void fix_line( );
00052 static void redraw_line( );
00053 static void clear_line( );
00054 static void clear_eoline( );
00055 static void copy_line( );
00056 
00062 void reset_kbd_line( char *prompt, char *line, int *code)
00063 {
00064         /* print the prompt if necessary */
00065         if (*code >= 0)
00066                 fputs( prompt, stderr);
00067 
00068         /* Load line if necessary */
00069         if (*code == 0) {
00070                 cur_line[0] = '\0';
00071                 cur_pos = 0;
00072                 max_pos = 0;
00073         } else {
00074                 clear_line( prompt);
00075                 copy_line( line);
00076         }
00077 }
00078 
00096 int CFC_API kbd_line( char *prompt, char *line, int *code)
00097 {
00098         int cur_char;
00099 
00100         /* set the termio so we can do our own input processing */
00101         set_termio( );
00102 
00103     reset_kbd_line( prompt, line, code);
00104 
00105         /* determine if stdin is a tty or not and will enable exit on EOF if not */
00106         if (!isatty( STDIN_FILENO)) {
00107                 if ((fgets( line, MAXBUF, stdin)) == NULL)
00108                         strcpy( line, "sic\\exit");
00109                 *code = 0;
00110                 reset_termio( );
00111                 return (int)strlen( line);
00112         }
00113 
00114         /* get characters */
00115         for (;;) {
00116         do {
00117 #ifndef WIN32
00118             cur_char = getc( stdin);
00119 #else
00120             cur_char = _getch( );
00121 #endif
00122         } while (cur_char == EOF); /* to avoid return form getc on signal */
00123 
00124                 if (cur_char == 011)
00125                         cur_char = 040;         /* ^I mapped to <SP> */
00126 
00127                 /* Convert Arrow keystrokes to Control characters: */
00128 #ifndef WIN32
00129         /* <ESC> ansi */
00130         if (cur_char == 033) {
00131             /* Get the 1st extended code. */
00132             cur_char = getc( stdin);
00133             if (cur_char == 0133) {     /* [ */
00134                 cur_char = getc( stdin);        /* Get the 2nd extended code. */
00135                 switch (cur_char) {
00136                 case 0104:              /* Left Arrow. <ESC>[D */
00137                     cur_char = 002;
00138                     break;
00139                 case 0103:              /* Right Arrow. <ESC>[C */
00140                     cur_char = 006;
00141                     break;
00142                 case 0101:              /* Up Arrow. <ESC>[A */
00143                     cur_char = 020;
00144                     break;
00145                 case 0102:              /* Down Arrow. <ESC>[B */
00146                     cur_char = 016;
00147                     break;
00148                 default:
00149                     cur_char = 0;
00150                     break;
00151                 }
00152             } else if (cur_char == 0117) {      /* "O" is keypad 1st code */
00153                 cur_char = getc( stdin);        /* Get the 2nd extended code. */
00154                 switch (cur_char) {
00155                 case 0104:              /* Left Arrow. <ESC>[D */
00156                     cur_char = 002;
00157                     break;
00158                 case 0103:              /* Right Arrow. <ESC>[C */
00159                     cur_char = 006;
00160                     break;
00161                 case 0101:              /* Up Arrow. <ESC>[A */
00162                     cur_char = 020;
00163                     break;
00164                 case 0102:              /* Down Arrow. <ESC>[B */
00165                     cur_char = 016;
00166                     break;
00167                 case 0162:              /* EDT End Of Line */
00168                     cur_char = 005;
00169                     break;
00170                 case 0123:              /* EDT Kill Line */
00171                     cur_char = 025;     /* ^U */
00172                     break;
00173                 case 0154:              /* EDT Kill Char */
00174                     cur_char = 004;     /* ^D */
00175                     break;
00176                 case 0115:              /* EDT ENTER */
00177                     cur_char = 010;
00178                     break;
00179                 case 0163:              /* EDT NEXT CHAR */
00180                     cur_char = 006;
00181                     break;
00182                 default:
00183                     cur_char = 005;     /*does not any mess... */
00184                     break;
00185                 }
00186             } else {
00187                 cur_char = 005; /*does not any mess... */
00188             }
00189         }
00190 #else
00191         if ((cur_char == 0xe0) || (cur_char == 0)) { /* Extended */
00192             cur_char = _getch();
00193 
00194             switch(cur_char) {
00195             case 0107:
00196                 cur_char = 001;
00197                 break;
00198             case 0110:
00199                 cur_char = 020;
00200                 break;
00201             case 0111:
00202                 cur_char = 0;
00203                 break;
00204             case 0113:
00205                 cur_char = 002;
00206                 break;
00207             case 0115:
00208                 cur_char = 006;
00209                 break;
00210             case 0117:
00211                 cur_char = 005;
00212                 break;
00213             case 0120:
00214                 cur_char = 016;
00215                 break;
00216             case 0121:
00217                 cur_char = 0;
00218                 break;
00219             case 0122:
00220                 cur_char = 0;
00221                 break;
00222             case 0123:
00223                 cur_char = 004;
00224                 break;
00225             default:
00226                 break;
00227             }
00228         }
00229 #endif
00230 
00231         if (isprint( cur_char)) {
00232                         int i;
00233 
00234                         for (i = max_pos; i > cur_pos; i--) {
00235                                 cur_line[i] = cur_line[i - 1];
00236                         }
00237                         putc( cur_char, stderr);
00238                         cur_line[cur_pos] = cur_char;
00239                         cur_pos += 1;
00240                         max_pos += 1;
00241                         if (cur_pos < max_pos)
00242                                 fix_line( );
00243                         cur_line[max_pos] = '\0';
00244 
00245 /* else interpret unix terminal driver characters */
00246 #ifdef VERASE
00247                 } else if (cur_char == orig_termio.c_cc[VERASE]) {
00248 
00249                         /* DEL? */
00250                         if (cur_pos > 0) {
00251                                 int i;
00252 
00253                                 cur_pos -= 1;
00254                                 putc( BACKSPACE, stderr);
00255                                 for (i = cur_pos; i < max_pos; i++)
00256                                         cur_line[i] = cur_line[i + 1];
00257                                 max_pos -= 1;
00258                                 fix_line( );
00259                         }
00260 #endif /* VERASE */
00261 #ifdef VEOF
00262                 } else if (cur_char == orig_termio.c_cc[VEOF]) {
00263 
00264                         /* ^D? */
00265                         if (max_pos == 0) {
00266                                 reset_termio( );
00267                                 *code = 0;
00268                                 return 0;
00269                         }
00270                         if ((cur_pos < max_pos) && (cur_char == 004)) {
00271 
00272                                 /* ^D */
00273                                 int i;
00274 
00275                                 for (i = cur_pos; i < max_pos; i++)
00276                                         cur_line[i] = cur_line[i + 1];
00277                                 max_pos -= 1;
00278                                 fix_line( );
00279                         }
00280 #endif /* VEOF */
00281 #ifdef VKILL
00282                 } else if (cur_char == orig_termio.c_cc[VKILL]) {
00283 
00284                         /* ^U? */
00285                         clear_line( prompt);
00286 #endif /* VKILL */
00287 #ifdef VWERASE
00288                 } else if (cur_char == orig_termio.c_cc[VWERASE]) {
00289 
00290                         /* ^W? */
00291                         while ((cur_pos > 0) && (cur_line[cur_pos - 1] == SPACE)) {
00292                                 cur_pos -= 1;
00293                                 putc( BACKSPACE, stderr);
00294                         }
00295                         while ((cur_pos > 0) && (cur_line[cur_pos - 1] != SPACE)) {
00296                                 cur_pos -= 1;
00297                                 putc( BACKSPACE, stderr);
00298                         }
00299                         clear_eoline( );
00300                         max_pos = cur_pos;
00301 #endif /* VWERASE */
00302 #ifdef VREPRINT
00303                 } else if (cur_char == orig_termio.c_cc[VREPRINT]) {
00304 
00305                         /* ^R? */
00306                         putc( '\n', stderr);    /* go to a fresh line */
00307                         redraw_line( prompt);
00308 #else /* VREPRINT */
00309 #ifdef VRPRNT                                   /* on Ultrix VREPRINT is VRPRNT */
00310                 } else if (cur_char == orig_termio.c_cc[VRPRNT]) {
00311 
00312                         /* ^R? */
00313                         putc( '\n', stderr);    /* go to a fresh line */
00314                         redraw_line( prompt);
00315 #endif /* VRPRNT */
00316 #endif /* VREPRINT */
00317 #ifdef VSUSP
00318                 } else if (cur_char == orig_termio.c_cc[VSUSP]) {
00319                         reset_termio( );
00320                         kill( 0, SIGTSTP);
00321 
00322                         /* process stops here */
00323                         set_termio( );
00324 
00325                         /* print the prompt */
00326                         redraw_line( prompt);
00327 #endif /* VSUSP */
00328                 } else {
00329 
00330                         /* do normal editing commands */
00331 
00332                         /* some of these are also done above */
00333                         int i;
00334 
00335                         switch (cur_char) {
00336                         case EOF:
00337                         case 004:                       /* ^D */
00338                                 if (cur_char == EOF || max_pos == 0) {
00339                                         reset_termio( );
00340                                         *code = 0;
00341                                         copy_line( "sic\\exit");
00342                                         fix_line( );
00343                                         putc( '\n', stderr);
00344                                         strcpy( line, cur_line);
00345                                         return (int)strlen( line);
00346                                 }
00347                                 if (cur_pos < max_pos) {
00348                                         for (i = cur_pos; i < max_pos; i++)
00349                                                 cur_line[i] = cur_line[i + 1];
00350                                         max_pos -= 1;
00351                                         fix_line( );
00352                                 }
00353                                 break;
00354                         case 001:                       /* ^A */
00355                                 while (cur_pos > 0) {
00356                                         cur_pos -= 1;
00357                                         putc( BACKSPACE, stderr);
00358                                 }
00359                                 break;
00360                         case 002:                       /* ^B */
00361                                 if (cur_pos > 0) {
00362                                         cur_pos -= 1;
00363                                         putc( BACKSPACE, stderr);
00364                                 }
00365                                 break;
00366                         case 005:                       /* ^E */
00367                                 while (cur_pos < max_pos) {
00368                                         putc( cur_line[cur_pos], stderr);
00369                                         cur_pos += 1;
00370                                 }
00371                                 break;
00372                         case 006:                       /* ^F */
00373                                 if (cur_pos < max_pos) {
00374                                         putc( cur_line[cur_pos], stderr);
00375                                         cur_pos += 1;
00376                                 }
00377                                 break;
00378                         case 013:                       /* ^K */
00379                                 clear_eoline( );
00380                                 max_pos = cur_pos;
00381                                 break;
00382 
00383                         /* Return the code to calling program */
00384                         case 020:                       /* ^P */
00385                                 if (*code < 2) {
00386                                         *code = -1;
00387                                         reset_termio( );
00388                                         return 0;
00389                                 }
00390                                 break;
00391                         case 016:                       /* ^N */
00392                                 if (*code < 2) {
00393                                         *code = 1;
00394                                         reset_termio( );
00395                                         return 0;
00396                                 }
00397                                 break;
00398 
00399                         /* go to a fresh line */
00400                         case 014:                       /* ^L */
00401                         case 022:                       /* ^R */
00402                                 putc( '\n', stderr);
00403                                 redraw_line( prompt);
00404                                 break;
00405                         case 0177:                      /* DEL */
00406                         case 010:                       /* ^H */
00407                                 if (cur_pos > 0) {
00408                                         cur_pos -= 1;
00409                                         putc( BACKSPACE, stderr);
00410                                         for (i = cur_pos; i < max_pos; i++)
00411                                                 cur_line[i] = cur_line[i + 1];
00412                                         max_pos -= 1;
00413                                         fix_line( );
00414                                 }
00415                                 break;
00416                         case 025:                       /* ^U */
00417                                 clear_line( prompt);
00418                                 break;
00419                         case 027:                       /* ^W */
00420                                 while ((cur_pos > 0) && (cur_line[cur_pos - 1] == SPACE)) {
00421                                         cur_pos -= 1;
00422                                         putc( BACKSPACE, stderr);
00423                                 }
00424                                 while ((cur_pos > 0) && (cur_line[cur_pos - 1] != SPACE)) {
00425                                         cur_pos -= 1;
00426                                         putc( BACKSPACE, stderr);
00427                                 }
00428                                 clear_eoline( );
00429                                 max_pos = cur_pos;
00430                                 break;
00431                                 break;
00432 
00433                         /* OK end of input */
00434                         case '\n':                      /* ^J */
00435                         case '\r':                      /* ^M */
00436                                 cur_line[max_pos + 1] = '\0';
00437                                 putc( '\n', stderr);
00438                                 reset_termio( );
00439                                 *code = 0;
00440                                 strcpy( line, cur_line);
00441                                 return (int)strlen( cur_line);
00442                         default:
00443                                 break;
00444                         }                                       /* End switch */
00445                 }                                               /* End Else */
00446         }                                                       /* End For */
00447 }                                                               /* End Code */
00448 
00449 
00450 /* fix up the line from cur_pos to max_pos
00451  * do not need any terminal capabilities except backspace,
00452  * and space overwrites a character
00453  */
00454 static void fix_line( )
00455 {
00456         int i;
00457 
00458         /* write tail of string */
00459         for (i = cur_pos; i < max_pos; i++)
00460                 putc( cur_line[i], stderr);
00461 
00462         /* write a space at the end of the line in case we deleted one */
00463         putc( SPACE, stderr);
00464 
00465         /* backup to original position */
00466         for (i = max_pos + 1; i > cur_pos; i--)
00467                 putc( BACKSPACE, stderr);
00468 }
00469 
00470 
00471 /* redraw the entire line, putting the cursor where it belongs */
00472 static void redraw_line( prompt)
00473 char *prompt;
00474 {
00475         int i;
00476 
00477         fputs( prompt, stderr);
00478         fputs( cur_line, stderr);
00479 
00480         /* put the cursor where it belongs */
00481         for (i = max_pos; i > cur_pos; i--)
00482                 putc( BACKSPACE, stderr);
00483 }
00484 
00485 
00486 /* clear cur_line and the screen line */
00487 static void clear_line( prompt)
00488 char *prompt;
00489 {
00490         int i;
00491 
00492         for (i = 0; i < max_pos; i++)
00493                 sav_line[i] = cur_line[i];
00494         sav_line[i] = '\0';
00495         for (i = 0; i < max_pos; i++)
00496                 cur_line[i] = '\0';
00497         for (i = cur_pos; i > 0; i--)
00498                 putc( BACKSPACE, stderr);
00499         for (i = 0; i < max_pos; i++)
00500                 putc( SPACE, stderr);
00501         putc( '\r', stderr);
00502         fputs( prompt, stderr);
00503         cur_pos = 0;
00504         max_pos = 0;
00505 }
00506 
00507 /* clear to end of line and the screen end of line */
00508 static void clear_eoline( prompt)
00509 char *prompt;
00510 {
00511         int i;
00512 
00513         for (i = 0; i < max_pos - cur_pos; i++)
00514                 sav_line[i] = cur_line[i + cur_pos];
00515         sav_line[i] = '\0';
00516         for (i = cur_pos; i < max_pos; i++)
00517                 cur_line[i] = '\0';
00518         for (i = cur_pos; i < max_pos; i++)
00519                 putc( SPACE, stderr);
00520         for (i = cur_pos; i < max_pos; i++)
00521                 putc( BACKSPACE, stderr);
00522 }
00523 
00524 
00525 /* copy line to cur_line, draw it and set cur_pos and max_pos */
00526 static void copy_line( line)
00527 char *line;
00528 {
00529         strcpy( cur_line, line);
00530         fputs( cur_line, stderr);
00531         cur_pos = max_pos = (int)strlen( cur_line);
00532 }
00533 
00534 /* End of READ_LINE */
00535 

Generated on Tue Mar 13 15:15:40 2007 for SIC by  doxygen 1.5.1