1*f157d2e2Sskrll /* $NetBSD: db_input.c,v 1.28 2020/10/30 06:57:08 skrll Exp $ */
2cf92afd6Scgd
361f28255Scgd /*
461f28255Scgd * Mach Operating System
561f28255Scgd * Copyright (c) 1991,1990 Carnegie Mellon University
661f28255Scgd * All Rights Reserved.
761f28255Scgd *
861f28255Scgd * Permission to use, copy, modify and distribute this software and its
961f28255Scgd * documentation is hereby granted, provided that both the copyright
1061f28255Scgd * notice and this permission notice appear in all copies of the
1161f28255Scgd * software, derivative works or modified versions, and any portions
1261f28255Scgd * thereof, and that both notices appear in supporting documentation.
1361f28255Scgd *
14b13e5d14Spk * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
1561f28255Scgd * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1661f28255Scgd * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1761f28255Scgd *
1861f28255Scgd * Carnegie Mellon requests users of this software to return to
1961f28255Scgd *
2061f28255Scgd * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
2161f28255Scgd * School of Computer Science
2261f28255Scgd * Carnegie Mellon University
2361f28255Scgd * Pittsburgh PA 15213-3890
2461f28255Scgd *
2561f28255Scgd * any improvements or extensions that they make and grant Carnegie the
2661f28255Scgd * rights to redistribute these changes.
2737cabe30Scgd *
2861f28255Scgd * Author: David B. Golub, Carnegie Mellon University
2961f28255Scgd * Date: 7/90
3061f28255Scgd */
3161f28255Scgd
321ac69d9cSlukem #include <sys/cdefs.h>
33*f157d2e2Sskrll __KERNEL_RCSID(0, "$NetBSD: db_input.c,v 1.28 2020/10/30 06:57:08 skrll Exp $");
341ac69d9cSlukem
35cd6b1c8fSad #ifdef _KERNEL_OPT
3694b2e6e6Sitohy #include "opt_ddbparam.h"
37cd6b1c8fSad #endif
38466e784eSjonathan
39f1a5c330Smycroft #include <sys/param.h>
40f1a5c330Smycroft #include <sys/proc.h>
41f1a5c330Smycroft
42cd6b1c8fSad #include <ddb/ddb.h>
438c2e3b4bSchristos
448c2e3b4bSchristos #include <dev/cons.h>
4561f28255Scgd
464e3ba1eaSlukem #ifndef DDB_HISTORY_SIZE
474e3ba1eaSlukem #define DDB_HISTORY_SIZE 0
484e3ba1eaSlukem #endif /* DDB_HISTORY_SIZE */
4998ec14c8Schristos
5061f28255Scgd /*
5161f28255Scgd * Character input and editing.
5261f28255Scgd */
5361f28255Scgd
5461f28255Scgd /*
5561f28255Scgd * We don't track output position while editing input,
5661f28255Scgd * since input always ends with a new-line. We just
5761f28255Scgd * reset the line position at the end.
5861f28255Scgd */
594eaa4d66Ssimonb static char *db_lbuf_start; /* start of input line buffer */
604eaa4d66Ssimonb static char *db_lbuf_end; /* end of input line buffer */
614eaa4d66Ssimonb static char *db_lc; /* current character */
624eaa4d66Ssimonb static char *db_le; /* one past last character */
634e3ba1eaSlukem #if DDB_HISTORY_SIZE != 0
644eaa4d66Ssimonb static char db_history[DDB_HISTORY_SIZE]; /* start of history buffer */
654eaa4d66Ssimonb static char *db_history_curr = db_history; /* start of current line */
664eaa4d66Ssimonb static char *db_history_last = db_history; /* start of last line */
674eaa4d66Ssimonb static char *db_history_prev = (char *) 0; /* start of previous line */
6898ec14c8Schristos #endif
6998ec14c8Schristos
7061f28255Scgd
7161f28255Scgd #define CTRL(c) ((c) & 0x1f)
7261f28255Scgd #define isspace(c) ((c) == ' ' || (c) == '\t')
7361f28255Scgd #define BLANK ' '
7461f28255Scgd #define BACKUP '\b'
7561f28255Scgd
764eaa4d66Ssimonb static int cnmaygetc(void);
7702e608f6Schristos static void db_putstring(const char *, int);
784eaa4d66Ssimonb static void db_putnchars(int, int);
794eaa4d66Ssimonb static void db_delete(int, int);
804eaa4d66Ssimonb static void db_delete_line(void);
814eaa4d66Ssimonb static int db_inputchar(int);
828c2e3b4bSchristos
834eaa4d66Ssimonb static void
db_putstring(const char * s,int count)8402e608f6Schristos db_putstring(const char *s, int count)
8561f28255Scgd {
864eaa4d66Ssimonb
8761f28255Scgd while (--count >= 0)
8861f28255Scgd cnputc(*s++);
8961f28255Scgd }
9061f28255Scgd
914eaa4d66Ssimonb static void
db_putnchars(int c,int count)924eaa4d66Ssimonb db_putnchars(int c, int count)
9361f28255Scgd {
944eaa4d66Ssimonb
9561f28255Scgd while (--count >= 0)
9661f28255Scgd cnputc(c);
9761f28255Scgd }
9861f28255Scgd
9961f28255Scgd /*
10061f28255Scgd * Delete N characters, forward or backward
10161f28255Scgd */
10261f28255Scgd #define DEL_FWD 0
10361f28255Scgd #define DEL_BWD 1
1044eaa4d66Ssimonb static void
db_delete(int n,int bwd)1054eaa4d66Ssimonb db_delete(int n, int bwd)
10661f28255Scgd {
1075e3d7e53Saugustss char *p;
10861f28255Scgd
10961f28255Scgd if (bwd) {
11061f28255Scgd db_lc -= n;
11161f28255Scgd db_putnchars(BACKUP, n);
11261f28255Scgd }
11361f28255Scgd for (p = db_lc; p < db_le-n; p++) {
11461f28255Scgd *p = *(p+n);
11561f28255Scgd cnputc(*p);
11661f28255Scgd }
11761f28255Scgd db_putnchars(BLANK, n);
11861f28255Scgd db_putnchars(BACKUP, db_le - db_lc);
11961f28255Scgd db_le -= n;
12061f28255Scgd }
12161f28255Scgd
1224eaa4d66Ssimonb static void
db_delete_line(void)1234eaa4d66Ssimonb db_delete_line(void)
12498ec14c8Schristos {
1254eaa4d66Ssimonb
12698ec14c8Schristos db_delete(db_le - db_lc, DEL_FWD);
12798ec14c8Schristos db_delete(db_lc - db_lbuf_start, DEL_BWD);
12898ec14c8Schristos db_le = db_lc = db_lbuf_start;
12998ec14c8Schristos }
13098ec14c8Schristos
1314e3ba1eaSlukem #if DDB_HISTORY_SIZE != 0
1324e9aaafeStls
1334e9aaafeStls #define INC_DB_CURR() do { \
1344e9aaafeStls ++db_history_curr; \
1354e9aaafeStls if (db_history_curr > db_history + DDB_HISTORY_SIZE - 1) \
13698ec14c8Schristos db_history_curr = db_history; \
1374e9aaafeStls } while (0)
1384e9aaafeStls #define DEC_DB_CURR() do { \
1394e9aaafeStls --db_history_curr; \
14098ec14c8Schristos if (db_history_curr < db_history) \
1414e9aaafeStls db_history_curr = db_history + DDB_HISTORY_SIZE - 1; \
1424e9aaafeStls } while (0)
14398ec14c8Schristos
1445de383f4Senami static inline void
db_hist_put(int c)1455de383f4Senami db_hist_put(int c)
1464e9aaafeStls {
1474e9aaafeStls KASSERT(&db_history[0] <= db_history_last);
1484e9aaafeStls KASSERT(db_history_last <= &db_history[DDB_HISTORY_SIZE-1]);
1494e9aaafeStls
1504e9aaafeStls *db_history_last++ = c;
1514e9aaafeStls
1524e9aaafeStls if (db_history_last > &db_history[DDB_HISTORY_SIZE-1])
1534e9aaafeStls db_history_last = db_history;
1544e9aaafeStls }
1555de383f4Senami #endif
1564e9aaafeStls
1574e9aaafeStls
1584f3d5a9cSthorpej /* returns true at end-of-line */
1594eaa4d66Ssimonb static int
db_inputchar(int c)1604eaa4d66Ssimonb db_inputchar(int c)
16161f28255Scgd {
16261f28255Scgd switch (c) {
16361f28255Scgd case CTRL('b'):
16461f28255Scgd /* back up one character */
16561f28255Scgd if (db_lc > db_lbuf_start) {
16661f28255Scgd cnputc(BACKUP);
16761f28255Scgd db_lc--;
16861f28255Scgd }
16961f28255Scgd break;
17061f28255Scgd case CTRL('f'):
17161f28255Scgd /* forward one character */
17261f28255Scgd if (db_lc < db_le) {
17361f28255Scgd cnputc(*db_lc);
17461f28255Scgd db_lc++;
17561f28255Scgd }
17661f28255Scgd break;
17761f28255Scgd case CTRL('a'):
17861f28255Scgd /* beginning of line */
17961f28255Scgd while (db_lc > db_lbuf_start) {
18061f28255Scgd cnputc(BACKUP);
18161f28255Scgd db_lc--;
18261f28255Scgd }
18361f28255Scgd break;
18461f28255Scgd case CTRL('e'):
18561f28255Scgd /* end of line */
18661f28255Scgd while (db_lc < db_le) {
18761f28255Scgd cnputc(*db_lc);
18861f28255Scgd db_lc++;
18961f28255Scgd }
19061f28255Scgd break;
19161f28255Scgd case CTRL('h'):
19261f28255Scgd case 0177:
19361f28255Scgd /* erase previous character */
19461f28255Scgd if (db_lc > db_lbuf_start)
19561f28255Scgd db_delete(1, DEL_BWD);
19661f28255Scgd break;
19761f28255Scgd case CTRL('d'):
19861f28255Scgd /* erase next character */
19961f28255Scgd if (db_lc < db_le)
20061f28255Scgd db_delete(1, DEL_FWD);
20161f28255Scgd break;
20261f28255Scgd case CTRL('k'):
20361f28255Scgd /* delete to end of line */
20461f28255Scgd if (db_lc < db_le)
20561f28255Scgd db_delete(db_le - db_lc, DEL_FWD);
20661f28255Scgd break;
20798ec14c8Schristos case CTRL('u'):
20898ec14c8Schristos /* delete line */
20998ec14c8Schristos db_delete_line();
21098ec14c8Schristos break;
21161f28255Scgd case CTRL('t'):
21261f28255Scgd /* twiddle last 2 characters */
21367c55e54Sjhawk if (db_lc >= db_lbuf_start + 1) {
21467c55e54Sjhawk if (db_lc < db_le) {
21567c55e54Sjhawk c = db_lc[-1];
21667c55e54Sjhawk db_lc[-1] = db_lc[0];
21767c55e54Sjhawk db_lc[0] = c;
21867c55e54Sjhawk cnputc(BACKUP);
21967c55e54Sjhawk cnputc(db_lc[-1]);
22067c55e54Sjhawk cnputc(db_lc[0]);
22167c55e54Sjhawk db_lc++;
22267c55e54Sjhawk } else if (db_lc >= db_lbuf_start + 2) {
22361f28255Scgd c = db_lc[-2];
22461f28255Scgd db_lc[-2] = db_lc[-1];
22561f28255Scgd db_lc[-1] = c;
22661f28255Scgd cnputc(BACKUP);
22761f28255Scgd cnputc(BACKUP);
22861f28255Scgd cnputc(db_lc[-2]);
22961f28255Scgd cnputc(db_lc[-1]);
23061f28255Scgd }
23167c55e54Sjhawk }
23261f28255Scgd break;
2334e3ba1eaSlukem #if DDB_HISTORY_SIZE != 0
23498ec14c8Schristos case CTRL('p'):
23598ec14c8Schristos DEC_DB_CURR();
23698ec14c8Schristos while (db_history_curr != db_history_last) {
23798ec14c8Schristos DEC_DB_CURR();
23898ec14c8Schristos if (*db_history_curr == '\0')
23998ec14c8Schristos break;
24098ec14c8Schristos }
24198ec14c8Schristos db_delete_line();
24298ec14c8Schristos if (db_history_curr == db_history_last) {
24398ec14c8Schristos INC_DB_CURR();
24498ec14c8Schristos db_le = db_lc = db_lbuf_start;
24598ec14c8Schristos } else {
2465e3d7e53Saugustss char *p;
24798ec14c8Schristos INC_DB_CURR();
24898ec14c8Schristos for (p = db_history_curr, db_le = db_lbuf_start;
24998ec14c8Schristos *p; ) {
25098ec14c8Schristos *db_le++ = *p++;
2514e9aaafeStls if (p >= db_history + DDB_HISTORY_SIZE) {
25298ec14c8Schristos p = db_history;
25398ec14c8Schristos }
25498ec14c8Schristos }
25598ec14c8Schristos db_lc = db_le;
25698ec14c8Schristos }
25798ec14c8Schristos db_putstring(db_lbuf_start, db_le - db_lbuf_start);
25898ec14c8Schristos break;
25998ec14c8Schristos case CTRL('n'):
26098ec14c8Schristos while (db_history_curr != db_history_last) {
26198ec14c8Schristos if (*db_history_curr == '\0')
26298ec14c8Schristos break;
26398ec14c8Schristos INC_DB_CURR();
26498ec14c8Schristos }
26598ec14c8Schristos if (db_history_curr != db_history_last) {
26698ec14c8Schristos INC_DB_CURR();
26798ec14c8Schristos db_delete_line();
26898ec14c8Schristos if (db_history_curr != db_history_last) {
2695e3d7e53Saugustss char *p;
27098ec14c8Schristos for (p = db_history_curr,
27198ec14c8Schristos db_le = db_lbuf_start; *p;) {
27298ec14c8Schristos *db_le++ = *p++;
2734e9aaafeStls if (p >= db_history + DDB_HISTORY_SIZE) {
27498ec14c8Schristos p = db_history;
27598ec14c8Schristos }
27698ec14c8Schristos }
27798ec14c8Schristos db_lc = db_le;
27898ec14c8Schristos }
27998ec14c8Schristos db_putstring(db_lbuf_start, db_le - db_lbuf_start);
28098ec14c8Schristos }
28198ec14c8Schristos break;
28298ec14c8Schristos #endif
28361f28255Scgd case CTRL('r'):
28461f28255Scgd db_putstring("^R\n", 3);
28561f28255Scgd if (db_le > db_lbuf_start) {
28661f28255Scgd db_putstring(db_lbuf_start, db_le - db_lbuf_start);
28761f28255Scgd db_putnchars(BACKUP, db_le - db_lc);
28861f28255Scgd }
28961f28255Scgd break;
29061f28255Scgd case '\n':
29161f28255Scgd case '\r':
2924e3ba1eaSlukem #if DDB_HISTORY_SIZE != 0
29398ec14c8Schristos /* Check if it same than previous line */
29498ec14c8Schristos if (db_history_curr == db_history_prev) {
2955e3d7e53Saugustss char *pp, *pc;
29698ec14c8Schristos
29798ec14c8Schristos /* Is it unmodified */
29898ec14c8Schristos for (pp = db_history_prev, pc = db_lbuf_start;
29998ec14c8Schristos pc != db_le && *pp; pp++, pc++) {
30098ec14c8Schristos if (*pp != *pc)
30198ec14c8Schristos break;
3024e9aaafeStls if (++pp >= db_history + DDB_HISTORY_SIZE) {
30398ec14c8Schristos pp = db_history;
30498ec14c8Schristos }
3054e9aaafeStls if (++pc >= db_history + DDB_HISTORY_SIZE) {
30698ec14c8Schristos pc = db_history;
30798ec14c8Schristos }
30898ec14c8Schristos }
30998ec14c8Schristos if (!*pp && pc == db_le) {
31098ec14c8Schristos /* Repeted previous line, not saved */
31198ec14c8Schristos db_history_curr = db_history_last;
31298ec14c8Schristos *db_le++ = c;
3134f3d5a9cSthorpej return (true);
31498ec14c8Schristos }
31598ec14c8Schristos }
31698ec14c8Schristos if (db_le != db_lbuf_start) {
3175e3d7e53Saugustss char *p;
3184e9aaafeStls
31998ec14c8Schristos db_history_prev = db_history_last;
3204e9aaafeStls
3214e9aaafeStls for (p = db_lbuf_start; p != db_le; ) {
3224e9aaafeStls db_hist_put(*p++);
32398ec14c8Schristos }
3244e9aaafeStls db_hist_put(0);
32598ec14c8Schristos }
32698ec14c8Schristos db_history_curr = db_history_last;
32798ec14c8Schristos #endif
32861f28255Scgd *db_le++ = c;
32961f28255Scgd return (1);
33061f28255Scgd default:
33161f28255Scgd if (db_le == db_lbuf_end) {
33261f28255Scgd cnputc('\007');
33361f28255Scgd }
33461f28255Scgd else if (c >= ' ' && c <= '~') {
3355e3d7e53Saugustss char *p;
33661f28255Scgd
33761f28255Scgd for (p = db_le; p > db_lc; p--)
33861f28255Scgd *p = *(p-1);
33961f28255Scgd *db_lc++ = c;
34061f28255Scgd db_le++;
34161f28255Scgd cnputc(c);
34261f28255Scgd db_putstring(db_lc, db_le - db_lc);
34361f28255Scgd db_putnchars(BACKUP, db_le - db_lc);
34461f28255Scgd }
34561f28255Scgd break;
34661f28255Scgd }
34761f28255Scgd return (0);
34861f28255Scgd }
34961f28255Scgd
35061f28255Scgd int
db_readline(char * lstart,int lsize)3514eaa4d66Ssimonb db_readline(char *lstart, int lsize)
35261f28255Scgd {
353cd6b1c8fSad
35461f28255Scgd db_force_whitespace(); /* synch output position */
35561f28255Scgd
35661f28255Scgd db_lbuf_start = lstart;
35761f28255Scgd db_lbuf_end = lstart + lsize;
35861f28255Scgd db_lc = lstart;
35961f28255Scgd db_le = lstart;
36061f28255Scgd
36161f28255Scgd while (!db_inputchar(cngetc()))
36261f28255Scgd continue;
36361f28255Scgd
36461f28255Scgd db_putchar('\n'); /* synch output position */
36561f28255Scgd
36661f28255Scgd *db_le = 0;
36761f28255Scgd return (db_le - db_lbuf_start);
36861f28255Scgd }
36961f28255Scgd
37061f28255Scgd void
db_check_interrupt(void)3714eaa4d66Ssimonb db_check_interrupt(void)
37261f28255Scgd {
3735e3d7e53Saugustss int c;
37461f28255Scgd
37561f28255Scgd c = cnmaygetc();
37661f28255Scgd switch (c) {
37761f28255Scgd case -1: /* no character */
37861f28255Scgd return;
37961f28255Scgd
38061f28255Scgd case CTRL('c'):
38161f28255Scgd db_error((char *)0);
38261f28255Scgd /*NOTREACHED*/
38361f28255Scgd
38461f28255Scgd case CTRL('s'):
38561f28255Scgd do {
38661f28255Scgd c = cnmaygetc();
3874f0f8fdfSmycroft if (c == CTRL('c')) {
38861f28255Scgd db_error((char *)0);
3894f0f8fdfSmycroft /*NOTREACHED*/
3904f0f8fdfSmycroft }
39161f28255Scgd } while (c != CTRL('q'));
39261f28255Scgd break;
39361f28255Scgd
39461f28255Scgd default:
39561f28255Scgd /* drop on floor */
39661f28255Scgd break;
39761f28255Scgd }
39861f28255Scgd }
39961f28255Scgd
4008c2e3b4bSchristos static int
cnmaygetc(void)4014eaa4d66Ssimonb cnmaygetc(void)
40261f28255Scgd {
4034eaa4d66Ssimonb
40461f28255Scgd return (-1);
40561f28255Scgd }
406