]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_input.c
xnu-344.49.tar.gz
[apple/xnu.git] / osfmk / ddb / db_input.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * @OSF_COPYRIGHT@
27 */
28 /*
29 * HISTORY
30 *
31 * Revision 1.1.1.1 1998/09/22 21:05:48 wsanchez
32 * Import of Mac OS X kernel (~semeria)
33 *
34 * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez
35 * Import of OSF Mach kernel (~mburg)
36 *
37 * Revision 1.3.10.2 1994/09/23 01:19:37 ezf
38 * change marker to not FREE
39 * [1994/09/22 21:10:05 ezf]
40 *
41 * Revision 1.3.10.1 1994/06/11 21:11:48 bolinger
42 * Merge up to NMK17.2.
43 * [1994/06/11 20:01:41 bolinger]
44 *
45 * Revision 1.3.8.2 1994/02/11 14:21:41 paire
46 * Added string.h header file for strlen declaration.
47 * [94/02/09 paire]
48 *
49 * Revision 1.3.8.1 1994/02/08 10:57:55 bernadat
50 * Added db_auto_completion variable.
51 * [93/08/17 paire]
52 *
53 * Added support of symbol completion by typing '\t'.
54 * [93/08/14 paire]
55 * [94/02/07 bernadat]
56 *
57 * Revision 1.3.2.4 1993/08/11 20:37:51 elliston
58 * Add ANSI Prototypes. CR #9523.
59 * [1993/08/11 03:33:21 elliston]
60 *
61 * Revision 1.3.2.3 1993/07/27 18:27:30 elliston
62 * Add ANSI prototypes. CR #9523.
63 * [1993/07/27 18:12:01 elliston]
64 *
65 * Revision 1.3.2.2 1993/06/09 02:20:13 gm
66 * CR9176 - ANSI C violations: trailing tokens on CPP
67 * directives, extra semicolons after decl_ ..., asm keywords
68 * [1993/06/07 18:57:14 jeffc]
69 *
70 * Added to OSF/1 R1.3 from NMK15.0.
71 * [1993/06/02 20:56:26 jeffc]
72 *
73 * Revision 1.3 1993/04/19 16:02:17 devrcs
74 * Replaced ^R (redraw) with ^L [barbou@gr.osf.org]
75 *
76 * Added ^R and ^S commands for history search commands
77 * ^U does not erase end of the line anymore. (only erases
78 * from the beginning of the line to current position).
79 * [barbou@gr.osf.org]
80 *
81 * ^C now erases the entire line. [barbou@gr.osf.org]
82 * [92/12/03 bernadat]
83 *
84 * Fixed history management: Do not store repeated typed
85 * command. Null terminate current command in case it is a
86 * substring of the last command.
87 * [92/10/02 bernadat]
88 *
89 * Revision 1.2 1992/11/25 01:04:24 robert
90 * integrate changes for norma_14 below
91 *
92 * Philippe Bernadat (bernadat) at gr.osf.org 02-Oct-92
93 * Fixed history management: Do not store repeated typed
94 * command. Null terminate current command in case it is a
95 * substring of the last command.
96 * [1992/11/20 00:56:07 robert]
97 *
98 * integrate changes below for norma_14
99 * [1992/11/13 19:21:34 robert]
100 *
101 * Revision 1.1 1992/09/30 02:01:08 robert
102 * Initial revision
103 *
104 * $EndLog$
105 */
106 /* CMU_HIST */
107 /*
108 * Revision 2.7.3.2 92/09/15 17:14:26 jeffreyh
109 * Fixed history code. (Only one char. out of 2 was checked to
110 * compare to last command)
111 * [barbou@gr.osf.org]
112 *
113 * Revision 2.7.3.1 92/03/03 16:13:30 jeffreyh
114 * Pick up changes from TRUNK
115 * [92/02/26 10:59:36 jeffreyh]
116 *
117 * Revision 2.8 92/02/19 15:07:44 elf
118 * Added delete_line (Ctrl-U).
119 * [92/02/17 kivinen]
120 *
121 * Added command line history. Ctrl-P = previous, Ctrl-N = next. If
122 * DB_HISTORY_SIZE is 0 then command history is disabled.
123 * [92/02/17 kivinen]
124 *
125 * Revision 2.7 91/10/09 16:00:03 af
126 * Revision 2.6.2.1 91/10/05 13:06:12 jeffreyh
127 * Fixed incorrect db_lbuf_end setting.
128 * [91/08/29 tak]
129 *
130 * Revision 2.6.2.1 91/10/05 13:06:12 jeffreyh
131 * Fixed incorrect db_lbuf_end setting.
132 * [91/08/29 tak]
133 *
134 * Revision 2.6 91/07/09 23:15:49 danner
135 * Add include of machine/db_machdep.h to allow machine-specific
136 * overrides via defines.
137 * [91/07/08 danner]
138 *
139 * Revision 2.5 91/05/14 15:34:03 mrt
140 * Correcting copyright
141 *
142 * Revision 2.4 91/02/14 14:41:53 mrt
143 * Add input line editing.
144 * [90/11/11 dbg]
145 *
146 * Revision 2.3 91/02/05 17:06:32 mrt
147 * Changed to new Mach copyright
148 * [91/01/31 16:18:13 mrt]
149 *
150 * Revision 2.2 90/08/27 21:51:03 dbg
151 * Reduce lint.
152 * [90/08/07 dbg]
153 * Created.
154 * [90/07/25 dbg]
155 *
156 */
157 /* CMU_ENDHIST */
158 /*
159 * Mach Operating System
160 * Copyright (c) 1991,1990 Carnegie Mellon University
161 * All Rights Reserved.
162 *
163 * Permission to use, copy, modify and distribute this software and its
164 * documentation is hereby granted, provided that both the copyright
165 * notice and this permission notice appear in all copies of the
166 * software, derivative works or modified versions, and any portions
167 * thereof, and that both notices appear in supporting documentation.
168 *
169 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
170 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
171 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
172 *
173 * Carnegie Mellon requests users of this software to return to
174 *
175 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
176 * School of Computer Science
177 * Carnegie Mellon University
178 * Pittsburgh PA 15213-3890
179 *
180 * any improvements or extensions that they make and grant Carnegie Mellon
181 * the rights to redistribute these changes.
182 */
183 /*
184 */
185 /*
186 * Author: David B. Golub, Carnegie Mellon University
187 * Date: 7/90
188 */
189
190 #include <string.h>
191 #include <mach/boolean.h>
192 #include <machine/db_machdep.h>
193 #include <kern/misc_protos.h>
194 #include <ddb/db_output.h>
195 #include <ddb/db_lex.h>
196 #include <ddb/db_command.h>
197 #include <ddb/db_input.h>
198 #include <ddb/db_sym.h>
199
200 #ifndef DB_HISTORY_SIZE
201 #define DB_HISTORY_SIZE 4000
202 #endif /* DB_HISTORY_SIZE */
203
204 /*
205 * Character input and editing.
206 */
207
208 /*
209 * We don't track output position while editing input,
210 * since input always ends with a new-line. We just
211 * reset the line position at the end.
212 */
213 char * db_lbuf_start; /* start of input line buffer */
214 char * db_lbuf_end; /* end of input line buffer */
215 char * db_lc; /* current character */
216 char * db_le; /* one past last character */
217 int db_completion; /* number of incomplete symbols matched */
218 int db_auto_completion = 10; /* number of line to display without asking */
219 #if DB_HISTORY_SIZE != 0
220 char db_history[DB_HISTORY_SIZE]; /* start of history buffer */
221 int db_history_size = DB_HISTORY_SIZE;/* size of history buffer */
222 char * db_history_curr = db_history; /* start of current line */
223 char * db_history_last = db_history; /* start of last line */
224 char * db_history_prev = (char *) 0; /* start of previous line */
225 int db_hist_unmodified = 0; /* unmodified line from history */
226 int db_hist_search = 0; /* are we in hist search mode ? */
227 char db_hist_search_string[DB_LEX_LINE_SIZE];/* the string to look for */
228 int db_hist_ignore_dups = 0; /* don't duplicate commands in hist */
229 #endif
230
231 #define CTRL(c) ((c) & 0x1f)
232 #define isspace(c) ((c) == ' ' || (c) == '\t')
233 #define BLANK ' '
234 #define BACKUP '\b'
235
236
237
238 /* Prototypes for functions local to this file. XXX -- should be static!
239 */
240 void db_putstring(
241 char *s,
242 int count);
243
244 void db_putnchars(
245 int c,
246 int count);
247
248 void db_delete(
249 int n,
250 int bwd);
251
252 void db_delete_line(void);
253
254 boolean_t db_hist_substring(
255 char *string,
256 char *substring);
257
258 boolean_t db_inputchar(int c);
259
260 extern jmp_buf_t *db_recover;
261
262 void
263 db_putstring(
264 char *s,
265 int count)
266 {
267 while (--count >= 0)
268 cnputc(*s++);
269 }
270
271 void
272 db_putnchars(
273 int c,
274 int count)
275 {
276 while (--count >= 0)
277 cnputc(c);
278 }
279
280 /*
281 * Delete N characters, forward or backward
282 */
283 #define DEL_FWD 0
284 #define DEL_BWD 1
285 void
286 db_delete(
287 int n,
288 int bwd)
289 {
290 register char *p;
291
292 if (bwd) {
293 db_lc -= n;
294 db_putnchars(BACKUP, n);
295 }
296 for (p = db_lc; p < db_le-n; p++) {
297 *p = *(p+n);
298 cnputc(*p);
299 }
300 db_putnchars(BLANK, n);
301 db_putnchars(BACKUP, db_le - db_lc);
302 db_le -= n;
303 }
304
305 void
306 db_delete_line(void)
307 {
308 db_delete(db_le - db_lc, DEL_FWD);
309 db_delete(db_lc - db_lbuf_start, DEL_BWD);
310 db_le = db_lc = db_lbuf_start;
311 }
312
313 #if DB_HISTORY_SIZE != 0
314 #define INC_DB_CURR() \
315 do { \
316 db_history_curr++; \
317 if (db_history_curr > \
318 db_history + db_history_size - 1) \
319 db_history_curr = db_history; \
320 } while (0)
321 #define DEC_DB_CURR() \
322 do { \
323 db_history_curr--; \
324 if (db_history_curr < db_history) \
325 db_history_curr = db_history + \
326 db_history_size - 1; \
327 } while (0)
328 #endif
329
330 /* returs TRUE if "substring" is a substring of "string" */
331 boolean_t
332 db_hist_substring(
333 char *string,
334 char *substring)
335 {
336 register char *cp1, *cp2;
337
338 cp1 = string;
339 while (*cp1)
340 cp1++;
341 cp2 = substring;
342 while (*cp2)
343 cp2++;
344
345 while (cp2 > substring) {
346 cp1--; cp2--;
347 }
348
349 while (cp1 >= string) {
350 register char *cp3;
351
352 cp2 = substring;
353 cp3 = cp1;
354 while (*cp2 && *cp2 == *cp3) {
355 cp2++; cp3++;
356 }
357 if (*cp2 == '\0') {
358 return TRUE;
359 }
360 cp1--;
361 }
362 return FALSE;
363 }
364
365 /* returns TRUE at end-of-line */
366 boolean_t
367 db_inputchar(int c)
368 {
369 char *sym;
370 char *start;
371 char *restart;
372 jmp_buf_t db_jmpbuf;
373 jmp_buf_t *db_prev;
374 char *p;
375 int len;
376
377 switch(db_completion) {
378 case -1:
379 db_putchar('\n');
380 db_prev = db_recover;
381 if (_setjmp(db_recover = &db_jmpbuf) == 0 &&
382 (c == 'y' || c == ' ' || c == '\t'))
383 db_print_completion(db_tok_string);
384 db_recover = db_prev;
385 db_completion = 0;
386 db_reset_more();
387 db_output_prompt();
388 if (db_le > db_lbuf_start) {
389 for (start = db_lbuf_start; start < db_le; start++)
390 db_putchar(*start);
391 db_putnchars(BACKUP, db_le - db_lc);
392 }
393 return(FALSE);
394
395 case 0:
396 break;
397
398 default:
399 if (c == '\t') {
400 db_printf("\nThere are %d possibilities. ", db_completion);
401 db_printf("Do you really wish to see them all [n] ? ");
402 db_force_whitespace();
403 db_completion = -1;
404 db_reset_more();
405 return(FALSE);
406 }
407 db_completion = 0;
408 break;
409 }
410
411 switch (c) {
412 case '\t':
413 /* symbol completion */
414 if (db_lc == db_lbuf_start || db_auto_completion == 0)
415 break;
416 if (db_le == db_lbuf_end) {
417 cnputc('\007');
418 break;
419 }
420 start = db_lc - 1;
421 while (start >= db_lbuf_start &&
422 ((*start >= 'A' && *start <= 'Z') ||
423 (*start >= 'a' && *start <= 'z') ||
424 (*start >= '0' && *start <= '9') ||
425 *start == '_' || *start == ':'))
426 start--;
427 if (start == db_lc - 1)
428 break;
429 if (start > db_lbuf_start && *start == '$') {
430 cnputc('\007');
431 break;
432 }
433 sym = db_tok_string;
434 restart = ++start;
435 do {
436 *sym++ = *start++;
437 } while (start != db_lc &&
438 sym != db_tok_string + sizeof(db_tok_string));
439 if (sym == db_tok_string + sizeof(db_tok_string)) {
440 cnputc('\007');
441 break;
442 }
443 *sym = '\0';
444 db_completion = db_lookup_incomplete(db_tok_string,
445 sizeof(db_tok_string));
446 if (db_completion == 0) {
447 /* symbol unknown */
448 cnputc('\007');
449 break;
450 }
451
452 len = strlen(db_tok_string) - (start - restart);
453 if (db_completion == 1 &&
454 (db_le == db_lc ||
455 (db_le > db_lc) && *db_lc != ' '))
456 len++;
457 for (p = db_le - 1; p >= db_lc; p--)
458 *(p + len) = *p;
459 db_le += len;
460 for (sym = &db_tok_string[start - restart];
461 *sym != '\0'; sym++)
462 *db_lc++ = *sym;
463
464 if (db_completion == 1 || db_completion > db_auto_completion) {
465 for (sym = &db_tok_string[start - restart];
466 *sym != '\0'; sym++)
467 cnputc(*sym);
468 if (db_completion == 1) {
469 if (db_le == db_lc ||
470 (db_le > db_lc) && *db_lc != ' ') {
471 cnputc(' ');
472 *db_lc++ = ' ';
473 }
474 db_completion = 0;
475 }
476 db_putstring(db_lc, db_le - db_lc);
477 db_putnchars(BACKUP, db_le - db_lc);
478 }
479
480 if (db_completion > 1) {
481 cnputc('\007');
482 if (db_completion <= db_auto_completion) {
483 db_putchar('\n');
484 db_print_completion(db_tok_string);
485 db_completion = 0;
486 db_reset_more();
487 db_output_prompt();
488 if (db_le > db_lbuf_start) {
489 for (start = db_lbuf_start; start < db_le; start++)
490 db_putchar(*start);
491 db_putnchars(BACKUP, db_le - db_lc);
492 }
493 }
494 }
495 break;
496
497 case CTRL('b'):
498 /* back up one character */
499 if (db_lc > db_lbuf_start) {
500 cnputc(BACKUP);
501 db_lc--;
502 }
503 break;
504 case CTRL('f'):
505 /* forward one character */
506 if (db_lc < db_le) {
507 cnputc(*db_lc);
508 db_lc++;
509 }
510 break;
511 case CTRL('a'):
512 /* beginning of line */
513 while (db_lc > db_lbuf_start) {
514 cnputc(BACKUP);
515 db_lc--;
516 }
517 break;
518 case CTRL('e'):
519 /* end of line */
520 while (db_lc < db_le) {
521 cnputc(*db_lc);
522 db_lc++;
523 }
524 break;
525 case CTRL('h'):
526 case 0177:
527 /* erase previous character */
528 if (db_lc > db_lbuf_start)
529 db_delete(1, DEL_BWD);
530 break;
531 case CTRL('d'):
532 /* erase next character */
533 if (db_lc < db_le)
534 db_delete(1, DEL_FWD);
535 break;
536 case CTRL('k'):
537 /* delete to end of line */
538 if (db_lc < db_le)
539 db_delete(db_le - db_lc, DEL_FWD);
540 break;
541 case CTRL('u'):
542 /* delete to beginning of line */
543 if (db_lc > db_lbuf_start)
544 db_delete(db_lc - db_lbuf_start, DEL_BWD);
545 break;
546 case CTRL('t'):
547 /* twiddle last 2 characters */
548 if (db_lc >= db_lbuf_start + 2) {
549 c = db_lc[-2];
550 db_lc[-2] = db_lc[-1];
551 db_lc[-1] = c;
552 cnputc(BACKUP);
553 cnputc(BACKUP);
554 cnputc(db_lc[-2]);
555 cnputc(db_lc[-1]);
556 }
557 break;
558 case CTRL('c'):
559 case CTRL('g'):
560 db_delete_line();
561 #if DB_HISTORY_SIZE != 0
562 db_history_curr = db_history_last;
563 if (c == CTRL('g') && db_hist_search) {
564 char *p;
565 for (p = db_hist_search_string, db_le = db_lbuf_start;
566 *p; ) {
567 *db_le++ = *p++;
568 }
569 db_lc = db_le;
570 *db_le = '\0';
571 db_putstring(db_lbuf_start, db_le - db_lbuf_start);
572 }
573 #endif
574 break;
575 #if DB_HISTORY_SIZE != 0
576 case CTRL('r'):
577 if (db_hist_search++ == 0) {
578 /* starting an history lookup */
579 register char *cp1, *cp2;
580 for (cp1 = db_lbuf_start, cp2 = db_hist_search_string;
581 cp1 < db_le;
582 cp1++, cp2++)
583 *cp2 = *cp1;
584 *cp2 = '\0';
585 db_hist_search++;
586 }
587 /* FALL THROUGH */
588 case CTRL('p'):
589 {
590 char * old_history_curr = db_history_curr;
591
592 if (db_hist_unmodified++ == 0)
593 db_hist_unmodified++;
594 DEC_DB_CURR();
595 while (db_history_curr != db_history_last) {
596 DEC_DB_CURR();
597 if (*db_history_curr == '\0') {
598 INC_DB_CURR();
599 if (db_hist_search <= 1) {
600 if (*db_history_curr == '\0')
601 cnputc('\007');
602 else
603 DEC_DB_CURR();
604 break;
605 }
606 if (*db_history_curr == '\0') {
607 cnputc('\007');
608 db_history_curr = old_history_curr;
609 DEC_DB_CURR();
610 break;
611 }
612 if (db_history_curr != db_history_last &&
613 db_hist_substring(db_history_curr,
614 db_hist_search_string)) {
615 DEC_DB_CURR();
616 break;
617 }
618 DEC_DB_CURR();
619 }
620 }
621 if (db_history_curr == db_history_last) {
622 cnputc('\007');
623 db_history_curr = old_history_curr;
624 } else {
625 register char *p;
626 INC_DB_CURR();
627 db_delete_line();
628 for (p = db_history_curr, db_le = db_lbuf_start;
629 *p; ) {
630 *db_le++ = *p++;
631 if (p == db_history + db_history_size) {
632 p = db_history;
633 }
634 }
635 db_lc = db_le;
636 *db_le = '\0';
637 db_putstring(db_lbuf_start, db_le - db_lbuf_start);
638 }
639 break;
640 }
641 case CTRL('s'):
642 if (db_hist_search++ == 0) {
643 /* starting an history lookup */
644 register char *cp1, *cp2;
645 for (cp1 = db_lbuf_start, cp2 = db_hist_search_string;
646 cp1 < db_le;
647 cp1++, cp2++)
648 *cp2 = *cp1;
649 *cp2 = '\0';
650 db_hist_search++;
651 }
652 /* FALL THROUGH */
653 case CTRL('n'):
654 {
655 char *old_history_curr = db_history_curr;
656
657 if (db_hist_unmodified++ == 0)
658 db_hist_unmodified++;
659 while (db_history_curr != db_history_last) {
660 if (*db_history_curr == '\0') {
661 if (db_hist_search <= 1)
662 break;
663 INC_DB_CURR();
664 if (db_history_curr != db_history_last &&
665 db_hist_substring(db_history_curr,
666 db_hist_search_string)) {
667 DEC_DB_CURR();
668 break;
669 }
670 DEC_DB_CURR();
671 }
672 INC_DB_CURR();
673 }
674 if (db_history_curr != db_history_last) {
675 INC_DB_CURR();
676 if (db_history_curr != db_history_last) {
677 register char *p;
678 db_delete_line();
679 for (p = db_history_curr,
680 db_le = db_lbuf_start; *p;) {
681 *db_le++ = *p++;
682 if (p == db_history +
683 db_history_size) {
684 p = db_history;
685 }
686 }
687 db_lc = db_le;
688 *db_le = '\0';
689 db_putstring(db_lbuf_start,
690 db_le - db_lbuf_start);
691 } else {
692 cnputc('\007');
693 db_history_curr = old_history_curr;
694 }
695 } else {
696 cnputc('\007');
697 db_history_curr = old_history_curr;
698 }
699 break;
700 }
701 #endif
702 /* refresh the command line */
703 case CTRL('l'):
704 db_putstring("^L\n", 3);
705 if (db_le > db_lbuf_start) {
706 db_putstring(db_lbuf_start, db_le - db_lbuf_start);
707 db_putnchars(BACKUP, db_le - db_lc);
708 }
709 break;
710 case '\n':
711 case '\r':
712 #if DB_HISTORY_SIZE != 0
713 /* Check if it same than previous line */
714 if (db_history_prev) {
715 register char *pp, *pc;
716
717 /* Is it unmodified */
718 for (p = db_history_prev, pc = db_lbuf_start;
719 pc != db_le && *p;) {
720 if (*p != *pc)
721 break;
722 if (++p == db_history + db_history_size) {
723 p = db_history;
724 }
725 if (++pc == db_history + db_history_size) {
726 pc = db_history;
727 }
728 }
729 if (!*p && pc == db_le) {
730 /* Repeted previous line, not saved */
731 db_history_curr = db_history_last;
732 *db_le++ = c;
733 db_hist_search = 0;
734 db_hist_unmodified = 0;
735 return (TRUE);
736 }
737 }
738 if (db_le != db_lbuf_start &&
739 (db_hist_unmodified == 0 || !db_hist_ignore_dups)) {
740 db_history_prev = db_history_last;
741 for (p = db_lbuf_start; p != db_le; p++) {
742 *db_history_last++ = *p;
743 if (db_history_last == db_history +
744 db_history_size) {
745 db_history_last = db_history;
746 }
747 }
748 *db_history_last++ = '\0';
749 }
750 db_history_curr = db_history_last;
751 #endif
752 *db_le++ = c;
753 db_hist_search = 0;
754 db_hist_unmodified = 0;
755 return (TRUE);
756 default:
757 if (db_le == db_lbuf_end) {
758 cnputc('\007');
759 }
760 else if (c >= ' ' && c <= '~') {
761 for (p = db_le; p > db_lc; p--)
762 *p = *(p-1);
763 *db_lc++ = c;
764 db_le++;
765 cnputc(c);
766 db_putstring(db_lc, db_le - db_lc);
767 db_putnchars(BACKUP, db_le - db_lc);
768 }
769 break;
770 }
771 if (db_hist_search)
772 db_hist_search--;
773 if (db_hist_unmodified)
774 db_hist_unmodified--;
775 return (FALSE);
776 }
777
778 int
779 db_readline(
780 char * lstart,
781 int lsize)
782 {
783 db_force_whitespace(); /* synch output position */
784
785 db_lbuf_start = lstart;
786 db_lbuf_end = lstart + lsize - 1;
787 db_lc = lstart;
788 db_le = lstart;
789
790 while (!db_inputchar(cngetc()))
791 continue;
792
793 db_putchar('\n'); /* synch output position */
794
795 *db_le = 0;
796 return (db_le - db_lbuf_start);
797 }
798
799 void
800 db_check_interrupt(void)
801 {
802 register int c;
803
804 c = cnmaygetc();
805 switch (c) {
806 case -1: /* no character */
807 return;
808
809 case CTRL('c'):
810 db_error((char *)0);
811 /*NOTREACHED*/
812
813 case CTRL('s'):
814 do {
815 c = cnmaygetc();
816 if (c == CTRL('c'))
817 db_error((char *)0);
818 } while (c != CTRL('q'));
819 break;
820
821 default:
822 /* drop on floor */
823 break;
824 }
825 }