xref: /dragonfly/sys/ddb/db_input.c (revision 1ab20d67)
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: src/sys/ddb/db_input.c,v 1.28.2.1 2002/03/08 16:37:10 yar Exp $
27  * $DragonFly: src/sys/ddb/db_input.c,v 1.4 2003/08/27 10:47:13 rob Exp $
28  */
29 
30 /*
31  *	Author: David B. Golub, Carnegie Mellon University
32  *	Date:	7/90
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/cons.h>
38 
39 #include <ddb/ddb.h>
40 #include <ddb/db_output.h>
41 
42 /*
43  * Character input and editing.
44  */
45 
46 /*
47  * We don't track output position while editing input,
48  * since input always ends with a new-line.  We just
49  * reset the line position at the end.
50  */
51 static char *	db_lbuf_start;	/* start of input line buffer */
52 static char *	db_lbuf_end;	/* end of input line buffer */
53 static char *	db_lc;		/* current character */
54 static char *	db_le;		/* one past last character */
55 
56 /*
57  * Simple input line history support.
58  */
59 static char	db_lhistory[2048];
60 static int	db_lhistlsize, db_lhistidx, db_lhistcur;
61 static int	db_lhist_nlines;
62 
63 #define	CTRL(c)		((c) & 0x1f)
64 #define	BLANK		' '
65 #define	BACKUP		'\b'
66 
67 static int	cnmaygetc (void);
68 static void	db_delete (int n, int bwd);
69 static int	db_inputchar (int c);
70 static void	db_putnchars (int c, int count);
71 static void	db_putstring (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 	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('u'):
199 		/* kill entire line: */
200 		/* at first, delete to beginning of line */
201 		if (db_lc > db_lbuf_start)
202 		    db_delete(db_lc - db_lbuf_start, DEL_BWD);
203 		/* FALLTHROUGH */
204 	    case CTRL('k'):
205 		/* delete to end of line */
206 		if (db_lc < db_le)
207 		    db_delete(db_le - db_lc, DEL_FWD);
208 		break;
209 	    case CTRL('t'):
210 		/* twiddle last 2 characters */
211 		if (db_lc >= db_lbuf_start + 2) {
212 		    c = db_lc[-2];
213 		    db_lc[-2] = db_lc[-1];
214 		    db_lc[-1] = c;
215 		    cnputc(BACKUP);
216 		    cnputc(BACKUP);
217 		    cnputc(db_lc[-2]);
218 		    cnputc(db_lc[-1]);
219 		}
220 		break;
221 	    case CTRL('r'):
222 		db_putstring("^R\n", 3);
223 	    redraw:
224 		if (db_le > db_lbuf_start) {
225 		    db_putstring(db_lbuf_start, db_le - db_lbuf_start);
226 		    db_putnchars(BACKUP, db_le - db_lc);
227 		}
228 		break;
229 	    case CTRL('p'):
230 		/* Make previous history line the active one. */
231 		if (db_lhistcur >= 0) {
232 		    bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
233 			  db_lbuf_start, db_lhistlsize);
234 		    db_lhistcur--;
235 		    goto hist_redraw;
236 		}
237 		break;
238 	    case CTRL('n'):
239 		/* Make next history line the active one. */
240 		if (db_lhistcur < db_lhistidx - 1) {
241 		    db_lhistcur += 2;
242 		    bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
243 			  db_lbuf_start, db_lhistlsize);
244 		} else {
245 		    /*
246 		     * ^N through tail of history, reset the
247 		     * buffer to zero length.
248 		     */
249 		    *db_lbuf_start = '\0';
250 		    db_lhistcur = db_lhistidx;
251 		}
252 
253 	    hist_redraw:
254 		db_putnchars(BACKUP, db_le - db_lbuf_start);
255 		db_putnchars(BLANK, db_le - db_lbuf_start);
256 		db_putnchars(BACKUP, db_le - db_lbuf_start);
257 		db_le = index(db_lbuf_start, '\0');
258 		if (db_le[-1] == '\r' || db_le[-1] == '\n')
259 		    *--db_le = '\0';
260 		db_lc = db_le;
261 		goto redraw;
262 
263 	    case -1:
264 		/*
265 		 * eek! the console returned eof.
266 		 * probably that means we HAVE no console.. we should try bail
267 		 * XXX
268 		 */
269 		c = '\r';
270 	    case '\n':
271 	    case '\r':
272 		*db_le++ = c;
273 		return (1);
274 	    default:
275 		if (db_le == db_lbuf_end) {
276 		    cnputc('\007');
277 		}
278 		else if (c >= ' ' && c <= '~') {
279 		    char *p;
280 
281 		    for (p = db_le; p > db_lc; p--)
282 			*p = *(p-1);
283 		    *db_lc++ = c;
284 		    db_le++;
285 		    cnputc(c);
286 		    db_putstring(db_lc, db_le - db_lc);
287 		    db_putnchars(BACKUP, db_le - db_lc);
288 		}
289 		break;
290 	}
291 	return (0);
292 }
293 
294 int
295 cnmaygetc()
296 {
297 	return (-1);
298 }
299 
300 int
301 db_readline(lstart, lsize)
302 	char *	lstart;
303 	int	lsize;
304 {
305 	if (lsize != db_lhistlsize) {
306 		/*
307 		 * (Re)initialize input line history.  Throw away any
308 		 * existing history.
309 		 */
310 		db_lhist_nlines = sizeof(db_lhistory) / lsize;
311 		db_lhistlsize = lsize;
312 		db_lhistidx = -1;
313 	}
314 	db_lhistcur = db_lhistidx;
315 
316 	db_force_whitespace();	/* synch output position */
317 
318 	db_lbuf_start = lstart;
319 	db_lbuf_end   = lstart + lsize;
320 	db_lc = lstart;
321 	db_le = lstart;
322 
323 	while (!db_inputchar(cngetc()))
324 	    continue;
325 
326 	db_printf("\n");	/* synch output position */
327 	*db_le = 0;
328 
329 	if (db_le - db_lbuf_start > 1) {
330 	    /* Maintain input line history for non-empty lines. */
331 	    if (++db_lhistidx == db_lhist_nlines) {
332 		/* Rotate history. */
333 		ovbcopy(db_lhistory + db_lhistlsize, db_lhistory,
334 			db_lhistlsize * (db_lhist_nlines - 1));
335 		db_lhistidx--;
336 	    }
337 	    bcopy(lstart, db_lhistory + db_lhistidx * db_lhistlsize,
338 		  db_lhistlsize);
339 	}
340 
341 	return (db_le - db_lbuf_start);
342 }
343 
344 void
345 db_check_interrupt()
346 {
347 	int	c;
348 
349 	c = cnmaygetc();
350 	switch (c) {
351 	    case -1:		/* no character */
352 		return;
353 
354 	    case CTRL('c'):
355 		db_error((char *)0);
356 		/*NOTREACHED*/
357 
358 	    case CTRL('s'):
359 		do {
360 		    c = cnmaygetc();
361 		    if (c == CTRL('c'))
362 			db_error((char *)0);
363 		} while (c != CTRL('q'));
364 		break;
365 
366 	    default:
367 		/* drop on floor */
368 		break;
369 	}
370 }
371