Advertisement
drankinatty

C - 20 Line Pager w/Line Numbers and Continue/Quit Control

Apr 2nd, 2021 (edited)
718
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.92 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <ctype.h>
  4. #include <termios.h>
  5.  
  6. #define MAXC 1024       /* if you need a constant, #define one (or more) */
  7. #define LINES  20
  8.  
  9. /* avoid use of global variables, okay when used as flag or in callback functions.
  10.  * you could pass address of both struct termios variables as parameters if desired.
  11.  */
  12. static struct termios cooked, raw;  /* keyboard modes cooked (normal) and raw */
  13. static int inrawmode;
  14. static int modesfilled;
  15. static int linenumbers;
  16.  
  17. /** set (toggle) keyboard between cooked (normal buffered mode) and
  18.  *  raw (unbuffered / noncanonical) mode each time the function is called.
  19.  *  on first call, the termios structs cooked & raw are filled. for all
  20.  *  remaining calls, tcsetattr either sets raw mode or restores cooked
  21.  *  mode based on the flag 'inrawmode'.
  22.  */
  23. int kbd_toggle_raw_mode (void)
  24. {
  25.     if (inrawmode) {                        /* if in raw mode, switch back to cooked */
  26.         if (tcsetattr (0, TCSANOW, &cooked)) {  /* validate change */
  27.             fprintf (stderr, "%s() error: tcsetattr failed.\n", __func__);
  28.             return -1;
  29.         }
  30.         inrawmode = 0;                      /* set in raw mode flag false */
  31.     }
  32.     else {                                  /* in cooked mode, switch to raw mode */
  33.         if (!modesfilled) {                 /* if first time called */
  34.             if (tcgetattr (0, &cooked)) {   /* save orig settings / validate */
  35.                 fprintf (stderr, "%s() error: tcgetattr failed.\n", __func__);
  36.                 return -1;
  37.             }
  38.             /* copy cooked to raw to initialize raw struct */
  39.             memcpy (&raw, &cooked, sizeof(struct termios));
  40.            
  41.             raw.c_lflag &= ~(ICANON | ECHO);  /* set flags for raw mode */
  42.             raw.c_cc[VTIME] = 0;
  43.             raw.c_cc[VMIN] = 1;
  44.            
  45.             modesfilled = 1;                /* set flag indicating both structs filled */
  46.         }
  47.         if (tcsetattr (0, TCSANOW, &raw)) { /* set raw mode / validate */
  48.             fprintf (stderr, "%s() error: tcsetattr failed.\n", __func__);
  49.             return -1;
  50.         }
  51.         inrawmode = 1;                      /* set in raw mode flag true */
  52.     }
  53.    
  54.     return 0;
  55. }
  56.  
  57. /** requires filename to page as first argument, any second
  58.  *  argument will enable line number of output.
  59.  *  pressing any whitespace (space, tab, newline) will page
  60.  *  next 20 lines, 'c' will continue to end, 'q' will quit
  61.  *  at that point.
  62.  */
  63. int main (int argc, char **argv) {
  64.    
  65.     char line[MAXC];                    /* buffer to hold each line */
  66.     int n = 0, pager = 1;               /* line counter, flag to page/continue to end */
  67.     /* use filename provided as 1st argument (stdin by default)
  68.      * allows piping output or redirecting file to program
  69.      * (no line numbering control in that case of input on stdin)
  70.      */
  71.     FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
  72.    
  73.     if (!fp) {  /* validate file open for reading */
  74.         perror ("file open failed");
  75.         return 1;
  76.     }
  77.    
  78.     if (argc > 2)                               /* if addition argument given */
  79.         linenumbers = 1;                        /* enable line numbers */
  80.    
  81.     while (fgets (line, MAXC, fp)) {            /* read each line into line */
  82.         n += 1;                                 /* increment line number counter */
  83.         if (linenumbers)                        /* if line number flag set */
  84.             printf ("%3d  ", n);                /* output line numbers */
  85.         fputs (line, stdout);                   /* output line */
  86.         if (pager && n % LINES == 0) {          /* pager set && LINES no. of lines out */
  87.             int c, quit = 0;                    /* char to read, quit flag */
  88.             if (kbd_toggle_raw_mode() == -1)    /* if error in setting raw mode, warn */
  89.                 fputs ("\nerror: unable to change to raw keyboard mode.\n\n", stderr);
  90.             /* read user input, check if not space and not EOF */
  91.             for (c = getchar(); !isspace(c) && c != EOF; c = getchar())
  92.                 if (c == 'c') {                 /* if user input 'c' */
  93.                     pager = 0;                  /* set pager flag false */
  94.                     break;
  95.                 }
  96.                 else if (c == 'q') {            /* if user input 'q' */
  97.                     quit = 1;                   /* set quit flag true */
  98.                     break;
  99.                 }
  100.             if (kbd_toggle_raw_mode() == -1)    /* if error switing to cooked, warn */
  101.                 fputs ("\nerror: unable to restore keyboard mode.\n\n", stderr);
  102.             if (c == EOF || quit)               /* if c is EOF, manual EOF from user */
  103.                 break;                          /* Ctrl+d Unix, (Ctrl+z on windows) */
  104.         }
  105.     }
  106.  
  107.     if (fp != stdin)   /* close file if not stdin */
  108.         fclose (fp);
  109.  
  110.     return 0;
  111. }
  112.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement