Advertisement
cutecoder

Simple file reader in NCurses

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