#include <string.h>
#include <mach/boolean.h>
#include <machine/db_machdep.h>
#include <kern/misc_protos.h>
#include <ddb/db_output.h>
#include <ddb/db_lex.h>
#include <ddb/db_command.h>
#include <ddb/db_input.h>
#include <ddb/db_sym.h>
#ifndef DB_HISTORY_SIZE
#define DB_HISTORY_SIZE 4000
#endif
char * db_lbuf_start;
char * db_lbuf_end;
char * db_lc;
char * db_le;
int db_completion;
int db_auto_completion = 10;
#if DB_HISTORY_SIZE != 0
char db_history[DB_HISTORY_SIZE];
int db_history_size = DB_HISTORY_SIZE;
char * db_history_curr = db_history;
char * db_history_last = db_history;
char * db_history_prev = (char *) 0;
int db_hist_unmodified = 0;
int db_hist_search = 0;
char db_hist_search_string[DB_LEX_LINE_SIZE];
int db_hist_ignore_dups = 0;
#endif
#define CTRL(c) ((c) & 0x1f)
#define isspace(c) ((c) == ' ' || (c) == '\t')
#define BLANK ' '
#define BACKUP '\b'
void db_putstring(const char *s, int count);
void db_putnchars(
int c,
int count);
void db_delete(
int n,
int bwd);
void db_delete_line(void);
boolean_t db_hist_substring(
char *string,
char *substring);
boolean_t db_inputchar(int c);
extern jmp_buf_t *db_recover;
void
db_putstring(const char *s, int count)
{
while (--count >= 0)
cnputc(*s++);
}
void
db_putnchars(
int c,
int count)
{
while (--count >= 0)
cnputc(c);
}
#define DEL_FWD 0
#define DEL_BWD 1
void
db_delete(
int n,
int bwd)
{
register char *p;
if (bwd) {
db_lc -= n;
db_putnchars(BACKUP, n);
}
for (p = db_lc; p < db_le-n; p++) {
*p = *(p+n);
cnputc(*p);
}
db_putnchars(BLANK, n);
db_putnchars(BACKUP, db_le - db_lc);
db_le -= n;
}
void
db_delete_line(void)
{
db_delete(db_le - db_lc, DEL_FWD);
db_delete(db_lc - db_lbuf_start, DEL_BWD);
db_le = db_lc = db_lbuf_start;
}
#if DB_HISTORY_SIZE != 0
#define INC_DB_CURR() \
do { \
db_history_curr++; \
if (db_history_curr > \
db_history + db_history_size - 1) \
db_history_curr = db_history; \
} while (0)
#define DEC_DB_CURR() \
do { \
db_history_curr--; \
if (db_history_curr < db_history) \
db_history_curr = db_history + \
db_history_size - 1; \
} while (0)
#endif
boolean_t
db_hist_substring(
char *string,
char *substring)
{
register char *cp1, *cp2;
cp1 = string;
while (*cp1)
cp1++;
cp2 = substring;
while (*cp2)
cp2++;
while (cp2 > substring) {
cp1--; cp2--;
}
while (cp1 >= string) {
register char *cp3;
cp2 = substring;
cp3 = cp1;
while (*cp2 && *cp2 == *cp3) {
cp2++; cp3++;
}
if (*cp2 == '\0') {
return TRUE;
}
cp1--;
}
return FALSE;
}
boolean_t
db_inputchar(int c)
{
char *sym;
char *start;
char *restart;
jmp_buf_t db_jmpbuf;
jmp_buf_t *local_prev;
char *p;
int len;
switch(db_completion) {
case -1:
db_putchar('\n');
local_prev = db_recover;
if (_setjmp(db_recover = &db_jmpbuf) == 0 &&
(c == 'y' || c == ' ' || c == '\t'))
db_print_completion(db_tok_string);
db_recover = local_prev;
db_completion = 0;
db_reset_more();
db_output_prompt();
if (db_le > db_lbuf_start) {
for (start = db_lbuf_start; start < db_le; start++)
db_putchar(*start);
db_putnchars(BACKUP, db_le - db_lc);
}
return(FALSE);
case 0:
break;
default:
if (c == '\t') {
db_printf("\nThere are %d possibilities. ", db_completion);
db_printf("Do you really wish to see them all [n] ? ");
db_force_whitespace();
db_completion = -1;
db_reset_more();
return(FALSE);
}
db_completion = 0;
break;
}
switch (c) {
case '\t':
if (db_lc == db_lbuf_start || db_auto_completion == 0)
break;
if (db_le == db_lbuf_end) {
cnputc('\007');
break;
}
start = db_lc - 1;
while (start >= db_lbuf_start &&
((*start >= 'A' && *start <= 'Z') ||
(*start >= 'a' && *start <= 'z') ||
(*start >= '0' && *start <= '9') ||
*start == '_' || *start == ':'))
start--;
if (start == db_lc - 1)
break;
if (start > db_lbuf_start && *start == '$') {
cnputc('\007');
break;
}
sym = db_tok_string;
restart = ++start;
do {
*sym++ = *start++;
} while (start != db_lc &&
sym != db_tok_string + sizeof(db_tok_string));
if (sym == db_tok_string + sizeof(db_tok_string)) {
cnputc('\007');
break;
}
*sym = '\0';
db_completion = db_lookup_incomplete(db_tok_string,
sizeof(db_tok_string));
if (db_completion == 0) {
cnputc('\007');
break;
}
len = strlen(db_tok_string) - (start - restart);
if (db_completion == 1 &&
(db_le == db_lc ||
((db_le > db_lc) && *db_lc != ' ')))
len++;
for (p = db_le - 1; p >= db_lc; p--)
*(p + len) = *p;
db_le += len;
for (sym = &db_tok_string[start - restart];
*sym != '\0'; sym++)
*db_lc++ = *sym;
if (db_completion == 1 || db_completion > db_auto_completion) {
for (sym = &db_tok_string[start - restart];
*sym != '\0'; sym++)
cnputc(*sym);
if (db_completion == 1) {
if (db_le == db_lc ||
((db_le > db_lc) && *db_lc != ' ')) {
cnputc(' ');
*db_lc++ = ' ';
}
db_completion = 0;
}
db_putstring(db_lc, db_le - db_lc);
db_putnchars(BACKUP, db_le - db_lc);
}
if (db_completion > 1) {
cnputc('\007');
if (db_completion <= db_auto_completion) {
db_putchar('\n');
db_print_completion(db_tok_string);
db_completion = 0;
db_reset_more();
db_output_prompt();
if (db_le > db_lbuf_start) {
for (start = db_lbuf_start; start < db_le; start++)
db_putchar(*start);
db_putnchars(BACKUP, db_le - db_lc);
}
}
}
break;
case CTRL('b'):
if (db_lc > db_lbuf_start) {
cnputc(BACKUP);
db_lc--;
}
break;
case CTRL('f'):
if (db_lc < db_le) {
cnputc(*db_lc);
db_lc++;
}
break;
case CTRL('a'):
while (db_lc > db_lbuf_start) {
cnputc(BACKUP);
db_lc--;
}
break;
case CTRL('e'):
while (db_lc < db_le) {
cnputc(*db_lc);
db_lc++;
}
break;
case CTRL('h'):
case 0177:
if (db_lc > db_lbuf_start)
db_delete(1, DEL_BWD);
break;
case CTRL('d'):
if (db_lc < db_le)
db_delete(1, DEL_FWD);
break;
case CTRL('k'):
if (db_lc < db_le)
db_delete(db_le - db_lc, DEL_FWD);
break;
case CTRL('u'):
if (db_lc > db_lbuf_start)
db_delete(db_lc - db_lbuf_start, DEL_BWD);
break;
case CTRL('t'):
if (db_lc >= db_lbuf_start + 2) {
c = db_lc[-2];
db_lc[-2] = db_lc[-1];
db_lc[-1] = c;
cnputc(BACKUP);
cnputc(BACKUP);
cnputc(db_lc[-2]);
cnputc(db_lc[-1]);
}
break;
case CTRL('c'):
case CTRL('g'):
db_delete_line();
#if DB_HISTORY_SIZE != 0
db_history_curr = db_history_last;
if (c == CTRL('g') && db_hist_search) {
for (p = db_hist_search_string, db_le = db_lbuf_start;
*p; ) {
*db_le++ = *p++;
}
db_lc = db_le;
*db_le = '\0';
db_putstring(db_lbuf_start, db_le - db_lbuf_start);
}
#endif
break;
#if DB_HISTORY_SIZE != 0
case CTRL('r'):
if (db_hist_search++ == 0) {
register char *cp1, *cp2;
for (cp1 = db_lbuf_start, cp2 = db_hist_search_string;
cp1 < db_le;
cp1++, cp2++)
*cp2 = *cp1;
*cp2 = '\0';
db_hist_search++;
}
case CTRL('p'):
{
char * old_history_curr = db_history_curr;
if (db_hist_unmodified++ == 0)
db_hist_unmodified++;
DEC_DB_CURR();
while (db_history_curr != db_history_last) {
DEC_DB_CURR();
if (*db_history_curr == '\0') {
INC_DB_CURR();
if (db_hist_search <= 1) {
if (*db_history_curr == '\0')
cnputc('\007');
else
DEC_DB_CURR();
break;
}
if (*db_history_curr == '\0') {
cnputc('\007');
db_history_curr = old_history_curr;
DEC_DB_CURR();
break;
}
if (db_history_curr != db_history_last &&
db_hist_substring(db_history_curr,
db_hist_search_string)) {
DEC_DB_CURR();
break;
}
DEC_DB_CURR();
}
}
if (db_history_curr == db_history_last) {
cnputc('\007');
db_history_curr = old_history_curr;
} else {
INC_DB_CURR();
db_delete_line();
for (p = db_history_curr, db_le = db_lbuf_start;
*p; ) {
*db_le++ = *p++;
if (p == db_history + db_history_size) {
p = db_history;
}
}
db_lc = db_le;
*db_le = '\0';
db_putstring(db_lbuf_start, db_le - db_lbuf_start);
}
break;
}
case CTRL('s'):
if (db_hist_search++ == 0) {
register char *cp1, *cp2;
for (cp1 = db_lbuf_start, cp2 = db_hist_search_string;
cp1 < db_le;
cp1++, cp2++)
*cp2 = *cp1;
*cp2 = '\0';
db_hist_search++;
}
case CTRL('n'):
{
char *old_history_curr = db_history_curr;
if (db_hist_unmodified++ == 0)
db_hist_unmodified++;
while (db_history_curr != db_history_last) {
if (*db_history_curr == '\0') {
if (db_hist_search <= 1)
break;
INC_DB_CURR();
if (db_history_curr != db_history_last &&
db_hist_substring(db_history_curr,
db_hist_search_string)) {
DEC_DB_CURR();
break;
}
DEC_DB_CURR();
}
INC_DB_CURR();
}
if (db_history_curr != db_history_last) {
INC_DB_CURR();
if (db_history_curr != db_history_last) {
db_delete_line();
for (p = db_history_curr,
db_le = db_lbuf_start; *p;) {
*db_le++ = *p++;
if (p == db_history +
db_history_size) {
p = db_history;
}
}
db_lc = db_le;
*db_le = '\0';
db_putstring(db_lbuf_start,
db_le - db_lbuf_start);
} else {
cnputc('\007');
db_history_curr = old_history_curr;
}
} else {
cnputc('\007');
db_history_curr = old_history_curr;
}
break;
}
#endif
case CTRL('l'):
db_putstring("^L\n", 3);
if (db_le > db_lbuf_start) {
db_putstring(db_lbuf_start, db_le - db_lbuf_start);
db_putnchars(BACKUP, db_le - db_lc);
}
break;
case '\n':
case '\r':
#if DB_HISTORY_SIZE != 0
if (db_history_prev) {
char *pc;
for (p = db_history_prev, pc = db_lbuf_start;
pc != db_le && *p;) {
if (*p != *pc)
break;
if (++p == db_history + db_history_size) {
p = db_history;
}
if (++pc == db_history + db_history_size) {
pc = db_history;
}
}
if (!*p && pc == db_le) {
db_history_curr = db_history_last;
*db_le++ = c;
db_hist_search = 0;
db_hist_unmodified = 0;
return (TRUE);
}
}
if (db_le != db_lbuf_start &&
(db_hist_unmodified == 0 || !db_hist_ignore_dups)) {
db_history_prev = db_history_last;
for (p = db_lbuf_start; p != db_le; p++) {
*db_history_last++ = *p;
if (db_history_last == db_history +
db_history_size) {
db_history_last = db_history;
}
}
*db_history_last++ = '\0';
}
db_history_curr = db_history_last;
#endif
*db_le++ = c;
db_hist_search = 0;
db_hist_unmodified = 0;
return (TRUE);
default:
if (db_le == db_lbuf_end) {
cnputc('\007');
}
else if (c >= ' ' && c <= '~') {
for (p = db_le; p > db_lc; p--)
*p = *(p-1);
*db_lc++ = c;
db_le++;
cnputc(c);
db_putstring(db_lc, db_le - db_lc);
db_putnchars(BACKUP, db_le - db_lc);
}
break;
}
if (db_hist_search)
db_hist_search--;
if (db_hist_unmodified)
db_hist_unmodified--;
return (FALSE);
}
int
db_readline(
char * lstart,
int lsize)
{
db_force_whitespace();
db_lbuf_start = lstart;
db_lbuf_end = lstart + lsize - 1;
db_lc = lstart;
db_le = lstart;
while (!db_inputchar(cngetc()))
continue;
db_putchar('\n');
*db_le = 0;
return (db_le - db_lbuf_start);
}
void
db_check_interrupt(void)
{
register int c;
c = cnmaygetc();
switch (c) {
case -1:
return;
case CTRL('c'):
db_error((char *)0);
case CTRL('s'):
do {
c = cnmaygetc();
if (c == CTRL('c'))
db_error((char *)0);
} while (c != CTRL('q'));
break;
default:
break;
}
}