extern int more_main(int argc, char **argv) { int c, lines, input = 0; int please_display_more_prompt; struct stat st; FILE *file; int len, page_height; #if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS struct winsize win = { 0, 0, 0, 0 }; #endif argc--; argv++; #ifdef BB_FEATURE_USE_TERMIOS cin = fopen("/dev/tty", "r"); if (!cin) cin = fopen("/dev/console", "r"); getTermSettings(fileno(cin), &initial_settings); new_settings = initial_settings; new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; new_settings.c_lflag &= ~ICANON; new_settings.c_lflag &= ~ECHO; setTermSettings(fileno(cin), &new_settings); # ifdef BB_FEATURE_AUTOWIDTH ioctl(fileno(stdout), TIOCGWINSZ, &win); if (win.ws_row > 4) terminal_height = win.ws_row - 2; if (win.ws_col > 0) terminal_width = win.ws_col - 1; # endif (void) signal(SIGINT, gotsig); (void) signal(SIGQUIT, gotsig); (void) signal(SIGTERM, gotsig); #endif do { if (argc == 0) { file = stdin; } else file = xfopen(*argv, "r"); fstat(fileno(file), &st); len=0; lines = 0; page_height = terminal_height; please_display_more_prompt = 0; while ((c = getc(file)) != EOF) { if (please_display_more_prompt) { len = printf("--More-- "); if (file != stdin) { #if _FILE_OFFSET_BITS == 64 len += printf("(%d%% of %lld bytes)", #else len += printf("(%d%% of %ld bytes)", #endif (int) (100 * ((double) ftell(file) / (double) st.st_size)), st.st_size); } len += printf("%s", #ifdef BB_FEATURE_USE_TERMIOS "" #else "\n" #endif ); fflush(stdout); /* * We've just displayed the "--More--" prompt, so now we need * to get input from the user. */ #ifdef BB_FEATURE_USE_TERMIOS input = getc(cin); #else input = getc(stdin); #endif #ifdef BB_FEATURE_USE_TERMIOS /* Erase the "More" message */ while (--len >= 0) putc('\b', stdout); while (++len <= terminal_width) putc(' ', stdout); while (--len >= 0) putc('\b', stdout); fflush(stdout); #endif len=0; lines = 0; page_height = terminal_height; please_display_more_prompt = 0; } /* * There are two input streams to worry about here: * * c : the character we are reading from the file being "mored" * input : a character received from the keyboard * * If we hit a newline in the _file_ stream, we want to test and * see if any characters have been hit in the _input_ stream. This * allows the user to quit while in the middle of a file. */ if (c == '\n') { switch (input) { case 'q': goto end; case '\n': /* increment by just one line if we are at * the end of this line*/ please_display_more_prompt = 1; break; } /* Adjust the terminal height for any overlap, so that * no lines get lost off the top. */ if (len >= terminal_width) { div_t result = div( len, terminal_width); if (result.quot) { if (result.rem) page_height-=result.quot; else page_height-=(result.quot-1); } } if (++lines >= page_height) { please_display_more_prompt = 1; } len=0; } /* * If we just read a newline from the file being 'mored' and any * key other than a return is hit, scroll by one page */ putc(c, stdout); len++; } fclose(file); fflush(stdout); argv++; } while (--argc > 0);
int more_main(int argc UNUSED_PARAM, char **argv) { int c = c; /* for compiler */ int lines; int input = 0; int spaces = 0; int please_display_more_prompt; struct stat st; FILE *file; FILE *cin; int len; unsigned terminal_width; unsigned terminal_height; INIT_G(); argv++; /* Another popular pager, most, detects when stdout * is not a tty and turns into cat. This makes sense. */ if (!isatty(STDOUT_FILENO)) return bb_cat(argv); cin = fopen_for_read(CURRENT_TTY); if (!cin) return bb_cat(argv); if (ENABLE_FEATURE_USE_TERMIOS) { cin_fileno = fileno(cin); getTermSettings(cin_fileno, &initial_settings); new_settings = initial_settings; new_settings.c_lflag &= ~(ICANON | ECHO); new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; setTermSettings(cin_fileno, &new_settings); bb_signals(0 + (1 << SIGINT) + (1 << SIGQUIT) + (1 << SIGTERM) , gotsig); } do { file = stdin; if (*argv) { file = fopen_or_warn(*argv, "r"); if (!file) continue; } st.st_size = 0; fstat(fileno(file), &st); please_display_more_prompt = 0; /* never returns w, h <= 1 */ get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height); terminal_height -= 1; len = 0; lines = 0; while (spaces || (c = getc(file)) != EOF) { int wrap; if (spaces) spaces--; loop_top: if (input != 'r' && please_display_more_prompt) { len = printf("--More-- "); if (st.st_size != 0) { uoff_t d = (uoff_t)st.st_size / 100; if (d == 0) d = 1; len += printf("(%u%% of %"OFF_FMT"u bytes)", (int) ((uoff_t)ftello(file) / d), st.st_size); } fflush_all(); /* * We've just displayed the "--More--" prompt, so now we need * to get input from the user. */ for (;;) { input = getc(cin); input = tolower(input); if (!ENABLE_FEATURE_USE_TERMIOS) printf("\033[A"); /* cursor up */ /* Erase the last message */ printf("\r%*s\r", len, ""); /* Due to various multibyte escape * sequences, it's not ok to accept * any input as a command to scroll * the screen. We only allow known * commands, else we show help msg. */ if (input == ' ' || input == '\n' || input == 'q' || input == 'r') break; len = printf("(Enter:next line Space:next page Q:quit R:show the rest)"); } len = 0; lines = 0; please_display_more_prompt = 0; if (input == 'q') goto end; /* The user may have resized the terminal. * Re-read the dimensions. */ if (ENABLE_FEATURE_USE_TERMIOS) { get_terminal_width_height(cin_fileno, &terminal_width, &terminal_height); terminal_height -= 1; } } /* Crudely convert tabs into spaces, which are * a bajillion times easier to deal with. */ if (c == '\t') { spaces = ((unsigned)~len) % CONVERTED_TAB_SIZE; c = ' '; } /* * There are two input streams to worry about here: * * c : the character we are reading from the file being "mored" * input: a character received from the keyboard * * If we hit a newline in the _file_ stream, we want to test and * see if any characters have been hit in the _input_ stream. This * allows the user to quit while in the middle of a file. */ wrap = (++len > terminal_width); if (c == '\n' || wrap) { /* Then outputting this character * will move us to a new line. */ if (++lines >= terminal_height || input == '\n') please_display_more_prompt = 1; len = 0; } if (c != '\n' && wrap) { /* Then outputting this will also put a character on * the beginning of that new line. Thus we first want to * display the prompt (if any), so we skip the putchar() * and go back to the top of the loop, without reading * a new character. */ putchar('\n'); goto loop_top; } /* My small mind cannot fathom backspaces and UTF-8 */ putchar(c); die_if_ferror_stdout(); /* if tty was destroyed (closed xterm, etc) */ } fclose(file); fflush_all(); } while (*argv && *++argv); end: setTermSettings(cin_fileno, &initial_settings); return 0; }
int cmdedit_read_input(char *prompt, char command[BUFSIZ]) { int break_out = 0; int lastWasTab = FALSE; unsigned char c; unsigned int ic; #if ENABLE_FEATURE_COMMAND_EDITING_VI unsigned int prevc; int vi_cmdmode = 0; #endif /* prepare before init handlers */ cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ len = 0; command_ps = command; getTermSettings(0, (void *) &initial_settings); memcpy(&new_settings, &initial_settings, sizeof(struct termios)); new_settings.c_lflag &= ~ICANON; /* unbuffered input */ /* Turn off echoing and CTRL-C, so we can trap it */ new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; /* Turn off CTRL-C, so we can trap it */ # ifndef _POSIX_VDISABLE # define _POSIX_VDISABLE '\0' # endif new_settings.c_cc[VINTR] = _POSIX_VDISABLE; command[0] = 0; setTermSettings(0, (void *) &new_settings); handlers_sets |= SET_RESET_TERM; /* Now initialize things */ cmdedit_init(); /* Print out the command prompt */ parse_prompt(prompt); while (1) { fflush(stdout); /* buffered out to fast */ if (safe_read(0, &c, 1) < 1) /* if we can't read input then exit */ goto prepare_to_die; ic = c; #if ENABLE_FEATURE_COMMAND_EDITING_VI newdelflag = 1; if (vi_cmdmode) ic |= vbit; #endif switch (ic) { case '\n': case '\r': vi_case( case '\n'|vbit: ) vi_case( case '\r'|vbit: ) /* Enter */ goto_new_line(); break_out = 1; break; case CNTRL('A'): vi_case( case '0'|vbit: ) /* Control-a -- Beginning of line */ input_backward(cursor); break; case CNTRL('B'): vi_case( case 'h'|vbit: ) vi_case( case '\b'|vbit: ) vi_case( case DEL|vbit: ) /* Control-b -- Move back one character */ input_backward(1); break; case CNTRL('C'): vi_case( case CNTRL('C')|vbit: ) /* Control-c -- stop gathering input */ goto_new_line(); #if !ENABLE_ASH command[0] = 0; len = 0; lastWasTab = FALSE; put_prompt(); #else len = 0; break_out = -1; /* to control traps */ #endif break; case CNTRL('D'): /* Control-d -- Delete one character, or exit * if the len=0 and no chars to delete */ if (len == 0) { errno = 0; prepare_to_die: #if !ENABLE_ASH printf("exit"); goto_new_line(); /* cmdedit_reset_term() called in atexit */ exit(EXIT_SUCCESS); #else /* to control stopped jobs */ len = break_out = -1; break; #endif } else { input_delete(0); } break; case CNTRL('E'): vi_case( case '$'|vbit: ) /* Control-e -- End of line */ input_end(); break; case CNTRL('F'): vi_case( case 'l'|vbit: ) vi_case( case ' '|vbit: ) /* Control-f -- Move forward one character */ input_forward(); break; case '\b': case DEL: /* Control-h and DEL */ input_backspace(); break; case '\t': #if ENABLE_FEATURE_COMMAND_TAB_COMPLETION input_tab(&lastWasTab); #endif break; case CNTRL('K'): /* Control-k -- clear to end of line */ command[cursor] = 0; len = cursor; printf("\033[J"); break; case CNTRL('L'): vi_case( case CNTRL('L')|vbit: ) /* Control-l -- clear screen */ printf("\033[H"); redraw(0, len - cursor); break; #if MAX_HISTORY > 0 case CNTRL('N'): vi_case( case CNTRL('N')|vbit: ) vi_case( case 'j'|vbit: ) /* Control-n -- Get next command in history */ if (get_next_history()) goto rewrite_line; break; case CNTRL('P'): vi_case( case CNTRL('P')|vbit: ) vi_case( case 'k'|vbit: ) /* Control-p -- Get previous command from history */ if (cur_history > 0) { get_previous_history(); goto rewrite_line; } else { beep(); } break; #endif case CNTRL('U'): vi_case( case CNTRL('U')|vbit: ) /* Control-U -- Clear line before cursor */ if (cursor) { strcpy(command, command + cursor); redraw(cmdedit_y, len -= cursor); } break; case CNTRL('W'): vi_case( case CNTRL('W')|vbit: ) /* Control-W -- Remove the last word */ while (cursor > 0 && isspace(command[cursor-1])) input_backspace(); while (cursor > 0 &&!isspace(command[cursor-1])) input_backspace(); break; #if ENABLE_FEATURE_COMMAND_EDITING_VI case 'i'|vbit: vi_cmdmode = 0; break; case 'I'|vbit: input_backward(cursor); vi_cmdmode = 0; break; case 'a'|vbit: input_forward(); vi_cmdmode = 0; break; case 'A'|vbit: input_end(); vi_cmdmode = 0; break; case 'x'|vbit: input_delete(1); break; case 'X'|vbit: if (cursor > 0) { input_backward(1); input_delete(1); } break; case 'W'|vbit: vi_Word_motion(command, 1); break; case 'w'|vbit: vi_word_motion(command, 1); break; case 'E'|vbit: vi_End_motion(command); break; case 'e'|vbit: vi_end_motion(command); break; case 'B'|vbit: vi_Back_motion(command); break; case 'b'|vbit: vi_back_motion(command); break; case 'C'|vbit: vi_cmdmode = 0; /* fall through */ case 'D'|vbit: goto clear_to_eol; case 'c'|vbit: vi_cmdmode = 0; /* fall through */ case 'd'|vbit: { int nc, sc; sc = cursor; prevc = ic; if (safe_read(0, &c, 1) < 1) goto prepare_to_die; if (c == (prevc & 0xff)) { /* "cc", "dd" */ input_backward(cursor); goto clear_to_eol; break; } switch (c) { case 'w': case 'W': case 'e': case 'E': switch (c) { case 'w': /* "dw", "cw" */ vi_word_motion(command, vi_cmdmode); break; case 'W': /* 'dW', 'cW' */ vi_Word_motion(command, vi_cmdmode); break; case 'e': /* 'de', 'ce' */ vi_end_motion(command); input_forward(); break; case 'E': /* 'dE', 'cE' */ vi_End_motion(command); input_forward(); break; } nc = cursor; input_backward(cursor - sc); while (nc-- > cursor) input_delete(1); break; case 'b': /* "db", "cb" */ case 'B': /* implemented as B */ if (c == 'b') vi_back_motion(command); else vi_Back_motion(command); while (sc-- > cursor) input_delete(1); break; case ' ': /* "d ", "c " */ input_delete(1); break; case '$': /* "d$", "c$" */ clear_to_eol: while (cursor < len) input_delete(1); break; } break; } case 'p'|vbit: input_forward(); /* fallthrough */ case 'P'|vbit: put(); break; case 'r'|vbit: if (safe_read(0, &c, 1) < 1) goto prepare_to_die; if (c == 0) beep(); else { *(command + cursor) = c; putchar(c); putchar('\b'); } break; #endif /* FEATURE_COMMAND_EDITING_VI */ case ESC: #if ENABLE_FEATURE_COMMAND_EDITING_VI if (vi_mode) { /* ESC: insert mode --> command mode */ vi_cmdmode = 1; input_backward(1); break; } #endif /* escape sequence follows */ if (safe_read(0, &c, 1) < 1) goto prepare_to_die; /* different vt100 emulations */ if (c == '[' || c == 'O') { vi_case( case '['|vbit: ) vi_case( case 'O'|vbit: ) if (safe_read(0, &c, 1) < 1) goto prepare_to_die; } if (c >= '1' && c <= '9') { unsigned char dummy; if (safe_read(0, &dummy, 1) < 1) goto prepare_to_die; if (dummy != '~') c = 0; } switch (c) { #if ENABLE_FEATURE_COMMAND_TAB_COMPLETION case '\t': /* Alt-Tab */ input_tab(&lastWasTab); break; #endif #if MAX_HISTORY > 0 case 'A': /* Up Arrow -- Get previous command from history */ if (cur_history > 0) { get_previous_history(); goto rewrite_line; } else { beep(); } break; case 'B': /* Down Arrow -- Get next command in history */ if (!get_next_history()) break; /* Rewrite the line with the selected history item */ rewrite_line: /* change command */ len = strlen(strcpy(command, history[cur_history])); /* redraw and go to eol (bol, in vi */ #if ENABLE_FEATURE_COMMAND_EDITING_VI redraw(cmdedit_y, vi_mode ? 9999:0); #else redraw(cmdedit_y, 0); #endif break; #endif case 'C': /* Right Arrow -- Move forward one character */ input_forward(); break; case 'D': /* Left Arrow -- Move back one character */ input_backward(1); break; case '3': /* Delete */ input_delete(0); break; case '1': case 'H': /* <Home> */ input_backward(cursor); break; case '4': case 'F': /* <End> */ input_end(); break; default: c = 0; beep(); } break; default: /* If it's regular input, do the normal thing */ #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT /* Control-V -- Add non-printable symbol */ if (c == CNTRL('V')) { if (safe_read(0, &c, 1) < 1) goto prepare_to_die; if (c == 0) { beep(); break; } } else #endif { #if ENABLE_FEATURE_COMMAND_EDITING_VI if (vi_cmdmode) /* don't self-insert */ break; #endif 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; *(command + cursor + 1) = 0; cmdedit_set_out_char(0); } else { /* Insert otherwise */ int sc = cursor; memmove(command + sc + 1, command + sc, len - sc); *(command + sc) = c; sc++; /* rewrite from cursor */ input_end(); /* to prev x pos + 1 */ input_backward(cursor - sc); } break; } if (break_out) /* Enter is the command terminator, no more input. */ break; if (c != '\t') lastWasTab = FALSE; }
/* Returns: * -1 on read errors or EOF, or on bare Ctrl-D. * 0 on ctrl-C, * >0 length of input string, including terminating '\n' */ int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *st) { int lastWasTab = FALSE; unsigned int ic; unsigned char c; smallint break_out = 0; #if ENABLE_FEATURE_EDITING_VI smallint vi_cmdmode = 0; smalluint prevc; #endif if (maxsize > MAX_LINELEN) maxsize = MAX_LINELEN; /* With null flags, no other fields are ever used */ state = st ? st : (line_input_t*) &const_int_0; #if ENABLE_FEATURE_EDITING_SAVEHISTORY if ((state->flags & SAVE_HISTORY) && state->hist_file) load_history(state->hist_file); #endif /* prepare before init handlers */ cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ command_len = 0; command_ps = command; command[0] = '\0'; getTermSettings(0, (void *) &initial_settings); memcpy(&new_settings, &initial_settings, sizeof(new_settings)); new_settings.c_lflag &= ~ICANON; /* unbuffered input */ /* Turn off echoing and CTRL-C, so we can trap it */ new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); /* Hmm, in linux c_cc[] is not parsed if ICANON is off */ new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; /* Turn off CTRL-C, so we can trap it */ #ifndef _POSIX_VDISABLE #define _POSIX_VDISABLE '\0' #endif new_settings.c_cc[VINTR] = _POSIX_VDISABLE; setTermSettings(0, (void *) &new_settings); /* Now initialize things */ previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); win_changed(0); /* do initial resizing */ #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR { struct passwd *entry; entry = getpwuid(geteuid()); if (entry) { /* If we enter read_line_input for the Nth time, * they may be already allocated! Need to free. */ free(user_buf); if (home_pwd_buf != null_str) free(home_pwd_buf); user_buf = xstrdup(entry->pw_name); home_pwd_buf = xstrdup(entry->pw_dir); /* They are not freed on exit (too small to bother) */ } } #endif /* Print out the command prompt */ parse_prompt(prompt); while (1) { fflush(stdout); if (safe_read(0, &c, 1) < 1) { /* if we can't read input then exit */ goto prepare_to_die; } ic = c; #if ENABLE_FEATURE_EDITING_VI newdelflag = 1; if (vi_cmdmode) ic |= vbit; #endif switch (ic) { case '\n': case '\r': vi_case('\n'|vbit:) vi_case('\r'|vbit:) /* Enter */ goto_new_line(); break_out = 1; break; #if ENABLE_FEATURE_EDITING_FANCY_KEYS case CTRL('A'): vi_case('0'|vbit:) /* Control-a -- Beginning of line */ input_backward(cursor); break; case CTRL('B'): vi_case('h'|vbit:) vi_case('\b'|vbit:) vi_case('\x7f'|vbit:) /* DEL */ /* Control-b -- Move back one character */ input_backward(1); break; #endif case CTRL('C'): vi_case(CTRL('C')|vbit:) /* Control-c -- stop gathering input */ goto_new_line(); command_len = 0; break_out = -1; /* "do not append '\n'" */ break; case CTRL('D'): /* Control-d -- Delete one character, or exit * if the len=0 and no chars to delete */ if (command_len == 0) { errno = 0; prepare_to_die: /* to control stopped jobs */ break_out = command_len = -1; break; } input_delete(0); break; #if ENABLE_FEATURE_EDITING_FANCY_KEYS case CTRL('E'): vi_case('$'|vbit:) /* Control-e -- End of line */ input_end(); break; case CTRL('F'): vi_case('l'|vbit:) vi_case(' '|vbit:) /* Control-f -- Move forward one character */ input_forward(); break; #endif case '\b': case '\x7f': /* DEL */ /* Control-h and DEL */ input_backspace(); break; case '\t': input_tab(&lastWasTab); break; #if ENABLE_FEATURE_EDITING_FANCY_KEYS case CTRL('K'): /* Control-k -- clear to end of line */ command[cursor] = 0; command_len = cursor; printf("\033[J"); break; case CTRL('L'): vi_case(CTRL('L')|vbit:) /* Control-l -- clear screen */ printf("\033[H"); redraw(0, command_len - cursor); break; #endif #if MAX_HISTORY > 0 case CTRL('N'): vi_case(CTRL('N')|vbit:) vi_case('j'|vbit:) /* Control-n -- Get next command in history */ if (get_next_history()) goto rewrite_line; break; case CTRL('P'): vi_case(CTRL('P')|vbit:) vi_case('k'|vbit:) /* Control-p -- Get previous command from history */ if ((state->flags & DO_HISTORY) && state->cur_history > 0) { get_previous_history(); goto rewrite_line; } beep(); break; #endif #if ENABLE_FEATURE_EDITING_FANCY_KEYS case CTRL('U'): vi_case(CTRL('U')|vbit:) /* Control-U -- Clear line before cursor */ if (cursor) { strcpy(command, command + cursor); command_len -= cursor; redraw(cmdedit_y, command_len); } break; #endif case CTRL('W'): vi_case(CTRL('W')|vbit:) /* Control-W -- Remove the last word */ while (cursor > 0 && isspace(command[cursor-1])) input_backspace(); while (cursor > 0 && !isspace(command[cursor-1])) input_backspace(); break; #if ENABLE_FEATURE_EDITING_VI case 'i'|vbit: vi_cmdmode = 0; break; case 'I'|vbit: input_backward(cursor); vi_cmdmode = 0; break; case 'a'|vbit: input_forward(); vi_cmdmode = 0; break; case 'A'|vbit: input_end(); vi_cmdmode = 0; break; case 'x'|vbit: input_delete(1); break; case 'X'|vbit: if (cursor > 0) { input_backward(1); input_delete(1); } break; case 'W'|vbit: vi_Word_motion(command, 1); break; case 'w'|vbit: vi_word_motion(command, 1); break; case 'E'|vbit: vi_End_motion(command); break; case 'e'|vbit: vi_end_motion(command); break; case 'B'|vbit: vi_Back_motion(command); break; case 'b'|vbit: vi_back_motion(command); break; case 'C'|vbit: vi_cmdmode = 0; /* fall through */ case 'D'|vbit: goto clear_to_eol; case 'c'|vbit: vi_cmdmode = 0; /* fall through */ case 'd'|vbit: { int nc, sc; sc = cursor; prevc = ic; if (safe_read(0, &c, 1) < 1) goto prepare_to_die; if (c == (prevc & 0xff)) { /* "cc", "dd" */ input_backward(cursor); goto clear_to_eol; break; } switch (c) { case 'w': case 'W': case 'e': case 'E': switch (c) { case 'w': /* "dw", "cw" */ vi_word_motion(command, vi_cmdmode); break; case 'W': /* 'dW', 'cW' */ vi_Word_motion(command, vi_cmdmode); break; case 'e': /* 'de', 'ce' */ vi_end_motion(command); input_forward(); break; case 'E': /* 'dE', 'cE' */ vi_End_motion(command); input_forward(); break; } nc = cursor; input_backward(cursor - sc); while (nc-- > cursor) input_delete(1); break; case 'b': /* "db", "cb" */ case 'B': /* implemented as B */ if (c == 'b') vi_back_motion(command); else vi_Back_motion(command); while (sc-- > cursor) input_delete(1); break; case ' ': /* "d ", "c " */ input_delete(1); break; case '$': /* "d$", "c$" */ clear_to_eol: while (cursor < command_len) input_delete(1); break; } break; } case 'p'|vbit: input_forward(); /* fallthrough */ case 'P'|vbit: put(); break; case 'r'|vbit: if (safe_read(0, &c, 1) < 1) goto prepare_to_die; if (c == 0) beep(); else { *(command + cursor) = c; putchar(c); putchar('\b'); } break; #endif /* FEATURE_COMMAND_EDITING_VI */ case '\x1b': /* ESC */ #if ENABLE_FEATURE_EDITING_VI if (state->flags & VI_MODE) { /* ESC: insert mode --> command mode */ vi_cmdmode = 1; input_backward(1); break; } #endif /* escape sequence follows */ if (safe_read(0, &c, 1) < 1) goto prepare_to_die; /* different vt100 emulations */ if (c == '[' || c == 'O') { vi_case('['|vbit:) vi_case('O'|vbit:) if (safe_read(0, &c, 1) < 1) goto prepare_to_die; } if (c >= '1' && c <= '9') { unsigned char dummy; if (safe_read(0, &dummy, 1) < 1) goto prepare_to_die; if (dummy != '~') c = '\0'; } switch (c) { #if ENABLE_FEATURE_TAB_COMPLETION case '\t': /* Alt-Tab */ input_tab(&lastWasTab); break; #endif #if MAX_HISTORY > 0 case 'A': /* Up Arrow -- Get previous command from history */ if ((state->flags & DO_HISTORY) && state->cur_history > 0) { get_previous_history(); goto rewrite_line; } beep(); break; case 'B': /* Down Arrow -- Get next command in history */ if (!get_next_history()) break; rewrite_line: /* Rewrite the line with the selected history item */ /* change command */ command_len = strlen(strcpy(command, state->history[state->cur_history])); /* redraw and go to eol (bol, in vi */ redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); break; #endif case 'C': /* Right Arrow -- Move forward one character */ input_forward(); break; case 'D': /* Left Arrow -- Move back one character */ input_backward(1); break; case '3': /* Delete */ input_delete(0); break; case '1': // vt100? linux vt? or what? case '7': // vt100? linux vt? or what? case 'H': /* xterm's <Home> */ input_backward(cursor); break; case '4': // vt100? linux vt? or what? case '8': // vt100? linux vt? or what? case 'F': /* xterm's <End> */ input_end(); break; default: c = '\0'; beep(); } break; default: /* If it's regular input, do the normal thing */ #if ENABLE_FEATURE_NONPRINTABLE_INVERSE_PUT /* Control-V -- Add non-printable symbol */ if (c == CTRL('V')) { if (safe_read(0, &c, 1) < 1) goto prepare_to_die; if (c == 0) { beep(); break; } } else #endif #if ENABLE_FEATURE_EDITING_VI if (vi_cmdmode) /* Don't self-insert */ break; #endif if (!Isprint(c)) /* Skip non-printable characters */ break; if (command_len >= (maxsize - 2)) /* Need to leave space for enter */ break; command_len++; if (cursor == (command_len - 1)) { /* Append if at the end of the line */ command[cursor] = c; command[cursor+1] = '\0'; cmdedit_set_out_char(' '); } else { /* Insert otherwise */ int sc = cursor; memmove(command + sc + 1, command + sc, command_len - sc); command[sc] = c; sc++; /* rewrite from cursor */ input_end(); /* to prev x pos + 1 */ input_backward(cursor - sc); } break; } if (break_out) /* Enter is the command terminator, no more input. */ break; if (c != '\t') lastWasTab = FALSE; }
int more_main(int argc, char **argv) { int c, lines, input = 0; int please_display_more_prompt = 0; struct stat st; FILE *file; FILE *cin; int len, page_height; int terminal_width; int terminal_height; INIT_G(); argv++; /* Another popular pager, most, detects when stdout * is not a tty and turns into cat. This makes sense. */ if (!isatty(STDOUT_FILENO)) return bb_cat(argv); cin = fopen(CURRENT_TTY, "r"); if (!cin) return bb_cat(argv); #if ENABLE_FEATURE_USE_TERMIOS cin_fileno = fileno(cin); getTermSettings(cin_fileno, &initial_settings); new_settings = initial_settings; new_settings.c_lflag &= ~ICANON; new_settings.c_lflag &= ~ECHO; new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; setTermSettings(cin_fileno, &new_settings); signal(SIGINT, gotsig); signal(SIGQUIT, gotsig); signal(SIGTERM, gotsig); #endif please_display_more_prompt = 2; do { file = stdin; if (*argv) { file = fopen_or_warn(*argv, "r"); if (!file) continue; } st.st_size = 0; fstat(fileno(file), &st); please_display_more_prompt &= ~1; /* never returns w, h <= 1 */ get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height); terminal_width -= 1; terminal_height -= 1; len = 0; lines = 0; page_height = terminal_height; while ((c = getc(file)) != EOF) { if ((please_display_more_prompt & 3) == 3) { len = printf("--More-- "); if (/*file != stdin &&*/ st.st_size > 0) { len += printf("(%d%% of %"OFF_FMT"d bytes)", (int) (ftello(file)*100 / st.st_size), st.st_size); } fflush(stdout); /* * We've just displayed the "--More--" prompt, so now we need * to get input from the user. */ input = getc(cin); #if !ENABLE_FEATURE_USE_TERMIOS printf("\033[A"); /* up cursor */ #endif /* Erase the "More" message */ printf("\r%*s\r", len, ""); len = 0; lines = 0; /* Bottom line on page will become top line * after one page forward. Thus -1: */ page_height = terminal_height - 1; please_display_more_prompt &= ~1; if (input == 'q') goto end; } /* * There are two input streams to worry about here: * * c : the character we are reading from the file being "mored" * input: a character received from the keyboard * * If we hit a newline in the _file_ stream, we want to test and * see if any characters have been hit in the _input_ stream. This * allows the user to quit while in the middle of a file. */ if (c == '\n') { /* increment by just one line if we are at * the end of this line */ if (input == '\n') please_display_more_prompt |= 1; /* Adjust the terminal height for any overlap, so that * no lines get lost off the top. */ if (len >= terminal_width) { int quot, rem; quot = len / terminal_width; rem = len - (quot * terminal_width); page_height -= (quot - 1); if (rem) page_height--; } if (++lines >= page_height) { please_display_more_prompt |= 1; } len = 0; } /* * If we just read a newline from the file being 'mored' and any * key other than a return is hit, scroll by one page */ putc(c, stdout); /* My small mind cannot fathom tabs, backspaces, * and UTF-8 */ len++; } fclose(file); fflush(stdout); } while (*argv && *++argv); end: setTermSettings(cin_fileno, &initial_settings); return 0; }