db_input.c revision 104094
1139826Simp/*
253541Sshin * Mach Operating System
353541Sshin * Copyright (c) 1991,1990 Carnegie Mellon University
453541Sshin * All Rights Reserved.
553541Sshin *
653541Sshin * Permission to use, copy, modify and distribute this software and its
753541Sshin * documentation is hereby granted, provided that both the copyright
853541Sshin * notice and this permission notice appear in all copies of the
953541Sshin * software, derivative works or modified versions, and any portions
1053541Sshin * thereof, and that both notices appear in supporting documentation.
1153541Sshin *
1253541Sshin * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
1353541Sshin * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
1453541Sshin * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1553541Sshin *
1653541Sshin * Carnegie Mellon requests users of this software to return to
1753541Sshin *
1853541Sshin *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
1953541Sshin *  School of Computer Science
2053541Sshin *  Carnegie Mellon University
2153541Sshin *  Pittsburgh PA 15213-3890
2253541Sshin *
2353541Sshin * any improvements or extensions that they make and grant Carnegie the
2453541Sshin * rights to redistribute these changes.
2553541Sshin *
2653541Sshin * $FreeBSD: head/sys/ddb/db_input.c 104094 2002-09-28 17:15:38Z phk $
2753541Sshin */
28174510Sobrien
29174510Sobrien/*
3053541Sshin *	Author: David B. Golub, Carnegie Mellon University
3153541Sshin *	Date:	7/90
32174510Sobrien */
33174510Sobrien
34174510Sobrien#include <sys/param.h>
3562587Sitojun#include <sys/systm.h>
3662587Sitojun#include <sys/cons.h>
37225044Sbz
3855009Sshin#include <ddb/ddb.h>
39148921Ssuz#include <ddb/db_output.h>
4053541Sshin
4153541Sshin/*
4253541Sshin * Character input and editing.
4378064Sume */
4453541Sshin
4553541Sshin/*
4653541Sshin * We don't track output position while editing input,
4753541Sshin * since input always ends with a new-line.  We just
4853541Sshin * reset the line position at the end.
4953541Sshin */
5078064Sumestatic char *	db_lbuf_start;	/* start of input line buffer */
5153541Sshinstatic char *	db_lbuf_end;	/* end of input line buffer */
5253541Sshinstatic char *	db_lc;		/* current character */
5353541Sshinstatic char *	db_le;		/* one past last character */
54225044Sbz
5553541Sshin/*
5684994Sdarrenr * Simple input line history support.
5753541Sshin */
5853541Sshinstatic char	db_lhistory[2048];
5953541Sshinstatic int	db_lhistlsize, db_lhistidx, db_lhistcur;
6078064Sumestatic int	db_lhist_nlines;
6178064Sume
6262587Sitojun#define	CTRL(c)		((c) & 0x1f)
6378064Sume#define	BLANK		' '
6462587Sitojun#define	BACKUP		'\b'
6553541Sshin
66148385Sumestatic int	cnmaygetc(void);
6762587Sitojunstatic void	db_delete(int n, int bwd);
6853541Sshinstatic int	db_inputchar(int c);
6953541Sshinstatic void	db_putnchars(int c, int count);
7078064Sumestatic void	db_putstring(char *s, int count);
7178064Sume
72171167Sgnnstatic void
73105199Ssamdb_putstring(s, count)
74105199Ssam	char	*s;
75105199Ssam	int	count;
76171167Sgnn{
77105199Ssam	while (--count >= 0)
7884994Sdarrenr	    cnputc(*s++);
7984994Sdarrenr}
8053541Sshin
8153541Sshinstatic void
8253541Sshindb_putnchars(c, count)
8353541Sshin	int	c;
8453541Sshin	int	count;
8553541Sshin{
8653541Sshin	while (--count >= 0)
8753541Sshin	    cnputc(c);
8853541Sshin}
8953541Sshin
9053541Sshin/*
9153541Sshin * Delete N characters, forward or backward
9253541Sshin */
93171259Sdelphij#define	DEL_FWD		0
9453541Sshin#define	DEL_BWD		1
9553541Sshinstatic void
96122062Sumedb_delete(n, bwd)
97122062Sume	int	n;
98187989Sbz	int	bwd;
9953541Sshin{
10062587Sitojun	register char *p;
10162587Sitojun
102148385Sume	if (bwd) {
103225044Sbz	    db_lc -= n;
104171167Sgnn	    db_putnchars(BACKUP, n);
10553541Sshin	}
106122062Sume	for (p = db_lc; p < db_le-n; p++) {
10753541Sshin	    *p = *(p+n);
108225044Sbz	    cnputc(*p);
109225044Sbz	}
110225044Sbz	db_putnchars(BLANK, n);
111225044Sbz	db_putnchars(BACKUP, db_le - db_lc);
112225044Sbz	db_le -= n;
113225044Sbz}
114165118Sbz
11553541Sshin/* returns TRUE at end-of-line */
116171167Sgnnstatic int
11753541Sshindb_inputchar(c)
11853541Sshin	int	c;
11953541Sshin{
12053541Sshin	static int escstate;
12153541Sshin
12253541Sshin	if (escstate == 1) {
12353541Sshin		/* ESC seen, look for [ or O */
12453541Sshin		if (c == '[' || c == 'O')
125181803Sbz			escstate++;
12653541Sshin		else
12753541Sshin			escstate = 0; /* re-init state machine */
12853541Sshin		return (0);
129171167Sgnn	} else if (escstate == 2) {
13053541Sshin		escstate = 0;
13178064Sume		/*
13278064Sume		 * If a valid cursor key has been found, translate
13378064Sume		 * into an emacs-style control key, and fall through.
13478064Sume		 * Otherwise, drop off.
135120913Sume		 */
13678064Sume		switch (c) {
13762587Sitojun		case 'A':	/* up */
13878064Sume			c = CTRL('p');
13978064Sume			break;
140181803Sbz		case 'B':	/* down */
14153541Sshin			c = CTRL('n');
142181803Sbz			break;
143181803Sbz		case 'C':	/* right */
14453541Sshin			c = CTRL('f');
14553541Sshin			break;
14653541Sshin		case 'D':	/* left */
147165118Sbz			c = CTRL('b');
148165118Sbz			break;
14953541Sshin		default:
15053541Sshin			return (0);
15153541Sshin		}
15253541Sshin	}
15353541Sshin
15453541Sshin	switch (c) {
15553541Sshin	    case CTRL('['):
156148921Ssuz		escstate = 1;
157181803Sbz		break;
158148921Ssuz	    case CTRL('b'):
15953541Sshin		/* back up one character */
16053541Sshin		if (db_lc > db_lbuf_start) {
16153541Sshin		    cnputc(BACKUP);
16253541Sshin		    db_lc--;
16353541Sshin		}
16453541Sshin		break;
16553541Sshin	    case CTRL('f'):
16653541Sshin		/* forward one character */
167148921Ssuz		if (db_lc < db_le) {
168148921Ssuz		    cnputc(*db_lc);
169148921Ssuz		    db_lc++;
170148921Ssuz		}
17162587Sitojun		break;
17262587Sitojun	    case CTRL('a'):
17362587Sitojun		/* beginning of line */
17462587Sitojun		while (db_lc > db_lbuf_start) {
17562587Sitojun		    cnputc(BACKUP);
17662587Sitojun		    db_lc--;
17762587Sitojun		}
17862587Sitojun		break;
17962587Sitojun	    case CTRL('e'):
18062587Sitojun		/* end of line */
18162587Sitojun		while (db_lc < db_le) {
182171167Sgnn		    cnputc(*db_lc);
18353541Sshin		    db_lc++;
184171133Sgnn		}
185120913Sume		break;
18653541Sshin	    case CTRL('h'):
187181803Sbz	    case 0177:
188181803Sbz		/* erase previous character */
18962587Sitojun		if (db_lc > db_lbuf_start)
19062587Sitojun		    db_delete(1, DEL_BWD);
19162587Sitojun		break;
19262587Sitojun	    case CTRL('d'):
19362587Sitojun		/* erase next character */
19462587Sitojun		if (db_lc < db_le)
19562587Sitojun		    db_delete(1, DEL_FWD);
19653541Sshin		break;
19753541Sshin	    case CTRL('u'):
19853541Sshin		/* kill entire line: */
19953541Sshin		/* at first, delete to beginning of line */
20053541Sshin		if (db_lc > db_lbuf_start)
20153541Sshin		    db_delete(db_lc - db_lbuf_start, DEL_BWD);
20253541Sshin		/* FALLTHROUGH */
20353541Sshin	    case CTRL('k'):
20453541Sshin		/* delete to end of line */
20553541Sshin		if (db_lc < db_le)
20653541Sshin		    db_delete(db_le - db_lc, DEL_FWD);
20753541Sshin		break;
208181803Sbz	    case CTRL('t'):
209181803Sbz		/* twiddle last 2 characters */
210171133Sgnn		if (db_lc >= db_lbuf_start + 2) {
21162587Sitojun		    c = db_lc[-2];
21262587Sitojun		    db_lc[-2] = db_lc[-1];
21362587Sitojun		    db_lc[-1] = c;
21462587Sitojun		    cnputc(BACKUP);
21562587Sitojun		    cnputc(BACKUP);
21662587Sitojun		    cnputc(db_lc[-2]);
21762587Sitojun		    cnputc(db_lc[-1]);
21853541Sshin		}
21953541Sshin		break;
22053541Sshin	    case CTRL('r'):
22153541Sshin		db_putstring("^R\n", 3);
22253541Sshin	    redraw:
22353541Sshin		if (db_le > db_lbuf_start) {
224171133Sgnn		    db_putstring(db_lbuf_start, db_le - db_lbuf_start);
22553541Sshin		    db_putnchars(BACKUP, db_le - db_lc);
22662587Sitojun		}
22753541Sshin		break;
22853541Sshin	    case CTRL('p'):
22953541Sshin		/* Make previous history line the active one. */
23053541Sshin		if (db_lhistcur >= 0) {
231181803Sbz		    bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
232171133Sgnn			  db_lbuf_start, db_lhistlsize);
23362587Sitojun		    db_lhistcur--;
23462587Sitojun		    goto hist_redraw;
23562587Sitojun		}
23662587Sitojun		break;
23762587Sitojun	    case CTRL('n'):
23862587Sitojun		/* Make next history line the active one. */
23962587Sitojun		if (db_lhistcur < db_lhistidx - 1) {
24053541Sshin		    db_lhistcur += 2;
24153541Sshin		    bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
24253541Sshin			  db_lbuf_start, db_lhistlsize);
24353541Sshin		} else {
24453541Sshin		    /*
24553541Sshin		     * ^N through tail of history, reset the
24653541Sshin		     * buffer to zero length.
24753541Sshin		     */
24853541Sshin		    *db_lbuf_start = '\0';
24953541Sshin		    db_lhistcur = db_lhistidx;
250171133Sgnn		}
25153541Sshin
25253541Sshin	    hist_redraw:
25353541Sshin		db_putnchars(BACKUP, db_le - db_lbuf_start);
25453541Sshin		db_putnchars(BLANK, db_le - db_lbuf_start);
255122062Sume		db_putnchars(BACKUP, db_le - db_lbuf_start);
25653541Sshin		db_le = index(db_lbuf_start, '\0');
25753541Sshin		if (db_le[-1] == '\r' || db_le[-1] == '\n')
25853541Sshin		    *--db_le = '\0';
259122062Sume		db_lc = db_le;
260122062Sume		goto redraw;
261122062Sume
262122062Sume	    case -1:
263122062Sume		/*
264122062Sume		 * eek! the console returned eof.
265122062Sume		 * probably that means we HAVE no console.. we should try bail
266122062Sume		 * XXX
267122062Sume		 */
268126006Sume		c = '\r';
269126006Sume	    case '\n':
270126006Sume	    case '\r':
271126006Sume		*db_le++ = c;
272122062Sume		return (1);
273122062Sume	    default:
274122062Sume		if (db_le == db_lbuf_end) {
275126006Sume		    cnputc('\007');
276126006Sume		}
277126006Sume		else if (c >= ' ' && c <= '~') {
278126006Sume		    register char *p;
279126006Sume
280126006Sume		    for (p = db_le; p > db_lc; p--)
281126006Sume			*p = *(p-1);
28253541Sshin		    *db_lc++ = c;
28353541Sshin		    db_le++;
28453541Sshin		    cnputc(c);
28553541Sshin		    db_putstring(db_lc, db_le - db_lc);
28653541Sshin		    db_putnchars(BACKUP, db_le - db_lc);
28753541Sshin		}
28853541Sshin		break;
28953541Sshin	}
29053541Sshin	return (0);
29153541Sshin}
29253541Sshin
29353541Sshinstatic int
29453541Sshincnmaygetc()
29553541Sshin{
29653541Sshin	return (-1);
297171133Sgnn}
29853541Sshin
29953541Sshinint
30053541Sshindb_readline(lstart, lsize)
30153541Sshin	char *	lstart;
30253541Sshin	int	lsize;
30353541Sshin{
30453541Sshin	if (lsize != db_lhistlsize) {
30553541Sshin		/*
30653541Sshin		 * (Re)initialize input line history.  Throw away any
30753541Sshin		 * existing history.
30853541Sshin		 */
30953541Sshin		db_lhist_nlines = sizeof(db_lhistory) / lsize;
310120913Sume		db_lhistlsize = lsize;
31153541Sshin		db_lhistidx = -1;
31253541Sshin	}
31353541Sshin	db_lhistcur = db_lhistidx;
31453541Sshin
315181803Sbz	db_force_whitespace();	/* synch output position */
31662587Sitojun
31762587Sitojun	db_lbuf_start = lstart;
31862587Sitojun	db_lbuf_end   = lstart + lsize;
31962587Sitojun	db_lc = lstart;
32062587Sitojun	db_le = lstart;
32162587Sitojun
32262587Sitojun	while (!db_inputchar(cngetc()))
32353541Sshin	    continue;
32453541Sshin
325171133Sgnn	db_printf("\n");	/* synch output position */
326171260Sdelphij	*db_le = 0;
327171260Sdelphij
328171133Sgnn	if (db_le - db_lbuf_start > 1) {
329171260Sdelphij	    /* Maintain input line history for non-empty lines. */
330171133Sgnn	    if (++db_lhistidx == db_lhist_nlines) {
331171133Sgnn		/* Rotate history. */
332171133Sgnn		ovbcopy(db_lhistory + db_lhistlsize, db_lhistory,
333171133Sgnn			db_lhistlsize * (db_lhist_nlines - 1));
33453541Sshin		db_lhistidx--;
335122062Sume	    }
336171133Sgnn	    bcopy(lstart, db_lhistory + db_lhistidx * db_lhistlsize,
337126006Sume		  db_lhistlsize);
338126006Sume	}
339126006Sume
340126006Sume	return (db_le - db_lbuf_start);
341126006Sume}
342126006Sume
343126006Sumevoid
344126006Sumedb_check_interrupt()
345126006Sume{
346122062Sume	register int	c;
347122062Sume
348122062Sume	c = cnmaygetc();
349122062Sume	switch (c) {
350122062Sume	    case -1:		/* no character */
35153541Sshin		return;
352122062Sume
353122062Sume	    case CTRL('c'):
354187949Sbz		db_error((char *)0);
355122062Sume		/*NOTREACHED*/
356225044Sbz
357187989Sbz	    case CTRL('s'):
358187989Sbz		do {
359187989Sbz		    c = cnmaygetc();
360187989Sbz		    if (c == CTRL('c'))
361187989Sbz			db_error((char *)0);
362225044Sbz		} while (c != CTRL('q'));
363225044Sbz		break;
364225044Sbz
365187989Sbz	    default:
366187989Sbz		/* drop on floor */
367187989Sbz		break;
368187989Sbz	}
369187989Sbz}
370187989Sbz