Advertisement
cutecoder

Simple file reader in NCurses (using stdscr)

Sep 4th, 2023 (edited)
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 3.47 KB | Source Code | 0 0
  1. #include <curses.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <fcntl.h>
  5. #include <time.h>
  6. #include <unistd.h>
  7.  
  8. #define MAX_LINE 128
  9.  
  10. #define MIN(a, b) ({ \
  11.     __auto_type _a = (a); \
  12.     __auto_type _b = (b); \
  13.     _a < _b ? _a : _b; \
  14. })
  15.  
  16. struct line {
  17.     char text[MAX_LINE];
  18. };
  19.  
  20. struct buffer {
  21.     struct line *lines;
  22.     int nlines;
  23. };
  24.  
  25. struct buffer buf;
  26.  
  27. int width, height;
  28. int v_scroll;
  29.  
  30. int read_file(struct buffer *buf, const char *file)
  31. {
  32.     int fd;
  33.     char b[1024];
  34.     const char *p;
  35.     struct line *lines, *newlines;
  36.     int nlines;
  37.     int idx;
  38.     ssize_t r;
  39.  
  40.     if ((fd = open(file, O_RDONLY)) < 0)
  41.         return -1;
  42.  
  43.     lines = malloc(sizeof(*lines) * 8);
  44.     if (lines == NULL) {
  45.         close(fd);
  46.         return -1;
  47.     }
  48.     nlines = 0;
  49.     idx = 0;
  50.     while ((r = read(fd, b, sizeof(b))) > 0) {
  51.         p = b;
  52.         do {
  53.             if (*p == '\n') {
  54.                 lines[nlines].text[idx] = '\0';
  55.                 nlines++;
  56.                 newlines = realloc(lines, sizeof(*lines) * (nlines + 1));
  57.                 if (newlines == NULL)
  58.                     goto end;
  59.                 lines = newlines;
  60.                 idx = 0;
  61.             } else {
  62.                 if (idx + 1 == MAX_LINE)
  63.                     continue; /* cut off lines that are too long */
  64.                 lines[nlines].text[idx++] = *p;
  65.             }
  66.             p++;
  67.         } while(--r);
  68.     }
  69.  
  70. end:
  71.     close(fd);
  72.     lines[nlines].text[idx] = '\0';
  73.     buf->lines = lines;
  74.     buf->nlines = nlines + 1;
  75.     return 0;
  76. }
  77.  
  78. void draw_lines(WINDOW *win, int y, struct line *lines, int nlines, int from, int to)
  79. {
  80.     int begy, begx;
  81.     int maxy, maxx;
  82.  
  83.     getbegyx(win, begy, begx);
  84.     getmaxyx(win, maxy, maxx);
  85.     maxx -= begx;
  86.     maxy -= begy;
  87.     if (from < 0)
  88.         from = 0;
  89.     if (to < 0 || to >= nlines)
  90.         to = nlines - 1;
  91.     if (maxy - y < to - from)
  92.         to = maxy - y + from;
  93.     wattr_set(win, 0, 0, NULL);
  94.     for (; from <= to; from++, y++)
  95.         mvwaddstr(win, y, 0, lines[from].text);
  96. }
  97.  
  98. void handle_char(int c)
  99. {
  100.     switch (c) {
  101.     case 'j':
  102.         if (v_scroll == buf.nlines - height)
  103.             break;
  104.         scrl(1);
  105.         v_scroll++;
  106.         draw_lines(stdscr, height - 1, buf.lines, buf.nlines, v_scroll + height, v_scroll + height);
  107.         break;
  108.     case 'k':
  109.         if (v_scroll == 0)
  110.             break;
  111.         scrl(-1);
  112.         v_scroll--;
  113.         draw_lines(stdscr, 0, buf.lines, buf.nlines, v_scroll, v_scroll);
  114.         break;
  115.     case 'g':
  116.         erase();
  117.         draw_lines(stdscr, 0, buf.lines, buf.nlines, -1, -1);
  118.         break;
  119.     case 'G':
  120.         erase();
  121.         draw_lines(stdscr, 0, buf.lines, buf.nlines, buf.nlines - height, -1);
  122.         break;
  123.     }
  124. }
  125.  
  126. void do_refresh(void)
  127. {
  128.     refresh();
  129. }
  130.  
  131. int main(int argc, char **argv)
  132. {
  133.     if (argc < 2) {
  134.         fprintf(stderr, "usage: %s <file name>\n", argv[0]);
  135.         return -1;
  136.     }
  137.  
  138.     initscr();
  139.     noecho();
  140.     raw();
  141.     curs_set(0);
  142.     start_color();
  143.     keypad(stdscr, true);
  144.     scrollok(stdscr, true);
  145.     /* reserve the last line for the status bar */
  146.     setscrreg(0, LINES - 2);
  147.     refresh();
  148.  
  149.     if (read_file(&buf, argv[1]) < 0) {
  150.         endwin();
  151.         fprintf(stderr, "error reading file '%s'\n", argv[1]);
  152.         return -1;
  153.     }
  154.  
  155.     width = MIN(COLS, MAX_LINE);
  156.     height = MIN(LINES - 1, buf.nlines);
  157.     v_scroll = 0;
  158.  
  159.     /* Draw initial content */
  160.     draw_lines(stdscr, 0, buf.lines, buf.nlines, -1, -1);
  161.  
  162.     const time_t start = time(NULL);
  163.  
  164.     /* Main loop */
  165.     while (1) {
  166.         /* Draw status bar */
  167.         attr_set(A_REVERSE, 0, NULL);
  168.         mvprintw(LINES - 1, 0, "%4d (%3d%%)", v_scroll + 1, 100 * v_scroll / (buf.nlines - height));
  169.         hline(' ', COLS - getcurx(stdscr));
  170.  
  171.         do_refresh();
  172.         int c = 0;
  173.         if (rand() % 2 == 0)
  174.             c = 'j';
  175.         else
  176.             c = 'k';
  177.         handle_char(c);
  178.         /* Run for 30 seconds */
  179.         if (time(NULL) - start == 30)
  180.             break;
  181.     }
  182.  
  183.     endwin();
  184.     return 0;
  185. }
  186.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement