catpoint.c - catpoint - Catpoint simple presenting software.
 (HTM) git clone git://r-36.net/catpoint
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       catpoint.c (4824B)
       ---
            1 /* See LICENSE file for license details. */
            2 
            3 #include <sys/mman.h>
            4 #include <sys/stat.h>
            5 #include <sys/types.h>
            6 #include <sys/wait.h>
            7 
            8 #include <curses.h>
            9 #include <errno.h>
           10 #include <fcntl.h>
           11 #include <locale.h>
           12 #include <signal.h>
           13 #include <stdarg.h>
           14 #include <stdio.h>
           15 #include <stdlib.h>
           16 #include <string.h>
           17 #include <unistd.h>
           18 
           19 void die(const char *, ...);
           20 
           21 char *currentslidep, **slidefiles; /* the slides */
           22 int nslides, currentslide, currentslidelen;
           23 
           24 volatile sig_atomic_t slidechanged = 1;
           25 
           26 void
           27 unloadcurrentslide(void)
           28 {
           29         if (currentslidep == NULL)
           30                 return;
           31 
           32         if (munmap(currentslidep, currentslidelen) < 0)
           33                 die("munmap: %s", slidefiles[currentslide]);
           34 }
           35 
           36 void
           37 setupwin(void)
           38 {
           39         initscr();
           40         cbreak();
           41         noecho();
           42         nonl();
           43         intrflush(stdscr, FALSE);
           44         keypad(stdscr, TRUE);
           45         curs_set(FALSE); /* hide cursor */
           46 }
           47 
           48 void
           49 cleanup(void)
           50 {
           51         unloadcurrentslide();
           52 
           53         endwin(); /* restore terminal */
           54 }
           55 
           56 /* print to stderr, call cleanup() and _exit(). */
           57 void
           58 die(const char *fmt, ...)
           59 {
           60         va_list ap;
           61         int saved_errno;
           62 
           63         saved_errno = errno;
           64         cleanup();
           65 
           66         va_start(ap, fmt);
           67         vfprintf(stderr, fmt, ap);
           68         va_end(ap);
           69 
           70         if (saved_errno)
           71                 fprintf(stderr, ": %s", strerror(saved_errno));
           72         fflush(stderr);
           73         (void)!write(2, "\n", 1);
           74 
           75         _exit(1);
           76 }
           77 
           78 void
           79 quit(int sig)
           80 {
           81         cleanup();
           82         _exit(128 + sig);
           83 }
           84 
           85 void
           86 executeslide(char **argv)
           87 {
           88         pid_t pid;
           89 
           90         endwin();
           91 
           92         fprintf(stderr, "\x1b[H\x1b[J");
           93         fflush(stderr);
           94 
           95         switch ((pid = fork())) {
           96         case 0:
           97                 execvp(argv[0], argv);
           98         case -1:
           99                 perror(argv[0]);
          100                 break;
          101         default:
          102                 waitpid(pid, NULL, 0);
          103         }
          104 
          105         setupwin();
          106 }
          107 
          108 void
          109 loadcurrentslide(char **argv, int slide)
          110 {
          111         struct stat statbuf;
          112         int fd;
          113 
          114         unloadcurrentslide();
          115 
          116         fd = open(slidefiles[slide], O_RDONLY, 0);
          117         if (fd < 0)
          118                 die("open: %s", slidefiles[slide]);
          119         if (fstat(fd, &statbuf) < 0)
          120                 die("fstat: %s", slidefiles[slide]);
          121         currentslidep = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
          122         if (currentslidep == MAP_FAILED) {
          123                 currentslidep = NULL;
          124                 die("mmap: %s", slidefiles[slide]);
          125         }
          126         currentslidelen = statbuf.st_size;
          127         close(fd);
          128 }
          129 
          130 void
          131 reloadcurrentslide(int sig)
          132 {
          133         /*
          134          * Keep this out of SIGHUP, in case this is used somewhere else.
          135          */
          136         slidechanged = 1;
          137 
          138         if (sig == SIGHUP) {
          139                 /* Make ncurses redisplay slide. */
          140                 if (raise(SIGWINCH) < 0)
          141                         die("raise");
          142         }
          143 }
          144 
          145 void
          146 setsignal()
          147 {
          148         struct sigaction sa;
          149 
          150         memset(&sa, 0, sizeof(sa));
          151         sigemptyset(&sa.sa_mask);
          152         sa.sa_flags = 0;
          153 
          154         sa.sa_handler = quit;
          155         sigaction(SIGINT, &sa, NULL);
          156         sigaction(SIGQUIT, &sa, NULL);
          157         sigaction(SIGTERM, &sa, NULL);
          158 
          159         sa.sa_handler = reloadcurrentslide;
          160         sigaction(SIGHUP, &sa, NULL);
          161 }
          162 
          163 int
          164 main(int argc, char *argv[])
          165 {
          166         int c;
          167 
          168         if (argc == 1) {
          169                 errno = 0;
          170                 die("usage: %s file ...", argv[0]);
          171         }
          172 
          173         slidefiles = ++argv;
          174         nslides = --argc;
          175 
          176         setsignal();
          177         setlocale(LC_ALL, "");
          178 
          179         /* start */
          180         currentslide = 0;
          181         currentslidep = NULL;
          182         currentslidelen = 0;
          183 
          184         /* init curses */
          185         setupwin();
          186 
          187 show:
          188         /* display slide if changed */
          189         if (slidechanged) {
          190                 slidechanged = 0;
          191                 loadcurrentslide(slidefiles, currentslide);
          192         }
          193         clear();
          194         refresh();
          195 
          196         if (access(slidefiles[currentslide], X_OK) == 0) {
          197                 executeslide(slidefiles + currentslide);
          198         } else {
          199                 printw("%.*s", currentslidelen, currentslidep);
          200         }
          201 
          202 again:
          203         c = getch();
          204         switch (c) {
          205         /* powerpoint remote presenter shortcuts */
          206         case 4: /* ^D, EOT */
          207         case 27:
          208         case KEY_F(5):
          209         /* end presentation */
          210         case 'q':
          211                 break;
          212         /* next without transition */
          213         case 'J':
          214         case 'L':
          215                 for (int i = currentslide + 1; i < nslides; i++) {
          216                         if (access(slidefiles[i], X_OK) && i != currentslide) {
          217                                 currentslide = i;
          218                                 slidechanged = 1;
          219                                 goto show;
          220                         }
          221                 }
          222                 goto again;
          223         /* next */
          224         case ' ':
          225         case 'l':
          226         case 'j':
          227         case KEY_RIGHT:
          228         case KEY_DOWN:
          229         case KEY_NPAGE:
          230                 if (currentslide < nslides - 1) {
          231                         slidechanged = 1;
          232                         currentslide++;
          233                         goto show;
          234                 }
          235                 goto again;
          236         /* prev without transition */
          237         case 'H':
          238         case 'K':
          239                 for (int i = currentslide - 1; i >= 0; i--) {
          240                         if (access(slidefiles[i], X_OK) && i != currentslide) {
          241                                 currentslide = i;
          242                                 slidechanged = 1;
          243                                 goto show;
          244                         }
          245                 }
          246                 goto again;
          247         /* prev */
          248         case 'h':
          249         case 'k':
          250         case KEY_LEFT:
          251         case KEY_UP:
          252         case KEY_PPAGE:
          253                 if (currentslide > 0) {
          254                         slidechanged = 1;
          255                         currentslide--;
          256                         goto show;
          257                 }
          258                 goto again;
          259         /* shortcut from powerpoint. Needed for remote presenters. */
          260         case '.':
          261         /* first */
          262         case 'u':
          263         case KEY_BEG:
          264         case KEY_HOME:
          265                 if (currentslide != 0)
          266                         slidechanged = 1;
          267                 currentslide = 0;
          268                 goto show;
          269         /* last */
          270         case 'i':
          271         case KEY_END:
          272                 if (currentslide != (nslides - 1))
          273                         slidechanged = 1;
          274                 currentslide = nslides - 1;
          275                 goto show;
          276         /* reload */
          277         case 'r':
          278         case 12: /* ^L, redraw */
          279         case KEY_RESIZE: /* resize / SIGWINCH */
          280                 goto show;
          281         default:
          282                 /* printf("key pressed = '%d'\n", c); */
          283                 goto again;
          284         }
          285 
          286         cleanup();
          287 
          288         return 0;
          289 }