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