xref: /freebsd/sys/ddb/db_input.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
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  *	$Id: db_input.c,v 1.13 1996/05/08 04:28:34 gpalmer Exp $
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/malloc.h>
36 #include <sys/systm.h>
37 
38 #include <machine/cons.h>
39 
40 #include <ddb/ddb.h>
41 #include <ddb/db_output.h>
42 
43 /*
44  * Character input and editing.
45  */
46 
47 /*
48  * We don't track output position while editing input,
49  * since input always ends with a new-line.  We just
50  * reset the line position at the end.
51  */
52 static char *	db_lbuf_start;	/* start of input line buffer */
53 static char *	db_lbuf_end;	/* end of input line buffer */
54 static char *	db_lc;		/* current character */
55 static char *	db_le;		/* one past last character */
56 
57 /*
58  * Simple input line history support.
59  */
60 static char *	db_lhistory;
61 static int	db_lhistlsize, db_lhistidx, db_lhistcur;
62 #define DB_LHIST_NLINES 10
63 
64 #define	CTRL(c)		((c) & 0x1f)
65 #define	isspace(c)	((c) == ' ' || (c) == '\t')
66 #define	BLANK		' '
67 #define	BACKUP		'\b'
68 
69 static int	cnmaygetc __P((void));
70 static void	db_delete __P((int n, int bwd));
71 static int	db_inputchar __P((int c));
72 static void	db_putnchars __P((int c, int count));
73 static void	db_putstring __P((char *s, int count));
74 
75 void
76 db_putstring(s, count)
77 	char	*s;
78 	int	count;
79 {
80 	while (--count >= 0)
81 	    cnputc(*s++);
82 }
83 
84 void
85 db_putnchars(c, count)
86 	int	c;
87 	int	count;
88 {
89 	while (--count >= 0)
90 	    cnputc(c);
91 }
92 
93 /*
94  * Delete N characters, forward or backward
95  */
96 #define	DEL_FWD		0
97 #define	DEL_BWD		1
98 void
99 db_delete(n, bwd)
100 	int	n;
101 	int	bwd;
102 {
103 	register char *p;
104 
105 	if (bwd) {
106 	    db_lc -= n;
107 	    db_putnchars(BACKUP, n);
108 	}
109 	for (p = db_lc; p < db_le-n; p++) {
110 	    *p = *(p+n);
111 	    cnputc(*p);
112 	}
113 	db_putnchars(BLANK, n);
114 	db_putnchars(BACKUP, db_le - db_lc);
115 	db_le -= n;
116 }
117 
118 /* returns TRUE at end-of-line */
119 int
120 db_inputchar(c)
121 	int	c;
122 {
123 	switch (c) {
124 	    case CTRL('b'):
125 		/* back up one character */
126 		if (db_lc > db_lbuf_start) {
127 		    cnputc(BACKUP);
128 		    db_lc--;
129 		}
130 		break;
131 	    case CTRL('f'):
132 		/* forward one character */
133 		if (db_lc < db_le) {
134 		    cnputc(*db_lc);
135 		    db_lc++;
136 		}
137 		break;
138 	    case CTRL('a'):
139 		/* beginning of line */
140 		while (db_lc > db_lbuf_start) {
141 		    cnputc(BACKUP);
142 		    db_lc--;
143 		}
144 		break;
145 	    case CTRL('e'):
146 		/* end of line */
147 		while (db_lc < db_le) {
148 		    cnputc(*db_lc);
149 		    db_lc++;
150 		}
151 		break;
152 	    case CTRL('h'):
153 	    case 0177:
154 		/* erase previous character */
155 		if (db_lc > db_lbuf_start)
156 		    db_delete(1, DEL_BWD);
157 		break;
158 	    case CTRL('d'):
159 		/* erase next character */
160 		if (db_lc < db_le)
161 		    db_delete(1, DEL_FWD);
162 		break;
163 	    case CTRL('k'):
164 		/* delete to end of line */
165 		if (db_lc < db_le)
166 		    db_delete(db_le - db_lc, DEL_FWD);
167 		break;
168 	    case CTRL('t'):
169 		/* twiddle last 2 characters */
170 		if (db_lc >= db_lbuf_start + 2) {
171 		    c = db_lc[-2];
172 		    db_lc[-2] = db_lc[-1];
173 		    db_lc[-1] = c;
174 		    cnputc(BACKUP);
175 		    cnputc(BACKUP);
176 		    cnputc(db_lc[-2]);
177 		    cnputc(db_lc[-1]);
178 		}
179 		break;
180 	    case CTRL('r'):
181 		db_putstring("^R\n", 3);
182 	    redraw:
183 		if (db_le > db_lbuf_start) {
184 		    db_putstring(db_lbuf_start, db_le - db_lbuf_start);
185 		    db_putnchars(BACKUP, db_le - db_lc);
186 		}
187 		break;
188 	    case CTRL('p'):
189 		/* Make previous history line the active one. */
190 		if (db_lhistcur >= 0) {
191 		    bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
192 			  db_lbuf_start, db_lhistlsize);
193 		    db_lhistcur--;
194 		    goto hist_redraw;
195 		}
196 		break;
197 	    case CTRL('n'):
198 		/* Make next history line the active one. */
199 		if (db_lhistcur < db_lhistidx - 1) {
200 		    db_lhistcur += 2;
201 		    bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
202 			  db_lbuf_start, db_lhistlsize);
203 		} else {
204 		    /*
205 		     * ^N through tail of history, reset the
206 		     * buffer to zero length.
207 		     */
208 		    *db_lbuf_start = '\0';
209 		    db_lhistcur = db_lhistidx;
210 		}
211 
212 	    hist_redraw:
213 		db_putnchars(BACKUP, db_le - db_lbuf_start);
214 		db_putnchars(BLANK, db_le - db_lbuf_start);
215 		db_putnchars(BACKUP, db_le - db_lbuf_start);
216 		db_le = index(db_lbuf_start, '\0');
217 		if (db_le[-1] == '\r' || db_le[-1] == '\n')
218 		    *--db_le = '\0';
219 		db_lc = db_le;
220 		goto redraw;
221 
222 	    case '\n':
223 	    case '\r':
224 		*db_le++ = c;
225 		return (1);
226 	    default:
227 		if (db_le == db_lbuf_end) {
228 		    cnputc('\007');
229 		}
230 		else if (c >= ' ' && c <= '~') {
231 		    register char *p;
232 
233 		    for (p = db_le; p > db_lc; p--)
234 			*p = *(p-1);
235 		    *db_lc++ = c;
236 		    db_le++;
237 		    cnputc(c);
238 		    db_putstring(db_lc, db_le - db_lc);
239 		    db_putnchars(BACKUP, db_le - db_lc);
240 		}
241 		break;
242 	}
243 	return (0);
244 }
245 
246 int
247 cnmaygetc()
248 {
249 	return (-1);
250 }
251 
252 int
253 db_readline(lstart, lsize)
254 	char *	lstart;
255 	int	lsize;
256 {
257 	if (db_lhistory && lsize != db_lhistlsize) {
258 		/* Should not happen, but to be sane, throw history away. */
259 		FREE(db_lhistory, M_TEMP);
260 		db_lhistory = 0;
261 	}
262 	if (db_lhistory == 0) {
263 		/* Initialize input line history. */
264 		db_lhistlsize = lsize;
265 		db_lhistidx = -1;
266 		MALLOC(db_lhistory, char *, lsize * DB_LHIST_NLINES,
267 		       M_TEMP, M_NOWAIT);
268 	}
269 	db_lhistcur = db_lhistidx;
270 
271 	db_force_whitespace();	/* synch output position */
272 
273 	db_lbuf_start = lstart;
274 	db_lbuf_end   = lstart + lsize;
275 	db_lc = lstart;
276 	db_le = lstart;
277 
278 	while (!db_inputchar(cngetc()))
279 	    continue;
280 
281 	db_printf("\n");	/* synch output position */
282 	*db_le = 0;
283 
284 	if (db_le - db_lbuf_start > 1) {
285 	    /* Maintain input line history for non-empty lines. */
286 	    if (++db_lhistidx == DB_LHIST_NLINES) {
287 		/* Rotate history. */
288 		ovbcopy(db_lhistory + db_lhistlsize, db_lhistory,
289 			db_lhistlsize * (DB_LHIST_NLINES - 1));
290 		db_lhistidx--;
291 	    }
292 	    bcopy(lstart, db_lhistory + (db_lhistidx * db_lhistlsize),
293 		  db_lhistlsize);
294 	}
295 
296 	return (db_le - db_lbuf_start);
297 }
298 
299 void
300 db_check_interrupt()
301 {
302 	register int	c;
303 
304 	c = cnmaygetc();
305 	switch (c) {
306 	    case -1:		/* no character */
307 		return;
308 
309 	    case CTRL('c'):
310 		db_error((char *)0);
311 		/*NOTREACHED*/
312 
313 	    case CTRL('s'):
314 		do {
315 		    c = cnmaygetc();
316 		    if (c == CTRL('c'))
317 			db_error((char *)0);
318 		} while (c != CTRL('q'));
319 		break;
320 
321 	    default:
322 		/* drop on floor */
323 		break;
324 	}
325 }
326 
327 /* called from kdb_trap in db_interface.c */
328 void
329 cnpollc (flag)
330 	int flag;
331 {
332 }
333