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