Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/ddb/db_input.c
39476 views
1
/*-
2
* SPDX-License-Identifier: MIT-CMU
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
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 [email protected]
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
/*
29
* Author: David B. Golub, Carnegie Mellon University
30
* Date: 7/90
31
*/
32
33
#include <sys/param.h>
34
#include <sys/systm.h>
35
#include <sys/cons.h>
36
#include <sys/sysctl.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
* Raw input buffer, processed only for certain control characters.
57
*/
58
#define DB_RAW_SIZE 512
59
static char db_raw[DB_RAW_SIZE];
60
static u_int db_raw_pos;
61
static u_int db_raw_cnt;
62
static int db_raw_warned;
63
static int ddb_prioritize_control_input = 1;
64
SYSCTL_INT(_debug_ddb, OID_AUTO, prioritize_control_input, CTLFLAG_RWTUN,
65
&ddb_prioritize_control_input, 0,
66
"Drop input when the buffer fills in order to keep servicing ^C/^S/^Q");
67
68
/*
69
* Simple input line history support.
70
*/
71
static char db_lhistory[2048];
72
static int db_lhistlsize, db_lhistidx, db_lhistcur;
73
static int db_lhist_nlines;
74
75
#define CTRL(c) ((c) & 0x1f)
76
#define BLANK ' '
77
#define BACKUP '\b'
78
79
static void db_delete(int n, int bwd);
80
static int db_inputchar(int c);
81
static void db_putnchars(int c, int count);
82
static void db_putstring(char *s, int count);
83
static int db_raw_pop(void);
84
static void db_raw_push(int);
85
static int db_raw_space(void);
86
87
static void
88
db_putstring(char *s, int count)
89
{
90
while (--count >= 0)
91
cnputc(*s++);
92
}
93
94
static void
95
db_putnchars(int c, int count)
96
{
97
while (--count >= 0)
98
cnputc(c);
99
}
100
101
/*
102
* Delete N characters, forward or backward
103
*/
104
#define DEL_FWD 0
105
#define DEL_BWD 1
106
static void
107
db_delete(int n, int bwd)
108
{
109
char *p;
110
111
if (bwd) {
112
db_lc -= n;
113
db_putnchars(BACKUP, n);
114
}
115
for (p = db_lc; p < db_le-n; p++) {
116
*p = *(p+n);
117
cnputc(*p);
118
}
119
db_putnchars(BLANK, n);
120
db_putnchars(BACKUP, db_le - db_lc);
121
db_le -= n;
122
}
123
124
/* returns true at end-of-line */
125
static int
126
db_inputchar(int c)
127
{
128
static int escstate;
129
130
if (escstate == 1) {
131
/* ESC seen, look for [ or O */
132
if (c == '[' || c == 'O')
133
escstate++;
134
else
135
escstate = 0; /* re-init state machine */
136
return (0);
137
} else if (escstate == 2) {
138
escstate = 0;
139
/*
140
* If a valid cursor key has been found, translate
141
* into an emacs-style control key, and fall through.
142
* Otherwise, drop off.
143
*/
144
switch (c) {
145
case 'A': /* up */
146
c = CTRL('p');
147
break;
148
case 'B': /* down */
149
c = CTRL('n');
150
break;
151
case 'C': /* right */
152
c = CTRL('f');
153
break;
154
case 'D': /* left */
155
c = CTRL('b');
156
break;
157
default:
158
return (0);
159
}
160
}
161
162
switch (c) {
163
case CTRL('['):
164
escstate = 1;
165
break;
166
case CTRL('b'):
167
/* back up one character */
168
if (db_lc > db_lbuf_start) {
169
cnputc(BACKUP);
170
db_lc--;
171
}
172
break;
173
case CTRL('f'):
174
/* forward one character */
175
if (db_lc < db_le) {
176
cnputc(*db_lc);
177
db_lc++;
178
}
179
break;
180
case CTRL('a'):
181
/* beginning of line */
182
while (db_lc > db_lbuf_start) {
183
cnputc(BACKUP);
184
db_lc--;
185
}
186
break;
187
case CTRL('e'):
188
/* end of line */
189
while (db_lc < db_le) {
190
cnputc(*db_lc);
191
db_lc++;
192
}
193
break;
194
case CTRL('h'):
195
case 0177:
196
/* erase previous character */
197
if (db_lc > db_lbuf_start)
198
db_delete(1, DEL_BWD);
199
break;
200
case CTRL('d'):
201
/* erase next character */
202
if (db_lc < db_le)
203
db_delete(1, DEL_FWD);
204
break;
205
case CTRL('u'):
206
case CTRL('c'):
207
/* kill entire line: */
208
/* at first, delete to beginning of line */
209
if (db_lc > db_lbuf_start)
210
db_delete(db_lc - db_lbuf_start, DEL_BWD);
211
/* FALLTHROUGH */
212
case CTRL('k'):
213
/* delete to end of line */
214
if (db_lc < db_le)
215
db_delete(db_le - db_lc, DEL_FWD);
216
break;
217
case CTRL('t'):
218
/* twiddle last 2 characters */
219
if (db_lc >= db_lbuf_start + 2) {
220
c = db_lc[-2];
221
db_lc[-2] = db_lc[-1];
222
db_lc[-1] = c;
223
cnputc(BACKUP);
224
cnputc(BACKUP);
225
cnputc(db_lc[-2]);
226
cnputc(db_lc[-1]);
227
}
228
break;
229
case CTRL('w'):
230
/* erase previous word */
231
for (; db_lc > db_lbuf_start;) {
232
if (*(db_lc - 1) != ' ')
233
break;
234
db_delete(1, DEL_BWD);
235
}
236
for (; db_lc > db_lbuf_start;) {
237
if (*(db_lc - 1) == ' ')
238
break;
239
db_delete(1, DEL_BWD);
240
}
241
break;
242
case CTRL('r'):
243
db_putstring("^R\n", 3);
244
redraw:
245
if (db_le > db_lbuf_start) {
246
db_putstring(db_lbuf_start, db_le - db_lbuf_start);
247
db_putnchars(BACKUP, db_le - db_lc);
248
}
249
break;
250
case CTRL('p'):
251
/* Make previous history line the active one. */
252
if (db_lhistcur >= 0) {
253
bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
254
db_lbuf_start, db_lhistlsize);
255
db_lhistcur--;
256
goto hist_redraw;
257
}
258
break;
259
case CTRL('n'):
260
/* Make next history line the active one. */
261
if (db_lhistcur < db_lhistidx - 1) {
262
db_lhistcur += 2;
263
bcopy(db_lhistory + db_lhistcur * db_lhistlsize,
264
db_lbuf_start, db_lhistlsize);
265
} else {
266
/*
267
* ^N through tail of history, reset the
268
* buffer to zero length.
269
*/
270
*db_lbuf_start = '\0';
271
db_lhistcur = db_lhistidx;
272
}
273
274
hist_redraw:
275
db_putnchars(BACKUP, db_lc - db_lbuf_start);
276
db_putnchars(BLANK, db_le - db_lbuf_start);
277
db_putnchars(BACKUP, db_le - db_lbuf_start);
278
db_le = strchr(db_lbuf_start, '\0');
279
if (db_le[-1] == '\r' || db_le[-1] == '\n')
280
*--db_le = '\0';
281
db_lc = db_le;
282
goto redraw;
283
284
case -1:
285
/*
286
* eek! the console returned eof.
287
* probably that means we HAVE no console.. we should try bail
288
* XXX
289
*/
290
c = '\r';
291
case '\n':
292
/* FALLTHROUGH */
293
case '\r':
294
*db_le++ = c;
295
return (1);
296
default:
297
if (db_le == db_lbuf_end) {
298
cnputc('\007');
299
}
300
else if (c >= ' ' && c <= '~') {
301
char *p;
302
303
for (p = db_le; p > db_lc; p--)
304
*p = *(p-1);
305
*db_lc++ = c;
306
db_le++;
307
cnputc(c);
308
db_putstring(db_lc, db_le - db_lc);
309
db_putnchars(BACKUP, db_le - db_lc);
310
}
311
break;
312
}
313
return (0);
314
}
315
316
/* Get a character from the console, first checking the raw input buffer. */
317
int
318
db_getc(void)
319
{
320
int c;
321
322
if (db_raw_cnt == 0) {
323
c = cngetc();
324
} else {
325
c = db_raw_pop();
326
if (c == '\r')
327
c = '\n';
328
}
329
return (c);
330
}
331
332
/* Whether the raw input buffer has space to accept another character. */
333
static int
334
db_raw_space(void)
335
{
336
337
return (db_raw_cnt < DB_RAW_SIZE);
338
}
339
340
/* Un-get a character from the console by buffering it. */
341
static void
342
db_raw_push(int c)
343
{
344
345
if (!db_raw_space())
346
db_error(NULL);
347
db_raw[(db_raw_pos + db_raw_cnt++) % DB_RAW_SIZE] = c;
348
}
349
350
/* Drain a character from the raw input buffer. */
351
static int
352
db_raw_pop(void)
353
{
354
355
if (db_raw_cnt == 0)
356
return (-1);
357
db_raw_cnt--;
358
db_raw_warned = 0;
359
return (db_raw[db_raw_pos++ % DB_RAW_SIZE]);
360
}
361
362
int
363
db_readline(char *lstart, int lsize)
364
{
365
366
if (lsize < 2)
367
return (0);
368
if (lsize != db_lhistlsize) {
369
/*
370
* (Re)initialize input line history. Throw away any
371
* existing history.
372
*/
373
db_lhist_nlines = sizeof(db_lhistory) / lsize;
374
db_lhistlsize = lsize;
375
db_lhistidx = -1;
376
}
377
db_lhistcur = db_lhistidx;
378
379
db_force_whitespace(); /* synch output position */
380
381
db_lbuf_start = lstart;
382
db_lbuf_end = lstart + lsize - 2; /* Will append NL and NUL. */
383
db_lc = lstart;
384
db_le = lstart;
385
386
while (!db_inputchar(db_getc()))
387
continue;
388
389
db_capture_write(lstart, db_le - db_lbuf_start);
390
db_printf("\n"); /* synch output position */
391
*db_le = 0;
392
393
if (db_le - db_lbuf_start > 1) {
394
/* Maintain input line history for non-empty lines. */
395
if (++db_lhistidx == db_lhist_nlines) {
396
/* Rotate history. */
397
bcopy(db_lhistory + db_lhistlsize, db_lhistory,
398
db_lhistlsize * (db_lhist_nlines - 1));
399
db_lhistidx--;
400
}
401
bcopy(lstart, db_lhistory + db_lhistidx * db_lhistlsize,
402
db_lhistlsize);
403
}
404
405
return (db_le - db_lbuf_start);
406
}
407
408
static void
409
db_do_interrupt(const char *reason)
410
{
411
412
/* Do a pager quit too because some commands have jmpbuf handling. */
413
db_disable_pager();
414
db_pager_quit = 1;
415
db_error(reason);
416
}
417
418
void
419
db_check_interrupt(void)
420
{
421
int c;
422
423
/*
424
* Check console input for control characters. Non-control input is
425
* buffered. When buffer space is exhausted, either stop responding to
426
* control input or drop further non-control input on the floor.
427
*/
428
for (;;) {
429
if (!ddb_prioritize_control_input && !db_raw_space())
430
return;
431
c = cncheckc();
432
switch (c) {
433
case -1: /* no character */
434
return;
435
436
case CTRL('c'):
437
db_do_interrupt("^C");
438
/*NOTREACHED*/
439
440
case CTRL('s'):
441
do {
442
c = cncheckc();
443
if (c == CTRL('c'))
444
db_do_interrupt("^C");
445
} while (c != CTRL('q'));
446
break;
447
448
default:
449
if (db_raw_space()) {
450
db_raw_push(c);
451
} else if (!db_raw_warned) {
452
db_raw_warned = 1;
453
db_printf("\n--Exceeded input buffer--\n");
454
}
455
break;
456
}
457
}
458
}
459
460