roff.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  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 "a.h"
  10. enum
  11. {
  12. MAXREQ = 100,
  13. MAXRAW = 40,
  14. MAXESC = 60,
  15. MAXLINE = 1024,
  16. MAXIF = 20,
  17. MAXARG = 10,
  18. };
  19. typedef struct Esc Esc;
  20. typedef struct Req Req;
  21. typedef struct Raw Raw;
  22. /* escape sequence handler, like for \c */
  23. struct Esc
  24. {
  25. Rune r;
  26. int (*f)(void);
  27. int mode;
  28. };
  29. /* raw request handler, like for .ie */
  30. struct Raw
  31. {
  32. Rune *name;
  33. void (*f)(Rune*);
  34. };
  35. /* regular request handler, like for .ft */
  36. struct Req
  37. {
  38. int argc;
  39. Rune *name;
  40. void (*f)(int, Rune**);
  41. };
  42. int dot = '.';
  43. int tick = '\'';
  44. int backslash = '\\';
  45. int inputmode;
  46. Req req[MAXREQ];
  47. int nreq;
  48. Raw raw[MAXRAW];
  49. int nraw;
  50. Esc esc[MAXESC];
  51. int nesc;
  52. int iftrue[MAXIF];
  53. int niftrue;
  54. int isoutput;
  55. int linepos;
  56. void
  57. addraw(Rune *name, void (*f)(Rune*))
  58. {
  59. Raw *r;
  60. if(nraw >= nelem(raw)){
  61. fprint(2, "too many raw requets\n");
  62. return;
  63. }
  64. r = &raw[nraw++];
  65. r->name = erunestrdup(name);
  66. r->f = f;
  67. }
  68. void
  69. delraw(Rune *name)
  70. {
  71. int i;
  72. for(i=0; i<nraw; i++){
  73. if(runestrcmp(raw[i].name, name) == 0){
  74. if(i != --nraw){
  75. free(raw[i].name);
  76. raw[i] = raw[nraw];
  77. }
  78. return;
  79. }
  80. }
  81. }
  82. void
  83. renraw(Rune *from, Rune *to)
  84. {
  85. int i;
  86. delraw(to);
  87. for(i=0; i<nraw; i++)
  88. if(runestrcmp(raw[i].name, from) == 0){
  89. free(raw[i].name);
  90. raw[i].name = erunestrdup(to);
  91. return;
  92. }
  93. }
  94. void
  95. addreq(Rune *s, void (*f)(int, Rune**), int argc)
  96. {
  97. Req *r;
  98. if(nreq >= nelem(req)){
  99. fprint(2, "too many requests\n");
  100. return;
  101. }
  102. r = &req[nreq++];
  103. r->name = erunestrdup(s);
  104. r->f = f;
  105. r->argc = argc;
  106. }
  107. void
  108. delreq(Rune *name)
  109. {
  110. int i;
  111. for(i=0; i<nreq; i++){
  112. if(runestrcmp(req[i].name, name) == 0){
  113. if(i != --nreq){
  114. free(req[i].name);
  115. req[i] = req[nreq];
  116. }
  117. return;
  118. }
  119. }
  120. }
  121. void
  122. renreq(Rune *from, Rune *to)
  123. {
  124. int i;
  125. delreq(to);
  126. for(i=0; i<nreq; i++)
  127. if(runestrcmp(req[i].name, from) == 0){
  128. free(req[i].name);
  129. req[i].name = erunestrdup(to);
  130. return;
  131. }
  132. }
  133. void
  134. addesc(Rune r, int (*f)(void), int mode)
  135. {
  136. Esc *e;
  137. if(nesc >= nelem(esc)){
  138. fprint(2, "too many escapes\n");
  139. return;
  140. }
  141. e = &esc[nesc++];
  142. e->r = r;
  143. e->f = f;
  144. e->mode = mode;
  145. }
  146. /*
  147. * Get the next logical character in the input stream.
  148. */
  149. int
  150. getnext(void)
  151. {
  152. int i, r;
  153. next:
  154. r = getrune();
  155. if(r < 0)
  156. return -1;
  157. if(r == Uformatted){
  158. br();
  159. assert(!isoutput);
  160. while((r = getrune()) >= 0 && r != Uunformatted){
  161. if(r == Uformatted)
  162. continue;
  163. outrune(r);
  164. }
  165. goto next;
  166. }
  167. if(r == Uunformatted)
  168. goto next;
  169. if(r == backslash){
  170. r = getrune();
  171. if(r < 0)
  172. return -1;
  173. for(i=0; i<nesc; i++){
  174. if(r == esc[i].r && (inputmode&esc[i].mode)==inputmode){
  175. if(esc[i].f == e_warn)
  176. warn("ignoring %C%C", backslash, r);
  177. r = esc[i].f();
  178. if(r <= 0)
  179. goto next;
  180. return r;
  181. }
  182. }
  183. if(inputmode&(ArgMode|CopyMode)){
  184. ungetrune(r);
  185. r = backslash;
  186. }
  187. }
  188. return r;
  189. }
  190. void
  191. ungetnext(Rune r)
  192. {
  193. /*
  194. * really we want to undo the getrunes that led us here,
  195. * since the call after ungetnext might be getrune!
  196. */
  197. ungetrune(r);
  198. }
  199. int
  200. _readx(Rune *p, int n, int nmode, int line)
  201. {
  202. int c, omode;
  203. Rune *e;
  204. while((c = getrune()) == ' ' || c == '\t')
  205. ;
  206. ungetrune(c);
  207. omode = inputmode;
  208. inputmode = nmode;
  209. e = p+n-1;
  210. for(c=getnext(); p<e; c=getnext()){
  211. if(c < 0)
  212. break;
  213. if(!line && (c == ' ' || c == '\t'))
  214. break;
  215. if(c == '\n'){
  216. if(!line)
  217. ungetnext(c);
  218. break;
  219. }
  220. *p++ = c;
  221. }
  222. inputmode = omode;
  223. *p = 0;
  224. if(c < 0)
  225. return -1;
  226. return 0;
  227. }
  228. /*
  229. * Get the next argument from the current line.
  230. */
  231. Rune*
  232. copyarg(void)
  233. {
  234. static Rune buf[MaxLine];
  235. int c;
  236. Rune *r;
  237. if(_readx(buf, sizeof buf, ArgMode, 0) < 0)
  238. return nil;
  239. r = runestrstr(buf, L("\\\""));
  240. if(r){
  241. *r = 0;
  242. while((c = getrune()) >= 0 && c != '\n')
  243. ;
  244. ungetrune('\n');
  245. }
  246. r = erunestrdup(buf);
  247. return r;
  248. }
  249. /*
  250. * Read the current line in given mode. Newline not kept.
  251. * Uses different buffer from copyarg!
  252. */
  253. Rune*
  254. readline(int m)
  255. {
  256. static Rune buf[MaxLine];
  257. Rune *r;
  258. if(_readx(buf, sizeof buf, m, 1) < 0)
  259. return nil;
  260. r = erunestrdup(buf);
  261. return r;
  262. }
  263. /*
  264. * Given the argument line (already read in copy+arg mode),
  265. * parse into arguments. Note that \" has been left in place
  266. * during copy+arg mode parsing, so comments still need to be stripped.
  267. */
  268. int
  269. parseargs(Rune *p, Rune **argv)
  270. {
  271. int argc;
  272. Rune *w;
  273. for(argc=0; argc<MAXARG; argc++){
  274. while(*p == ' ' || *p == '\t')
  275. p++;
  276. if(*p == 0)
  277. break;
  278. argv[argc] = p;
  279. if(*p == '"'){
  280. /* quoted argument */
  281. if(*(p+1) == '"'){
  282. /* empty argument */
  283. *p = 0;
  284. p += 2;
  285. }else{
  286. /* parse quoted string */
  287. w = p++;
  288. for(; *p; p++){
  289. if(*p == '"' && *(p+1) == '"')
  290. *w++ = '"';
  291. else if(*p == '"'){
  292. p++;
  293. break;
  294. }else
  295. *w++ = *p;
  296. }
  297. *w = 0;
  298. }
  299. }else{
  300. /* unquoted argument - need to watch out for \" comment */
  301. for(; *p; p++){
  302. if(*p == ' ' || *p == '\t'){
  303. *p++ = 0;
  304. break;
  305. }
  306. if(*p == '\\' && *(p+1) == '"'){
  307. *p = 0;
  308. if(p != argv[argc])
  309. argc++;
  310. return argc;
  311. }
  312. }
  313. }
  314. }
  315. return argc;
  316. }
  317. /*
  318. * Process a dot line. The dot has been read.
  319. */
  320. void
  321. dotline(int dot)
  322. {
  323. int argc, i;
  324. Rune *a, *argv[1+MAXARG];
  325. /*
  326. * Read request/macro name
  327. */
  328. a = copyarg();
  329. if(a == nil || a[0] == 0){
  330. free(a);
  331. getrune(); /* \n */
  332. return;
  333. }
  334. argv[0] = a;
  335. /*
  336. * Check for .if, .ie, and others with special parsing.
  337. */
  338. for(i=0; i<nraw; i++){
  339. if(runestrcmp(raw[i].name, a) == 0){
  340. raw[i].f(raw[i].name);
  341. free(a);
  342. return;
  343. }
  344. }
  345. /*
  346. * Read rest of line in copy mode, invoke regular request.
  347. */
  348. a = readline(ArgMode);
  349. if(a == nil){
  350. free(argv[0]);
  351. return;
  352. }
  353. argc = 1+parseargs(a, argv+1);
  354. for(i=0; i<nreq; i++){
  355. if(runestrcmp(req[i].name, argv[0]) == 0){
  356. if(req[i].argc != -1){
  357. if(argc < 1+req[i].argc){
  358. warn("not enough arguments for %C%S", dot, req[i].name);
  359. free(argv[0]);
  360. free(a);
  361. return;
  362. }
  363. if(argc > 1+req[i].argc)
  364. warn("too many arguments for %C%S", dot, req[i].name);
  365. }
  366. req[i].f(argc, argv);
  367. free(argv[0]);
  368. free(a);
  369. return;
  370. }
  371. }
  372. /*
  373. * Invoke user-defined macros.
  374. */
  375. runmacro(dot, argc, argv);
  376. free(argv[0]);
  377. free(a);
  378. }
  379. /*
  380. * newlines are magical in various ways.
  381. */
  382. int bol;
  383. void
  384. newline(void)
  385. {
  386. int n;
  387. if(bol)
  388. sp(eval(L("1v")));
  389. bol = 1;
  390. if((n=getnr(L(".ce"))) > 0){
  391. nr(L(".ce"), n-1);
  392. br();
  393. }
  394. if(getnr(L(".fi")) == 0)
  395. br();
  396. outrune('\n');
  397. }
  398. void
  399. startoutput(void)
  400. {
  401. char *align;
  402. double ps, vs, lm, rm, ti;
  403. Rune buf[200];
  404. if(isoutput)
  405. return;
  406. isoutput = 1;
  407. if(getnr(L(".paragraph")) == 0)
  408. return;
  409. nr(L(".ns"), 0);
  410. isoutput = 1;
  411. ps = getnr(L(".s"));
  412. if(ps <= 1)
  413. ps = 10;
  414. ps /= 72.0;
  415. USED(ps);
  416. vs = getnr(L(".v"))*getnr(L(".ls")) * 1.0/UPI;
  417. vs /= (10.0/72.0); /* ps */
  418. if(vs == 0)
  419. vs = 1.2;
  420. lm = (getnr(L(".o"))+getnr(L(".i"))) * 1.0/UPI;
  421. ti = getnr(L(".ti")) * 1.0/UPI;
  422. nr(L(".ti"), 0);
  423. rm = 8.0 - getnr(L(".l"))*1.0/UPI - getnr(L(".o"))*1.0/UPI;
  424. if(rm < 0)
  425. rm = 0;
  426. switch(getnr(L(".j"))){
  427. default:
  428. case 0:
  429. align = "left";
  430. break;
  431. case 1:
  432. align = "justify";
  433. break;
  434. case 3:
  435. align = "center";
  436. break;
  437. case 5:
  438. align = "right";
  439. break;
  440. }
  441. if(getnr(L(".ce")))
  442. align = "center";
  443. if(!getnr(L(".margin")))
  444. runesnprint(buf, nelem(buf), "<p style=\"line-height: %.1fem; text-indent: %.2fin; margin-top: 0; margin-bottom: 0; text-align: %s;\">\n",
  445. vs, ti, align);
  446. else
  447. runesnprint(buf, nelem(buf), "<p style=\"line-height: %.1fem; margin-left: %.2fin; text-indent: %.2fin; margin-right: %.2fin; margin-top: 0; margin-bottom: 0; text-align: %s;\">\n",
  448. vs, lm, ti, rm, align);
  449. outhtml(buf);
  450. }
  451. void
  452. br(void)
  453. {
  454. if(!isoutput)
  455. return;
  456. isoutput = 0;
  457. nr(L(".dv"), 0);
  458. dv(0);
  459. hideihtml();
  460. if(getnr(L(".paragraph")))
  461. outhtml(L("</p>"));
  462. }
  463. void
  464. r_margin(int argc, Rune **argv)
  465. {
  466. USED(argc);
  467. nr(L(".margin"), eval(argv[1]));
  468. }
  469. int inrequest;
  470. void
  471. runinput(void)
  472. {
  473. int c;
  474. bol = 1;
  475. for(;;){
  476. c = getnext();
  477. if(c < 0)
  478. break;
  479. if((c == dot || c == tick) && bol){
  480. inrequest = 1;
  481. dotline(c);
  482. bol = 1;
  483. inrequest = 0;
  484. }else if(c == '\n'){
  485. newline();
  486. itrap();
  487. linepos = 0;
  488. }else{
  489. outtrap();
  490. startoutput();
  491. showihtml();
  492. if(c == '\t'){
  493. /* XXX do better */
  494. outrune(' ');
  495. while(++linepos%4)
  496. outrune(' ');
  497. }else{
  498. outrune(c);
  499. linepos++;
  500. }
  501. bol = 0;
  502. }
  503. }
  504. }
  505. void
  506. run(void)
  507. {
  508. t1init();
  509. t2init();
  510. t3init();
  511. t4init();
  512. t5init();
  513. t6init();
  514. t7init();
  515. t8init();
  516. /* t9init(); t9.c */
  517. t10init();
  518. t11init();
  519. /* t12init(); t12.c */
  520. t13init();
  521. t14init();
  522. t15init();
  523. t16init();
  524. t17init();
  525. t18init();
  526. t19init();
  527. t20init();
  528. htmlinit();
  529. hideihtml();
  530. addreq(L("margin"), r_margin, 1);
  531. nr(L(".margin"), 1);
  532. nr(L(".paragraph"), 1);
  533. runinput();
  534. while(popinput())
  535. ;
  536. dot = '.';
  537. if(verbose)
  538. fprint(2, "eof\n");
  539. runmacro1(L("eof"));
  540. closehtml();
  541. }
  542. void
  543. out(Rune *s)
  544. {
  545. if(s == nil)
  546. return;
  547. for(; *s; s++)
  548. outrune(*s);
  549. }
  550. void (*outcb)(Rune);
  551. void
  552. inroman(Rune r)
  553. {
  554. int f;
  555. f = getnr(L(".f"));
  556. nr(L(".f"), 1);
  557. runmacro1(L("font"));
  558. outrune(r);
  559. nr(L(".f"), f);
  560. runmacro1(L("font"));
  561. }
  562. void
  563. Brune(Rune r)
  564. {
  565. if(r == '&')
  566. Bprint(&bout, "&amp;");
  567. else if(r == '<')
  568. Bprint(&bout, "&lt;");
  569. else if(r == '>')
  570. Bprint(&bout, "&gt;");
  571. else if(r < Runeself || utf8)
  572. Bprint(&bout, "%C", r);
  573. else
  574. Bprint(&bout, "%S", rune2html(r));
  575. }
  576. void
  577. outhtml(Rune *s)
  578. {
  579. Rune r;
  580. for(; *s; s++){
  581. switch(r = *s){
  582. case '<':
  583. r = Ult;
  584. break;
  585. case '>':
  586. r = Ugt;
  587. break;
  588. case '&':
  589. r = Uamp;
  590. break;
  591. case ' ':
  592. r = Uspace;
  593. break;
  594. }
  595. outrune(r);
  596. }
  597. }
  598. void
  599. outrune(Rune r)
  600. {
  601. switch(r){
  602. case ' ':
  603. if(getnr(L(".fi")) == 0)
  604. r = Unbsp;
  605. break;
  606. case Uformatted:
  607. case Uunformatted:
  608. abort();
  609. }
  610. if(outcb){
  611. if(r == ' ')
  612. r = Uspace;
  613. outcb(r);
  614. return;
  615. }
  616. /* writing to bout */
  617. switch(r){
  618. case Uempty:
  619. return;
  620. case Upl:
  621. inroman('+');
  622. return;
  623. case Ueq:
  624. inroman('=');
  625. return;
  626. case Umi:
  627. inroman(0x2212);
  628. return;
  629. case Utick:
  630. r = '\'';
  631. break;
  632. case Ubtick:
  633. r = '`';
  634. break;
  635. case Uminus:
  636. r = '-';
  637. break;
  638. case '\'':
  639. Bprint(&bout, "&rsquo;");
  640. return;
  641. case '`':
  642. Bprint(&bout, "&lsquo;");
  643. return;
  644. case Uamp:
  645. Bputrune(&bout, '&');
  646. return;
  647. case Ult:
  648. Bputrune(&bout, '<');
  649. return;
  650. case Ugt:
  651. Bputrune(&bout, '>');
  652. return;
  653. case Uspace:
  654. Bputrune(&bout, ' ');
  655. return;
  656. case 0x2032:
  657. /*
  658. * In Firefox, at least, the prime is not
  659. * a superscript by default.
  660. */
  661. Bprint(&bout, "<sup>");
  662. Brune(r);
  663. Bprint(&bout, "</sup>");
  664. return;
  665. }
  666. Brune(r);
  667. }
  668. void
  669. r_nop(int argc, Rune **argv)
  670. {
  671. USED(argc);
  672. USED(argv);
  673. }
  674. void
  675. r_warn(int argc, Rune **argv)
  676. {
  677. USED(argc);
  678. warn("ignoring %C%S", dot, argv[0]);
  679. }
  680. int
  681. e_warn(void)
  682. {
  683. /* dispatch loop prints a warning for us */
  684. return 0;
  685. }
  686. int
  687. e_nop(void)
  688. {
  689. return 0;
  690. }