2 * SPDX-License-Identifier: MIT-CMU
4 * Mach Operating System
5 * Copyright (c) 1991,1990 Carnegie Mellon University
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
29 * Author: David B. Golub, Carnegie Mellon University
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
39 #include <sys/sysctl.h>
42 #include <ddb/db_output.h>
45 * Character input and editing.
49 * We don't track output position while editing input,
50 * since input always ends with a new-line. We just
51 * reset the line position at the end.
53 static char * db_lbuf_start; /* start of input line buffer */
54 static char * db_lbuf_end; /* end of input line buffer */
55 static char * db_lc; /* current character */
56 static char * db_le; /* one past last character */
59 * Raw input buffer, processed only for certain control characters.
61 #define DB_RAW_SIZE 512
62 static char db_raw[DB_RAW_SIZE];
63 static u_int db_raw_pos;
64 static u_int db_raw_cnt;
65 static int db_raw_warned;
66 static int ddb_prioritize_control_input = 1;
67 SYSCTL_INT(_debug_ddb, OID_AUTO, prioritize_control_input, CTLFLAG_RWTUN,
68 &ddb_prioritize_control_input, 0,
69 "Drop input when the buffer fills in order to keep servicing ^C/^S/^Q");
72 * Simple input line history support.
74 static char db_lhistory[2048];
75 static int db_lhistlsize, db_lhistidx, db_lhistcur;
76 static int db_lhist_nlines;
78 #define CTRL(c) ((c) & 0x1f)
82 static void db_delete(int n, int bwd);
83 static int db_inputchar(int c);
84 static void db_putnchars(int c, int count);
85 static void db_putstring(char *s, int count);
86 static int db_raw_pop(void);
87 static void db_raw_push(int);
88 static int db_raw_space(void);
91 db_putstring(s, count)
100 db_putnchars(c, count)
109 * Delete N characters, forward or backward
122 db_putnchars(BACKUP, n);
124 for (p = db_lc; p < db_le-n; p++) {
128 db_putnchars(BLANK, n);
129 db_putnchars(BACKUP, db_le - db_lc);
133 /* returns true at end-of-line */
141 /* ESC seen, look for [ or O */
142 if (c == '[' || c == 'O')
145 escstate = 0; /* re-init state machine */
147 } else if (escstate == 2) {
150 * If a valid cursor key has been found, translate
151 * into an emacs-style control key, and fall through.
152 * Otherwise, drop off.
161 case 'C': /* right */
177 /* back up one character */
178 if (db_lc > db_lbuf_start) {
184 /* forward one character */
191 /* beginning of line */
192 while (db_lc > db_lbuf_start) {
199 while (db_lc < db_le) {
206 /* erase previous character */
207 if (db_lc > db_lbuf_start)
208 db_delete(1, DEL_BWD);
211 /* erase next character */
213 db_delete(1, DEL_FWD);
217 /* kill entire line: */
218 /* at first, delete to beginning of line */
219 if (db_lc > db_lbuf_start)
220 db_delete(db_lc - db_lbuf_start, DEL_BWD);
223 /* delete to end of line */
225 db_delete(db_le - db_lc, DEL_FWD);
228 /* twiddle last 2 characters */
229 if (db_lc >= db_lbuf_start + 2) {
231 db_lc[-2] = db_lc[-1];
240 /* erase previous word */
241 for (; db_lc > db_lbuf_start;) {
242 if (*(db_lc - 1) != ' ')
244 db_delete(1, DEL_BWD);
246 for (; db_lc > db_lbuf_start;) {
247 if (*(db_lc - 1) == ' ')
249 db_delete(1, DEL_BWD);
253 db_putstring("^R\n", 3);
255 if (db_le > db_lbuf_start) {
256 db_putstring(db_lbuf_start, db_le - db_lbuf_start);
257 db_putnchars(BACKUP, db_le - db_lc);
261 /* Make previous history line the active one. */
262 if (db_lhistcur >= 0) {
263 bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
264 db_lbuf_start, db_lhistlsize);
270 /* Make next history line the active one. */
271 if (db_lhistcur < db_lhistidx - 1) {
273 bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
274 db_lbuf_start, db_lhistlsize);
277 * ^N through tail of history, reset the
278 * buffer to zero length.
280 *db_lbuf_start = '\0';
281 db_lhistcur = db_lhistidx;
285 db_putnchars(BACKUP, db_lc - db_lbuf_start);
286 db_putnchars(BLANK, db_le - db_lbuf_start);
287 db_putnchars(BACKUP, db_le - db_lbuf_start);
288 db_le = strchr(db_lbuf_start, '\0');
289 if (db_le[-1] == '\r' || db_le[-1] == '\n')
296 * eek! the console returned eof.
297 * probably that means we HAVE no console.. we should try bail
307 if (db_le == db_lbuf_end) {
310 else if (c >= ' ' && c <= '~') {
313 for (p = db_le; p > db_lc; p--)
318 db_putstring(db_lc, db_le - db_lc);
319 db_putnchars(BACKUP, db_le - db_lc);
326 /* Get a character from the console, first checking the raw input buffer. */
332 if (db_raw_cnt == 0) {
342 /* Whether the raw input buffer has space to accept another character. */
347 return (db_raw_cnt < DB_RAW_SIZE);
350 /* Un-get a character from the console by buffering it. */
357 db_raw[(db_raw_pos + db_raw_cnt++) % DB_RAW_SIZE] = c;
360 /* Drain a character from the raw input buffer. */
369 return (db_raw[db_raw_pos++ % DB_RAW_SIZE]);
373 db_readline(lstart, lsize)
380 if (lsize != db_lhistlsize) {
382 * (Re)initialize input line history. Throw away any
385 db_lhist_nlines = sizeof(db_lhistory) / lsize;
386 db_lhistlsize = lsize;
389 db_lhistcur = db_lhistidx;
391 db_force_whitespace(); /* synch output position */
393 db_lbuf_start = lstart;
394 db_lbuf_end = lstart + lsize - 2; /* Will append NL and NUL. */
398 while (!db_inputchar(db_getc()))
401 db_capture_write(lstart, db_le - db_lbuf_start);
402 db_printf("\n"); /* synch output position */
405 if (db_le - db_lbuf_start > 1) {
406 /* Maintain input line history for non-empty lines. */
407 if (++db_lhistidx == db_lhist_nlines) {
408 /* Rotate history. */
409 bcopy(db_lhistory + db_lhistlsize, db_lhistory,
410 db_lhistlsize * (db_lhist_nlines - 1));
413 bcopy(lstart, db_lhistory + db_lhistidx * db_lhistlsize,
417 return (db_le - db_lbuf_start);
421 db_do_interrupt(const char *reason)
424 /* Do a pager quit too because some commands have jmpbuf handling. */
431 db_check_interrupt(void)
436 * Check console input for control characters. Non-control input is
437 * buffered. When buffer space is exhausted, either stop responding to
438 * control input or drop further non-control input on the floor.
441 if (!ddb_prioritize_control_input && !db_raw_space())
445 case -1: /* no character */
449 db_do_interrupt("^C");
456 db_do_interrupt("^C");
457 } while (c != CTRL('q'));
461 if (db_raw_space()) {
463 } else if (!db_raw_warned) {
465 db_printf("\n--Exceeded input buffer--\n");