xref: /netbsd-src/sys/ddb/db_input.c (revision f157d2e256aee5de41e854acb423250852410f16)
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