X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=cmdedit.c;h=22831b10c7c96763e2511fb6994fb141080616b8;hb=77bd2db32527a81dd777f6835fddacc801855cbc;hp=8a7a5fb034b8a578c79456feee3dbcf77af8d011;hpb=c7c634bd88c57d910c6089de7f0091ca4e3d1843;p=oweals%2Fbusybox.git diff --git a/cmdedit.c b/cmdedit.c index 8a7a5fb03..22831b10c 100644 --- a/cmdedit.c +++ b/cmdedit.c @@ -1,10 +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. @@ -37,7 +39,7 @@ #include #include #include -#include +#include #include #include @@ -51,11 +53,37 @@ 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 */ struct history { char *s; @@ -63,85 +91,45 @@ struct history { struct history *n; }; +#define xwrite write -/* Version of write which resumes after a signal is caught. */ -int xwrite(int fd, char *buf, int nbytes) +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); + /* sparc and other have broken termios support: use old termio handling. */ + setTermSettings(fileno(stdin), (void*) &initial_settings); } -void prepareToDie(int sig) +void clean_up_and_die(int sig) { cmdedit_reset_term(); fprintf(stdout, "\n"); - exit(TRUE); + 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; } } - -void input_delete(int outputFd, int cursor) -{ - 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); - } - - xwrite(outputFd, " \b", 2); - - while (j-- > cursor) - xwrite(outputFd, "\b", 1); -} - - +/* Go to END position */ void input_end(int outputFd, int *cursor, int len) { while (*cursor < len) { @@ -150,22 +138,22 @@ void input_end(int outputFd, int *cursor, int len) } } - -void input_backspace(int outputFd, int *cursor, int *len) +/* Delete the char in back of the cursor */ +void input_backspace(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, + memmove(command + *cursor, command + *cursor + 1, BUFSIZ - *cursor + 1); for (j = *cursor; j < (BUFSIZ - 1); j++) { - if (!*(parsenextc + j)) + if (!*(command + j)) break; else - xwrite(outputFd, (parsenextc + j), 1); + xwrite(outputFd, (command + j), 1); } xwrite(outputFd, " \b", 2); @@ -177,27 +165,210 @@ void input_backspace(int outputFd, int *cursor, int *len) } } -char** username_completion_matches(char* command, int *num_matches) +/* Delete the char in front of the cursor */ +void input_delete(char* command, int outputFd, int cursor, int *len) +{ + 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); + --*len; +} + +/* Move forward one charactor */ +void input_forward(int outputFd, int *cursor, int len) +{ + if (*cursor < len) { + xwrite(outputFd, "\033[C", 3); + ++*cursor; + } +} + +/* Move back one charactor */ +void input_backward(int outputFd, int *cursor) +{ + if (*cursor > 0) { + xwrite(outputFd, "\033[D", 3); + --*cursor; + } +} + + + +#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_completion_matches\n"); + fprintf(stderr, "\nin username_tab_completion\n"); return (matches); } -char** find_path_executable_n_cwd_matches(char* command, int *num_matches) + +#include +char** exe_n_cwd_tab_completion(char* command, int *num_matches) { + char *dirName; char **matches = (char **) NULL; - matches = malloc(sizeof(char*)*100); + 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)); + } + } - matches[0] = malloc(sizeof(char)*50); - matches[1] = malloc(sizeof(char)*50); + return (matches); +} - sprintf(matches[0], "Hello"); - sprintf(matches[1], "Howdy"); - *num_matches=2; +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 possable 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; + } -// fprintf(stderr, "\nin find_path_executable_n_cwd_matches\n"); - return (matches); + /* skip any leading white space */ + while (*tmp && isspace(*tmp)) + ++tmp; + + /* Free up any memory already allocated */ + if (matches) { + free(matches); + matches = (char **) NULL; + } + + /* 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 + +void get_previous_history(struct history **hp, char* command) +{ + free((*hp)->s); + (*hp)->s = strdup(command); + *hp = (*hp)->p; +} + +void get_next_history(struct history **hp, char* command) +{ + free((*hp)->s); + (*hp)->s = strdup(command); + *hp = (*hp)->n; } /* @@ -216,12 +387,12 @@ char** find_path_executable_n_cwd_matches(char* command, int *num_matches) * Furthermore, the "vi" command editing keys are not implemented. * * TODO: implement TAB command completion. :) - * */ -extern int cmdedit_read_input(char* prompt, int inputFd, int outputFd, - char command[BUFSIZ]) +extern void cmdedit_read_input(char* prompt, char command[BUFSIZ]) { + int inputFd=fileno(stdin); + int outputFd=fileno(stdout); int nr = 0; int len = 0; int j = 0; @@ -233,261 +404,157 @@ extern int cmdedit_read_input(char* prompt, int inputFd, int outputFd, 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); + + 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; - } else { - xioctl(inputFd, TCSETA, (void *) &new_term); } + setTermSettings(inputFd, (void*) &new_settings); - memset(parsenextc, 0, BUFSIZ); + memset(command, 0, BUFSIZ); while (1) { if ((ret = read(inputFd, &c, 1)) < 1) - return ret; + return; + //fprintf(stderr, "got a '%c' (%d)\n", c, c); 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 5: - /* Control-e -- End of line */ - input_end(outputFd, &cursor, len); - break; case 2: /* Control-b -- Move back one character */ - if (cursor > 0) { - xwrite(outputFd, "\033[D", 3); - cursor--; + 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, sizeof(command)); + 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 */ - if (cursor < len) { - xwrite(outputFd, "\033[C", 3); - cursor++; - } + input_forward(outputFd, &cursor, len); break; - case 4: - /* Control-d -- Delete one character */ - if (cursor != len) { - input_delete(outputFd, cursor); - len--; - } else if (len == 0) { - prepareToDie(0); - exit(0); - } + 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 */ + /* Control-n -- Get next command in history */ if (hp && hp->n && hp->n->s) { - free(hp->s); - hp->s = strdup(parsenextc); - hp = hp->n; - goto hop; + get_next_history(&hp, command); + goto rewrite_line; + } else { + xwrite(outputFd, "\007", 1); } break; case 16: - /* Control-p -- Get previous command */ + /* Control-p -- Get previous command from history */ if (hp && hp->p) { - free(hp->s); - hp->s = strdup(parsenextc); - hp = hp->p; - goto hop; - } - break; - case '\t': - { - /* 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 possable matches. If you don't like - * that, feel free to fix it. - */ - - /* Make a local copy of the string -- up - * to the the position of the cursor */ - matchBuf = (char *) calloc(BUFSIZ, sizeof(char)); - strncpy(matchBuf, parsenextc, 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; - } - - /* skip any leading white space */ - while (*tmp && isspace(*tmp)) - ++tmp; - - /* Free up any memory already allocated */ - if (matches) { - free(matches); - matches = (char **) NULL; - } - - /* If the word starts in `~', and there is no slash in the word, - * then try completing this word as a username. */ - if (*tmp == '~' && !strchr(tmp, '/')) - matches = username_completion_matches(tmp, &num_matches); - - /* Try to match any executable in our patch, and everything - * in the current working directory that matches. - */ - if (!matches) - matches = find_path_executable_n_cwd_matches(tmp, &num_matches); - } else { - if ( matches && num_matches>0 ) { - int i, col; - - fprintf(stderr, "\nTabbing...\n"); - - /* Make a list of the matches */ - col += xwrite(outputFd, "\n", 1); - for (i=0,col=0; i 60 && matches[i+1] != NULL) { - xwrite(outputFd, "\n", 1); - col = 0; - } - } - xwrite(outputFd, "\n", 1); - - len+=strlen(prompt); - fprintf(stderr, "len=%d\n", len); - - /* Move to the beginning of the line */ - input_home(outputFd, &len); - - /* erase everything */ - for (j = 0; j < len; j++) - xwrite(outputFd, " ", 1); - - /* return to begining of line */ - input_home(outputFd, &cursor); - - /* Rewrite the prompt) */ - xwrite(outputFd, prompt, strlen(prompt)); - - /* Rewrite the command */ - len = strlen(parsenextc); - xwrite(outputFd, parsenextc, len); - - /* Move back to where the cursor used to be */ - for (cursor=pos; cursor > 0; cursor--) - xwrite(outputFd, "\b", 1); - cursor = pos; - - //fprintf(stderr, "\nprompt='%s'\n", prompt); - } - } - break; + get_previous_history(&hp, command); + goto rewrite_line; + } else { + xwrite(outputFd, "\007", 1); } - case '\b': - case DEL: - /* Backspace */ - 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; + return; if (c == '[') { /* 91 */ if ((ret = read(inputFd, &c, 1)) < 1) - return ret; + return; switch (c) { case 'A': - /* Up Arrow -- Get previous command */ + /* Up Arrow -- Get previous command from history */ if (hp && hp->p) { - free(hp->s); - hp->s = strdup(parsenextc); - hp = hp->p; - goto hop; + get_previous_history(&hp, command); + goto rewrite_line; + } else { + xwrite(outputFd, "\007", 1); } break; case 'B': - /* Down Arrow -- Get next command */ + /* Down Arrow -- Get next command in history */ if (hp && hp->n && hp->n->s) { - free(hp->s); - hp->s = strdup(parsenextc); - hp = hp->n; - goto hop; + get_next_history(&hp, command); + goto rewrite_line; + } else { + xwrite(outputFd, "\007", 1); } break; - /* This is where we rewrite the line - * using the selected history item */ - hop: - len = strlen(parsenextc); - - /* return to begining of line */ - for (; cursor > 0; cursor--) - xwrite(outputFd, "\b", 1); - xwrite(outputFd, parsenextc, len); - - /* erase old command */ - for (j = 0; j < len; j++) - xwrite(outputFd, " ", 1); - - /* return to begining of line */ - for (j = len; j > 0; j--) - xwrite(outputFd, "\b", 1); - - memset(parsenextc, 0, BUFSIZ); + /* Rewrite the line with the selected history item */ + rewrite_line: + /* erase old command from command line */ + len = strlen(command)-strlen(hp->s); + while (len>0) + input_backspace(command, outputFd, &cursor, &len); + input_home(outputFd, &cursor); + /* write new command */ - strcpy(parsenextc, hp->s); + strcpy(command, hp->s); len = strlen(hp->s); - xwrite(outputFd, parsenextc, len); + xwrite(outputFd, command, len); cursor = len; break; case 'C': /* Right Arrow -- Move forward one character */ - if (cursor < len) { - xwrite(outputFd, "\033[C", 3); - cursor++; - } + input_forward(outputFd, &cursor, len); break; case 'D': /* Left Arrow -- Move back one character */ - if (cursor > 0) { - xwrite(outputFd, "\033[D", 3); - cursor--; - } + input_backward(outputFd, &cursor); break; case '3': /* Delete */ - if (cursor != len) { - input_delete(outputFd, cursor); - len--; - } + input_delete(command, outputFd, cursor, &len); break; case '1': /* Home (Ctrl-A) */ @@ -497,15 +564,17 @@ extern int cmdedit_read_input(char* prompt, int inputFd, int outputFd, /* 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 ret; /* read 126 (~) */ + return; /* read 126 (~) */ } if (c == 'O') { /* 79 */ if ((ret = read(inputFd, &c, 1)) < 1) - return ret; + return; switch (c) { case 'H': /* Home (xterm) */ @@ -515,6 +584,8 @@ extern int cmdedit_read_input(char* prompt, int inputFd, int outputFd, /* End (xterm) */ input_end(outputFd, &cursor, len); break; + default: + xwrite(outputFd, "\007", 1); } } c = 0; @@ -523,8 +594,9 @@ extern int cmdedit_read_input(char* prompt, int inputFd, int outputFd, default: /* If it's regular input, do the normal thing */ - if (!isprint(c)) /* Skip non-printable characters */ + if (!isprint(c)) { /* Skip non-printable characters */ break; + } if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ break; @@ -532,15 +604,15 @@ extern int cmdedit_read_input(char* prompt, int inputFd, int outputFd, len++; if (cursor == (len - 1)) { /* Append if at the end of the line */ - *(parsenextc + cursor) = c; + *(command + cursor) = c; } else { /* Insert otherwise */ - memmove(parsenextc + cursor + 1, parsenextc + cursor, + memmove(command + cursor + 1, command + cursor, len - cursor - 1); - *(parsenextc + cursor) = c; + *(command + cursor) = c; for (j = cursor; j < len; j++) - xwrite(outputFd, parsenextc + j, 1); + xwrite(outputFd, command + j, 1); for (; j > cursor; j--) xwrite(outputFd, "\033[D", 3); } @@ -559,12 +631,12 @@ extern int cmdedit_read_input(char* prompt, int inputFd, int outputFd, } nr = len + 1; - xioctl(inputFd, TCSETA, (void *) &old_term); + setTermSettings(inputFd, (void *) &initial_settings); reset_term = 0; /* Handle command history log */ - if (*(parsenextc)) { + if (*(command)) { struct history *h = his_end; @@ -574,7 +646,7 @@ extern int cmdedit_read_input(char* prompt, int inputFd, int outputFd, h->n = malloc(sizeof(struct history)); h->p = NULL; - h->s = strdup(parsenextc); + h->s = strdup(command); h->n->p = h; h->n->n = NULL; h->n->s = NULL; @@ -587,7 +659,7 @@ extern int cmdedit_read_input(char* prompt, int inputFd, int outputFd, h->n->p = h; h->n->n = NULL; h->n->s = NULL; - h->s = strdup(parsenextc); + h->s = strdup(command); his_end = h->n; /* After max history, remove the oldest command */ @@ -605,14 +677,15 @@ extern int cmdedit_read_input(char* prompt, int inputFd, int outputFd, } } - return nr; + return; } extern void cmdedit_init(void) { atexit(cmdedit_reset_term); - signal(SIGINT, prepareToDie); - signal(SIGQUIT, prepareToDie); - signal(SIGTERM, prepareToDie); + signal(SIGKILL, clean_up_and_die); + signal(SIGINT, clean_up_and_die); + signal(SIGQUIT, clean_up_and_die); + signal(SIGTERM, clean_up_and_die); } #endif /* BB_FEATURE_SH_COMMAND_EDITING */