roff.c 11 KB

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