htroff.c 10 KB

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