more: by Tristan Schmelcher
No binary (build failed)
—
(log yok)
| @@ -29,11 +29,11 @@ struct globals { | |
| }; | |
| #define G (*(struct globals*)bb_common_bufsiz1) | |
| //#define G (*ptr_to_globals) | |
| + | #define INIT_G() ((void)0) |
| + | //#define INIT_G() PTR_TO_GLOBALS = xzalloc(sizeof(G)) |
| #define initial_settings (G.initial_settings) | |
| #define new_settings (G.new_settings ) | |
| #define cin_fileno (G.cin_fileno ) | |
| - | #define INIT_G() ((void)0) |
| - | //#define INIT_G() PTR_TO_GLOBALS = xzalloc(sizeof(G)) |
| #define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp) | |
| #define getTermSettings(fd, argp) tcgetattr(fd, argp) | |
| @@ -50,16 +50,20 @@ static void gotsig(int sig) | |
| #define setTermSettings(fd, argp) ((void)0) | |
| #endif /* FEATURE_USE_TERMIOS */ | |
| + | #define CONVERTED_TAB_SIZE 8 |
| int more_main(int argc, char **argv); | |
| int more_main(int argc, char **argv) | |
| { | |
| - | int c, lines, input = 0; |
| - | int please_display_more_prompt = 0; |
| + | int c = c; /* for gcc */ |
| + | int lines; |
| + | int input = 0; |
| + | int spaces = 0; |
| + | int please_display_more_prompt; |
| struct stat st; | |
| FILE *file; | |
| FILE *cin; | |
| - | int len, page_height; |
| + | int len; |
| int terminal_width; | |
| int terminal_height; | |
| @@ -87,7 +91,6 @@ int more_main(int argc, char **argv) | |
| signal(SIGQUIT, gotsig); | |
| signal(SIGTERM, gotsig); | |
| #endif | |
| - | please_display_more_prompt = 2; |
| do { | |
| file = stdin; | |
| @@ -99,19 +102,21 @@ int more_main(int argc, char **argv) | |
| st.st_size = 0; | |
| fstat(fileno(file), &st); | |
| - | please_display_more_prompt &= ~1; |
| + | please_display_more_prompt = 0; |
| /* 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) { |
| + | while (spaces || (c = getc(file)) != EOF) { |
| + | int wrap; |
| + | if (spaces) |
| + | spaces--; |
| + | loop_top: |
| + | if (input != 'r' && please_display_more_prompt) { |
| len = printf("--More-- "); | |
| - | if (/*file != stdin &&*/ st.st_size > 0) { |
| + | if (st.st_size > 0) { |
| len += printf("(%d%% of %"OFF_FMT"d bytes)", | |
| (int) (ftello(file)*100 / st.st_size), | |
| st.st_size); | |
| @@ -122,23 +127,44 @@ int more_main(int argc, char **argv) | |
| * We've just displayed the "--More--" prompt, so now we need | |
| * to get input from the user. | |
| */ | |
| - | input = getc(cin); |
| + | for (;;) { |
| + | input = getc(cin); |
| + | input = tolower(input); |
| #if !ENABLE_FEATURE_USE_TERMIOS | |
| - | printf("\033[A"); /* up cursor */ |
| + | printf("\033[A"); /* up cursor */ |
| #endif | |
| - | /* Erase the "More" message */ |
| - | printf("\r%*s\r", len, ""); |
| + | /* 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; | |
| - | /* Bottom line on page will become top line |
| - | * after one page forward. Thus -1: */ |
| - | page_height = terminal_height - 1; |
| - | please_display_more_prompt &= ~1; |
| + | please_display_more_prompt = 0; |
| if (input == 'q') | |
| goto end; | |
| + | |
| + | /* The user may have resized the terminal. |
| + | * Re-read the dimensions. */ |
| + | 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 = CONVERTED_TAB_SIZE - 1; |
| + | c = ' '; |
| + | } |
| + | |
| /* | |
| * There are two input streams to worry about here: | |
| * | |
| @@ -149,34 +175,24 @@ int more_main(int argc, char **argv) | |
| * 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; |
| - | } |
| + | 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 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++; |
| + | 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. */ |
| + | goto loop_top; |
| + | } |
| + | /* My small mind cannot fathom backspaces and UTF-8 */ |
| + | putchar(c); |
| } | |
| fclose(file); | |
| fflush(stdout); | |