X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=inline;f=cmdedit.c;h=042064f1ed663acd7db2c64002014f1af1772afd;hb=437bf72785cdd8c9d689c241a94c79f1f71a2354;hp=d1604f1d1dc41423bcfe03bc1cfb90d135b44867;hpb=13456d1fcd0122d8464c3c3e1c356d86a56e6c08;p=oweals%2Fbusybox.git diff --git a/cmdedit.c b/cmdedit.c index d1604f1d1..042064f1e 100644 --- a/cmdedit.c +++ b/cmdedit.c @@ -1,9 +1,12 @@ +/* vi: set sw=4 ts=4: */ /* - * Termios command line History and Editting for NetBSD sh (ash) + * Termios command line History and Editting, originally + * intended for NetBSD sh (ash) * Copyright (c) 1999 * Main code: Adam Rogoyski * Etc: Dave Cinege - * Adjusted for busybox: Erik Andersen + * Majorly adjusted/re-written for busybox: + * Erik Andersen * * You may use this code as you wish, so long as the original author(s) * are attributed in any redistributions of the source code. @@ -36,370 +39,703 @@ #include #include #include -#include +#include #include #include -#include "cmdedit.h" - -#define MAX_HISTORY 15 /* Maximum length of the linked list for the command line history */ +#define MAX_HISTORY 15 /* Maximum length of the linked list for the command line history */ #define ESC 27 #define DEL 127 +#define member(c, s) ((c) ? ((char *)strchr ((s), (c)) != (char *)NULL) : 0) +#define whitespace(c) (((c) == ' ') || ((c) == '\t')) static struct history *his_front = NULL; /* First element in command line list */ static struct history *his_end = NULL; /* Last element in command line list */ -static struct termio old_term, new_term; /* Current termio and the previous termio before starting ash */ +/* ED: sparc termios is broken: revert back to old termio handling. */ +#ifdef BB_FEATURE_USE_TERMIOS + +#if #cpu(sparc) +# include +# define termios termio +# define setTermSettings(fd,argp) ioctl(fd,TCSETAF,argp) +# define getTermSettings(fd,argp) ioctl(fd,TCGETA,argp) +#else +# include +# define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) +# define getTermSettings(fd,argp) tcgetattr(fd, argp); +#endif + +/* Current termio and the previous termio before starting sh */ +struct termios initial_settings, new_settings; + + +#ifndef _POSIX_VDISABLE +#define _POSIX_VDISABLE '\0' +#endif + +#endif + + + +static int cmdedit_termw = 80; /* actual terminal width */ +static int cmdedit_scroll = 27; /* width of EOL scrolling region */ static int history_counter = 0; /* Number of commands in history list */ -static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ -char *parsenextc; /* copy of parsefile->nextc */ +static int reset_term = 0; /* Set to true if the terminal needs to be reset upon exit */ +static int exithandler_set = 0; /* Set to true when atexit() has been called */ struct history { - char *s; - struct history *p; - struct history *n; + char *s; + struct history *p; + struct history *n; }; +#define xwrite write -/* Version of write which resumes after a signal is caught. */ -int xwrite(int fd, char *buf, int nbytes) +/* + * TODO: Someday we want to implement 'horizontal scrolling' of the + * command-line when the user has typed more than the current width. This + * would allow the user to see a 'window' of what he has typed. + */ +void +cmdedit_setwidth(int w) { - int ntry; - int i; - int n; - - n = nbytes; - ntry = 0; - for (;;) { - i = write(fd, buf, n); - if (i > 0) { - if ((n -= i) <= 0) - return nbytes; - buf += i; - ntry = 0; - } else if (i == 0) { - if (++ntry > 10) - return nbytes - n; - } else if (errno != EINTR) { - return -1; + if (w > 20) { + cmdedit_termw = w; + cmdedit_scroll = w / 3; + } else { + errorMsg("\n*** Error: minimum screen width is 21\n"); } - } -} - - -/* Version of ioctl that retries after a signal is caught. */ -int xioctl(int fd, unsigned long request, char *arg) -{ - int i; - while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); - return i; } void cmdedit_reset_term(void) { - if (reset_term) - xioctl(fileno(stdin), TCSETA, (void *) &old_term); + if (reset_term) + /* sparc and other have broken termios support: use old termio handling. */ + setTermSettings(fileno(stdin), (void*) &initial_settings); +#ifdef BB_FEATURE_CLEAN_UP + if (his_front) { + struct history *n; + //while(his_front!=his_end) { + while(his_front!=his_end) { + n = his_front->n; + free(his_front->s); + free(his_front); + his_front=n; + } + } +#endif } -void gotaSignal(int sig) +void clean_up_and_die(int sig) { - cmdedit_reset_term(); - fprintf(stdout, "\n"); - exit(TRUE); + cmdedit_reset_term(); + fprintf(stdout, "\n"); + if (sig!=SIGINT) + exit(TRUE); } +/* Go to HOME position */ void input_home(int outputFd, int *cursor) -{ /* Command line input routines */ - while (*cursor > 0) { - xwrite(outputFd, "\b", 1); - --*cursor; - } +{ + while (*cursor > 0) { + xwrite(outputFd, "\b", 1); + --*cursor; + } } +/* Go to END position */ +void input_end(int outputFd, int *cursor, int len) +{ + while (*cursor < len) { + xwrite(outputFd, "\033[C", 3); + ++*cursor; + } +} -void input_delete(int outputFd, int cursor) +/* Delete the char in back of the cursor */ +void input_backspace(char* command, int outputFd, int *cursor, int *len) { - int j = 0; + int j = 0; - memmove(parsenextc + cursor, parsenextc + cursor + 1, - BUFSIZ - cursor - 1); - for (j = cursor; j < (BUFSIZ - 1); j++) { - if (!*(parsenextc + j)) - break; - else - xwrite(outputFd, (parsenextc + j), 1); - } +/* Debug crap */ +//fprintf(stderr, "\nerik: len=%d, cursor=%d, strlen(command)='%d'\n", *len, *cursor, strlen(command)); +//xwrite(outputFd, command, *len); +//*cursor = *len; - xwrite(outputFd, " \b", 2); - while (j-- > cursor) - xwrite(outputFd, "\b", 1); -} + if (*cursor > 0) { + xwrite(outputFd, "\b \b", 3); + --*cursor; + memmove(command + *cursor, command + *cursor + 1, + BUFSIZ - *cursor + 1); + for (j = *cursor; j < (BUFSIZ - 1); j++) { + if (!*(command + j)) + break; + else + xwrite(outputFd, (command + j), 1); + } -void input_end(int outputFd, int *cursor, int len) -{ - while (*cursor < len) { - xwrite(outputFd, "\033[C", 3); - ++*cursor; - } -} + xwrite(outputFd, " \b", 2); + while (j-- > *cursor) + xwrite(outputFd, "\b", 1); -void input_backspace(int outputFd, int *cursor, int *len) + --*len; + } +} + +/* Delete the char in front of the cursor */ +void input_delete(char* command, int outputFd, int cursor, int *len) { - int j = 0; - - if (*cursor > 0) { - xwrite(outputFd, "\b \b", 3); - --*cursor; - memmove(parsenextc + *cursor, parsenextc + *cursor + 1, - BUFSIZ - *cursor + 1); - - for (j = *cursor; j < (BUFSIZ - 1); j++) { - if (!*(parsenextc + j)) - break; - else - xwrite(outputFd, (parsenextc + j), 1); + int j = 0; + + if (cursor == *len) + return; + + memmove(command + cursor, command + cursor + 1, + BUFSIZ - cursor - 1); + for (j = cursor; j < (BUFSIZ - 1); j++) { + if (!*(command + j)) + break; + else + xwrite(outputFd, (command + j), 1); } xwrite(outputFd, " \b", 2); - while (j-- > *cursor) - xwrite(outputFd, "\b", 1); - + while (j-- > cursor) + xwrite(outputFd, "\b", 1); --*len; - } } -extern int cmdedit_read_input(int inputFd, int outputFd, - char command[BUFSIZ]) +/* Move forward one charactor */ +void input_forward(int outputFd, int *cursor, int len) { + if (*cursor < len) { + xwrite(outputFd, "\033[C", 3); + ++*cursor; + } +} - int nr = 0; - int len = 0; - int j = 0; - int cursor = 0; - int break_out = 0; - int ret = 0; - char c = 0; - struct history *hp = his_end; - - memset(command, 0, sizeof(command)); - parsenextc = command; - if (!reset_term) { - xioctl(inputFd, TCGETA, (void *) &old_term); - memcpy(&new_term, &old_term, sizeof(struct termio)); - new_term.c_cc[VMIN] = 1; - new_term.c_cc[VTIME] = 0; - new_term.c_lflag &= ~ICANON; /* unbuffered input */ - new_term.c_lflag &= ~ECHO; - xioctl(inputFd, TCSETA, (void *) &new_term); - reset_term = 1; - } else { - xioctl(inputFd, TCSETA, (void *) &new_term); - } - - memset(parsenextc, 0, BUFSIZ); - - while (1) { - - if ((ret = read(inputFd, &c, 1)) < 1) - return ret; - - switch (c) { - case 1: /* Control-A Beginning of line */ - input_home(outputFd, &cursor); - break; - case 5: /* Control-E EOL */ - input_end(outputFd, &cursor, len); - break; - case 4: /* Control-D */ - if (cursor != len) { - input_delete(outputFd, cursor); - len--; - } - break; - case '\b': /* Backspace */ - case DEL: - input_backspace(outputFd, &cursor, &len); - break; - case '\n': /* Enter */ - *(parsenextc + len++ + 1) = c; - xwrite(outputFd, &c, 1); - break_out = 1; - break; - case ESC: /* escape sequence follows */ - if ((ret = read(inputFd, &c, 1)) < 1) - return ret; - - if (c == '[') { /* 91 */ - if ((ret = read(inputFd, &c, 1)) < 1) - return ret; +/* Move back one charactor */ +void input_backward(int outputFd, int *cursor) +{ + if (*cursor > 0) { + xwrite(outputFd, "\033[D", 3); + --*cursor; + } +} - switch (c) { - case 'A': - if (hp && hp->p) { /* Up */ - hp = hp->p; - goto hop; - } - break; - case 'B': - if (hp && hp->n && hp->n->s) { /* Down */ - hp = hp->n; - goto hop; - } - break; - - hop: /* hop */ - len = strlen(parsenextc); - - for (; cursor > 0; cursor--) /* return to begining of line */ - xwrite(outputFd, "\b", 1); - for (j = 0; j < len; j++) /* erase old command */ - xwrite(outputFd, " ", 1); - for (j = len; j > 0; j--) /* return to begining of line */ - xwrite(outputFd, "\b", 1); +#ifdef BB_FEATURE_SH_TAB_COMPLETION +char** username_tab_completion(char* command, int *num_matches) +{ + char **matches = (char **) NULL; + *num_matches=0; + fprintf(stderr, "\nin username_tab_completion\n"); + return (matches); +} - strcpy(parsenextc, hp->s); /* write new command */ - len = strlen(hp->s); - xwrite(outputFd, parsenextc, len); - cursor = len; - break; - case 'C': /* Right */ - if (cursor < len) { - xwrite(outputFd, "\033[C", 3); - cursor++; - } - break; - case 'D': /* Left */ - if (cursor > 0) { - xwrite(outputFd, "\033[D", 3); - cursor--; - } - break; - case '3': /* Delete */ - if (cursor != len) { - input_delete(outputFd, cursor); - len--; - } - break; - case '1': /* Home (Ctrl-A) */ - input_home(outputFd, &cursor); - break; - case '4': /* End (Ctrl-E) */ - input_end(outputFd, &cursor, len); - break; - } - if (c == '1' || c == '3' || c == '4') - if ((ret = read(inputFd, &c, 1)) < 1) - return ret; /* read 126 (~) */ - } - if (c == 'O') { /* 79 */ - if ((ret = read(inputFd, &c, 1)) < 1) - return ret; - switch (c) { - case 'H': /* Home (xterm) */ - input_home(outputFd, &cursor); - break; - case 'F': /* End (xterm) */ - input_end(outputFd, &cursor, len); - break; +#include +char** exe_n_cwd_tab_completion(char* command, int *num_matches) +{ + char *dirName; + char **matches = (char **) NULL; + DIR *dir; + struct dirent *next; + + matches = malloc( sizeof(char*)*50); + + /* Stick a wildcard onto the command, for later use */ + strcat( command, "*"); + + /* Now wall the current directory */ + dirName = get_current_dir_name(); + dir = opendir(dirName); + if (!dir) { + /* Don't print an error, just shut up and return */ + *num_matches=0; + return (matches); + } + while ((next = readdir(dir)) != NULL) { + + /* Some quick sanity checks */ + if ((strcmp(next->d_name, "..") == 0) + || (strcmp(next->d_name, ".") == 0)) { + continue; + } + /* See if this matches */ + if (check_wildcard_match(next->d_name, command) == TRUE) { + /* Cool, found a match. Add it to the list */ + matches[*num_matches] = malloc(strlen(next->d_name)+1); + strcpy( matches[*num_matches], next->d_name); + ++*num_matches; + //matches = realloc( matches, sizeof(char*)*(*num_matches)); } - } - c = 0; - break; - - default: /* If it's regular input, do the normal thing */ - - if (!isprint(c)) /* Skip non-printable characters */ - break; - - if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ - break; + } - len++; + return (matches); +} - if (cursor == (len - 1)) { /* Append if at the end of the line */ - *(parsenextc + cursor) = c; - } else { /* Insert otherwise */ - memmove(parsenextc + cursor + 1, parsenextc + cursor, - len - cursor - 1); +void input_tab(char* command, char* prompt, int outputFd, int *cursor, int *len) +{ + /* Do TAB completion */ + static int num_matches=0; + static char **matches = (char **) NULL; + int pos = cursor; + + + if (lastWasTab == FALSE) { + char *tmp, *tmp1, *matchBuf; + + /* For now, we will not bother with trying to distinguish + * whether the cursor is in/at a command extression -- we + * will always try all possible matches. If you don't like + * that then feel free to fix it. + */ + + /* Make a local copy of the string -- up + * to the position of the cursor */ + matchBuf = (char *) calloc(BUFSIZ, sizeof(char)); + strncpy(matchBuf, command, cursor); + tmp=matchBuf; + + /* skip past any command seperator tokens */ + while (*tmp && (tmp1=strpbrk(tmp, ";|&{(`")) != NULL) { + tmp=++tmp1; + /* skip any leading white space */ + while (*tmp && isspace(*tmp)) + ++tmp; + } - *(parsenextc + cursor) = c; + /* skip any leading white space */ + while (*tmp && isspace(*tmp)) + ++tmp; - for (j = cursor; j < len; j++) - xwrite(outputFd, parsenextc + j, 1); - for (; j > cursor; j--) - xwrite(outputFd, "\033[D", 3); - } + /* Free up any memory already allocated */ + if (matches) { + free(matches); + matches = (char **) NULL; + } - cursor++; - xwrite(outputFd, &c, 1); - break; + /* If the word starts with `~' and there is no slash in the word, + * then try completing this word as a username. */ + + /* FIXME -- this check is broken! */ + if (*tmp == '~' && !strchr(tmp, '/')) + matches = username_tab_completion(tmp, &num_matches); + + /* Try to match any executable in our path and everything + * in the current working directory that matches. */ + if (!matches) + matches = exe_n_cwd_tab_completion(tmp, &num_matches); + + /* Don't leak memory */ + free( matchBuf); + + /* Did we find exactly one match? */ + if (matches && num_matches==1) { + /* write out the matched command */ + strncpy(command+pos, matches[0]+pos, strlen(matches[0])-pos); + len=strlen(command); + cursor=len; + xwrite(outputFd, matches[0]+pos, strlen(matches[0])-pos); + break; + } + } else { + /* Ok -- the last char was a TAB. Since they + * just hit TAB again, print a list of all the + * available choices... */ + if ( matches && num_matches>0 ) { + int i, col; + + /* Go to the next line */ + xwrite(outputFd, "\n", 1); + /* Print the list of matches */ + for (i=0,col=0; i 60 && matches[i+1] != NULL) { + xwrite(outputFd, "\n", 1); + col = 0; + } + } + /* Go to the next line */ + xwrite(outputFd, "\n", 1); + /* Rewrite the prompt */ + xwrite(outputFd, prompt, strlen(prompt)); + /* Rewrite the command */ + xwrite(outputFd, command, len); + /* Put the cursor back to where it used to be */ + for (cursor=len; cursor > pos; cursor--) + xwrite(outputFd, "\b", 1); + } } +} +#endif - if (break_out) /* Enter is the command terminator, no more input. */ - break; - } - - nr = len + 1; - xioctl(inputFd, TCSETA, (void *) &old_term); - reset_term = 0; +void get_previous_history(struct history **hp, char* command) +{ + if ((*hp)->s) + free((*hp)->s); + (*hp)->s = strdup(command); + *hp = (*hp)->p; +} +void get_next_history(struct history **hp, char* command) +{ + if ((*hp)->s) + free((*hp)->s); + (*hp)->s = strdup(command); + *hp = (*hp)->n; +} - if (*(parsenextc)) { /* Handle command history log */ +/* + * This function is used to grab a character buffer + * from the input file descriptor and allows you to + * a string with full command editing (sortof like + * a mini readline). + * + * The following standard commands are not implemented: + * ESC-b -- Move back one word + * ESC-f -- Move forward one word + * ESC-d -- Delete back one word + * ESC-h -- Delete forward one word + * CTL-t -- Transpose two characters + * + * Furthermore, the "vi" command editing keys are not implemented. + * + * TODO: implement TAB command completion. :) + */ +extern void cmdedit_read_input(char* prompt, char command[BUFSIZ]) +{ - struct history *h = his_end; + int inputFd=fileno(stdin); + int outputFd=fileno(stdout); + int nr = 0; + int len = 0; + int j = 0; + int cursor = 0; + int break_out = 0; + int ret = 0; + int lastWasTab = FALSE; + char c = 0; + struct history *hp = his_end; + + if (!reset_term) { + + getTermSettings(inputFd, (void*) &initial_settings); + memcpy(&new_settings, &initial_settings, sizeof(struct termios)); + new_settings.c_cc[VMIN] = 1; + new_settings.c_cc[VTIME] = 0; + new_settings.c_cc[VINTR] = _POSIX_VDISABLE; /* Turn off CTRL-C, so we can trap it */ + new_settings.c_lflag &= ~ICANON; /* unbuffered input */ + new_settings.c_lflag &= ~(ECHO|ECHOCTL|ECHONL); /* Turn off echoing */ + reset_term = 1; + } + setTermSettings(inputFd, (void*) &new_settings); - if (!h) { /* No previous history */ - h = his_front = malloc(sizeof(struct history)); - h->n = malloc(sizeof(struct history)); - h->p = NULL; - h->s = strdup(parsenextc); + memset(command, 0, BUFSIZ); - h->n->p = h; - h->n->n = NULL; - h->n->s = NULL; - his_end = h->n; - history_counter++; - } else { /* Add a new history command */ + while (1) { - h->n = malloc(sizeof(struct history)); + if ((ret = read(inputFd, &c, 1)) < 1) + return; + //fprintf(stderr, "got a '%c' (%d)\n", c, c); - h->n->p = h; - h->n->n = NULL; - h->n->s = NULL; - h->s = strdup(parsenextc); - his_end = h->n; + switch (c) { + case '\n': + case '\r': + /* Enter */ + *(command + len++ + 1) = c; + xwrite(outputFd, &c, 1); + break_out = 1; + break; + case 1: + /* Control-a -- Beginning of line */ + input_home(outputFd, &cursor); + case 2: + /* Control-b -- Move back one character */ + input_backward(outputFd, &cursor); + break; + case 3: + /* Control-c -- leave the current line, + * and start over on the next line */ + + /* Go to the next line */ + xwrite(outputFd, "\n", 1); + + /* Rewrite the prompt */ + xwrite(outputFd, prompt, strlen(prompt)); + + /* Reset the command string */ + memset(command, 0, BUFSIZ); + len = cursor = 0; + + break; + case 4: + /* Control-d -- Delete one character, or exit + * if the len=0 and no chars to delete */ + if (len == 0) { + xwrite(outputFd, "exit", 4); + clean_up_and_die(0); + } else { + input_delete(command, outputFd, cursor, &len); + } + break; + case 5: + /* Control-e -- End of line */ + input_end(outputFd, &cursor, len); + break; + case 6: + /* Control-f -- Move forward one character */ + input_forward(outputFd, &cursor, len); + break; + case '\b': + case DEL: + /* Control-h and DEL */ + input_backspace(command, outputFd, &cursor, &len); + break; + case '\t': +#ifdef BB_FEATURE_SH_TAB_COMPLETION + input_tab(command, prompt, outputFd, &cursor, &len); +#endif + break; + case 14: + /* Control-n -- Get next command in history */ + if (hp && hp->n && hp->n->s) { + get_next_history(&hp, command); + goto rewrite_line; + } else { + xwrite(outputFd, "\007", 1); + } + break; + case 16: + /* Control-p -- Get previous command from history */ + if (hp && hp->p) { + get_previous_history(&hp, command); + goto rewrite_line; + } else { + xwrite(outputFd, "\007", 1); + } + break; + case ESC:{ + /* escape sequence follows */ + if ((ret = read(inputFd, &c, 1)) < 1) + return; + + if (c == '[') { /* 91 */ + if ((ret = read(inputFd, &c, 1)) < 1) + return; + + switch (c) { + case 'A': + /* Up Arrow -- Get previous command from history */ + if (hp && hp->p) { + get_previous_history(&hp, command); + goto rewrite_line; + } else { + xwrite(outputFd, "\007", 1); + } + break; + case 'B': + /* Down Arrow -- Get next command in history */ + if (hp && hp->n && hp->n->s) { + get_next_history(&hp, command); + goto rewrite_line; + } else { + xwrite(outputFd, "\007", 1); + } + break; + + /* Rewrite the line with the selected history item */ + rewrite_line: + /* erase old command from command line */ + len = strlen(command)-strlen(hp->s); + + while (len>cursor) + input_delete(command, outputFd, cursor, &len); + while (cursor>0) + input_backspace(command, outputFd, &cursor, &len); + input_home(outputFd, &cursor); + + /* write new command */ + strcpy(command, hp->s); + len = strlen(hp->s); + xwrite(outputFd, command, len); + cursor = len; + break; + case 'C': + /* Right Arrow -- Move forward one character */ + input_forward(outputFd, &cursor, len); + break; + case 'D': + /* Left Arrow -- Move back one character */ + input_backward(outputFd, &cursor); + break; + case '3': + /* Delete */ + input_delete(command, outputFd, cursor, &len); + break; + case '1': + /* Home (Ctrl-A) */ + input_home(outputFd, &cursor); + break; + case '4': + /* End (Ctrl-E) */ + input_end(outputFd, &cursor, len); + break; + default: + xwrite(outputFd, "\007", 1); + } + if (c == '1' || c == '3' || c == '4') + if ((ret = read(inputFd, &c, 1)) < 1) + return; /* read 126 (~) */ + } + if (c == 'O') { + /* 79 */ + if ((ret = read(inputFd, &c, 1)) < 1) + return; + switch (c) { + case 'H': + /* Home (xterm) */ + input_home(outputFd, &cursor); + break; + case 'F': + /* End (xterm) */ + input_end(outputFd, &cursor, len); + break; + default: + xwrite(outputFd, "\007", 1); + } + } + c = 0; + break; + } + + default: /* If it's regular input, do the normal thing */ + + if (!isprint(c)) { /* Skip non-printable characters */ + break; + } + + if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ + break; + + len++; + + if (cursor == (len - 1)) { /* Append if at the end of the line */ + *(command + cursor) = c; + } else { /* Insert otherwise */ + memmove(command + cursor + 1, command + cursor, + len - cursor - 1); + + *(command + cursor) = c; + + for (j = cursor; j < len; j++) + xwrite(outputFd, command + j, 1); + for (; j > cursor; j--) + xwrite(outputFd, "\033[D", 3); + } - if (history_counter >= MAX_HISTORY) { /* After max history, remove the last known command */ + cursor++; + xwrite(outputFd, &c, 1); + break; + } + if (c == '\t') + lastWasTab = TRUE; + else + lastWasTab = FALSE; - struct history *p = his_front->n; + if (break_out) /* Enter is the command terminator, no more input. */ + break; + } - p->p = NULL; - free(his_front->s); - free(his_front); - his_front = p; - } else { - history_counter++; - } + nr = len + 1; + setTermSettings(inputFd, (void *) &initial_settings); + reset_term = 0; + + + /* Handle command history log */ + if (*(command)) { + + struct history *h = his_end; + + if (!h) { + /* No previous history -- this memory is never freed */ + h = his_front = malloc(sizeof(struct history)); + h->n = malloc(sizeof(struct history)); + + h->p = NULL; + h->s = strdup(command); + h->n->p = h; + h->n->n = NULL; + h->n->s = NULL; + his_end = h->n; + history_counter++; + } else { + /* Add a new history command -- this memory is never freed */ + h->n = malloc(sizeof(struct history)); + + h->n->p = h; + h->n->n = NULL; + h->n->s = NULL; + h->s = strdup(command); + his_end = h->n; + + /* After max history, remove the oldest command */ + if (history_counter >= MAX_HISTORY) { + + struct history *p = his_front->n; + + p->p = NULL; + free(his_front->s); + free(his_front); + his_front = p; + } else { + history_counter++; + } + } } - } - return nr; + return; } extern void cmdedit_init(void) { - atexit(cmdedit_reset_term); - signal(SIGINT, gotaSignal); - signal(SIGQUIT, gotaSignal); - signal(SIGTERM, gotaSignal); + if(exithandler_set == 0) { + atexit(cmdedit_reset_term); /* be sure to do this only once */ + exithandler_set = 1; + } + signal(SIGKILL, clean_up_and_die); + signal(SIGINT, clean_up_and_die); + signal(SIGQUIT, clean_up_and_die); + signal(SIGTERM, clean_up_and_die); +} + +/* +** Undo the effects of cmdedit_init() as good as we can: +** I am not aware of a way to revoke an atexit() handler, +** but, fortunately, our particular handler can be made +** a no-op by setting reset_term = 0. +*/ +extern void cmdedit_terminate(void) +{ + cmdedit_reset_term(); + reset_term = 0; + signal(SIGKILL, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTERM, SIG_DFL); } -#endif /* BB_FEATURE_SH_COMMAND_EDITING */ + + + +#endif /* BB_FEATURE_SH_COMMAND_EDITING */