2 /* Copyright (C) 2003, 2004, 2009 Free Software Foundation, Inc.
3 Written by Gaius Mulley (gaius@glam.ac.uk)
5 This file is part of groff.
7 groff 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 3 of the License, or
10 (at your option) any later version.
12 groff 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
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 extern int debug_state;
26 #include "stringclass.h"
30 static int no_of_statems = 0; // debugging aid
32 int_value::int_value()
33 : value(0), is_known(0)
37 int_value::~int_value()
41 void int_value::diff(FILE *fp, const char *s, int_value compare)
43 if (differs(compare)) {
47 fputs(i_to_a(compare.value), fp);
49 value = compare.value;
56 void int_value::set(int v)
62 void int_value::unset()
67 void int_value::set_if_unknown(int v)
73 int int_value::differs(int_value compare)
75 return compare.is_known
76 && (!is_known || value != compare.value);
79 bool_value::bool_value()
83 bool_value::~bool_value()
87 void bool_value::diff(FILE *fp, const char *s, bool_value compare)
89 if (differs(compare)) {
93 value = compare.value;
100 units_value::units_value()
104 units_value::~units_value()
108 void units_value::diff(FILE *fp, const char *s, units_value compare)
110 if (differs(compare)) {
114 fputs(i_to_a(compare.value), fp);
116 value = compare.value;
123 void units_value::set(hunits v)
126 value = v.to_units();
129 int units_value::differs(units_value compare)
131 return compare.is_known
132 && (!is_known || value != compare.value);
135 string_value::string_value()
136 : value(string("")), is_known(0)
140 string_value::~string_value()
144 void string_value::diff(FILE *fp, const char *s, string_value compare)
146 if (differs(compare)) {
150 fputs(compare.value.contents(), fp);
152 value = compare.value;
157 void string_value::set(string v)
163 void string_value::unset()
168 int string_value::differs(string_value compare)
170 return compare.is_known
171 && (!is_known || value != compare.value);
176 issue_no = no_of_statems;
180 statem::statem(statem *copy)
183 for (i = 0; i < LAST_BOOL; i++)
184 bool_values[i] = copy->bool_values[i];
185 for (i = 0; i < LAST_INT; i++)
186 int_values[i] = copy->int_values[i];
187 for (i = 0; i < LAST_UNITS; i++)
188 units_values[i] = copy->units_values[i];
189 for (i = 0; i < LAST_STRING; i++)
190 string_values[i] = copy->string_values[i];
191 issue_no = copy->issue_no;
198 void statem::flush(FILE *fp, statem *compare)
200 int_values[MTSM_FI].diff(fp, "devtag:.fi",
201 compare->int_values[MTSM_FI]);
202 int_values[MTSM_RJ].diff(fp, "devtag:.rj",
203 compare->int_values[MTSM_RJ]);
204 int_values[MTSM_SP].diff(fp, "devtag:.sp",
205 compare->int_values[MTSM_SP]);
206 units_values[MTSM_IN].diff(fp, "devtag:.in",
207 compare->units_values[MTSM_IN]);
208 units_values[MTSM_LL].diff(fp, "devtag:.ll",
209 compare->units_values[MTSM_LL]);
210 units_values[MTSM_PO].diff(fp, "devtag:.po",
211 compare->units_values[MTSM_PO]);
212 string_values[MTSM_TA].diff(fp, "devtag:.ta",
213 compare->string_values[MTSM_TA]);
214 units_values[MTSM_TI].diff(fp, "devtag:.ti",
215 compare->units_values[MTSM_TI]);
216 int_values[MTSM_CE].diff(fp, "devtag:.ce",
217 compare->int_values[MTSM_CE]);
218 bool_values[MTSM_EOL].diff(fp, "devtag:.eol",
219 compare->bool_values[MTSM_EOL]);
220 bool_values[MTSM_BR].diff(fp, "devtag:.br",
221 compare->bool_values[MTSM_BR]);
223 fprintf(stderr, "compared state %d\n", compare->issue_no);
228 void statem::add_tag(int_value_state t, int v)
230 int_values[t].set(v);
233 void statem::add_tag(units_value_state t, hunits v)
235 units_values[t].set(v);
238 void statem::add_tag(bool_value_state t)
240 bool_values[t].set(1);
243 void statem::add_tag(string_value_state t, string v)
245 string_values[t].set(v);
248 void statem::add_tag_if_unknown(int_value_state t, int v)
250 int_values[t].set_if_unknown(v);
253 void statem::sub_tag_ce()
255 int_values[MTSM_CE].unset();
259 * add_tag_ta - add the tab settings to the minimum troff state machine
262 void statem::add_tag_ta()
265 string s = string("");
269 t = curenv->tabs.distance_to_next_tab(l, &d);
274 s += as_string(l.to_units());
278 s += as_string(l.to_units());
282 s += as_string(l.to_units());
287 } while (t != TAB_NONE && l < curenv->get_line_length());
289 string_values[MTSM_TA].set(s);
293 void statem::update(statem *older, statem *newer, int_value_state t)
295 if (newer->int_values[t].differs(older->int_values[t])
296 && !newer->int_values[t].is_known)
297 newer->int_values[t].set(older->int_values[t].value);
300 void statem::update(statem *older, statem *newer, units_value_state t)
302 if (newer->units_values[t].differs(older->units_values[t])
303 && !newer->units_values[t].is_known)
304 newer->units_values[t].set(older->units_values[t].value);
307 void statem::update(statem *older, statem *newer, bool_value_state t)
309 if (newer->bool_values[t].differs(older->bool_values[t])
310 && !newer->bool_values[t].is_known)
311 newer->bool_values[t].set(older->bool_values[t].value);
314 void statem::update(statem *older, statem *newer, string_value_state t)
316 if (newer->string_values[t].differs(older->string_values[t])
317 && !newer->string_values[t].is_known)
318 newer->string_values[t].set(older->string_values[t].value);
321 void statem::merge(statem *newer, statem *older)
323 if (newer == 0 || older == 0)
325 update(older, newer, MTSM_EOL);
326 update(older, newer, MTSM_BR);
327 update(older, newer, MTSM_FI);
328 update(older, newer, MTSM_LL);
329 update(older, newer, MTSM_PO);
330 update(older, newer, MTSM_RJ);
331 update(older, newer, MTSM_SP);
332 update(older, newer, MTSM_TA);
333 update(older, newer, MTSM_TI);
334 update(older, newer, MTSM_CE);
342 stack::stack(statem *s, stack *n)
358 driver = new statem();
369 * push_state - push the current troff state and use `n' as
370 * the new troff state.
373 void mtsm::push_state(statem *n)
376 #if defined(DEBUGGING)
378 fprintf(stderr, "--> state %d pushed\n", n->issue_no) ; fflush(stderr);
380 sp = new stack(n, sp);
384 void mtsm::pop_state()
387 #if defined(DEBUGGING)
389 fprintf(stderr, "--> state popped\n") ; fflush(stderr);
392 fatal("empty state machine stack");
404 * inherit - scan the stack and collects inherited values.
407 void mtsm::inherit(statem *s, int reset_bool)
409 if (sp && sp->state) {
410 if (s->units_values[MTSM_IN].is_known
411 && sp->state->units_values[MTSM_IN].is_known)
412 s->units_values[MTSM_IN].value += sp->state->units_values[MTSM_IN].value;
413 s->update(sp->state, s, MTSM_FI);
414 s->update(sp->state, s, MTSM_LL);
415 s->update(sp->state, s, MTSM_PO);
416 s->update(sp->state, s, MTSM_RJ);
417 s->update(sp->state, s, MTSM_TA);
418 s->update(sp->state, s, MTSM_TI);
419 s->update(sp->state, s, MTSM_CE);
420 if (sp->state->bool_values[MTSM_BR].is_known
421 && sp->state->bool_values[MTSM_BR].value) {
423 sp->state->bool_values[MTSM_BR].set(0);
424 s->bool_values[MTSM_BR].set(1);
426 fprintf(stderr, "inherited br from pushed state %d\n",
427 sp->state->issue_no);
429 else if (s->bool_values[MTSM_BR].is_known
430 && s->bool_values[MTSM_BR].value)
431 if (! s->int_values[MTSM_CE].is_known)
432 s->bool_values[MTSM_BR].unset();
433 if (sp->state->bool_values[MTSM_EOL].is_known
434 && sp->state->bool_values[MTSM_EOL].value) {
436 sp->state->bool_values[MTSM_EOL].set(0);
437 s->bool_values[MTSM_EOL].set(1);
442 void mtsm::flush(FILE *fp, statem *s, string tag_list)
446 driver->flush(fp, s);
447 // Set rj, ce, ti to unknown if they were known and
448 // we have seen an eol or br. This ensures that these values
449 // are emitted during the next glyph (as they step from n..0
451 if ((driver->bool_values[MTSM_EOL].is_known
452 && driver->bool_values[MTSM_EOL].value)
453 || (driver->bool_values[MTSM_BR].is_known
454 && driver->bool_values[MTSM_BR].value)) {
455 if (driver->units_values[MTSM_TI].is_known)
456 driver->units_values[MTSM_TI].is_known = 0;
457 if (driver->int_values[MTSM_RJ].is_known
458 && driver->int_values[MTSM_RJ].value > 0)
459 driver->int_values[MTSM_RJ].is_known = 0;
460 if (driver->int_values[MTSM_CE].is_known
461 && driver->int_values[MTSM_CE].value > 0)
462 driver->int_values[MTSM_CE].is_known = 0;
464 // reset the boolean values
465 driver->bool_values[MTSM_BR].set(0);
466 driver->bool_values[MTSM_EOL].set(0);
468 driver->int_values[MTSM_SP].set(0);
469 // lastly write out any direct tag entries
470 if (tag_list != string("")) {
471 string t = tag_list + '\0';
472 fputs(t.contents(), fp);
478 * display_state - dump out a synopsis of the state to stderr.
481 void statem::display_state()
483 fprintf(stderr, " <state ");
484 if (bool_values[MTSM_BR].is_known)
485 if (bool_values[MTSM_BR].value)
486 fprintf(stderr, "[br]");
488 fprintf(stderr, "[!br]");
489 if (bool_values[MTSM_EOL].is_known)
490 if (bool_values[MTSM_EOL].value)
491 fprintf(stderr, "[eol]");
493 fprintf(stderr, "[!eol]");
494 if (int_values[MTSM_SP].is_known)
495 if (int_values[MTSM_SP].value)
496 fprintf(stderr, "[sp %d]", int_values[MTSM_SP].value);
498 fprintf(stderr, "[!sp]");
499 fprintf(stderr, ">");
503 int mtsm::has_changed(int_value_state t, statem *s)
505 return driver->int_values[t].differs(s->int_values[t]);
508 int mtsm::has_changed(units_value_state t, statem *s)
510 return driver->units_values[t].differs(s->units_values[t]);
513 int mtsm::has_changed(bool_value_state t, statem *s)
515 return driver->bool_values[t].differs(s->bool_values[t]);
518 int mtsm::has_changed(string_value_state t, statem *s)
520 return driver->string_values[t].differs(s->string_values[t]);
523 int mtsm::changed(statem *s)
525 if (s == 0 || !is_html)
529 int result = has_changed(MTSM_EOL, s)
530 || has_changed(MTSM_BR, s)
531 || has_changed(MTSM_FI, s)
532 || has_changed(MTSM_IN, s)
533 || has_changed(MTSM_LL, s)
534 || has_changed(MTSM_PO, s)
535 || has_changed(MTSM_RJ, s)
536 || has_changed(MTSM_SP, s)
537 || has_changed(MTSM_TA, s)
538 || has_changed(MTSM_CE, s);
543 void mtsm::add_tag(FILE *fp, string s)
547 fputs(s.contents(), fp);
554 state_set::state_set()
555 : boolset(0), intset(0), unitsset(0), stringset(0)
559 state_set::~state_set()
563 void state_set::incl(bool_value_state b)
565 boolset |= 1 << (int)b;
568 void state_set::incl(int_value_state i)
570 intset |= 1 << (int)i;
573 void state_set::incl(units_value_state u)
575 unitsset |= 1 << (int)u;
578 void state_set::incl(string_value_state s)
580 stringset |= 1 << (int)s;
583 void state_set::excl(bool_value_state b)
585 boolset &= ~(1 << (int)b);
588 void state_set::excl(int_value_state i)
590 intset &= ~(1 << (int)i);
593 void state_set::excl(units_value_state u)
595 unitsset &= ~(1 << (int)u);
598 void state_set::excl(string_value_state s)
600 stringset &= ~(1 << (int)s);
603 int state_set::is_in(bool_value_state b)
605 return (boolset & (1 << (int)b)) != 0;
608 int state_set::is_in(int_value_state i)
610 return (intset & (1 << (int)i)) != 0;
613 int state_set::is_in(units_value_state u)
615 return (unitsset & (1 << (int)u) != 0);
618 int state_set::is_in(string_value_state s)
620 return (stringset & (1 << (int)s) != 0);
623 void state_set::add(units_value_state, int n)
628 units state_set::val(units_value_state)