fbpdf: remove the use of STD*_FILENO aliases
[fbpdf.git] / fbpdf.c
blobdb256dfc9f96b8e5cb0806a8473f4b6e36115ad5
1 /*
2 * fbpdf - a small framebuffer pdf viewer using mupdf
4 * Copyright (C) 2009-2013 Ali Gholami Rudi <ali at rudi dot ir>
6 * This program is released under the Modified BSD license.
7 */
8 #include <ctype.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <pty.h>
15 #include "draw.h"
16 #include "doc.h"
18 #define MIN(a, b) ((a) < (b) ? (a) : (b))
19 #define MAX(a, b) ((a) > (b) ? (a) : (b))
21 #define PAGESTEPS 8
22 #define CTRLKEY(x) ((x) - 96)
23 #define ISMARK(x) (isalpha(x) || (x) == '\'' || (x) == '`')
24 #define MAXWIDTH 2
25 #define MAXHEIGHT 3
26 #define PDFCOLS (1 << 11)
27 #define PDFROWS (1 << 12)
28 #define MAXZOOM (100)
30 static struct doc *doc;
31 static fbval_t pbuf[PDFROWS * PDFCOLS]; /* current page */
32 static int prows, pcols; /* the dimensions of current page */
34 static int num = 1;
35 static struct termios termios;
36 static char filename[256];
37 static int mark[128]; /* mark page number */
38 static int mark_head[128]; /* mark head position */
39 static int zoom = 15;
40 static int rotate;
41 static int head;
42 static int left;
43 static int count;
45 static void draw(void)
47 int i;
48 for (i = head; i < MIN(head + fb_rows(), PDFROWS); i++)
49 fb_set(i - head, 0, pbuf + i * PDFCOLS + left, fb_cols());
52 static int showpage(int p, int h)
54 if (p < 1 || p > doc_pages(doc))
55 return 0;
56 memset(pbuf, 0x00, sizeof(pbuf));
57 prows = PDFROWS;
58 pcols = PDFCOLS;
59 doc_draw(doc, p, zoom, rotate, pbuf, &prows, &pcols);
60 num = p;
61 head = h;
62 draw();
63 return 0;
66 static void zoom_page(int z)
68 int _zoom = zoom;
69 zoom = MIN(MAXZOOM, MAX(1, z));
70 showpage(num, MIN(PDFROWS - fb_rows(), head * zoom / _zoom));
73 static void setmark(int c)
75 if (ISMARK(c)) {
76 mark[c] = num;
77 mark_head[c] = head / zoom;
81 static void jmpmark(int c, int offset)
83 if (c == '`')
84 c = '\'';
85 if (ISMARK(c) && mark[c]) {
86 int dst = mark[c];
87 int dst_head = offset ? mark_head[c] * zoom : 0;
88 setmark('\'');
89 showpage(dst, dst_head);
93 static int readkey(void)
95 unsigned char b;
96 if (read(0, &b, 1) <= 0)
97 return -1;
98 return b;
101 static int getcount(int def)
103 int result = count ? count : def;
104 count = 0;
105 return result;
108 static void printinfo(void)
110 printf("\x1b[H");
111 printf("FBPDF: file:%s page:%d(%d) zoom:%d%% \x1b[K",
112 filename, num, doc_pages(doc), zoom * 10);
113 fflush(stdout);
116 static void term_setup(void)
118 struct termios newtermios;
119 tcgetattr(0, &termios);
120 newtermios = termios;
121 newtermios.c_lflag &= ~ICANON;
122 newtermios.c_lflag &= ~ECHO;
123 tcsetattr(0, TCSAFLUSH, &newtermios);
126 static void term_cleanup(void)
128 tcsetattr(0, 0, &termios);
131 static void sigcont(int sig)
133 term_setup();
136 static void reload(void)
138 doc_close(doc);
139 doc = doc_open(filename);
140 showpage(num, head);
143 static int rightmost(int cont)
145 int ret = 0;
146 int i, j;
147 for (i = 0; i < prows; i++) {
148 j = PDFCOLS - 1;
149 while (j > ret && pbuf[i * PDFCOLS + j] == FB_VAL(0, 0, 0))
150 j--;
151 while (cont && j > ret &&
152 pbuf[i * PDFCOLS + j] == FB_VAL(255, 255, 255))
153 j--;
154 if (ret < j)
155 ret = j;
157 return ret;
160 static int leftmost(int cont)
162 int ret = PDFCOLS;
163 int i, j;
164 for (i = 0; i < prows; i++) {
165 j = 0;
166 while (j < ret && pbuf[i * PDFCOLS + j] == FB_VAL(0, 0, 0))
167 j++;
168 while (cont && j < ret &&
169 pbuf[i * PDFCOLS + j] == FB_VAL(255, 255, 255))
170 j++;
171 if (ret > j)
172 ret = j;
174 return ret;
177 static void mainloop(void)
179 int step = fb_rows() / PAGESTEPS;
180 int hstep = fb_cols() / PAGESTEPS;
181 int c;
182 term_setup();
183 signal(SIGCONT, sigcont);
184 showpage(num, 0);
185 while ((c = readkey()) != -1) {
186 switch (c) {
187 case CTRLKEY('f'):
188 case 'J':
189 showpage(num + getcount(1), 0);
190 break;
191 case CTRLKEY('b'):
192 case 'K':
193 showpage(num - getcount(1), 0);
194 break;
195 case 'G':
196 setmark('\'');
197 showpage(getcount(doc_pages(doc)), 0);
198 break;
199 case 'z':
200 zoom_page(getcount(15));
201 break;
202 case 'w':
203 zoom_page(zoom * fb_cols() / pcols);
204 break;
205 case 'W':
206 if (leftmost(1) < rightmost(1))
207 zoom_page(zoom * (fb_cols() - hstep) /
208 (rightmost(1) - leftmost(1)));
209 break;
210 case 'f':
211 zoom_page(zoom * fb_rows() / prows);
212 break;
213 case 'r':
214 rotate = getcount(0);
215 showpage(num, 0);
216 break;
217 case 'i':
218 printinfo();
219 break;
220 case 'q':
221 term_cleanup();
222 return;
223 case 27:
224 count = 0;
225 break;
226 case 'm':
227 setmark(readkey());
228 break;
229 case 'e':
230 reload();
231 break;
232 case '`':
233 case '\'':
234 jmpmark(readkey(), c == '`');
235 break;
236 default:
237 if (isdigit(c))
238 count = count * 10 + c - '0';
240 switch (c) {
241 case 'j':
242 head += step * getcount(1);
243 break;
244 case 'k':
245 head -= step * getcount(1);
246 break;
247 case 'l':
248 left += hstep * getcount(1);
249 break;
250 case 'h':
251 left -= hstep * getcount(1);
252 break;
253 case 'H':
254 head = 0;
255 break;
256 case 'L':
257 head = MAX(0, prows - fb_rows());
258 break;
259 case 'M':
260 head = (prows - fb_rows()) / 2;
261 break;
262 case ' ':
263 case CTRL('d'):
264 head += fb_rows() * getcount(1) - step;
265 break;
266 case 127:
267 case CTRL('u'):
268 head -= fb_rows() * getcount(1) - step;
269 break;
270 case '[':
271 left = leftmost(0);
272 break;
273 case ']':
274 left = rightmost(0) - fb_cols();
275 break;
276 case '{':
277 left = leftmost(1) - hstep / 2;
278 break;
279 case '}':
280 left = rightmost(1) + hstep / 2 - fb_cols();
281 break;
282 case CTRLKEY('l'):
283 break;
284 default:
285 /* no need to redraw */
286 continue;
288 head = MAX(0, MIN(PDFROWS - fb_rows(), head));
289 left = MAX(0, MIN(PDFCOLS - fb_cols(), left));
290 draw();
294 static char *usage =
295 "usage: fbpdf [-r rotation] [-z zoom x10] [-p page] filename\n";
297 int main(int argc, char *argv[])
299 int i = 1;
300 if (argc < 2) {
301 printf(usage);
302 return 1;
304 strcpy(filename, argv[argc - 1]);
305 doc = doc_open(filename);
306 if (!doc) {
307 fprintf(stderr, "cannot open <%s>\n", filename);
308 return 1;
310 while (i + 2 < argc && argv[i][0] == '-') {
311 if (argv[i][1] == 'r')
312 rotate = atoi(argv[i + 1]);
313 if (argv[i][1] == 'z')
314 zoom = atoi(argv[i + 1]);
315 if (argv[i][1] == 'p')
316 num = atoi(argv[i + 1]);
317 i += 2;
319 printf("\x1b[?25l"); /* hide the cursor */
320 printf("\x1b[2J"); /* clear the screen */
321 printinfo();
322 if (fb_init())
323 return 1;
324 left = (PDFCOLS - fb_cols()) / 2;
325 if (FBM_BPP(fb_mode()) != sizeof(fbval_t))
326 fprintf(stderr, "fbpdf: fbval_t doesn't match fb depth\n");
327 else
328 mainloop();
329 fb_free();
330 printf("\x1b[?25h\n"); /* show the cursor */
331 doc_close(doc);
332 return 0;