Home | History | Annotate | Download | only in pending
      1 /* more.c - View FILE (or stdin) one screenful at a time.
      2  *
      3  * Copyright 2013 Bilal Qureshi <bilal.jmi (at) gmail.com>
      4  *
      5  * No Standard
      6 
      7 USE_MORE(NEWTOY(more, NULL, TOYFLAG_USR|TOYFLAG_BIN))
      8 
      9 config MORE
     10   bool "more"
     11   default n
     12   help
     13     usage: more [FILE]...
     14 
     15     View FILE (or stdin) one screenful at a time.
     16 */
     17 
     18 #define FOR_more
     19 #include "toys.h"
     20 
     21 GLOBALS(
     22   struct termios inf;
     23   int cin_fd;
     24 )
     25 
     26 static void signal_handler(int sig)
     27 {
     28   tcsetattr(TT.cin_fd, TCSANOW, &TT.inf);
     29   xputc('\n');
     30   signal(sig, SIG_DFL);
     31   raise(sig);
     32   _exit(sig | 128);
     33 }
     34 
     35 static void show_file_header(const char *name)
     36 {
     37   printf(":::::::::::::::::::::::\n%s\n:::::::::::::::::::::::\n", name);
     38 }
     39 
     40 static int prompt(FILE *cin, const char* fmt, ...)
     41 {
     42   int input_key;
     43   va_list ap;
     44 
     45   printf("\33[7m"); // Reverse video before printing the prompt.
     46 
     47   va_start(ap, fmt);
     48   vfprintf(stdout, fmt, ap);
     49   va_end(ap);
     50 
     51   while (1) {
     52     fflush(NULL);
     53     input_key = tolower(getc(cin));
     54     printf("\33[0m\33[1K\r"); // Reset all attributes, erase to start of line.
     55     if (strchr(" \nrq", input_key)) {
     56       fflush(NULL);
     57       return input_key;
     58     }
     59     printf("\33[7m(Enter:Next line Space:Next page Q:Quit R:Show the rest)");
     60   }
     61 }
     62 
     63 static void do_cat_operation(int fd, char *name)
     64 {
     65   char *buf = NULL;
     66 
     67   if (toys.optc > 1) show_file_header(name);
     68   for (; (buf = get_line(fd)); free(buf)) printf("%s\n", buf);
     69 }
     70 
     71 void more_main()
     72 {
     73   int ch, input_key = 0, show_prompt;
     74   unsigned rows = 24, cols = 80, row = 0, col = 0;
     75   struct stat st;
     76   struct termios newf;
     77   FILE *fp, *cin;
     78 
     79   if (!isatty(STDOUT_FILENO) || !(cin = fopen("/dev/tty", "r"))) {
     80     loopfiles(toys.optargs, do_cat_operation);
     81     return;
     82   }
     83 
     84   TT.cin_fd = fileno(cin);
     85   tcgetattr(TT.cin_fd, &TT.inf);
     86 
     87   //Prepare terminal for input
     88   memcpy(&newf, &TT.inf, sizeof(struct termios));
     89   newf.c_lflag &= ~(ICANON | ECHO);
     90   newf.c_cc[VMIN] = 1;
     91   newf.c_cc[VTIME] = 0;
     92   tcsetattr(TT.cin_fd, TCSANOW, &newf);
     93 
     94   sigatexit(signal_handler);
     95 
     96   do {
     97     fp = stdin;
     98     if (*toys.optargs && !(fp = fopen(*toys.optargs, "r"))) {
     99         perror_msg("%s", *toys.optargs);
    100         goto next_file;
    101     }
    102     st.st_size = show_prompt = col = row = 0;
    103     fstat(fileno(fp), &st);
    104     terminal_size(&cols, &rows);
    105     rows--;
    106 
    107     if (toys.optc > 1) {
    108       show_file_header(*toys.optargs);
    109       row += 3;
    110     }
    111 
    112     while ((ch = getc(fp)) != EOF) {
    113       if (input_key != 'r' && show_prompt) {
    114         if (st.st_size)
    115           input_key = prompt(cin, "--More--(%d%% of %lld bytes)",
    116               (int) (100 * ( (double) ftell(fp) / (double) st.st_size)),
    117               (long long)st.st_size);
    118         else
    119           input_key = prompt(cin, "--More--");
    120         if (input_key == 'q') goto stop;
    121 
    122         col = row = show_prompt = 0;
    123         terminal_size(&cols, &rows);
    124         rows--;
    125       }
    126 
    127       putchar(ch);
    128       if (ch == '\t') col = (col | 0x7) + 1; else col++;
    129       if (col == cols) putchar(ch = '\n');
    130       if (ch == '\n') {
    131         col = 0;
    132         if (++row >= rows || input_key == '\n') show_prompt = 1;
    133       }
    134     }
    135     fclose(fp);
    136 
    137 next_file:
    138     if (*toys.optargs && *++toys.optargs) {
    139       input_key = prompt(cin, "--More--(Next file: %s)", *toys.optargs);
    140       if (input_key == 'q') goto stop;
    141     }
    142   } while (*toys.optargs);
    143 
    144 stop:
    145   tcsetattr(TT.cin_fd, TCSANOW, &TT.inf);
    146   fclose(cin);
    147   // Even if optarg not found, exit value still 0
    148   toys.exitval = 0;
    149 }
    150