Annotation of OpenXM_contrib/gnuplot/readline.c, Revision 1.1
1.1 ! maekawa 1: #ifndef lint
! 2: static char *RCSid = "$Id: readline.c,v 1.69 1998/04/14 00:16:12 drd Exp $";
! 3: #endif
! 4:
! 5: /* GNUPLOT - readline.c */
! 6:
! 7: /*[
! 8: * Copyright 1986 - 1993, 1998 Thomas Williams, Colin Kelley
! 9: *
! 10: * Permission to use, copy, and distribute this software and its
! 11: * documentation for any purpose with or without fee is hereby granted,
! 12: * provided that the above copyright notice appear in all copies and
! 13: * that both that copyright notice and this permission notice appear
! 14: * in supporting documentation.
! 15: *
! 16: * Permission to modify the software is granted, but not the right to
! 17: * distribute the complete modified source code. Modifications are to
! 18: * be distributed as patches to the released version. Permission to
! 19: * distribute binaries produced by compiling modified sources is granted,
! 20: * provided you
! 21: * 1. distribute the corresponding source modifications from the
! 22: * released version in the form of a patch file along with the binaries,
! 23: * 2. add special version identification to distinguish your version
! 24: * in addition to the base release version number,
! 25: * 3. provide your name and address as the primary contact for the
! 26: * support of your modified version, and
! 27: * 4. retain our contact information in regard to use of the base
! 28: * software.
! 29: * Permission to distribute the released version of the source code along
! 30: * with corresponding source modifications in the form of a patch file is
! 31: * granted with same provisions 2 through 4 for binary distributions.
! 32: *
! 33: * This software is provided "as is" without express or implied warranty
! 34: * to the extent permitted by applicable law.
! 35: ]*/
! 36:
! 37:
! 38: /*
! 39: * AUTHORS
! 40: *
! 41: * Original Software:
! 42: * Tom Tkacik
! 43: *
! 44: * Msdos port and some enhancements:
! 45: * Gershon Elber and many others.
! 46: *
! 47: * In add_history(), do not store duplicated entries:
! 48: * Petr Mikulik
! 49: */
! 50:
! 51: #include <signal.h>
! 52: /* get prototype for alloc and gpfaralloc */
! 53: #include "plot.h"
! 54:
! 55: #if defined(READLINE) && !defined(GNU_READLINE)
! 56:
! 57: /* a small portable version of GNU's readline
! 58: * this is not the BASH or GNU EMACS version of READLINE due to Copyleft
! 59: * restrictions
! 60: * do not need any terminal capabilities except backspace,
! 61: * and space overwrites a character
! 62: */
! 63:
! 64: /* NANO-EMACS line editing facility
! 65: * printable characters print as themselves (insert not overwrite)
! 66: * ^A moves to the beginning of the line
! 67: * ^B moves back a single character
! 68: * ^E moves to the end of the line
! 69: * ^F moves forward a single character
! 70: * ^K kills from current position to the end of line
! 71: * ^P moves back through history
! 72: * ^N moves forward through history
! 73: * ^H and DEL delete the previous character
! 74: * ^D deletes the current character, or EOF if line is empty
! 75: * ^L/^R redraw line in case it gets trashed
! 76: * ^U kills the entire line
! 77: * ^W kills last word
! 78: * LF and CR return the entire line regardless of the cursor postition
! 79: * EOF with an empty line returns (char *)NULL
! 80: *
! 81: * all other characters are ignored
! 82: */
! 83:
! 84: #ifdef __linux__
! 85: /* HBB: to get prototype for ioctl() */
! 86: # include <sys/ioctl.h>
! 87: #endif
! 88:
! 89: /* replaces the previous klugde in configure */
! 90: #if defined(HAVE_TERMIOS_H) && defined(HAVE_TCGETATTR)
! 91: # define TERMIOS
! 92: #else /* not HAVE_TERMIOS_H && HAVE_TCGETATTR */
! 93: # ifdef HAVE_SGTTY_H
! 94: # define SGTTY
! 95: # endif
! 96: #endif /* not HAVE_TERMIOS_H && HAVE_TCGETATTR */
! 97:
! 98: #if !defined(MSDOS) && !defined(ATARI) && !defined(MTOS) && !defined(_Windows) && !defined(DOS386) && !defined(OSK)
! 99:
! 100: /*
! 101: * Set up structures using the proper include file
! 102: */
! 103: # if defined(_IBMR2) || defined(alliant)
! 104: # define SGTTY
! 105: # endif
! 106:
! 107: /* submitted by Francois.Dagorn@cicb.fr */
! 108: # ifdef SGTTY
! 109: # include <sgtty.h>
! 110: static struct sgttyb orig_termio, rl_termio;
! 111: /* define terminal control characters */
! 112: static struct tchars s_tchars;
! 113: # ifndef VERASE
! 114: # define VERASE 0
! 115: # endif /* not VERASE */
! 116: # ifndef VEOF
! 117: # define VEOF 1
! 118: # endif /* not VEOF */
! 119: # ifndef VKILL
! 120: # define VKILL 2
! 121: # endif /* not VKILL */
! 122: # ifdef TIOCGLTC /* available only with the 'new' line discipline */
! 123: static struct ltchars s_ltchars;
! 124: # ifndef VWERASE
! 125: # define VWERASE 3
! 126: # endif /* not VWERASE */
! 127: # ifndef VREPRINT
! 128: # define VREPRINT 4
! 129: # endif /* not VREPRINT */
! 130: # ifndef VSUSP
! 131: # define VSUSP 5
! 132: # endif /* not VSUP */
! 133: # endif /* TIOCGLTC */
! 134: # ifndef NCCS
! 135: # define NCCS 6
! 136: # endif /* not NCCS */
! 137:
! 138: # else /* not SGTTY */
! 139:
! 140: /* SIGTSTP defines job control
! 141: * if there is job control then we need termios.h instead of termio.h
! 142: * (Are there any systems with job control that use termio.h? I hope not.)
! 143: */
! 144: # if defined(SIGTSTP) || defined(TERMIOS)
! 145: # ifndef TERMIOS
! 146: # define TERMIOS
! 147: # endif /* not TERMIOS */
! 148: # include <termios.h>
! 149: /* Added by Robert Eckardt, RobertE@beta.TP2.Ruhr-Uni-Bochum.de */
! 150: # ifdef ISC22
! 151: # ifndef ONOCR /* taken from sys/termio.h */
! 152: # define ONOCR 0000020 /* true at least for ISC 2.2 */
! 153: # endif /* not ONOCR */
! 154: # ifndef IUCLC
! 155: # define IUCLC 0001000
! 156: # endif /* not IUCLC */
! 157: # endif /* ISC22 */
! 158: # if !defined(IUCLC)
! 159: /* translate upper to lower case not supported */
! 160: # define IUCLC 0
! 161: # endif /* not IUCLC */
! 162:
! 163: static struct termios orig_termio, rl_termio;
! 164: # else /* not SIGSTP || TERMIOS */
! 165: # include <termio.h>
! 166: static struct termio orig_termio, rl_termio;
! 167: /* termio defines NCC instead of NCCS */
! 168: # define NCCS NCC
! 169: # endif /* not SIGTSTP || TERMIOS */
! 170: # endif /* SGTTY */
! 171:
! 172: /* ULTRIX defines VRPRNT instead of VREPRINT */
! 173: # if defined(VRPRNT) && !defined(VREPRINT)
! 174: # define VREPRINT VRPRNT
! 175: # endif /* VRPRNT */
! 176:
! 177: /* define characters to use with our input character handler */
! 178: static char term_chars[NCCS];
! 179:
! 180: static int term_set = 0; /* =1 if rl_termio set */
! 181:
! 182: #define special_getc() ansi_getc()
! 183: static int ansi_getc __PROTO((void));
! 184:
! 185: #else /* MSDOS or ATARI or MTOS or _Windows or DOS386 or OSK */
! 186:
! 187: # ifdef _Windows
! 188: # include <windows.h>
! 189: # include "win/wtext.h"
! 190: # include "win/wgnuplib.h"
! 191: extern TW textwin;
! 192: # define TEXTUSER 0xf1
! 193: # define TEXTGNUPLOT 0xf0
! 194: # define special_getc() msdos_getch()
! 195: static char msdos_getch __PROTO((void)); /* HBB 980308: PROTO'ed it */
! 196: # endif /* _Windows */
! 197:
! 198: # if defined(MSDOS) || defined(DOS386)
! 199: /* MSDOS specific stuff */
! 200: # ifdef DJGPP
! 201: # include <pc.h>
! 202: # endif /* DJGPP */
! 203: # ifdef __EMX__
! 204: # include <conio.h>
! 205: # endif /* __EMX__ */
! 206: # define special_getc() msdos_getch()
! 207: static char msdos_getch();
! 208: # endif /* MSDOS || DOS386 */
! 209:
! 210: # ifdef OSK
! 211: # include <sgstat.h>
! 212: # include <modes.h>
! 213:
! 214: # define STDIN 0
! 215: static int term_set = 0; /* =1 if new_settings is set */
! 216:
! 217: static struct _sgs old_settings; /* old terminal settings */
! 218: static struct _sgs new_settings; /* new terminal settings */
! 219:
! 220: # define special_getc() ansi_getc()
! 221: static int ansi_getc __PROTO((void));
! 222:
! 223: /* On OS9 a '\n' is a character 13 and '\r' == '\n'. This gives troubles
! 224: here, so we need a new putc wich handles this correctly and print a
! 225: character 10 on each place we want a '\n'.
! 226: */
! 227: # undef putc /* Undefine the macro for putc */
! 228:
! 229: static int putc(c, fp)
! 230: char c;
! 231: FILE *fp;
! 232: {
! 233: write(fileno(fp), &c, 1);
! 234: if (c == '\012') { /* A normal ASCII '\n' */
! 235: c = '\r';
! 236: write(fileno(fp), &c, 1);
! 237: }
! 238: }
! 239:
! 240: # endif /* OSK */
! 241:
! 242: # if defined(ATARI) || defined(MTOS)
! 243: # define special_getc() tos_getch()
! 244: # endif /* ATARI || MTOS */
! 245:
! 246: #endif /* MSDOS or ATARI or MTOS or _Windows or DOS386 or OSK */
! 247:
! 248: #ifdef OS2
! 249: # if defined( special_getc )
! 250: # undef special_getc()
! 251: # endif /* special_getc */
! 252: # define special_getc() msdos_getch()
! 253: static char msdos_getch __PROTO((void)); /* HBB 980308: PROTO'ed it */
! 254: #endif /* OS2 */
! 255:
! 256:
! 257: /* initial size and increment of input line length */
! 258: #define MAXBUF 1024
! 259: /* ^H */
! 260: #define BACKSPACE 0x08
! 261: #define SPACE ' '
! 262:
! 263: #ifdef OSK
! 264: # define NEWLINE '\012'
! 265: #else /* OSK */
! 266: # define NEWLINE '\n'
! 267: #endif /* not OSK */
! 268:
! 269: struct hist {
! 270: char *line;
! 271: struct hist *prev;
! 272: struct hist *next;
! 273: };
! 274:
! 275: static struct hist *history = NULL; /* no history yet */
! 276: static struct hist *cur_entry = NULL;
! 277:
! 278: static char *cur_line; /* current contents of the line */
! 279: static int line_len = 0;
! 280: static int cur_pos = 0; /* current position of the cursor */
! 281: static int max_pos = 0; /* maximum character position */
! 282:
! 283:
! 284: static void fix_line __PROTO((void));
! 285: static void redraw_line __PROTO((char *prompt));
! 286: static void clear_line __PROTO((char *prompt));
! 287: static void clear_eoline __PROTO((void));
! 288: static void copy_line __PROTO((char *line));
! 289: static void set_termio __PROTO((void));
! 290: static void reset_termio __PROTO((void));
! 291: static int ansi_getc __PROTO((void));
! 292: static int user_putc __PROTO((int ch));
! 293: static int user_puts __PROTO((char *str));
! 294: static void backspace __PROTO((void));
! 295: static void extend_cur_line __PROTO((void));
! 296:
! 297: /* user_putc and user_puts should be used in the place of
! 298: * fputc(ch,stderr) and fputs(str,stderr) for all output
! 299: * of user typed characters. This allows MS-Windows to
! 300: * display user input in a different color.
! 301: */
! 302: static int user_putc(ch)
! 303: int ch;
! 304: {
! 305: int rv;
! 306: #ifdef _Windows
! 307: TextAttr(&textwin, TEXTUSER);
! 308: #endif
! 309: rv = fputc(ch, stderr);
! 310: #ifdef _Windows
! 311: TextAttr(&textwin, TEXTGNUPLOT);
! 312: #endif
! 313: return rv;
! 314: }
! 315:
! 316: static int user_puts(str)
! 317: char *str;
! 318: {
! 319: int rv;
! 320: #ifdef _Windows
! 321: TextAttr(&textwin, TEXTUSER);
! 322: #endif
! 323: rv = fputs(str, stderr);
! 324: #ifdef _Windows
! 325: TextAttr(&textwin, TEXTGNUPLOT);
! 326: #endif
! 327: return rv;
! 328: }
! 329:
! 330: /* This function provides a centralized non-destructive backspace capability
! 331: * M. Castro
! 332: */
! 333: static void backspace()
! 334: {
! 335: user_putc(BACKSPACE);
! 336: }
! 337:
! 338: static void extend_cur_line()
! 339: {
! 340: char *new_line;
! 341:
! 342: /* extent input line length */
! 343: new_line = gp_realloc(cur_line, line_len + MAXBUF, NULL);
! 344: if (!new_line) {
! 345: reset_termio();
! 346: int_error("Can't extend readline length", NO_CARET);
! 347: }
! 348: cur_line = new_line;
! 349: line_len += MAXBUF;
! 350: FPRINTF((stderr, "\nextending readline length to %d chars\n", line_len));
! 351: }
! 352:
! 353: char *
! 354: readline(prompt)
! 355: char *prompt;
! 356: {
! 357:
! 358: int cur_char;
! 359: char *new_line;
! 360:
! 361: /* start with a string of MAXBUF chars */
! 362:
! 363: if (line_len != 0) {
! 364: free(cur_line);
! 365: line_len = 0;
! 366: }
! 367: cur_line = gp_alloc((unsigned long) MAXBUF, "readline");
! 368: line_len = MAXBUF;
! 369:
! 370: /* set the termio so we can do our own input processing */
! 371: set_termio();
! 372:
! 373: /* print the prompt */
! 374: fputs(prompt, stderr);
! 375: cur_line[0] = '\0';
! 376: cur_pos = 0;
! 377: max_pos = 0;
! 378: cur_entry = NULL;
! 379:
! 380: /* get characters */
! 381: for (;;) {
! 382: cur_char = special_getc();
! 383:
! 384: /*
! 385: * The #define CHARSET7BIT should be used when one encounters problems with
! 386: * 8bit characters that should not be entered on the commandline. I cannot
! 387: * think on any reasonable example where this could happen, but what do I know?
! 388: * After all, the unix world still ignores 8bit chars in most applications.
! 389: *
! 390: * Note that latin1 defines the chars 0x80-0x9f as control chars. For the
! 391: * benefit of Atari, MSDOS, Windows and NeXT I have decided to ignore this,
! 392: * since it would require more #ifs.
! 393: *
! 394: */
! 395:
! 396: #ifdef CHARSET7BIT
! 397: if (isprint(cur_char)) {
! 398: #else /* CHARSET7BIT */
! 399: if (isprint(cur_char) || (((unsigned char) cur_char > 0x7f) &&
! 400: cur_char != EOF)) {
! 401: #endif /* CHARSET7BIT */
! 402: int i;
! 403:
! 404: if (max_pos + 1 >= line_len) {
! 405: extend_cur_line();
! 406: }
! 407: for (i = max_pos; i > cur_pos; i--) {
! 408: cur_line[i] = cur_line[i - 1];
! 409: }
! 410: user_putc(cur_char);
! 411: cur_line[cur_pos] = cur_char;
! 412: cur_pos += 1;
! 413: max_pos += 1;
! 414: if (cur_pos < max_pos)
! 415: fix_line();
! 416: cur_line[max_pos] = '\0';
! 417:
! 418: /* else interpret unix terminal driver characters */
! 419: #ifdef VERASE
! 420: } else if (cur_char == term_chars[VERASE]) { /* DEL? */
! 421: if (cur_pos > 0) {
! 422: int i;
! 423: cur_pos -= 1;
! 424: backspace();
! 425: for (i = cur_pos; i < max_pos; i++)
! 426: cur_line[i] = cur_line[i + 1];
! 427: max_pos -= 1;
! 428: fix_line();
! 429: }
! 430: #endif /* VERASE */
! 431: #ifdef VEOF
! 432: } else if (cur_char == term_chars[VEOF]) { /* ^D? */
! 433: if (max_pos == 0) {
! 434: reset_termio();
! 435: return ((char *) NULL);
! 436: }
! 437: if ((cur_pos < max_pos) && (cur_char == 004)) { /* ^D */
! 438: int i;
! 439: for (i = cur_pos; i < max_pos; i++)
! 440: cur_line[i] = cur_line[i + 1];
! 441: max_pos -= 1;
! 442: fix_line();
! 443: }
! 444: #endif /* VEOF */
! 445: #ifdef VKILL
! 446: } else if (cur_char == term_chars[VKILL]) { /* ^U? */
! 447: clear_line(prompt);
! 448: #endif /* VKILL */
! 449: #ifdef VWERASE
! 450: } else if (cur_char == term_chars[VWERASE]) { /* ^W? */
! 451: while ((cur_pos > 0) &&
! 452: (cur_line[cur_pos - 1] == SPACE)) {
! 453: cur_pos -= 1;
! 454: backspace();
! 455: }
! 456: while ((cur_pos > 0) &&
! 457: (cur_line[cur_pos - 1] != SPACE)) {
! 458: cur_pos -= 1;
! 459: backspace();
! 460: }
! 461: clear_eoline();
! 462: max_pos = cur_pos;
! 463: #endif /* VWERASE */
! 464: #ifdef VREPRINT
! 465: } else if (cur_char == term_chars[VREPRINT]) { /* ^R? */
! 466: putc(NEWLINE, stderr); /* go to a fresh line */
! 467: redraw_line(prompt);
! 468: #endif /* VREPRINT */
! 469: #ifdef VSUSP
! 470: } else if (cur_char == term_chars[VSUSP]) {
! 471: reset_termio();
! 472: kill(0, SIGTSTP);
! 473:
! 474: /* process stops here */
! 475:
! 476: set_termio();
! 477: /* print the prompt */
! 478: redraw_line(prompt);
! 479: #endif /* VSUSP */
! 480: } else {
! 481: /* do normal editing commands */
! 482: /* some of these are also done above */
! 483: int i;
! 484: switch (cur_char) {
! 485: case EOF:
! 486: reset_termio();
! 487: return ((char *) NULL);
! 488: case 001: /* ^A */
! 489: while (cur_pos > 0) {
! 490: cur_pos -= 1;
! 491: backspace();
! 492: }
! 493: break;
! 494: case 002: /* ^B */
! 495: if (cur_pos > 0) {
! 496: cur_pos -= 1;
! 497: backspace();
! 498: }
! 499: break;
! 500: case 005: /* ^E */
! 501: while (cur_pos < max_pos) {
! 502: user_putc(cur_line[cur_pos]);
! 503: cur_pos += 1;
! 504: }
! 505: break;
! 506: case 006: /* ^F */
! 507: if (cur_pos < max_pos) {
! 508: user_putc(cur_line[cur_pos]);
! 509: cur_pos += 1;
! 510: }
! 511: break;
! 512: case 013: /* ^K */
! 513: clear_eoline();
! 514: max_pos = cur_pos;
! 515: break;
! 516: case 020: /* ^P */
! 517: if (history != NULL) {
! 518: if (cur_entry == NULL) {
! 519: cur_entry = history;
! 520: clear_line(prompt);
! 521: copy_line(cur_entry->line);
! 522: } else if (cur_entry->prev != NULL) {
! 523: cur_entry = cur_entry->prev;
! 524: clear_line(prompt);
! 525: copy_line(cur_entry->line);
! 526: }
! 527: }
! 528: break;
! 529: case 016: /* ^N */
! 530: if (cur_entry != NULL) {
! 531: cur_entry = cur_entry->next;
! 532: clear_line(prompt);
! 533: if (cur_entry != NULL)
! 534: copy_line(cur_entry->line);
! 535: else
! 536: cur_pos = max_pos = 0;
! 537: }
! 538: break;
! 539: case 014: /* ^L */
! 540: case 022: /* ^R */
! 541: putc(NEWLINE, stderr); /* go to a fresh line */
! 542: redraw_line(prompt);
! 543: break;
! 544: case 0177: /* DEL */
! 545: case 010: /* ^H */
! 546: if (cur_pos > 0) {
! 547: cur_pos -= 1;
! 548: backspace();
! 549: for (i = cur_pos; i < max_pos; i++)
! 550: cur_line[i] = cur_line[i + 1];
! 551: max_pos -= 1;
! 552: fix_line();
! 553: }
! 554: break;
! 555: case 004: /* ^D */
! 556: if (max_pos == 0) {
! 557: reset_termio();
! 558: return ((char *) NULL);
! 559: }
! 560: if (cur_pos < max_pos) {
! 561: for (i = cur_pos; i < max_pos; i++)
! 562: cur_line[i] = cur_line[i + 1];
! 563: max_pos -= 1;
! 564: fix_line();
! 565: }
! 566: break;
! 567: case 025: /* ^U */
! 568: clear_line(prompt);
! 569: break;
! 570: case 027: /* ^W */
! 571: while ((cur_pos > 0) &&
! 572: (cur_line[cur_pos - 1] == SPACE)) {
! 573: cur_pos -= 1;
! 574: backspace();
! 575: }
! 576: while ((cur_pos > 0) &&
! 577: (cur_line[cur_pos - 1] != SPACE)) {
! 578: cur_pos -= 1;
! 579: backspace();
! 580: }
! 581: clear_eoline();
! 582: max_pos = cur_pos;
! 583: break;
! 584: case '\n': /* ^J */
! 585: #ifndef OSK
! 586: case '\r': /* ^M */
! 587: #endif
! 588: cur_line[max_pos + 1] = '\0';
! 589: #ifdef OS2
! 590: while (cur_pos < max_pos) {
! 591: user_putc(cur_line[cur_pos]);
! 592: cur_pos += 1;
! 593: }
! 594: #endif
! 595: putc(NEWLINE, stderr);
! 596:
! 597: /* Shrink the block down to fit the string ?
! 598: * if the alloc fails, we still own block at cur_line,
! 599: * but this shouldn't really fail.
! 600: */
! 601: new_line = (char *) gp_realloc(cur_line, (unsigned long) (strlen(cur_line) + 1), "line resize");
! 602: if (new_line)
! 603: cur_line = new_line;
! 604: /* else we just hang on to what we had - it's not a problem */
! 605:
! 606: line_len = 0;
! 607: FPRINTF((stderr, "Resizing input line to %d chars\n", strlen(cur_line)));
! 608: reset_termio();
! 609: return (cur_line);
! 610: default:
! 611: break;
! 612: }
! 613: }
! 614: }
! 615: }
! 616:
! 617: /* fix up the line from cur_pos to max_pos
! 618: * do not need any terminal capabilities except backspace,
! 619: * and space overwrites a character
! 620: */
! 621: static void fix_line()
! 622: {
! 623: int i;
! 624:
! 625: /* write tail of string */
! 626: for (i = cur_pos; i < max_pos; i++)
! 627: user_putc(cur_line[i]);
! 628:
! 629: /* write a space at the end of the line in case we deleted one */
! 630: user_putc(SPACE);
! 631:
! 632: /* backup to original position */
! 633: for (i = max_pos + 1; i > cur_pos; i--)
! 634: backspace();
! 635:
! 636: }
! 637:
! 638: /* redraw the entire line, putting the cursor where it belongs */
! 639: static void redraw_line(prompt)
! 640: char *prompt;
! 641: {
! 642: int i;
! 643:
! 644: fputs(prompt, stderr);
! 645: user_puts(cur_line);
! 646:
! 647: /* put the cursor where it belongs */
! 648: for (i = max_pos; i > cur_pos; i--)
! 649: backspace();
! 650: }
! 651:
! 652: /* clear cur_line and the screen line */
! 653: static void clear_line(prompt)
! 654: char *prompt;
! 655: {
! 656: int i;
! 657: for (i = 0; i < max_pos; i++)
! 658: cur_line[i] = '\0';
! 659:
! 660: for (i = cur_pos; i > 0; i--)
! 661: backspace();
! 662:
! 663: for (i = 0; i < max_pos; i++)
! 664: putc(SPACE, stderr);
! 665:
! 666: putc('\r', stderr);
! 667: fputs(prompt, stderr);
! 668:
! 669: cur_pos = 0;
! 670: max_pos = 0;
! 671: }
! 672:
! 673: /* clear to end of line and the screen end of line */
! 674: static void clear_eoline()
! 675: {
! 676: int i;
! 677: for (i = cur_pos; i < max_pos; i++)
! 678: cur_line[i] = '\0';
! 679:
! 680: for (i = cur_pos; i < max_pos; i++)
! 681: putc(SPACE, stderr);
! 682: for (i = cur_pos; i < max_pos; i++)
! 683: backspace();
! 684: }
! 685:
! 686: /* copy line to cur_line, draw it and set cur_pos and max_pos */
! 687: static void copy_line(line)
! 688: char *line;
! 689: {
! 690: while (strlen(line) + 1 > line_len) {
! 691: extend_cur_line();
! 692: }
! 693: strcpy(cur_line, line);
! 694: user_puts(cur_line);
! 695: cur_pos = max_pos = strlen(cur_line);
! 696: }
! 697:
! 698: /* add line to the history */
! 699: void add_history(line)
! 700: char *line;
! 701: {
! 702: struct hist *entry;
! 703:
! 704: entry = history;
! 705: while (entry != NULL) {
! 706: /* Don't store duplicate entries */
! 707: if (!strcmp(entry->line, line)) {
! 708: /* cmd lines are equal, relink entry that was found last */
! 709: if (entry->next == NULL) {
! 710: /* previous command repeated, no change */
! 711: return;
! 712: }
! 713: if (entry->prev == NULL) {
! 714: /* current cmd line equals the first in the history */
! 715: (entry->next)->prev = NULL;
! 716: history->next = entry;
! 717: entry->prev = history;
! 718: entry->next = NULL;
! 719: history = entry;
! 720: return;
! 721: }
! 722: /* bridge over entry's vacancy, then move it to the end */
! 723: (entry->prev)->next = entry->next;
! 724: (entry->next)->prev = entry->prev;
! 725: entry->prev = history;
! 726: history->next = entry;
! 727: entry->next = NULL;
! 728: history = entry;
! 729: return;
! 730: }
! 731: entry = entry->prev;
! 732: } /* end of not-storing duplicated entries */
! 733:
! 734: entry = (struct hist *) gp_alloc((unsigned long) sizeof(struct hist), "history");
! 735: entry->line = gp_alloc((unsigned long) (strlen(line) + 1), "history");
! 736: strcpy(entry->line, line);
! 737:
! 738: entry->prev = history;
! 739: entry->next = NULL;
! 740: if (history != NULL) {
! 741: history->next = entry;
! 742: }
! 743: history = entry;
! 744: }
! 745:
! 746:
! 747: /* Convert ANSI arrow keys to control characters */
! 748: static int ansi_getc()
! 749: {
! 750: int c = getc(stdin);
! 751: if (c == 033) {
! 752: c = getc(stdin); /* check for CSI */
! 753: if (c == '[') {
! 754: c = getc(stdin); /* get command character */
! 755: switch (c) {
! 756: case 'D': /* left arrow key */
! 757: c = 002;
! 758: break;
! 759: case 'C': /* right arrow key */
! 760: c = 006;
! 761: break;
! 762: case 'A': /* up arrow key */
! 763: c = 020;
! 764: break;
! 765: case 'B': /* down arrow key */
! 766: c = 016;
! 767: break;
! 768: }
! 769: }
! 770: }
! 771: return c;
! 772: }
! 773:
! 774: #if defined(MSDOS) || defined(_Windows) || defined(DOS386) || defined(OS2)
! 775:
! 776: /* Convert Arrow keystrokes to Control characters: */
! 777: static char msdos_getch()
! 778: {
! 779: #ifdef DJGPP
! 780: char c;
! 781: int ch = getkey();
! 782: c = (ch & 0xff00) ? 0 : ch & 0xff;
! 783: #else /* not DJGPP */
! 784: # ifdef OS2
! 785: char c = getc(stdin);
! 786: # else /* not OS2 */
! 787: char c = getch();
! 788: # endif /* not OS2 */
! 789: #endif /* not DJGPP */
! 790:
! 791: if (c == 0) {
! 792: #ifdef DJGPP
! 793: c = ch & 0xff;
! 794: #else /* not DJGPP */
! 795: # ifdef OS2
! 796: c = getc(stdin);
! 797: # else /* not OS2 */
! 798: c = getch(); /* Get the extended code. */
! 799: # endif /* not OS2 */
! 800: #endif /* not DJGPP */
! 801: switch (c) {
! 802: case 75: /* Left Arrow. */
! 803: c = 002;
! 804: break;
! 805: case 77: /* Right Arrow. */
! 806: c = 006;
! 807: break;
! 808: case 72: /* Up Arrow. */
! 809: c = 020;
! 810: break;
! 811: case 80: /* Down Arrow. */
! 812: c = 016;
! 813: break;
! 814: case 115: /* Ctl Left Arrow. */
! 815: case 71: /* Home */
! 816: c = 001;
! 817: break;
! 818: case 116: /* Ctl Right Arrow. */
! 819: case 79: /* End */
! 820: c = 005;
! 821: break;
! 822: case 83: /* Delete */
! 823: c = 004;
! 824: break;
! 825: default:
! 826: c = 0;
! 827: break;
! 828: }
! 829: } else if (c == 033) { /* ESC */
! 830: c = 025;
! 831: }
! 832: return c;
! 833: }
! 834:
! 835: #endif /* MSDOS || _Windows || DOS386 || OS2 */
! 836:
! 837:
! 838: #if defined(ATARI) || defined(MTOS)
! 839:
! 840: /* Convert Arrow keystrokes to Control characters: TOS version */
! 841:
! 842: long poll_events(int); /* from term/atariaes.trm */
! 843:
! 844: /* this function is used in help.c as well. this means that the
! 845: * program doesn't work without -DREADLINE (which would be the case
! 846: * if help.c didn't use it as well, since no events would be processed)
! 847: */
! 848: char tos_getch()
! 849: {
! 850: long rawkey;
! 851: char c;
! 852: int scan_code;
! 853: static int in_help = 0;
! 854:
! 855: if (strcmp(term->name, "atari") == 0)
! 856: poll_events(0);
! 857:
! 858: if (in_help) {
! 859: switch (in_help) {
! 860: case 1:
! 861: case 5:
! 862: in_help++;
! 863: return 'e';
! 864: case 2:
! 865: case 6:
! 866: in_help++;
! 867: return 'l';
! 868: case 3:
! 869: case 7:
! 870: in_help++;
! 871: return 'p';
! 872: case 4:
! 873: in_help = 0;
! 874: return 0x0d;
! 875: case 8:
! 876: in_help = 0;
! 877: return ' ';
! 878: }
! 879: }
! 880: if (strcmp(term->name, "atari") == 0) {
! 881: do {
! 882: if (Bconstat(2))
! 883: rawkey = Cnecin();
! 884: else
! 885: rawkey = poll_events(1);
! 886: } while (rawkey == 0);
! 887: } else
! 888: rawkey = Cnecin();
! 889:
! 890: c = (char) rawkey;
! 891: scan_code = ((int) (rawkey >> 16)) & 0xff; /* get the scancode */
! 892: if (Kbshift(-1) & 0x00000007)
! 893: scan_code |= 0x80; /* shift or control ? */
! 894:
! 895: switch (scan_code) {
! 896: case 0x62: /* HELP */
! 897: case 0xe2: /* shift HELP */
! 898: if (max_pos == 0) {
! 899: if (scan_code == 0x62) {
! 900: in_help = 1;
! 901: } else {
! 902: in_help = 5;
! 903: }
! 904: return 'h';
! 905: } else {
! 906: return 0;
! 907: }
! 908: case 0x48: /* Up Arrow */
! 909: return 0x10; /* ^P */
! 910: case 0x50: /* Down Arrow */
! 911: return 0x0e; /* ^N */
! 912: case 0x4b: /* Left Arrow */
! 913: return 0x02; /* ^B */
! 914: case 0x4d: /* Right Arrow */
! 915: return 0x06; /* ^F */
! 916: case 0xcb: /* Shift Left Arrow */
! 917: case 0xf3: /* Ctrl Left Arrow (TOS-bug ?) */
! 918: case 0x47: /* Home */
! 919: return 0x01; /* ^A */
! 920: case 0xcd: /* Shift Right Arrow */
! 921: case 0xf4: /* Ctrl Right Arrow (TOS-bug ?) */
! 922: case 0xc7: /* Shift Home */
! 923: case 0xf7: /* Ctrl Home */
! 924: return 0x05; /* ^E */
! 925: case 0x61: /* Undo - redraw line */
! 926: return 0x0c; /* ^L */
! 927: default:
! 928: if (c == 0x1b)
! 929: return 0x15; /* ESC becomes ^U */
! 930: if (c == 0x7f)
! 931: return 0x04; /* Del becomes ^D */
! 932: break;
! 933: }
! 934: return c;
! 935: }
! 936:
! 937: #endif /* ATARI || MTOS */
! 938:
! 939: /* set termio so we can do our own input processing */
! 940: static void set_termio()
! 941: {
! 942: #if !defined(MSDOS) && !defined(ATARI) && !defined(MTOS) && !defined(_Windows) && !defined(DOS386)
! 943: /* set termio so we can do our own input processing */
! 944: /* and save the old terminal modes so we can reset them later */
! 945: if (term_set == 0) {
! 946: /*
! 947: * Get terminal modes.
! 948: */
! 949: # ifndef OSK
! 950: # ifdef SGTTY
! 951: ioctl(0, TIOCGETP, &orig_termio);
! 952: # else /* not SGTTY */
! 953: # ifdef TERMIOS
! 954: # ifdef TCGETS
! 955: ioctl(0, TCGETS, &orig_termio);
! 956: # else /* not TCGETS */
! 957: tcgetattr(0, &orig_termio);
! 958: # endif /* not TCGETS */
! 959: # else /* not TERMIOS */
! 960: ioctl(0, TCGETA, &orig_termio);
! 961: # endif /* TERMIOS */
! 962: # endif /* not SGTTY */
! 963: # else /* OSK */
! 964: setbuf(stdin, (char *) 0); /* Make stdin and stdout unbuffered */
! 965: setbuf(stderr, (char *) 0);
! 966: _gs_opt(STDIN, &new_settings);
! 967: # endif /* OSK */
! 968:
! 969: /*
! 970: * Save terminal modes
! 971: */
! 972: # ifndef OSK
! 973: rl_termio = orig_termio;
! 974: # else /* OSK */
! 975: _gs_opt(STDIN, &old_settings);
! 976: # endif /* OSK */
! 977:
! 978: /*
! 979: * Set the modes to the way we want them
! 980: * and save our input special characters
! 981: */
! 982: # ifndef OSK
! 983: # ifdef SGTTY
! 984: rl_termio.sg_flags |= CBREAK;
! 985: rl_termio.sg_flags &= ~(ECHO | XTABS);
! 986: ioctl(0, TIOCSETN, &rl_termio);
! 987:
! 988: ioctl(0, TIOCGETC, &s_tchars);
! 989: term_chars[VERASE] = orig_termio.sg_erase;
! 990: term_chars[VEOF] = s_tchars.t_eofc;
! 991: term_chars[VKILL] = orig_termio.sg_kill;
! 992: # ifdef TIOCGLTC
! 993: ioctl(0, TIOCGLTC, &s_ltchars);
! 994: term_chars[VWERASE] = s_ltchars.t_werasc;
! 995: term_chars[VREPRINT] = s_ltchars.t_rprntc;
! 996: term_chars[VSUSP] = s_ltchars.t_suspc;
! 997:
! 998: /* disable suspending process on ^Z */
! 999: s_ltchars.t_suspc = 0;
! 1000: ioctl(0, TIOCSLTC, &s_ltchars);
! 1001: # endif /* TIOCGLTC */
! 1002: # else /* not SGTTY */
! 1003: rl_termio.c_iflag &= ~(BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF);
! 1004: rl_termio.c_iflag |= (IGNBRK | IGNPAR);
! 1005:
! 1006: /* rl_termio.c_oflag &= ~(ONOCR); Costas Sphocleous Irvine,CA */
! 1007:
! 1008: rl_termio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH);
! 1009: # ifdef OS2
! 1010: /* for emx: remove default terminal processing */
! 1011: rl_termio.c_lflag &= ~(IDEFAULT);
! 1012: # endif /* OS2 */
! 1013: rl_termio.c_lflag |= (ISIG);
! 1014: rl_termio.c_cc[VMIN] = 1;
! 1015: rl_termio.c_cc[VTIME] = 0;
! 1016:
! 1017: # ifndef VWERASE
! 1018: # define VWERASE 3
! 1019: # endif /* VWERASE */
! 1020: term_chars[VERASE] = orig_termio.c_cc[VERASE];
! 1021: term_chars[VEOF] = orig_termio.c_cc[VEOF];
! 1022: term_chars[VKILL] = orig_termio.c_cc[VKILL];
! 1023: # ifdef TERMIOS
! 1024: term_chars[VWERASE] = orig_termio.c_cc[VWERASE];
! 1025: # ifdef VREPRINT
! 1026: term_chars[VREPRINT] = orig_termio.c_cc[VREPRINT];
! 1027: # else /* not VREPRINT */
! 1028: # ifdef VRPRNT
! 1029: term_chars[VRPRNT] = orig_termio.c_cc[VRPRNT];
! 1030: # endif /* VRPRNT */
! 1031: # endif /* not VREPRINT */
! 1032: term_chars[VSUSP] = orig_termio.c_cc[VSUSP];
! 1033:
! 1034: /* disable suspending process on ^Z */
! 1035: rl_termio.c_cc[VSUSP] = 0;
! 1036: # endif /* TERMIOS */
! 1037: # endif /* not SGTTY */
! 1038: # else /* OSK */
! 1039: new_settings._sgs_echo = 0; /* switch off terminal echo */
! 1040: new_settings._sgs_pause = 0; /* inhibit page pause */
! 1041: new_settings._sgs_eofch = 0; /* inhibit eof */
! 1042: new_settings._sgs_kbich = 0; /* inhibit ^C */
! 1043: new_settings._sgs_kbach = 0; /* inhibit ^E */
! 1044: # endif /* OSK */
! 1045:
! 1046: /*
! 1047: * Set the new terminal modes.
! 1048: */
! 1049: # ifndef OSK
! 1050: # ifdef SGTTY
! 1051: ioctl(0, TIOCSLTC, &s_ltchars);
! 1052: # else /* not SGTTY */
! 1053: # ifdef TERMIOS
! 1054: # ifdef TCSETSW
! 1055: ioctl(0, TCSETSW, &rl_termio);
! 1056: # else /* not TCSETSW */
! 1057: tcsetattr(0, TCSADRAIN, &rl_termio);
! 1058: # endif /* not TCSETSW */
! 1059: # else /* not TERMIOS */
! 1060: ioctl(0, TCSETAW, &rl_termio);
! 1061: # endif /* not TERMIOS */
! 1062: # endif /* not SGTTY */
! 1063: # else /* OSK */
! 1064: _ss_opt(STDIN, &new_settings);
! 1065: # endif /* OSK */
! 1066: term_set = 1;
! 1067: }
! 1068: #endif /* not MSDOS && not ATARI && not MTOS && not _Windows && not DOS386 */
! 1069: }
! 1070:
! 1071: static void reset_termio()
! 1072: {
! 1073: #if !defined(MSDOS) && !defined(ATARI) && !defined(MTOS) && !defined(_Windows) && !defined(DOS386)
! 1074: /* reset saved terminal modes */
! 1075: if (term_set == 1) {
! 1076: # ifndef OSK
! 1077: # ifdef SGTTY
! 1078: ioctl(0, TIOCSETN, &orig_termio);
! 1079: # ifdef TIOCGLTC
! 1080: /* enable suspending process on ^Z */
! 1081: s_ltchars.t_suspc = term_chars[VSUSP];
! 1082: ioctl(0, TIOCSLTC, &s_ltchars);
! 1083: # endif /* TIOCGLTC */
! 1084: # else /* not SGTTY */
! 1085: # ifdef TERMIOS
! 1086: # ifdef TCSETSW
! 1087: ioctl(0, TCSETSW, &orig_termio);
! 1088: # else /* not TCSETSW */
! 1089: tcsetattr(0, TCSADRAIN, &orig_termio);
! 1090: # endif /* not TCSETSW */
! 1091: # else /* not TERMIOS */
! 1092: ioctl(0, TCSETAW, &orig_termio);
! 1093: # endif /* TERMIOS */
! 1094: # endif /* not SGTTY */
! 1095: # else /* OSK */
! 1096: _ss_opt(STDIN, &old_settings);
! 1097: # endif /* OSK */
! 1098: term_set = 0;
! 1099: }
! 1100: #endif /* not MSDOS && not ATARI && not MTOS && not _Windows && not DOS386 */
! 1101: }
! 1102:
! 1103:
! 1104: #endif /* READLINE && not GNU_READLINE */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>