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