Sync-to-go: update copyright for 2015
[s-roff.git] / src / troff / mtsm.cpp
blob1adc61db5a5c25af7ff31dd1ed32597dd62b4e42
1 /*@
2 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
5 * Written by Gaius Mulley (gaius@glam.ac.uk)
7 * This is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2, or (at your option) any later
10 * version.
12 * This is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with groff; see the file COPYING. If not, write to the Free Software
19 * Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
21 #define DEBUGGING // FIXME ??
23 #include "config.h"
24 #include "troff-config.h"
26 #include "env.h"
27 #include "hvunits.h"
28 #include "mtsm.h"
29 #include "stringclass.h"
30 #include "troff.h"
32 extern int debug_state;
33 static int no_of_statems = 0; // debugging aid
35 int_value::int_value()
36 : value(0), is_known(0)
40 int_value::~int_value()
44 void int_value::diff(FILE *fp, const char *s, int_value compare)
46 if (differs(compare)) {
47 fputs("x X ", fp);
48 fputs(s, fp);
49 fputs(" ", fp);
50 fputs(i_to_a(compare.value), fp);
51 fputs("\n", fp);
52 value = compare.value;
53 is_known = 1;
54 if (debug_state)
55 fflush(fp);
59 void int_value::set(int v)
61 is_known = 1;
62 value = v;
65 void int_value::unset()
67 is_known = 0;
70 void int_value::set_if_unknown(int v)
72 if (!is_known)
73 set(v);
76 int int_value::differs(int_value compare)
78 return compare.is_known
79 && (!is_known || value != compare.value);
82 bool_value::bool_value()
86 bool_value::~bool_value()
90 void bool_value::diff(FILE *fp, const char *s, bool_value compare)
92 if (differs(compare)) {
93 fputs("x X ", fp);
94 fputs(s, fp);
95 fputs("\n", fp);
96 value = compare.value;
97 is_known = 1;
98 if (debug_state)
99 fflush(fp);
103 units_value::units_value()
107 units_value::~units_value()
111 void units_value::diff(FILE *fp, const char *s, units_value compare)
113 if (differs(compare)) {
114 fputs("x X ", fp);
115 fputs(s, fp);
116 fputs(" ", fp);
117 fputs(i_to_a(compare.value), fp);
118 fputs("\n", fp);
119 value = compare.value;
120 is_known = 1;
121 if (debug_state)
122 fflush(fp);
126 void units_value::set(hunits v)
128 is_known = 1;
129 value = v.to_units();
132 int units_value::differs(units_value compare)
134 return compare.is_known
135 && (!is_known || value != compare.value);
138 string_value::string_value()
139 : value(string("")), is_known(0)
143 string_value::~string_value()
147 void string_value::diff(FILE *fp, const char *s, string_value compare)
149 if (differs(compare)) {
150 fputs("x X ", fp);
151 fputs(s, fp);
152 fputs(" ", fp);
153 fputs(compare.value.contents(), fp);
154 fputs("\n", fp);
155 value = compare.value;
156 is_known = 1;
160 void string_value::set(string v)
162 is_known = 1;
163 value = v;
166 void string_value::unset()
168 is_known = 0;
171 int string_value::differs(string_value compare)
173 return compare.is_known
174 && (!is_known || value != compare.value);
177 statem::statem()
179 issue_no = no_of_statems;
180 no_of_statems++;
183 statem::statem(statem *copy)
185 int i;
186 for (i = 0; i < LAST_BOOL; i++)
187 bool_values[i] = copy->bool_values[i];
188 for (i = 0; i < LAST_INT; i++)
189 int_values[i] = copy->int_values[i];
190 for (i = 0; i < LAST_UNITS; i++)
191 units_values[i] = copy->units_values[i];
192 for (i = 0; i < LAST_STRING; i++)
193 string_values[i] = copy->string_values[i];
194 issue_no = copy->issue_no;
197 statem::~statem()
201 void statem::flush(FILE *fp, statem *compare)
203 int_values[MTSM_FI].diff(fp, "devtag:.fi",
204 compare->int_values[MTSM_FI]);
205 int_values[MTSM_RJ].diff(fp, "devtag:.rj",
206 compare->int_values[MTSM_RJ]);
207 int_values[MTSM_SP].diff(fp, "devtag:.sp",
208 compare->int_values[MTSM_SP]);
209 units_values[MTSM_IN].diff(fp, "devtag:.in",
210 compare->units_values[MTSM_IN]);
211 units_values[MTSM_LL].diff(fp, "devtag:.ll",
212 compare->units_values[MTSM_LL]);
213 units_values[MTSM_PO].diff(fp, "devtag:.po",
214 compare->units_values[MTSM_PO]);
215 string_values[MTSM_TA].diff(fp, "devtag:.ta",
216 compare->string_values[MTSM_TA]);
217 units_values[MTSM_TI].diff(fp, "devtag:.ti",
218 compare->units_values[MTSM_TI]);
219 int_values[MTSM_CE].diff(fp, "devtag:.ce",
220 compare->int_values[MTSM_CE]);
221 bool_values[MTSM_EOL].diff(fp, "devtag:.eol",
222 compare->bool_values[MTSM_EOL]);
223 bool_values[MTSM_BR].diff(fp, "devtag:.br",
224 compare->bool_values[MTSM_BR]);
225 if (debug_state) {
226 fprintf(stderr, "compared state %d\n", compare->issue_no);
227 fflush(stderr);
231 void statem::add_tag(int_value_state t, int v)
233 int_values[t].set(v);
236 void statem::add_tag(units_value_state t, hunits v)
238 units_values[t].set(v);
241 void statem::add_tag(bool_value_state t)
243 bool_values[t].set(1);
246 void statem::add_tag(string_value_state t, string v)
248 string_values[t].set(v);
251 void statem::add_tag_if_unknown(int_value_state t, int v)
253 int_values[t].set_if_unknown(v);
256 void statem::sub_tag_ce()
258 int_values[MTSM_CE].unset();
262 * add_tag_ta - add the tab settings to the minimum troff state machine
265 void statem::add_tag_ta()
267 if (is_html) {
268 string s = string("");
269 hunits d, l;
270 enum tab_type t;
271 do {
272 t = curenv->tabs.distance_to_next_tab(l, &d);
273 l += d;
274 switch (t) {
275 case TAB_LEFT:
276 s += " L ";
277 s += as_string(l.to_units());
278 break;
279 case TAB_CENTER:
280 s += " C ";
281 s += as_string(l.to_units());
282 break;
283 case TAB_RIGHT:
284 s += " R ";
285 s += as_string(l.to_units());
286 break;
287 case TAB_NONE:
288 break;
290 } while (t != TAB_NONE && l < curenv->get_line_length());
291 s += '\0';
292 string_values[MTSM_TA].set(s);
296 void statem::update(statem *older, statem *newer, int_value_state t)
298 if (newer->int_values[t].differs(older->int_values[t])
299 && !newer->int_values[t].is_known)
300 newer->int_values[t].set(older->int_values[t].value);
303 void statem::update(statem *older, statem *newer, units_value_state t)
305 if (newer->units_values[t].differs(older->units_values[t])
306 && !newer->units_values[t].is_known)
307 newer->units_values[t].set(older->units_values[t].value);
310 void statem::update(statem *older, statem *newer, bool_value_state t)
312 if (newer->bool_values[t].differs(older->bool_values[t])
313 && !newer->bool_values[t].is_known)
314 newer->bool_values[t].set(older->bool_values[t].value);
317 void statem::update(statem *older, statem *newer, string_value_state t)
319 if (newer->string_values[t].differs(older->string_values[t])
320 && !newer->string_values[t].is_known)
321 newer->string_values[t].set(older->string_values[t].value);
324 void statem::merge(statem *newer, statem *older)
326 if (newer == 0 || older == 0)
327 return;
328 update(older, newer, MTSM_EOL);
329 update(older, newer, MTSM_BR);
330 update(older, newer, MTSM_FI);
331 update(older, newer, MTSM_LL);
332 update(older, newer, MTSM_PO);
333 update(older, newer, MTSM_RJ);
334 update(older, newer, MTSM_SP);
335 update(older, newer, MTSM_TA);
336 update(older, newer, MTSM_TI);
337 update(older, newer, MTSM_CE);
340 stack::stack()
341 : next(0), state(0)
345 stack::stack(statem *s, stack *n)
346 : next(n), state(s)
350 stack::~stack()
352 if (state)
353 delete state;
354 if (next)
355 delete next;
358 mtsm::mtsm()
359 : sp(0)
361 driver = new statem();
364 mtsm::~mtsm()
366 delete driver;
367 if (sp)
368 delete sp;
372 * push_state - push the current troff state and use `n' as
373 * the new troff state.
376 void mtsm::push_state(statem *n)
378 if (is_html) {
379 #if defined(DEBUGGING)
380 if (debug_state)
381 fprintf(stderr, "--> state %d pushed\n", n->issue_no) ; fflush(stderr);
382 #endif
383 sp = new stack(n, sp);
387 void mtsm::pop_state()
389 if (is_html) {
390 #if defined(DEBUGGING)
391 if (debug_state)
392 fprintf(stderr, "--> state popped\n") ; fflush(stderr);
393 #endif
394 if (sp == 0)
395 fatal("empty state machine stack");
396 if (sp->state)
397 delete sp->state;
398 sp->state = 0;
399 stack *t = sp;
400 sp = sp->next;
401 t->next = 0;
402 delete t;
407 * inherit - scan the stack and collects inherited values.
410 void mtsm::inherit(statem *s, int reset_bool)
412 if (sp && sp->state) {
413 if (s->units_values[MTSM_IN].is_known
414 && sp->state->units_values[MTSM_IN].is_known)
415 s->units_values[MTSM_IN].value += sp->state->units_values[MTSM_IN].value;
416 s->update(sp->state, s, MTSM_FI);
417 s->update(sp->state, s, MTSM_LL);
418 s->update(sp->state, s, MTSM_PO);
419 s->update(sp->state, s, MTSM_RJ);
420 s->update(sp->state, s, MTSM_TA);
421 s->update(sp->state, s, MTSM_TI);
422 s->update(sp->state, s, MTSM_CE);
423 if (sp->state->bool_values[MTSM_BR].is_known
424 && sp->state->bool_values[MTSM_BR].value) {
425 if (reset_bool)
426 sp->state->bool_values[MTSM_BR].set(0);
427 s->bool_values[MTSM_BR].set(1);
428 if (debug_state)
429 fprintf(stderr, "inherited br from pushed state %d\n",
430 sp->state->issue_no);
432 else if (s->bool_values[MTSM_BR].is_known
433 && s->bool_values[MTSM_BR].value)
434 if (! s->int_values[MTSM_CE].is_known)
435 s->bool_values[MTSM_BR].unset();
436 if (sp->state->bool_values[MTSM_EOL].is_known
437 && sp->state->bool_values[MTSM_EOL].value) {
438 if (reset_bool)
439 sp->state->bool_values[MTSM_EOL].set(0);
440 s->bool_values[MTSM_EOL].set(1);
445 void mtsm::flush(FILE *fp, statem *s, string tag_list)
447 if (is_html && s) {
448 inherit(s, 1);
449 driver->flush(fp, s);
450 // Set rj, ce, ti to unknown if they were known and
451 // we have seen an eol or br. This ensures that these values
452 // are emitted during the next glyph (as they step from n..0
453 // at each newline).
454 if ((driver->bool_values[MTSM_EOL].is_known
455 && driver->bool_values[MTSM_EOL].value)
456 || (driver->bool_values[MTSM_BR].is_known
457 && driver->bool_values[MTSM_BR].value)) {
458 if (driver->units_values[MTSM_TI].is_known)
459 driver->units_values[MTSM_TI].is_known = 0;
460 if (driver->int_values[MTSM_RJ].is_known
461 && driver->int_values[MTSM_RJ].value > 0)
462 driver->int_values[MTSM_RJ].is_known = 0;
463 if (driver->int_values[MTSM_CE].is_known
464 && driver->int_values[MTSM_CE].value > 0)
465 driver->int_values[MTSM_CE].is_known = 0;
467 // reset the boolean values
468 driver->bool_values[MTSM_BR].set(0);
469 driver->bool_values[MTSM_EOL].set(0);
470 // reset space value
471 driver->int_values[MTSM_SP].set(0);
472 // lastly write out any direct tag entries
473 if (tag_list != string("")) {
474 string t = tag_list + '\0';
475 fputs(t.contents(), fp);
481 * display_state - dump out a synopsis of the state to stderr.
484 void statem::display_state()
486 fprintf(stderr, " <state ");
487 if (bool_values[MTSM_BR].is_known) {
488 if (bool_values[MTSM_BR].value)
489 fprintf(stderr, "[br]");
490 else
491 fprintf(stderr, "[!br]");
493 if (bool_values[MTSM_EOL].is_known) {
494 if (bool_values[MTSM_EOL].value)
495 fprintf(stderr, "[eol]");
496 else
497 fprintf(stderr, "[!eol]");
499 if (int_values[MTSM_SP].is_known) {
500 if (int_values[MTSM_SP].value)
501 fprintf(stderr, "[sp %d]", int_values[MTSM_SP].value);
502 else
503 fprintf(stderr, "[!sp]");
505 fprintf(stderr, ">");
506 fflush(stderr);
509 int mtsm::has_changed(int_value_state t, statem *s)
511 return driver->int_values[t].differs(s->int_values[t]);
514 int mtsm::has_changed(units_value_state t, statem *s)
516 return driver->units_values[t].differs(s->units_values[t]);
519 int mtsm::has_changed(bool_value_state t, statem *s)
521 return driver->bool_values[t].differs(s->bool_values[t]);
524 int mtsm::has_changed(string_value_state t, statem *s)
526 return driver->string_values[t].differs(s->string_values[t]);
529 int mtsm::changed(statem *s)
531 if (s == 0 || !is_html)
532 return 0;
533 s = new statem(s);
534 inherit(s, 0);
535 int result = has_changed(MTSM_EOL, s)
536 || has_changed(MTSM_BR, s)
537 || has_changed(MTSM_FI, s)
538 || has_changed(MTSM_IN, s)
539 || has_changed(MTSM_LL, s)
540 || has_changed(MTSM_PO, s)
541 || has_changed(MTSM_RJ, s)
542 || has_changed(MTSM_SP, s)
543 || has_changed(MTSM_TA, s)
544 || has_changed(MTSM_CE, s);
545 delete s;
546 return result;
549 void mtsm::add_tag(FILE *fp, string s)
551 fflush(fp);
552 s += '\0';
553 fputs(s.contents(), fp);
557 * state_set class
560 state_set::state_set()
561 : boolset(0), intset(0), unitsset(0), stringset(0)
565 state_set::~state_set()
569 void state_set::incl(bool_value_state b)
571 boolset |= 1 << (int)b;
574 void state_set::incl(int_value_state i)
576 intset |= 1 << (int)i;
579 void state_set::incl(units_value_state u)
581 unitsset |= 1 << (int)u;
584 void state_set::incl(string_value_state s)
586 stringset |= 1 << (int)s;
589 void state_set::excl(bool_value_state b)
591 boolset &= ~(1 << (int)b);
594 void state_set::excl(int_value_state i)
596 intset &= ~(1 << (int)i);
599 void state_set::excl(units_value_state u)
601 unitsset &= ~(1 << (int)u);
604 void state_set::excl(string_value_state s)
606 stringset &= ~(1 << (int)s);
609 int state_set::is_in(bool_value_state b)
611 return (boolset & (1 << (int)b)) != 0;
614 int state_set::is_in(int_value_state i)
616 return (intset & (1 << (int)i)) != 0;
619 int state_set::is_in(units_value_state u)
621 return ((unitsset & (1 << (int)u)) != 0);
624 int state_set::is_in(string_value_state s)
626 return ((stringset & (1 << (int)s)) != 0);
629 void state_set::add(units_value_state, int n)
631 unitsset += n;
634 units state_set::val(units_value_state)
636 return unitsset;
639 // s-it2-mode