htroff.c 10 KB

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