1 /* $OpenBSD: db_input.c,v 1.9 2002/03/14 01:26:51 millert Exp $ */
2 /* $NetBSD: db_input.c,v 1.7 1996/02/05 01:57:02 christos Exp $ */
3
4 /*
5 * Copyright (c) 2006 Thorsten Glaser <tg@mirbsd.de>
6 *
7 * Mach Operating System
8 * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
9 * All Rights Reserved.
10 *
11 * Permission to use, copy, modify and distribute this software and its
12 * documentation is hereby granted, provided that both the copyright
13 * notice and this permission notice appear in all copies of the
14 * software, derivative works or modified versions, and any portions
15 * thereof, and that both notices appear in supporting documentation.
16 *
17 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
18 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
19 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
20 *
21 * Carnegie Mellon requests users of this software to return to
22 *
23 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
24 * School of Computer Science
25 * Carnegie Mellon University
26 * Pittsburgh PA 15213-3890
27 *
28 * any improvements or extensions that they make and grant Carnegie Mellon
29 * the rights to redistribute these changes.
30 *
31 * Author: David B. Golub, Carnegie Mellon University
32 * Date: 7/90
33 */
34
35 #include <sys/param.h>
36 #include <sys/proc.h>
37
38 #include <uvm/uvm_extern.h>
39
40 #include <machine/db_machdep.h>
41
42 #include <ddb/db_var.h>
43 #include <ddb/db_output.h>
44 #include <ddb/db_command.h>
45 #include <ddb/db_sym.h>
46 #include <ddb/db_extern.h>
47
48 #include <dev/cons.h>
49
50 /* copy from sys/kern/subr_prf.c */
51 void kputchar(int, int, struct tty *);
52 #define TOLOG 0x04 /* to the kernel message buffer */
53 #define TODDB 0x10 /* to ddb console */
54
55 /*
56 * Character input and editing.
57 */
58
59 /*
60 * We don't track output position while editing input,
61 * since input always ends with a new-line. We just
62 * reset the line position at the end.
63 */
64 char * db_lbuf_start; /* start of input line buffer */
65 char * db_lbuf_end; /* end of input line buffer */
66 char * db_lc; /* current character */
67 char * db_le; /* one past last character */
68 #if DB_HISTORY_SIZE != 0
69 char db_history[DB_HISTORY_SIZE]; /* start of history buffer */
70 int db_history_size = DB_HISTORY_SIZE;/* size of history buffer */
71 char * db_history_curr = db_history; /* start of current line */
72 char * db_history_last = db_history; /* start of last line */
73 char * db_history_prev = (char *) 0; /* start of previous line */
74 #endif
75
76
77 #define CTRL(c) ((c) & 0x1f)
78 #define isspace(c) ((c) == ' ' || (c) == '\t')
79 #define BLANK ' '
80 #define BACKUP '\b'
81
82 static int cnmaygetc(void);
83
84 void
db_putstring(s,count)85 db_putstring(s, count)
86 char *s;
87 int count;
88 {
89 while (--count >= 0)
90 cnputc(*s++);
91 }
92
93 void
db_putnchars(c,count)94 db_putnchars(c, count)
95 int c;
96 int count;
97 {
98 while (--count >= 0)
99 cnputc(c);
100 }
101
102 /*
103 * Delete N characters, forward or backward
104 */
105 #define DEL_FWD 0
106 #define DEL_BWD 1
107 void
db_delete(n,bwd)108 db_delete(n, bwd)
109 int n;
110 int bwd;
111 {
112 register char *p;
113
114 if (bwd) {
115 db_lc -= n;
116 db_putnchars(BACKUP, n);
117 }
118 for (p = db_lc; p < db_le-n; p++) {
119 *p = *(p+n);
120 cnputc(*p);
121 }
122 db_putnchars(BLANK, n);
123 db_putnchars(BACKUP, db_le - db_lc);
124 db_le -= n;
125 }
126
127 void
db_delete_line(void)128 db_delete_line(void)
129 {
130 db_delete(db_le - db_lc, DEL_FWD);
131 db_delete(db_lc - db_lbuf_start, DEL_BWD);
132 db_le = db_lc = db_lbuf_start;
133 }
134
135 #if DB_HISTORY_SIZE != 0
136 #define INC_DB_CURR() \
137 do { \
138 db_history_curr++; \
139 if (db_history_curr > \
140 db_history + db_history_size - 1) \
141 db_history_curr = db_history; \
142 } while (0)
143 #define DEC_DB_CURR() \
144 do { \
145 db_history_curr--; \
146 if (db_history_curr < db_history) \
147 db_history_curr = db_history + \
148 db_history_size - 1; \
149 } while (0)
150 #endif
151
152 /* returns TRUE at end-of-line */
153 int
db_inputchar(c)154 db_inputchar(c)
155 int c;
156 {
157 switch (c) {
158 case CTRL('b'):
159 /* back up one character */
160 if (db_lc > db_lbuf_start) {
161 cnputc(BACKUP);
162 db_lc--;
163 }
164 break;
165 case CTRL('f'):
166 /* forward one character */
167 if (db_lc < db_le) {
168 cnputc(*db_lc);
169 db_lc++;
170 }
171 break;
172 case CTRL('a'):
173 /* beginning of line */
174 while (db_lc > db_lbuf_start) {
175 cnputc(BACKUP);
176 db_lc--;
177 }
178 break;
179 case CTRL('e'):
180 /* end of line */
181 while (db_lc < db_le) {
182 cnputc(*db_lc);
183 db_lc++;
184 }
185 break;
186 case CTRL('w'):
187 /* erase word back */
188 while (db_lc > db_lbuf_start && db_lc[-1] != BLANK)
189 db_delete(1, DEL_BWD);
190 break;
191 case CTRL('h'):
192 case 0177:
193 /* erase previous character */
194 if (db_lc > db_lbuf_start)
195 db_delete(1, DEL_BWD);
196 break;
197 case CTRL('d'):
198 /* erase next character */
199 if (db_lc < db_le)
200 db_delete(1, DEL_FWD);
201 break;
202 case CTRL('k'):
203 /* delete to end of line */
204 if (db_lc < db_le)
205 db_delete(db_le - db_lc, DEL_FWD);
206 break;
207 case CTRL('u'):
208 /* delete line */
209 db_delete_line();
210 break;
211 case CTRL('t'):
212 /* twiddle last 2 characters */
213 if (db_lc >= db_lbuf_start + 2) {
214 c = db_lc[-2];
215 db_lc[-2] = db_lc[-1];
216 db_lc[-1] = c;
217 cnputc(BACKUP);
218 cnputc(BACKUP);
219 cnputc(db_lc[-2]);
220 cnputc(db_lc[-1]);
221 }
222 break;
223 #if DB_HISTORY_SIZE != 0
224 case CTRL('p'):
225 DEC_DB_CURR();
226 while (db_history_curr != db_history_last) {
227 DEC_DB_CURR();
228 if (*db_history_curr == '\0')
229 break;
230 }
231 db_delete_line();
232 if (db_history_curr == db_history_last) {
233 INC_DB_CURR();
234 db_le = db_lc = db_lbuf_start;
235 } else {
236 register char *p;
237 INC_DB_CURR();
238 for (p = db_history_curr, db_le = db_lbuf_start;*p; ) {
239 *db_le++ = *p++;
240 if (p == db_history + db_history_size)
241 p = db_history;
242 }
243 db_lc = db_le;
244 }
245 db_putstring(db_lbuf_start, db_le - db_lbuf_start);
246 break;
247 case CTRL('n'):
248 while (db_history_curr != db_history_last) {
249 if (*db_history_curr == '\0')
250 break;
251 INC_DB_CURR();
252 }
253 if (db_history_curr != db_history_last) {
254 INC_DB_CURR();
255 db_delete_line();
256 if (db_history_curr != db_history_last) {
257 register char *p;
258 for (p = db_history_curr,
259 db_le = db_lbuf_start; *p;) {
260 *db_le++ = *p++;
261 if (p == db_history + db_history_size)
262 p = db_history;
263 }
264 db_lc = db_le;
265 }
266 db_putstring(db_lbuf_start, db_le - db_lbuf_start);
267 }
268 break;
269 #endif
270 case CTRL('r'):
271 db_putstring("^R\n", 3);
272 if (db_le > db_lbuf_start) {
273 db_putstring(db_lbuf_start, db_le - db_lbuf_start);
274 db_putnchars(BACKUP, db_le - db_lc);
275 }
276 break;
277 case '\n':
278 case '\r':
279 #if DB_HISTORY_SIZE != 0
280 /*
281 * Check whether current line is the same
282 * as previous saved line. If it is, don`t
283 * save it.
284 */
285 if (db_history_curr == db_history_prev) {
286 register char *pp, *pc;
287
288 /*
289 * Is it the same?
290 */
291 for (pp = db_history_prev, pc = db_lbuf_start;
292 pc != db_le && *pp; ) {
293 if (*pp != *pc)
294 break;
295 if (++pp == db_history + db_history_size)
296 pp = db_history;
297 pc++;
298 }
299 if (!*pp && pc == db_le) {
300 /*
301 * Repeated previous line. Don`t save.
302 */
303 db_history_curr = db_history_last;
304 *db_le++ = c;
305 return TRUE;
306 }
307 }
308 if (db_le != db_lbuf_start) {
309 register char *p;
310 db_history_prev = db_history_last;
311 for (p = db_lbuf_start; p != db_le; p++) {
312 *db_history_last++ = *p;
313 if (db_history_last ==
314 db_history + db_history_size)
315 db_history_last = db_history;
316 }
317 *db_history_last++ = '\0';
318 }
319 db_history_curr = db_history_last;
320 #endif
321 *db_le++ = c;
322 return TRUE;
323 default:
324 if (db_le == db_lbuf_end) {
325 cnputc('\007');
326 }
327 else if (c >= ' ' && c <= '~') {
328 register char *p;
329
330 for (p = db_le; p > db_lc; p--)
331 *p = *(p-1);
332 *db_lc++ = c;
333 db_le++;
334 cnputc(c);
335 db_putstring(db_lc, db_le - db_lc);
336 db_putnchars(BACKUP, db_le - db_lc);
337 }
338 break;
339 }
340 return FALSE;
341 }
342
343 int
db_readline(char * lstart,int lsize)344 db_readline(char *lstart, int lsize)
345 {
346 char *tlog_c = lstart;
347
348 db_force_whitespace(); /* synch output position */
349
350 db_lbuf_start = lstart;
351 db_lbuf_end = lstart + lsize - 1;
352 db_lc = lstart;
353 db_le = lstart;
354
355 while (!db_inputchar(cngetc()))
356 continue;
357
358 *db_le = 0;
359 /* synch ddb.log message buffer output */
360 if (db_log)
361 while (*tlog_c)
362 kputchar(*tlog_c++, TOLOG, NULL);
363 /* synch output position */
364 kputchar('\n', TODDB | (db_log ? TOLOG : 0), NULL);
365 return (db_le - db_lbuf_start);
366 }
367
368 void
db_check_interrupt(void)369 db_check_interrupt(void)
370 {
371 register int c;
372
373 c = cnmaygetc();
374 switch (c) {
375 case -1: /* no character */
376 return;
377
378 case CTRL('c'):
379 db_error((char *)0);
380 /*NOTREACHED*/
381
382 case CTRL('s'):
383 do {
384 c = cnmaygetc();
385 if (c == CTRL('c'))
386 db_error(NULL);
387 /*NOTREACHED*/
388 } while (c != CTRL('q'));
389 break;
390
391 default:
392 /* drop on floor */
393 break;
394 }
395 }
396
397 static int
cnmaygetc()398 cnmaygetc ()
399 {
400 return (-1);
401 }
402