]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/proof/htroff.c
fix filetype detecton by suffix so that multiple dots dont confuse it. (thanks kvik)
[plan9front.git] / sys / src / cmd / proof / htroff.c
1 #include        <u.h>
2 #include        <libc.h>
3 #include        <draw.h>
4 #include        <cursor.h>
5 #include        <event.h>
6 #include        <bio.h>
7 #include        "proof.h"
8
9 int     res;
10 int     hpos;
11 int     vpos;
12 int     DIV = 11;
13
14 Point offset;
15 Point xyoffset = { 0,0 };
16
17 Rectangle       view[MAXVIEW];
18 Rectangle       bound[MAXVIEW];         /* extreme points */
19 int     nview = 1;
20
21 int     lastp;  /* last page number we were on */
22
23 #define NPAGENUMS       200
24 struct pagenum {
25         int     num;
26         long    adr;
27 } pagenums[NPAGENUMS];
28 int     npagenums;
29
30 int     curfont, cursize;
31
32 char    *getcmdstr(void);
33
34 static void     initpage(void);
35 static void     view_setup(int);
36 static Point    scale(Point);
37 static void     clearview(Rectangle);
38 static int      addpage(int);
39 static void     spline(Image *, int, Point *);
40 static int      skipto(int, int);
41 static void     wiggly(int);
42 static void     devcntrl(void);
43 static void     eatline(void);
44 static int      getn(void);
45 static int      botpage(int);
46 static void     getstr(char *);
47
48 #define Do screen->r.min
49 #define Dc screen->r.max
50
51 /* declarations and definitions of font stuff are in font.c and main.c */
52
53 static void
54 initpage(void)
55 {
56         int i;
57
58         view_setup(nview);
59         for (i = 0; i < nview-1; i++)
60                 draw(screen, view[i], screen, nil, view[i+1].min);
61         clearview(view[nview-1]);
62         offset = view[nview-1].min;
63         vpos = 0;
64 }
65
66 static void
67 view_setup(int n)
68 {
69         int i, j, v, dx, dy, r, c;
70
71         switch (n) {
72         case 1: r = 1; c = 1; break;
73         case 2: r = 1; c = 2; break;
74         case 3: r = 1; c = 3; break;
75         case 4: r = 2; c = 2; break;
76         case 5: case 6: r = 2; c = 3; break;
77         case 7: case 8: case 9: r = 3; c = 3; break;
78         default: r = (n+2)/3; c = 3; break; /* finking out */
79         }
80         dx = (Dc.x - Do.x) / c;
81         dy = (Dc.y - Do.y) / r;
82         v = 0;
83         for (i = 0; i < r && v < n; i++)
84                 for (j = 0; j < c && v < n; j++) {
85                         view[v] = screen->r;
86                         view[v].min.x = Do.x + j * dx;
87                         view[v].max.x = Do.x + (j+1) * dx;
88                         view[v].min.y = Do.y + i * dy;
89                         view[v].max.y = Do.y + (i+1) * dy;
90                         v++;
91                 }
92 }
93
94 static void
95 clearview(Rectangle r)
96 {
97         draw(screen, r, display->white, nil, r.min);
98 }
99
100 int resized;
101 void eresized(int new)
102 {
103         /* this is called if we are resized */
104         if(new && getwindow(display, Refnone) < 0)
105                 drawerror(display, "can't reattach to window");
106         initpage();
107         resized = 1;
108 }
109
110 static Point
111 scale(Point p)
112 {
113         p.x /= DIV;
114         p.y /= DIV;
115         return addpt(xyoffset, addpt(offset,p));
116 }
117
118 static int
119 addpage(int n)
120 {
121         int i;
122
123         for (i = 0; i < npagenums; i++)
124                 if (n == pagenums[i].num)
125                         return i;
126         if (npagenums < NPAGENUMS-1) {
127                 pagenums[npagenums].num = n;
128                 pagenums[npagenums].adr = offsetc();
129                 npagenums++;
130         }
131         return npagenums;
132 }
133
134 void
135 readpage(void)
136 {
137         int c, i, a, alpha, phi;
138         static int first = 0;
139         int m, n, gonow = 1;
140         Rune r[32], t;
141         Point p,q,qq;
142
143         offset = screen->clipr.min;
144         esetcursor(&deadmouse);
145         while (gonow)
146         {
147                 c = getc();
148                 switch (c)
149                 {
150                 case -1:
151                         esetcursor(0);
152                         if (botpage(lastp+1)) {
153                                 initpage();
154                                 break;
155                         }
156                         exits(0);
157                 case 'p':       /* new page */
158                         lastp = getn();
159                         addpage(lastp);
160                         if (first++ > 0) {
161                                 esetcursor(0);
162                                 botpage(lastp);
163                                 esetcursor(&deadmouse);
164                         }
165                         initpage();
166                         break;
167                 case '\n':      /* when input is text */
168                 case ' ':
169                 case 0:         /* occasional noise creeps in */
170                         break;
171                 case '0': case '1': case '2': case '3': case '4':
172                 case '5': case '6': case '7': case '8': case '9':
173                         /* two motion digits plus a character */
174                         hpos += (c-'0')*10 + getc()-'0';
175
176                 /* FALLS THROUGH */
177                 case 'c':       /* single ascii character */
178                         r[0] = getrune();
179                         r[1] = 0;
180                         dochar(r);
181                         break;
182
183                 case 'C':
184                         for(i=0; ; i++){
185                                 t = getrune();
186                                 if(isspace(t))
187                                         break;
188                                 r[i] = t;
189                         }
190                         r[i] = 0;
191                         dochar(r);
192                         break;
193
194                 case 'N':
195                         r[0] = getn();
196                         r[1] = 0;
197                         dochar(r);
198                         break;
199
200                 case 'D':       /* draw function */
201                         switch (getc())
202                         {
203                         case 'l':       /* draw a line */
204                                 n = getn();
205                                 m = getn();
206                                 p = Pt(hpos,vpos);
207                                 q = addpt(p, Pt(n,m));
208                                 hpos += n;
209                                 vpos += m;
210                                 line(screen, scale(p), scale(q), 0, 0, 0, display->black, ZP);
211                                 break;
212                         case 'c':       /* circle */
213                                 /*nop*/
214                                 m = getn()/2;
215                                 p = Pt(hpos+m,vpos);
216                                 hpos += 2*m;
217                                 ellipse(screen, scale(p), m/DIV, m/DIV, 0, display->black, ZP);
218                                 /* p=currentpt; p.x+=dmap(m/2);circle bp,p,a,ONES,Mode*/
219                                 break;
220                         case 'e':       /* ellipse */
221                                 /*nop*/
222                                 m = getn()/2;
223                                 n = getn()/2;
224                                 p = Pt(hpos+m,vpos);
225                                 hpos += 2*m;
226                                 ellipse(screen, scale(p), m/DIV, n/DIV, 0, display->black, ZP);
227                                 break;
228                         case 'a':       /* arc */
229                                 p = scale(Pt(hpos,vpos));
230                                 n = getn();
231                                 m = getn();
232                                 hpos += n;
233                                 vpos += m;
234                                 q = scale(Pt(hpos,vpos));
235                                 n = getn();
236                                 m = getn();
237                                 hpos += n;
238                                 vpos += m;
239                                 qq = scale(Pt(hpos,vpos));
240                                 /*
241                                   * tricky: convert from 3-point clockwise to
242                                   * center, angle1, delta-angle counterclockwise.
243                                  */
244                                 a = hypot(qq.x-q.x, qq.y-q.y);
245                                 phi = atan2(q.y-p.y, p.x-q.x)*180./PI;
246                                 alpha = atan2(q.y-qq.y, qq.x-q.x)*180./PI - phi;
247                                 if(alpha < 0)
248                                         alpha += 360;
249                                 arc(screen, q, a, a, 0, display->black, ZP, phi, alpha);
250                                 break;
251                         case '~':       /* wiggly line */
252                                 wiggly(0);
253                                 break;
254                         default:
255                                 break;
256                         }
257                         eatline();
258                         break;
259                 case 's':
260                         n = getn();     /* ignore fractional sizes */
261                         if (cursize == n)
262                                 break;
263                         cursize = n;
264                         if (cursize >= NFONT)
265                                 cursize = NFONT-1;
266                         break;
267                 case 'f':
268                         curfont = getn();
269                         break;
270                 case 'H':       /* absolute horizontal motion */
271                         hpos = getn();
272                         break;
273                 case 'h':       /* relative horizontal motion */
274                         hpos += getn();
275                         break;
276                 case 'w':       /* word space */
277                         break;
278                 case 'V':
279                         vpos = getn();
280                         break;
281                 case 'v':
282                         vpos += getn();
283                         break;
284                 case '#':       /* comment */
285                 case 'n':       /* end of line */
286                         eatline();
287                         break;
288                 case 'x':       /* device control */
289                         devcntrl();
290                         break;
291                 default:
292                         fprint(2, "unknown input character %o %c at offset %lud\n", c, c, offsetc());
293                         exits("bad char");
294                 }
295         }
296         esetcursor(0);
297 }
298
299 static void
300 spline(Image *b, int n, Point *pp)
301 {
302         long w, t1, t2, t3, fac=1000; 
303         int i, j, steps=10; 
304         Point p, q;
305
306         for (i = n; i > 0; i--)
307                 pp[i] = pp[i-1];
308         pp[n+1] = pp[n];
309         n += 2;
310         p = pp[0];
311         for(i = 0; i < n-2; i++)
312         {
313                 for(j = 0; j < steps; j++)
314                 {
315                         w = fac * j / steps;
316                         t1 = w * w / (2 * fac);
317                         w = w - fac/2;
318                         t2 = 3*fac/4 - w * w / fac;
319                         w = w - fac/2;
320                         t3 = w * w / (2*fac);
321                         q.x = (t1*pp[i+2].x + t2*pp[i+1].x + 
322                                 t3*pp[i].x + fac/2) / fac;
323                         q.y = (t1*pp[i+2].y + t2*pp[i+1].y + 
324                                 t3*pp[i].y + fac/2) / fac;
325                         line(b, p, q, 0, 0, 0, display->black, ZP);
326                         p = q;
327                 }
328         }
329 }
330
331 /* Have to parse skipped pages, to find out what fonts are loaded. */
332 static int
333 skipto(int gotop, int curp)
334 {
335         char *p;
336         int i;
337
338         if (gotop == curp)
339                 return 1;
340         for (i = 0; i < npagenums; i++)
341                 if (pagenums[i].num == gotop) {
342                         if (seekc(pagenums[i].adr) == Beof) {
343                                 fprint(2, "can't rewind input\n");
344                                 return 0;
345                         }
346                         return 1;
347                 }
348         if (gotop <= curp) {
349             restart:
350                 if (seekc(0) == Beof) {
351                         fprint(2, "can't rewind input\n");
352                         return 0;
353                 }
354         }
355         for(;;){
356                 p = rdlinec();
357                 if (p == 0) {
358                         if(gotop>curp){
359                                 gotop = curp;
360                                 goto restart;
361                         }
362                         return 0;
363                 } else if (*p == 'p') {
364                         lastp = curp = atoi(p+1);
365                         addpage(lastp); /* maybe 1 too high */
366                         if (curp>=gotop)
367                                 return 1;
368                 }
369         }
370 }
371
372 static void
373 wiggly(int skip)
374 {
375         Point p[300];
376         int c,i,n;
377         for (n = 1; (c = getc()) != '\n' && c>=0; n++) {
378                 ungetc();
379                 p[n].x = getn();
380                 p[n].y = getn();
381         }
382         p[0] = Pt(hpos, vpos);
383         for (i = 1; i < n; i++)
384                 p[i] = addpt(p[i],p[i-1]);
385         hpos = p[n-1].x;
386         vpos = p[n-1].y;
387         for (i = 0; i < n; i++)
388                 p[i] = scale(p[i]);
389         if (!skip)
390                 spline(screen,n,p);
391 }
392
393 static void
394 devcntrl(void)  /* interpret device control functions */
395 {
396         char str[80];
397         int n;
398
399         getstr(str);
400         switch (str[0]) {       /* crude for now */
401         case 'i':       /* initialize */
402                 break;
403         case 'T':       /* device name */
404                 getstr(devname);
405                 break;
406         case 't':       /* trailer */
407                 break;
408         case 'p':       /* pause -- can restart */
409                 break;
410         case 's':       /* stop */
411                 break;
412         case 'r':       /* resolution assumed when prepared */
413                 res=getn();
414                 DIV = floor(.5 + res/(100.0*mag));
415                 if (DIV < 1)
416                         DIV = 1;
417                 mag = res/(100.0*DIV); /* adjust mag according to DIV coarseness */
418                 break;
419         case 'f':       /* font used */
420                 n = getn();
421                 getstr(str);
422                 loadfontname(n, str);
423                 break;
424         /* these don't belong here... */
425         case 'H':       /* char height */
426                 break;
427         case 'S':       /* slant */
428                 break;
429         case 'X':
430                 break;
431         }
432         eatline();
433 }
434
435 int
436 isspace(int c)
437 {
438         return c==' ' || c=='\t' || c=='\n';
439 }
440
441 static void
442 getstr(char *is)
443 {
444         uchar *s = (uchar *) is;
445
446         for (*s = getc(); isspace(*s); *s = getc())
447                 ;
448         for (; !isspace(*s); *++s = getc())
449                 ;
450         ungetc();
451         *s = 0;
452 }
453
454 static void
455 eatline(void)
456 {
457         int c;
458
459         while ((c=getc()) != '\n' && c >= 0)
460                 ;
461 }
462
463 static int
464 getn(void)
465 {
466         int n, c, sign;
467
468         while (c = getc())
469                 if (!isspace(c))
470                         break;
471         if(c == '-'){
472                 sign = -1;
473                 c = getc();
474         }else
475                 sign = 1;
476         for (n = 0; '0'<=c && c<='9'; c = getc())
477                 n = n*10 + c - '0';
478         while (c == ' ')
479                 c = getc();
480         ungetc();
481         return(n*sign);
482 }
483
484 static int
485 botpage(int np) /* called at bottom of page np-1 == top of page np */
486 {
487         char *p;
488         int n;
489
490         while (p = getcmdstr()) {
491                 if (*p == '\0')
492                         return 0;
493                 if (*p == 'q')
494                         exits(p);
495                 if (*p == 'c')          /* nop */
496                         continue;
497                 if (*p == 'm') {
498                         mag = atof(p+1);
499                         if (mag <= .1 || mag >= 10)
500                                 mag = DEFMAG;
501                         allfree();      /* zap fonts */
502                         DIV = floor(.5 + res/(100.0*mag));
503                         if (DIV < 1)
504                                 DIV = 1;
505                         mag = res/(100.0*DIV);
506                         return skipto(np-1, np);        /* reprint the page */
507                 }
508                 if (*p == 'x') {
509                         xyoffset.x += atoi(p+1)*100;
510                         skipto(np-1, np);
511                         return 1;
512                 }
513                 if (*p == 'y') {
514                         xyoffset.y += atoi(p+1)*100;
515                         skipto(np-1, np);
516                         return 1;
517                 }
518                 if (*p == '/') {        /* divide into n pieces */
519                         nview = atoi(p+1);
520                         if (nview < 1)
521                                 nview = 1;
522                         else if (nview > MAXVIEW)
523                                 nview = MAXVIEW;
524                         return skipto(np-1, np);
525                 }
526                 if (*p == 'p') {
527                         if (p[1] == '\0'){      /* bare 'p' */
528                                 if(skipto(np-1, np))
529                                         return 1;
530                                 continue;
531                         }
532                         p++;
533                 }
534                 if ('0'<=*p && *p<='9') {
535                         n = atoi(p);
536                         if(skipto(n, np))
537                                 return 1;
538                         continue;
539                 }
540                 if (*p == '-' || *p == '+') {
541                         n = atoi(p);
542                         if (n == 0)
543                                 n = *p == '-' ? -1 : 1;
544                         if(skipto(np - 1 + n, np))
545                                 return 1;
546                         continue;
547                 }
548                 if (*p == 'd') {
549                         dbg = 1 - dbg;
550                         continue;
551                 }
552
553                 fprint(2, "illegal;  try q, 17, +2, -1, p, m.7, /2, x1, y-.5 or return\n");
554         }
555         return 0;
556 }