db_input.c revision 49558
1138569Ssam/*
2170375Ssam * Mach Operating System
3138569Ssam * Copyright (c) 1991,1990 Carnegie Mellon University
4138569Ssam * All Rights Reserved.
5138569Ssam *
6138569Ssam * Permission to use, copy, modify and distribute this software and its
7138569Ssam * documentation is hereby granted, provided that both the copyright
8138569Ssam * notice and this permission notice appear in all copies of the
9138569Ssam * software, derivative works or modified versions, and any portions
10138569Ssam * thereof, and that both notices appear in supporting documentation.
11138569Ssam *
12138569Ssam * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13138569Ssam * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14138569Ssam * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15138569Ssam *
16138569Ssam * Carnegie Mellon requests users of this software to return to
17138569Ssam *
18138569Ssam *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19138569Ssam *  School of Computer Science
20138569Ssam *  Carnegie Mellon University
21138569Ssam *  Pittsburgh PA 15213-3890
22138569Ssam *
23138569Ssam * any improvements or extensions that they make and grant Carnegie the
24138569Ssam * rights to redistribute these changes.
25138569Ssam *
26138569Ssam *	$Id: db_input.c,v 1.24 1999/07/14 10:53:41 yokota Exp $
27138569Ssam */
28138569Ssam
29138569Ssam/*
30138569Ssam *	Author: David B. Golub, Carnegie Mellon University
31138569Ssam *	Date:	7/90
32138569Ssam */
33138569Ssam
34138569Ssam#include <sys/param.h>
35138569Ssam#include <sys/systm.h>
36237529Sadrian#include <sys/cons.h>
37138569Ssam
38178354Ssam#include <ddb/ddb.h>
39138569Ssam#include <ddb/db_output.h>
40138569Ssam
41138569Ssam/*
42138569Ssam * Character input and editing.
43138569Ssam */
44138569Ssam
45138569Ssam/*
46138569Ssam * We don't track output position while editing input,
47138569Ssam * since input always ends with a new-line.  We just
48138569Ssam * reset the line position at the end.
49138569Ssam */
50138569Ssamstatic char *	db_lbuf_start;	/* start of input line buffer */
51138569Ssamstatic char *	db_lbuf_end;	/* end of input line buffer */
52138569Ssamstatic char *	db_lc;		/* current character */
53138569Ssamstatic char *	db_le;		/* one past last character */
54138569Ssam
55138569Ssam/*
56138569Ssam * Simple input line history support.
57138569Ssam */
58138569Ssamstatic char	db_lhistory[2048];
59138569Ssamstatic int	db_lhistlsize, db_lhistidx, db_lhistcur;
60138569Ssamstatic int	db_lhist_nlines;
61138569Ssam
62138569Ssam#define	CTRL(c)		((c) & 0x1f)
63138569Ssam#define	isspace(c)	((c) == ' ' || (c) == '\t')
64138569Ssam#define	BLANK		' '
65138569Ssam#define	BACKUP		'\b'
66138569Ssam
67138569Ssamstatic int	cnmaygetc __P((void));
68138569Ssamstatic void	db_delete __P((int n, int bwd));
69138569Ssamstatic int	db_inputchar __P((int c));
70185522Ssamstatic void	db_putnchars __P((int c, int count));
71138569Ssamstatic void	db_putstring __P((char *s, int count));
72138569Ssam
73138569Ssamvoid
74138569Ssamdb_putstring(s, count)
75138569Ssam	char	*s;
76138569Ssam	int	count;
77138569Ssam{
78138569Ssam	while (--count >= 0)
79138569Ssam	    cnputc(*s++);
80138569Ssam}
81138569Ssam
82138569Ssamvoid
83138569Ssamdb_putnchars(c, count)
84138569Ssam	int	c;
85138569Ssam	int	count;
86138569Ssam{
87138569Ssam	while (--count >= 0)
88138569Ssam	    cnputc(c);
89138569Ssam}
90138569Ssam
91138569Ssam/*
92138569Ssam * Delete N characters, forward or backward
93138569Ssam */
94138569Ssam#define	DEL_FWD		0
95138569Ssam#define	DEL_BWD		1
96138569Ssamvoid
97138569Ssamdb_delete(n, bwd)
98138569Ssam	int	n;
99138569Ssam	int	bwd;
100138569Ssam{
101138569Ssam	register char *p;
102138569Ssam
103138569Ssam	if (bwd) {
104138569Ssam	    db_lc -= n;
105138569Ssam	    db_putnchars(BACKUP, n);
106138569Ssam	}
107138569Ssam	for (p = db_lc; p < db_le-n; p++) {
108138569Ssam	    *p = *(p+n);
109138569Ssam	    cnputc(*p);
110138569Ssam	}
111138569Ssam	db_putnchars(BLANK, n);
112138569Ssam	db_putnchars(BACKUP, db_le - db_lc);
113144546Ssam	db_le -= n;
114138569Ssam}
115138569Ssam
116138569Ssam/* returns TRUE at end-of-line */
117138569Ssamint
118138569Ssamdb_inputchar(c)
119138569Ssam	int	c;
120138569Ssam{
121138569Ssam	static int escstate;
122138569Ssam
123138569Ssam	if (escstate == 1) {
124138569Ssam		/* ESC seen, look for [ or O */
125138569Ssam		if (c == '[' || c == 'O')
126218160Sadrian			escstate++;
127218160Sadrian		else
128218160Sadrian			escstate = 0; /* re-init state machine */
129218160Sadrian		return (0);
130218160Sadrian	} else if (escstate == 2) {
131218160Sadrian		escstate = 0;
132138569Ssam		/*
133218160Sadrian		 * If a valid cursor key has been found, translate
134227364Sadrian		 * into an emacs-style control key, and fall through.
135218160Sadrian		 * Otherwise, drop off.
136218160Sadrian		 */
137218160Sadrian		switch (c) {
138227364Sadrian		case 'A':	/* up */
139218160Sadrian			c = CTRL('p');
140227364Sadrian			break;
141227364Sadrian		case 'B':	/* down */
142227364Sadrian			c = CTRL('n');
143227364Sadrian			break;
144227364Sadrian		case 'C':	/* right */
145227364Sadrian			c = CTRL('f');
146227364Sadrian			break;
147227364Sadrian		case 'D':	/* left */
148227364Sadrian			c = CTRL('b');
149218160Sadrian			break;
150218160Sadrian		default:
151218160Sadrian			return (0);
152138569Ssam		}
153144546Ssam	}
154138569Ssam
155138569Ssam	switch (c) {
156138569Ssam	    case CTRL('['):
157138569Ssam		escstate = 1;
158138569Ssam		break;
159138569Ssam	    case CTRL('b'):
160138569Ssam		/* back up one character */
161138569Ssam		if (db_lc > db_lbuf_start) {
162138569Ssam		    cnputc(BACKUP);
163138569Ssam		    db_lc--;
164138569Ssam		}
165144347Ssam		break;
166227364Sadrian	    case CTRL('f'):
167227364Sadrian		/* forward one character */
168138569Ssam		if (db_lc < db_le) {
169138569Ssam		    cnputc(*db_lc);
170138569Ssam		    db_lc++;
171165185Ssam		}
172138569Ssam		break;
173138569Ssam	    case CTRL('a'):
174138569Ssam		/* beginning of line */
175165185Ssam		while (db_lc > db_lbuf_start) {
176165185Ssam		    cnputc(BACKUP);
177178354Ssam		    db_lc--;
178178354Ssam		}
179178354Ssam		break;
180178354Ssam	    case CTRL('e'):
181138569Ssam		/* end of line */
182138569Ssam		while (db_lc < db_le) {
183138569Ssam		    cnputc(*db_lc);
184138569Ssam		    db_lc++;
185138569Ssam		}
186138569Ssam		break;
187138569Ssam	    case CTRL('h'):
188138569Ssam	    case 0177:
189138569Ssam		/* erase previous character */
190138569Ssam		if (db_lc > db_lbuf_start)
191138569Ssam		    db_delete(1, DEL_BWD);
192138569Ssam		break;
193138569Ssam	    case CTRL('d'):
194138569Ssam		/* erase next character */
195178354Ssam		if (db_lc < db_le)
196138569Ssam		    db_delete(1, DEL_FWD);
197138569Ssam		break;
198138569Ssam	    case CTRL('k'):
199138569Ssam		/* delete to end of line */
200138569Ssam		if (db_lc < db_le)
201178354Ssam		    db_delete(db_le - db_lc, DEL_FWD);
202178354Ssam		break;
203178354Ssam	    case CTRL('t'):
204138569Ssam		/* twiddle last 2 characters */
205138569Ssam		if (db_lc >= db_lbuf_start + 2) {
206138569Ssam		    c = db_lc[-2];
207138569Ssam		    db_lc[-2] = db_lc[-1];
208138569Ssam		    db_lc[-1] = c;
209138569Ssam		    cnputc(BACKUP);
210138569Ssam		    cnputc(BACKUP);
211138569Ssam		    cnputc(db_lc[-2]);
212138569Ssam		    cnputc(db_lc[-1]);
213138569Ssam		}
214138569Ssam		break;
215178354Ssam	    case CTRL('r'):
216178354Ssam		db_putstring("^R\n", 3);
217178354Ssam	    redraw:
218138569Ssam		if (db_le > db_lbuf_start) {
219138569Ssam		    db_putstring(db_lbuf_start, db_le - db_lbuf_start);
220138569Ssam		    db_putnchars(BACKUP, db_le - db_lc);
221138569Ssam		}
222138569Ssam		break;
223138569Ssam	    case CTRL('p'):
224138569Ssam		/* Make previous history line the active one. */
225138569Ssam		if (db_lhistcur >= 0) {
226138569Ssam		    bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
227138569Ssam			  db_lbuf_start, db_lhistlsize);
228138569Ssam		    db_lhistcur--;
229138569Ssam		    goto hist_redraw;
230138569Ssam		}
231138569Ssam		break;
232138569Ssam	    case CTRL('n'):
233138569Ssam		/* Make next history line the active one. */
234138569Ssam		if (db_lhistcur < db_lhistidx - 1) {
235138569Ssam		    db_lhistcur += 2;
236138569Ssam		    bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
237138569Ssam			  db_lbuf_start, db_lhistlsize);
238138569Ssam		} else {
239138569Ssam		    /*
240138569Ssam		     * ^N through tail of history, reset the
241138569Ssam		     * buffer to zero length.
242138569Ssam		     */
243138569Ssam		    *db_lbuf_start = '\0';
244138569Ssam		    db_lhistcur = db_lhistidx;
245138569Ssam		}
246138569Ssam
247138569Ssam	    hist_redraw:
248138569Ssam		db_putnchars(BACKUP, db_le - db_lbuf_start);
249138569Ssam		db_putnchars(BLANK, db_le - db_lbuf_start);
250138569Ssam		db_putnchars(BACKUP, db_le - db_lbuf_start);
251138569Ssam		db_le = index(db_lbuf_start, '\0');
252138569Ssam		if (db_le[-1] == '\r' || db_le[-1] == '\n')
253155477Ssam		    *--db_le = '\0';
254138569Ssam		db_lc = db_le;
255138569Ssam		goto redraw;
256138569Ssam
257138569Ssam	    case -1:
258138569Ssam		/*
259138569Ssam		 * eek! the console returned eof.
260138569Ssam		 * probably that means we HAVE no console.. we should try bail
261138569Ssam		 * XXX
262138569Ssam		 */
263138569Ssam		c = '\r';
264138569Ssam	    case '\n':
265178354Ssam	    case '\r':
266178354Ssam		*db_le++ = c;
267178354Ssam		return (1);
268178354Ssam	    default:
269178354Ssam		if (db_le == db_lbuf_end) {
270138569Ssam		    cnputc('\007');
271138569Ssam		}
272138569Ssam		else if (c >= ' ' && c <= '~') {
273138569Ssam		    register char *p;
274138569Ssam
275138569Ssam		    for (p = db_le; p > db_lc; p--)
276138569Ssam			*p = *(p-1);
277138569Ssam		    *db_lc++ = c;
278138569Ssam		    db_le++;
279184347Ssam		    cnputc(c);
280138569Ssam		    db_putstring(db_lc, db_le - db_lc);
281138569Ssam		    db_putnchars(BACKUP, db_le - db_lc);
282138569Ssam		}
283178354Ssam		break;
284138569Ssam	}
285138569Ssam	return (0);
286138569Ssam}
287138569Ssam
288138569Ssamint
289138569Ssamcnmaygetc()
290138569Ssam{
291138569Ssam	return (-1);
292138569Ssam}
293138569Ssam
294138569Ssamint
295138569Ssamdb_readline(lstart, lsize)
296138569Ssam	char *	lstart;
297138569Ssam	int	lsize;
298138569Ssam{
299138569Ssam	if (lsize != db_lhistlsize) {
300138569Ssam		/*
301170530Ssam		 * (Re)initialize input line history.  Throw away any
302170530Ssam		 * existing history.
303138569Ssam		 */
304138569Ssam		db_lhist_nlines = sizeof(db_lhistory) / lsize;
305138569Ssam		db_lhistlsize = lsize;
306138569Ssam		db_lhistidx = -1;
307138569Ssam	}
308138569Ssam	db_lhistcur = db_lhistidx;
309178354Ssam
310138569Ssam	db_force_whitespace();	/* synch output position */
311138569Ssam
312170530Ssam	db_lbuf_start = lstart;
313170530Ssam	db_lbuf_end   = lstart + lsize;
314170530Ssam	db_lc = lstart;
315170530Ssam	db_le = lstart;
316170530Ssam
317170530Ssam	while (!db_inputchar(cngetc()))
318170530Ssam	    continue;
319138569Ssam
320138569Ssam	db_printf("\n");	/* synch output position */
321138569Ssam	*db_le = 0;
322138569Ssam
323138569Ssam	if (db_le - db_lbuf_start > 1) {
324138569Ssam	    /* Maintain input line history for non-empty lines. */
325138569Ssam	    if (++db_lhistidx == db_lhist_nlines) {
326138569Ssam		/* Rotate history. */
327138569Ssam		ovbcopy(db_lhistory + db_lhistlsize, db_lhistory,
328138569Ssam			db_lhistlsize * (db_lhist_nlines - 1));
329138569Ssam		db_lhistidx--;
330138569Ssam	    }
331138569Ssam	    bcopy(lstart, db_lhistory + db_lhistidx * db_lhistlsize,
332138569Ssam		  db_lhistlsize);
333138569Ssam	}
334138569Ssam
335138569Ssam	return (db_le - db_lbuf_start);
336138569Ssam}
337138569Ssam
338138569Ssamvoid
339138569Ssamdb_check_interrupt()
340138569Ssam{
341138569Ssam	register int	c;
342138569Ssam
343138569Ssam	c = cnmaygetc();
344138569Ssam	switch (c) {
345138569Ssam	    case -1:		/* no character */
346138569Ssam		return;
347138569Ssam
348138569Ssam	    case CTRL('c'):
349138569Ssam		db_error((char *)0);
350138569Ssam		/*NOTREACHED*/
351138569Ssam
352178354Ssam	    case CTRL('s'):
353178354Ssam		do {
354178354Ssam		    c = cnmaygetc();
355138569Ssam		    if (c == CTRL('c'))
356178354Ssam			db_error((char *)0);
357138569Ssam		} while (c != CTRL('q'));
358138569Ssam		break;
359138569Ssam
360138569Ssam	    default:
361138569Ssam		/* drop on floor */
362138569Ssam		break;
363138569Ssam	}
364138569Ssam}
365138569Ssam
366138569Ssam/* called from kdb_trap in db_interface.c */
367138569Ssamvoid
368138569Ssamcnpollc (flag)
369138569Ssam	int flag;
370138569Ssam{
371138569Ssam}
372138569Ssam