xref: /freebsd/sys/ddb/db_input.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
1 /*
2  * Mach Operating System
3  * Copyright (c) 1991,1990 Carnegie Mellon University
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  *
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie the
24  * rights to redistribute these changes.
25  *
26  * $FreeBSD$
27  */
28 
29 /*
30  *	Author: David B. Golub, Carnegie Mellon University
31  *	Date:	7/90
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/cons.h>
37 
38 #include <ddb/ddb.h>
39 #include <ddb/db_output.h>
40 
41 /*
42  * Character input and editing.
43  */
44 
45 /*
46  * We don't track output position while editing input,
47  * since input always ends with a new-line.  We just
48  * reset the line position at the end.
49  */
50 static char *	db_lbuf_start;	/* start of input line buffer */
51 static char *	db_lbuf_end;	/* end of input line buffer */
52 static char *	db_lc;		/* current character */
53 static char *	db_le;		/* one past last character */
54 
55 /*
56  * Simple input line history support.
57  */
58 static char	db_lhistory[2048];
59 static int	db_lhistlsize, db_lhistidx, db_lhistcur;
60 static int	db_lhist_nlines;
61 
62 #define	CTRL(c)		((c) & 0x1f)
63 #define	isspace(c)	((c) == ' ' || (c) == '\t')
64 #define	BLANK		' '
65 #define	BACKUP		'\b'
66 
67 static int	cnmaygetc __P((void));
68 static void	db_delete __P((int n, int bwd));
69 static int	db_inputchar __P((int c));
70 static void	db_putnchars __P((int c, int count));
71 static void	db_putstring __P((char *s, int count));
72 
73 void
74 db_putstring(s, count)
75 	char	*s;
76 	int	count;
77 {
78 	while (--count >= 0)
79 	    cnputc(*s++);
80 }
81 
82 void
83 db_putnchars(c, count)
84 	int	c;
85 	int	count;
86 {
87 	while (--count >= 0)
88 	    cnputc(c);
89 }
90 
91 /*
92  * Delete N characters, forward or backward
93  */
94 #define	DEL_FWD		0
95 #define	DEL_BWD		1
96 void
97 db_delete(n, bwd)
98 	int	n;
99 	int	bwd;
100 {
101 	register char *p;
102 
103 	if (bwd) {
104 	    db_lc -= n;
105 	    db_putnchars(BACKUP, n);
106 	}
107 	for (p = db_lc; p < db_le-n; p++) {
108 	    *p = *(p+n);
109 	    cnputc(*p);
110 	}
111 	db_putnchars(BLANK, n);
112 	db_putnchars(BACKUP, db_le - db_lc);
113 	db_le -= n;
114 }
115 
116 /* returns TRUE at end-of-line */
117 int
118 db_inputchar(c)
119 	int	c;
120 {
121 	static int escstate;
122 
123 	if (escstate == 1) {
124 		/* ESC seen, look for [ or O */
125 		if (c == '[' || c == 'O')
126 			escstate++;
127 		else
128 			escstate = 0; /* re-init state machine */
129 		return (0);
130 	} else if (escstate == 2) {
131 		escstate = 0;
132 		/*
133 		 * If a valid cursor key has been found, translate
134 		 * into an emacs-style control key, and fall through.
135 		 * Otherwise, drop off.
136 		 */
137 		switch (c) {
138 		case 'A':	/* up */
139 			c = CTRL('p');
140 			break;
141 		case 'B':	/* down */
142 			c = CTRL('n');
143 			break;
144 		case 'C':	/* right */
145 			c = CTRL('f');
146 			break;
147 		case 'D':	/* left */
148 			c = CTRL('b');
149 			break;
150 		default:
151 			return (0);
152 		}
153 	}
154 
155 	switch (c) {
156 	    case CTRL('['):
157 		escstate = 1;
158 		break;
159 	    case CTRL('b'):
160 		/* back up one character */
161 		if (db_lc > db_lbuf_start) {
162 		    cnputc(BACKUP);
163 		    db_lc--;
164 		}
165 		break;
166 	    case CTRL('f'):
167 		/* forward one character */
168 		if (db_lc < db_le) {
169 		    cnputc(*db_lc);
170 		    db_lc++;
171 		}
172 		break;
173 	    case CTRL('a'):
174 		/* beginning of line */
175 		while (db_lc > db_lbuf_start) {
176 		    cnputc(BACKUP);
177 		    db_lc--;
178 		}
179 		break;
180 	    case CTRL('e'):
181 		/* end of line */
182 		while (db_lc < db_le) {
183 		    cnputc(*db_lc);
184 		    db_lc++;
185 		}
186 		break;
187 	    case CTRL('h'):
188 	    case 0177:
189 		/* erase previous character */
190 		if (db_lc > db_lbuf_start)
191 		    db_delete(1, DEL_BWD);
192 		break;
193 	    case CTRL('d'):
194 		/* erase next character */
195 		if (db_lc < db_le)
196 		    db_delete(1, DEL_FWD);
197 		break;
198 	    case CTRL('k'):
199 		/* delete to end of line */
200 		if (db_lc < db_le)
201 		    db_delete(db_le - db_lc, DEL_FWD);
202 		break;
203 	    case CTRL('t'):
204 		/* twiddle last 2 characters */
205 		if (db_lc >= db_lbuf_start + 2) {
206 		    c = db_lc[-2];
207 		    db_lc[-2] = db_lc[-1];
208 		    db_lc[-1] = c;
209 		    cnputc(BACKUP);
210 		    cnputc(BACKUP);
211 		    cnputc(db_lc[-2]);
212 		    cnputc(db_lc[-1]);
213 		}
214 		break;
215 	    case CTRL('r'):
216 		db_putstring("^R\n", 3);
217 	    redraw:
218 		if (db_le > db_lbuf_start) {
219 		    db_putstring(db_lbuf_start, db_le - db_lbuf_start);
220 		    db_putnchars(BACKUP, db_le - db_lc);
221 		}
222 		break;
223 	    case CTRL('p'):
224 		/* Make previous history line the active one. */
225 		if (db_lhistcur >= 0) {
226 		    bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
227 			  db_lbuf_start, db_lhistlsize);
228 		    db_lhistcur--;
229 		    goto hist_redraw;
230 		}
231 		break;
232 	    case CTRL('n'):
233 		/* Make next history line the active one. */
234 		if (db_lhistcur < db_lhistidx - 1) {
235 		    db_lhistcur += 2;
236 		    bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
237 			  db_lbuf_start, db_lhistlsize);
238 		} else {
239 		    /*
240 		     * ^N through tail of history, reset the
241 		     * buffer to zero length.
242 		     */
243 		    *db_lbuf_start = '\0';
244 		    db_lhistcur = db_lhistidx;
245 		}
246 
247 	    hist_redraw:
248 		db_putnchars(BACKUP, db_le - db_lbuf_start);
249 		db_putnchars(BLANK, db_le - db_lbuf_start);
250 		db_putnchars(BACKUP, db_le - db_lbuf_start);
251 		db_le = index(db_lbuf_start, '\0');
252 		if (db_le[-1] == '\r' || db_le[-1] == '\n')
253 		    *--db_le = '\0';
254 		db_lc = db_le;
255 		goto redraw;
256 
257 	    case -1:
258 		/*
259 		 * eek! the console returned eof.
260 		 * probably that means we HAVE no console.. we should try bail
261 		 * XXX
262 		 */
263 		c = '\r';
264 	    case '\n':
265 	    case '\r':
266 		*db_le++ = c;
267 		return (1);
268 	    default:
269 		if (db_le == db_lbuf_end) {
270 		    cnputc('\007');
271 		}
272 		else if (c >= ' ' && c <= '~') {
273 		    register char *p;
274 
275 		    for (p = db_le; p > db_lc; p--)
276 			*p = *(p-1);
277 		    *db_lc++ = c;
278 		    db_le++;
279 		    cnputc(c);
280 		    db_putstring(db_lc, db_le - db_lc);
281 		    db_putnchars(BACKUP, db_le - db_lc);
282 		}
283 		break;
284 	}
285 	return (0);
286 }
287 
288 int
289 cnmaygetc()
290 {
291 	return (-1);
292 }
293 
294 int
295 db_readline(lstart, lsize)
296 	char *	lstart;
297 	int	lsize;
298 {
299 	if (lsize != db_lhistlsize) {
300 		/*
301 		 * (Re)initialize input line history.  Throw away any
302 		 * existing history.
303 		 */
304 		db_lhist_nlines = sizeof(db_lhistory) / lsize;
305 		db_lhistlsize = lsize;
306 		db_lhistidx = -1;
307 	}
308 	db_lhistcur = db_lhistidx;
309 
310 	db_force_whitespace();	/* synch output position */
311 
312 	db_lbuf_start = lstart;
313 	db_lbuf_end   = lstart + lsize;
314 	db_lc = lstart;
315 	db_le = lstart;
316 
317 	while (!db_inputchar(cngetc()))
318 	    continue;
319 
320 	db_printf("\n");	/* synch output position */
321 	*db_le = 0;
322 
323 	if (db_le - db_lbuf_start > 1) {
324 	    /* Maintain input line history for non-empty lines. */
325 	    if (++db_lhistidx == db_lhist_nlines) {
326 		/* Rotate history. */
327 		ovbcopy(db_lhistory + db_lhistlsize, db_lhistory,
328 			db_lhistlsize * (db_lhist_nlines - 1));
329 		db_lhistidx--;
330 	    }
331 	    bcopy(lstart, db_lhistory + db_lhistidx * db_lhistlsize,
332 		  db_lhistlsize);
333 	}
334 
335 	return (db_le - db_lbuf_start);
336 }
337 
338 void
339 db_check_interrupt()
340 {
341 	register int	c;
342 
343 	c = cnmaygetc();
344 	switch (c) {
345 	    case -1:		/* no character */
346 		return;
347 
348 	    case CTRL('c'):
349 		db_error((char *)0);
350 		/*NOTREACHED*/
351 
352 	    case CTRL('s'):
353 		do {
354 		    c = cnmaygetc();
355 		    if (c == CTRL('c'))
356 			db_error((char *)0);
357 		} while (c != CTRL('q'));
358 		break;
359 
360 	    default:
361 		/* drop on floor */
362 		break;
363 	}
364 }
365 
366 /* called from kdb_trap in db_interface.c */
367 void
368 cnpollc (flag)
369 	int flag;
370 {
371 }
372