/contrib/groff/src/roff/troff/mtsm.cpp

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 634 lines · 512 code · 78 blank · 44 comment · 99 complexity · 7ca2cee6a3dedac4a9cb024f59cfaa1f MD5 · raw file

  1. // -*- C++ -*-
  2. /* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
  3. Written by Gaius Mulley (gaius@glam.ac.uk)
  4. This file is part of groff.
  5. groff is free software; you can redistribute it and/or modify it under
  6. the terms of the GNU General Public License as published by the Free
  7. Software Foundation; either version 2, or (at your option) any later
  8. version.
  9. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. for more details.
  13. You should have received a copy of the GNU General Public License along
  14. with groff; see the file COPYING. If not, write to the Free Software
  15. Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
  16. #define DEBUGGING
  17. extern int debug_state;
  18. #include "troff.h"
  19. #include "hvunits.h"
  20. #include "stringclass.h"
  21. #include "mtsm.h"
  22. #include "env.h"
  23. static int no_of_statems = 0; // debugging aid
  24. int_value::int_value()
  25. : value(0), is_known(0)
  26. {
  27. }
  28. int_value::~int_value()
  29. {
  30. }
  31. void int_value::diff(FILE *fp, const char *s, int_value compare)
  32. {
  33. if (differs(compare)) {
  34. fputs("x X ", fp);
  35. fputs(s, fp);
  36. fputs(" ", fp);
  37. fputs(i_to_a(compare.value), fp);
  38. fputs("\n", fp);
  39. value = compare.value;
  40. is_known = 1;
  41. if (debug_state)
  42. fflush(fp);
  43. }
  44. }
  45. void int_value::set(int v)
  46. {
  47. is_known = 1;
  48. value = v;
  49. }
  50. void int_value::unset()
  51. {
  52. is_known = 0;
  53. }
  54. void int_value::set_if_unknown(int v)
  55. {
  56. if (!is_known)
  57. set(v);
  58. }
  59. int int_value::differs(int_value compare)
  60. {
  61. return compare.is_known
  62. && (!is_known || value != compare.value);
  63. }
  64. bool_value::bool_value()
  65. {
  66. }
  67. bool_value::~bool_value()
  68. {
  69. }
  70. void bool_value::diff(FILE *fp, const char *s, bool_value compare)
  71. {
  72. if (differs(compare)) {
  73. fputs("x X ", fp);
  74. fputs(s, fp);
  75. fputs("\n", fp);
  76. value = compare.value;
  77. is_known = 1;
  78. if (debug_state)
  79. fflush(fp);
  80. }
  81. }
  82. units_value::units_value()
  83. {
  84. }
  85. units_value::~units_value()
  86. {
  87. }
  88. void units_value::diff(FILE *fp, const char *s, units_value compare)
  89. {
  90. if (differs(compare)) {
  91. fputs("x X ", fp);
  92. fputs(s, fp);
  93. fputs(" ", fp);
  94. fputs(i_to_a(compare.value), fp);
  95. fputs("\n", fp);
  96. value = compare.value;
  97. is_known = 1;
  98. if (debug_state)
  99. fflush(fp);
  100. }
  101. }
  102. void units_value::set(hunits v)
  103. {
  104. is_known = 1;
  105. value = v.to_units();
  106. }
  107. int units_value::differs(units_value compare)
  108. {
  109. return compare.is_known
  110. && (!is_known || value != compare.value);
  111. }
  112. string_value::string_value()
  113. : value(string("")), is_known(0)
  114. {
  115. }
  116. string_value::~string_value()
  117. {
  118. }
  119. void string_value::diff(FILE *fp, const char *s, string_value compare)
  120. {
  121. if (differs(compare)) {
  122. fputs("x X ", fp);
  123. fputs(s, fp);
  124. fputs(" ", fp);
  125. fputs(compare.value.contents(), fp);
  126. fputs("\n", fp);
  127. value = compare.value;
  128. is_known = 1;
  129. }
  130. }
  131. void string_value::set(string v)
  132. {
  133. is_known = 1;
  134. value = v;
  135. }
  136. void string_value::unset()
  137. {
  138. is_known = 0;
  139. }
  140. int string_value::differs(string_value compare)
  141. {
  142. return compare.is_known
  143. && (!is_known || value != compare.value);
  144. }
  145. statem::statem()
  146. {
  147. issue_no = no_of_statems;
  148. no_of_statems++;
  149. }
  150. statem::statem(statem *copy)
  151. {
  152. int i;
  153. for (i = 0; i < LAST_BOOL; i++)
  154. bool_values[i] = copy->bool_values[i];
  155. for (i = 0; i < LAST_INT; i++)
  156. int_values[i] = copy->int_values[i];
  157. for (i = 0; i < LAST_UNITS; i++)
  158. units_values[i] = copy->units_values[i];
  159. for (i = 0; i < LAST_STRING; i++)
  160. string_values[i] = copy->string_values[i];
  161. issue_no = copy->issue_no;
  162. }
  163. statem::~statem()
  164. {
  165. }
  166. void statem::flush(FILE *fp, statem *compare)
  167. {
  168. int_values[MTSM_FI].diff(fp, "devtag:.fi",
  169. compare->int_values[MTSM_FI]);
  170. int_values[MTSM_RJ].diff(fp, "devtag:.rj",
  171. compare->int_values[MTSM_RJ]);
  172. int_values[MTSM_SP].diff(fp, "devtag:.sp",
  173. compare->int_values[MTSM_SP]);
  174. units_values[MTSM_IN].diff(fp, "devtag:.in",
  175. compare->units_values[MTSM_IN]);
  176. units_values[MTSM_LL].diff(fp, "devtag:.ll",
  177. compare->units_values[MTSM_LL]);
  178. units_values[MTSM_PO].diff(fp, "devtag:.po",
  179. compare->units_values[MTSM_PO]);
  180. string_values[MTSM_TA].diff(fp, "devtag:.ta",
  181. compare->string_values[MTSM_TA]);
  182. units_values[MTSM_TI].diff(fp, "devtag:.ti",
  183. compare->units_values[MTSM_TI]);
  184. int_values[MTSM_CE].diff(fp, "devtag:.ce",
  185. compare->int_values[MTSM_CE]);
  186. bool_values[MTSM_EOL].diff(fp, "devtag:.eol",
  187. compare->bool_values[MTSM_EOL]);
  188. bool_values[MTSM_BR].diff(fp, "devtag:.br",
  189. compare->bool_values[MTSM_BR]);
  190. if (debug_state) {
  191. fprintf(stderr, "compared state %d\n", compare->issue_no);
  192. fflush(stderr);
  193. }
  194. }
  195. void statem::add_tag(int_value_state t, int v)
  196. {
  197. int_values[t].set(v);
  198. }
  199. void statem::add_tag(units_value_state t, hunits v)
  200. {
  201. units_values[t].set(v);
  202. }
  203. void statem::add_tag(bool_value_state t)
  204. {
  205. bool_values[t].set(1);
  206. }
  207. void statem::add_tag(string_value_state t, string v)
  208. {
  209. string_values[t].set(v);
  210. }
  211. void statem::add_tag_if_unknown(int_value_state t, int v)
  212. {
  213. int_values[t].set_if_unknown(v);
  214. }
  215. void statem::sub_tag_ce()
  216. {
  217. int_values[MTSM_CE].unset();
  218. }
  219. /*
  220. * add_tag_ta - add the tab settings to the minimum troff state machine
  221. */
  222. void statem::add_tag_ta()
  223. {
  224. if (is_html) {
  225. string s = string("");
  226. hunits d, l;
  227. enum tab_type t;
  228. do {
  229. t = curenv->tabs.distance_to_next_tab(l, &d);
  230. l += d;
  231. switch (t) {
  232. case TAB_LEFT:
  233. s += " L ";
  234. s += as_string(l.to_units());
  235. break;
  236. case TAB_CENTER:
  237. s += " C ";
  238. s += as_string(l.to_units());
  239. break;
  240. case TAB_RIGHT:
  241. s += " R ";
  242. s += as_string(l.to_units());
  243. break;
  244. case TAB_NONE:
  245. break;
  246. }
  247. } while (t != TAB_NONE && l < curenv->get_line_length());
  248. s += '\0';
  249. string_values[MTSM_TA].set(s);
  250. }
  251. }
  252. void statem::update(statem *older, statem *newer, int_value_state t)
  253. {
  254. if (newer->int_values[t].differs(older->int_values[t])
  255. && !newer->int_values[t].is_known)
  256. newer->int_values[t].set(older->int_values[t].value);
  257. }
  258. void statem::update(statem *older, statem *newer, units_value_state t)
  259. {
  260. if (newer->units_values[t].differs(older->units_values[t])
  261. && !newer->units_values[t].is_known)
  262. newer->units_values[t].set(older->units_values[t].value);
  263. }
  264. void statem::update(statem *older, statem *newer, bool_value_state t)
  265. {
  266. if (newer->bool_values[t].differs(older->bool_values[t])
  267. && !newer->bool_values[t].is_known)
  268. newer->bool_values[t].set(older->bool_values[t].value);
  269. }
  270. void statem::update(statem *older, statem *newer, string_value_state t)
  271. {
  272. if (newer->string_values[t].differs(older->string_values[t])
  273. && !newer->string_values[t].is_known)
  274. newer->string_values[t].set(older->string_values[t].value);
  275. }
  276. void statem::merge(statem *newer, statem *older)
  277. {
  278. if (newer == 0 || older == 0)
  279. return;
  280. update(older, newer, MTSM_EOL);
  281. update(older, newer, MTSM_BR);
  282. update(older, newer, MTSM_FI);
  283. update(older, newer, MTSM_LL);
  284. update(older, newer, MTSM_PO);
  285. update(older, newer, MTSM_RJ);
  286. update(older, newer, MTSM_SP);
  287. update(older, newer, MTSM_TA);
  288. update(older, newer, MTSM_TI);
  289. update(older, newer, MTSM_CE);
  290. }
  291. stack::stack()
  292. : next(0), state(0)
  293. {
  294. }
  295. stack::stack(statem *s, stack *n)
  296. : next(n), state(s)
  297. {
  298. }
  299. stack::~stack()
  300. {
  301. if (state)
  302. delete state;
  303. if (next)
  304. delete next;
  305. }
  306. mtsm::mtsm()
  307. : sp(0)
  308. {
  309. driver = new statem();
  310. }
  311. mtsm::~mtsm()
  312. {
  313. delete driver;
  314. if (sp)
  315. delete sp;
  316. }
  317. /*
  318. * push_state - push the current troff state and use `n' as
  319. * the new troff state.
  320. */
  321. void mtsm::push_state(statem *n)
  322. {
  323. if (is_html) {
  324. #if defined(DEBUGGING)
  325. if (debug_state)
  326. fprintf(stderr, "--> state %d pushed\n", n->issue_no) ; fflush(stderr);
  327. #endif
  328. sp = new stack(n, sp);
  329. }
  330. }
  331. void mtsm::pop_state()
  332. {
  333. if (is_html) {
  334. #if defined(DEBUGGING)
  335. if (debug_state)
  336. fprintf(stderr, "--> state popped\n") ; fflush(stderr);
  337. #endif
  338. if (sp == 0)
  339. fatal("empty state machine stack");
  340. if (sp->state)
  341. delete sp->state;
  342. sp->state = 0;
  343. stack *t = sp;
  344. sp = sp->next;
  345. t->next = 0;
  346. delete t;
  347. }
  348. }
  349. /*
  350. * inherit - scan the stack and collects inherited values.
  351. */
  352. void mtsm::inherit(statem *s, int reset_bool)
  353. {
  354. if (sp && sp->state) {
  355. if (s->units_values[MTSM_IN].is_known
  356. && sp->state->units_values[MTSM_IN].is_known)
  357. s->units_values[MTSM_IN].value += sp->state->units_values[MTSM_IN].value;
  358. s->update(sp->state, s, MTSM_FI);
  359. s->update(sp->state, s, MTSM_LL);
  360. s->update(sp->state, s, MTSM_PO);
  361. s->update(sp->state, s, MTSM_RJ);
  362. s->update(sp->state, s, MTSM_TA);
  363. s->update(sp->state, s, MTSM_TI);
  364. s->update(sp->state, s, MTSM_CE);
  365. if (sp->state->bool_values[MTSM_BR].is_known
  366. && sp->state->bool_values[MTSM_BR].value) {
  367. if (reset_bool)
  368. sp->state->bool_values[MTSM_BR].set(0);
  369. s->bool_values[MTSM_BR].set(1);
  370. if (debug_state)
  371. fprintf(stderr, "inherited br from pushed state %d\n",
  372. sp->state->issue_no);
  373. }
  374. else if (s->bool_values[MTSM_BR].is_known
  375. && s->bool_values[MTSM_BR].value)
  376. if (! s->int_values[MTSM_CE].is_known)
  377. s->bool_values[MTSM_BR].unset();
  378. if (sp->state->bool_values[MTSM_EOL].is_known
  379. && sp->state->bool_values[MTSM_EOL].value) {
  380. if (reset_bool)
  381. sp->state->bool_values[MTSM_EOL].set(0);
  382. s->bool_values[MTSM_EOL].set(1);
  383. }
  384. }
  385. }
  386. void mtsm::flush(FILE *fp, statem *s, string tag_list)
  387. {
  388. if (is_html && s) {
  389. inherit(s, 1);
  390. driver->flush(fp, s);
  391. // Set rj, ce, ti to unknown if they were known and
  392. // we have seen an eol or br. This ensures that these values
  393. // are emitted during the next glyph (as they step from n..0
  394. // at each newline).
  395. if ((driver->bool_values[MTSM_EOL].is_known
  396. && driver->bool_values[MTSM_EOL].value)
  397. || (driver->bool_values[MTSM_BR].is_known
  398. && driver->bool_values[MTSM_BR].value)) {
  399. if (driver->units_values[MTSM_TI].is_known)
  400. driver->units_values[MTSM_TI].is_known = 0;
  401. if (driver->int_values[MTSM_RJ].is_known
  402. && driver->int_values[MTSM_RJ].value > 0)
  403. driver->int_values[MTSM_RJ].is_known = 0;
  404. if (driver->int_values[MTSM_CE].is_known
  405. && driver->int_values[MTSM_CE].value > 0)
  406. driver->int_values[MTSM_CE].is_known = 0;
  407. }
  408. // reset the boolean values
  409. driver->bool_values[MTSM_BR].set(0);
  410. driver->bool_values[MTSM_EOL].set(0);
  411. // reset space value
  412. driver->int_values[MTSM_SP].set(0);
  413. // lastly write out any direct tag entries
  414. if (tag_list != string("")) {
  415. string t = tag_list + '\0';
  416. fputs(t.contents(), fp);
  417. }
  418. }
  419. }
  420. /*
  421. * display_state - dump out a synopsis of the state to stderr.
  422. */
  423. void statem::display_state()
  424. {
  425. fprintf(stderr, " <state ");
  426. if (bool_values[MTSM_BR].is_known)
  427. if (bool_values[MTSM_BR].value)
  428. fprintf(stderr, "[br]");
  429. else
  430. fprintf(stderr, "[!br]");
  431. if (bool_values[MTSM_EOL].is_known)
  432. if (bool_values[MTSM_EOL].value)
  433. fprintf(stderr, "[eol]");
  434. else
  435. fprintf(stderr, "[!eol]");
  436. if (int_values[MTSM_SP].is_known)
  437. if (int_values[MTSM_SP].value)
  438. fprintf(stderr, "[sp %d]", int_values[MTSM_SP].value);
  439. else
  440. fprintf(stderr, "[!sp]");
  441. fprintf(stderr, ">");
  442. fflush(stderr);
  443. }
  444. int mtsm::has_changed(int_value_state t, statem *s)
  445. {
  446. return driver->int_values[t].differs(s->int_values[t]);
  447. }
  448. int mtsm::has_changed(units_value_state t, statem *s)
  449. {
  450. return driver->units_values[t].differs(s->units_values[t]);
  451. }
  452. int mtsm::has_changed(bool_value_state t, statem *s)
  453. {
  454. return driver->bool_values[t].differs(s->bool_values[t]);
  455. }
  456. int mtsm::has_changed(string_value_state t, statem *s)
  457. {
  458. return driver->string_values[t].differs(s->string_values[t]);
  459. }
  460. int mtsm::changed(statem *s)
  461. {
  462. if (s == 0 || !is_html)
  463. return 0;
  464. s = new statem(s);
  465. inherit(s, 0);
  466. int result = has_changed(MTSM_EOL, s)
  467. || has_changed(MTSM_BR, s)
  468. || has_changed(MTSM_FI, s)
  469. || has_changed(MTSM_IN, s)
  470. || has_changed(MTSM_LL, s)
  471. || has_changed(MTSM_PO, s)
  472. || has_changed(MTSM_RJ, s)
  473. || has_changed(MTSM_SP, s)
  474. || has_changed(MTSM_TA, s)
  475. || has_changed(MTSM_CE, s);
  476. delete s;
  477. return result;
  478. }
  479. void mtsm::add_tag(FILE *fp, string s)
  480. {
  481. fflush(fp);
  482. s += '\0';
  483. fputs(s.contents(), fp);
  484. }
  485. /*
  486. * state_set class
  487. */
  488. state_set::state_set()
  489. : boolset(0), intset(0), unitsset(0), stringset(0)
  490. {
  491. }
  492. state_set::~state_set()
  493. {
  494. }
  495. void state_set::incl(bool_value_state b)
  496. {
  497. boolset |= 1 << (int)b;
  498. }
  499. void state_set::incl(int_value_state i)
  500. {
  501. intset |= 1 << (int)i;
  502. }
  503. void state_set::incl(units_value_state u)
  504. {
  505. unitsset |= 1 << (int)u;
  506. }
  507. void state_set::incl(string_value_state s)
  508. {
  509. stringset |= 1 << (int)s;
  510. }
  511. void state_set::excl(bool_value_state b)
  512. {
  513. boolset &= ~(1 << (int)b);
  514. }
  515. void state_set::excl(int_value_state i)
  516. {
  517. intset &= ~(1 << (int)i);
  518. }
  519. void state_set::excl(units_value_state u)
  520. {
  521. unitsset &= ~(1 << (int)u);
  522. }
  523. void state_set::excl(string_value_state s)
  524. {
  525. stringset &= ~(1 << (int)s);
  526. }
  527. int state_set::is_in(bool_value_state b)
  528. {
  529. return (boolset & (1 << (int)b)) != 0;
  530. }
  531. int state_set::is_in(int_value_state i)
  532. {
  533. return (intset & (1 << (int)i)) != 0;
  534. }
  535. // Note: this used to have a bug s.t. it always tested for bit 0 (benl 18/5/11)
  536. int state_set::is_in(units_value_state u)
  537. {
  538. return (unitsset & (1 << (int)u)) != 0;
  539. }
  540. // Note: this used to have a bug s.t. it always tested for bit 0 (benl 18/5/11)
  541. int state_set::is_in(string_value_state s)
  542. {
  543. return (stringset & (1 << (int)s)) != 0;
  544. }
  545. void state_set::add(units_value_state, int n)
  546. {
  547. unitsset += n;
  548. }
  549. units state_set::val(units_value_state)
  550. {
  551. return unitsset;
  552. }