diff options
Diffstat (limited to 'sys/ddb/db_input.c')
-rw-r--r-- | sys/ddb/db_input.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/sys/ddb/db_input.c b/sys/ddb/db_input.c new file mode 100644 index 0000000..fa66c0f --- /dev/null +++ b/sys/ddb/db_input.c @@ -0,0 +1,370 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* + * Author: David B. Golub, Carnegie Mellon University + * Date: 7/90 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/cons.h> + +#include <ddb/ddb.h> +#include <ddb/db_output.h> + +/* + * Character input and editing. + */ + +/* + * We don't track output position while editing input, + * since input always ends with a new-line. We just + * reset the line position at the end. + */ +static char * db_lbuf_start; /* start of input line buffer */ +static char * db_lbuf_end; /* end of input line buffer */ +static char * db_lc; /* current character */ +static char * db_le; /* one past last character */ + +/* + * Simple input line history support. + */ +static char db_lhistory[2048]; +static int db_lhistlsize, db_lhistidx, db_lhistcur; +static int db_lhist_nlines; + +#define CTRL(c) ((c) & 0x1f) +#define BLANK ' ' +#define BACKUP '\b' + +static int cnmaygetc(void); +static void db_delete(int n, int bwd); +static int db_inputchar(int c); +static void db_putnchars(int c, int count); +static void db_putstring(char *s, int count); + +static void +db_putstring(s, count) + char *s; + int count; +{ + while (--count >= 0) + cnputc(*s++); +} + +static void +db_putnchars(c, count) + int c; + int count; +{ + while (--count >= 0) + cnputc(c); +} + +/* + * Delete N characters, forward or backward + */ +#define DEL_FWD 0 +#define DEL_BWD 1 +static void +db_delete(n, bwd) + int n; + int bwd; +{ + register char *p; + + if (bwd) { + db_lc -= n; + db_putnchars(BACKUP, n); + } + for (p = db_lc; p < db_le-n; p++) { + *p = *(p+n); + cnputc(*p); + } + db_putnchars(BLANK, n); + db_putnchars(BACKUP, db_le - db_lc); + db_le -= n; +} + +/* returns TRUE at end-of-line */ +static int +db_inputchar(c) + int c; +{ + static int escstate; + + if (escstate == 1) { + /* ESC seen, look for [ or O */ + if (c == '[' || c == 'O') + escstate++; + else + escstate = 0; /* re-init state machine */ + return (0); + } else if (escstate == 2) { + escstate = 0; + /* + * If a valid cursor key has been found, translate + * into an emacs-style control key, and fall through. + * Otherwise, drop off. + */ + switch (c) { + case 'A': /* up */ + c = CTRL('p'); + break; + case 'B': /* down */ + c = CTRL('n'); + break; + case 'C': /* right */ + c = CTRL('f'); + break; + case 'D': /* left */ + c = CTRL('b'); + break; + default: + return (0); + } + } + + switch (c) { + case CTRL('['): + escstate = 1; + break; + case CTRL('b'): + /* back up one character */ + if (db_lc > db_lbuf_start) { + cnputc(BACKUP); + db_lc--; + } + break; + case CTRL('f'): + /* forward one character */ + if (db_lc < db_le) { + cnputc(*db_lc); + db_lc++; + } + break; + case CTRL('a'): + /* beginning of line */ + while (db_lc > db_lbuf_start) { + cnputc(BACKUP); + db_lc--; + } + break; + case CTRL('e'): + /* end of line */ + while (db_lc < db_le) { + cnputc(*db_lc); + db_lc++; + } + break; + case CTRL('h'): + case 0177: + /* erase previous character */ + if (db_lc > db_lbuf_start) + db_delete(1, DEL_BWD); + break; + case CTRL('d'): + /* erase next character */ + if (db_lc < db_le) + db_delete(1, DEL_FWD); + break; + case CTRL('u'): + /* kill entire line: */ + /* at first, delete to beginning of line */ + if (db_lc > db_lbuf_start) + db_delete(db_lc - db_lbuf_start, DEL_BWD); + /* FALLTHROUGH */ + case CTRL('k'): + /* delete to end of line */ + if (db_lc < db_le) + db_delete(db_le - db_lc, DEL_FWD); + break; + case CTRL('t'): + /* twiddle last 2 characters */ + if (db_lc >= db_lbuf_start + 2) { + c = db_lc[-2]; + db_lc[-2] = db_lc[-1]; + db_lc[-1] = c; + cnputc(BACKUP); + cnputc(BACKUP); + cnputc(db_lc[-2]); + cnputc(db_lc[-1]); + } + break; + case CTRL('r'): + db_putstring("^R\n", 3); + redraw: + if (db_le > db_lbuf_start) { + db_putstring(db_lbuf_start, db_le - db_lbuf_start); + db_putnchars(BACKUP, db_le - db_lc); + } + break; + case CTRL('p'): + /* Make previous history line the active one. */ + if (db_lhistcur >= 0) { + bcopy(db_lhistory + db_lhistcur * db_lhistlsize, + db_lbuf_start, db_lhistlsize); + db_lhistcur--; + goto hist_redraw; + } + break; + case CTRL('n'): + /* Make next history line the active one. */ + if (db_lhistcur < db_lhistidx - 1) { + db_lhistcur += 2; + bcopy(db_lhistory + db_lhistcur * db_lhistlsize, + db_lbuf_start, db_lhistlsize); + } else { + /* + * ^N through tail of history, reset the + * buffer to zero length. + */ + *db_lbuf_start = '\0'; + db_lhistcur = db_lhistidx; + } + + hist_redraw: + db_putnchars(BACKUP, db_le - db_lbuf_start); + db_putnchars(BLANK, db_le - db_lbuf_start); + db_putnchars(BACKUP, db_le - db_lbuf_start); + db_le = index(db_lbuf_start, '\0'); + if (db_le[-1] == '\r' || db_le[-1] == '\n') + *--db_le = '\0'; + db_lc = db_le; + goto redraw; + + case -1: + /* + * eek! the console returned eof. + * probably that means we HAVE no console.. we should try bail + * XXX + */ + c = '\r'; + case '\n': + /* FALLTHROUGH */ + case '\r': + *db_le++ = c; + return (1); + default: + if (db_le == db_lbuf_end) { + cnputc('\007'); + } + else if (c >= ' ' && c <= '~') { + register char *p; + + for (p = db_le; p > db_lc; p--) + *p = *(p-1); + *db_lc++ = c; + db_le++; + cnputc(c); + db_putstring(db_lc, db_le - db_lc); + db_putnchars(BACKUP, db_le - db_lc); + } + break; + } + return (0); +} + +static int +cnmaygetc() +{ + return (-1); +} + +int +db_readline(lstart, lsize) + char * lstart; + int lsize; +{ + if (lsize != db_lhistlsize) { + /* + * (Re)initialize input line history. Throw away any + * existing history. + */ + db_lhist_nlines = sizeof(db_lhistory) / lsize; + db_lhistlsize = lsize; + db_lhistidx = -1; + } + db_lhistcur = db_lhistidx; + + db_force_whitespace(); /* synch output position */ + + db_lbuf_start = lstart; + db_lbuf_end = lstart + lsize; + db_lc = lstart; + db_le = lstart; + + while (!db_inputchar(cngetc())) + continue; + + db_printf("\n"); /* synch output position */ + *db_le = 0; + + if (db_le - db_lbuf_start > 1) { + /* Maintain input line history for non-empty lines. */ + if (++db_lhistidx == db_lhist_nlines) { + /* Rotate history. */ + bcopy(db_lhistory + db_lhistlsize, db_lhistory, + db_lhistlsize * (db_lhist_nlines - 1)); + db_lhistidx--; + } + bcopy(lstart, db_lhistory + db_lhistidx * db_lhistlsize, + db_lhistlsize); + } + + return (db_le - db_lbuf_start); +} + +void +db_check_interrupt() +{ + register int c; + + c = cnmaygetc(); + switch (c) { + case -1: /* no character */ + return; + + case CTRL('c'): + db_error((char *)0); + /*NOTREACHED*/ + + case CTRL('s'): + do { + c = cnmaygetc(); + if (c == CTRL('c')) + db_error((char *)0); + } while (c != CTRL('q')); + break; + + default: + /* drop on floor */ + break; + } +} |