2 /* Copyright (C) 2003, 2004 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 2, or (at your option) any later
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 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. */
23 extern int debug_state
;
27 #include "stringclass.h"
31 static int no_of_statems
= 0; // debugging aid
33 int_value::int_value()
34 : value(0), is_known(0)
38 int_value::~int_value()
42 void int_value::diff(FILE *fp
, const char *s
, int_value compare
)
44 if (differs(compare
)) {
48 fputs(i_to_a(compare
.value
), fp
);
50 value
= compare
.value
;
57 void int_value::set(int v
)
63 void int_value::unset()
68 void int_value::set_if_unknown(int v
)
74 int int_value::differs(int_value compare
)
76 return compare
.is_known
77 && (!is_known
|| value
!= compare
.value
);
80 bool_value::bool_value()
84 bool_value::~bool_value()
88 void bool_value::diff(FILE *fp
, const char *s
, bool_value compare
)
90 if (differs(compare
)) {
94 value
= compare
.value
;
101 units_value::units_value()
105 units_value::~units_value()
109 void units_value::diff(FILE *fp
, const char *s
, units_value compare
)
111 if (differs(compare
)) {
115 fputs(i_to_a(compare
.value
), fp
);
117 value
= compare
.value
;
124 void units_value::set(hunits v
)
127 value
= v
.to_units();
130 int units_value::differs(units_value compare
)
132 return compare
.is_known
133 && (!is_known
|| value
!= compare
.value
);
136 string_value::string_value()
137 : value(string("")), is_known(0)
141 string_value::~string_value()
145 void string_value::diff(FILE *fp
, const char *s
, string_value compare
)
147 if (differs(compare
)) {
151 fputs(compare
.value
.contents(), fp
);
153 value
= compare
.value
;
158 void string_value::set(string v
)
164 void string_value::unset()
169 int string_value::differs(string_value compare
)
171 return compare
.is_known
172 && (!is_known
|| value
!= compare
.value
);
177 issue_no
= no_of_statems
;
181 statem::statem(statem
*copy
)
184 for (i
= 0; i
< LAST_BOOL
; i
++)
185 bool_values
[i
] = copy
->bool_values
[i
];
186 for (i
= 0; i
< LAST_INT
; i
++)
187 int_values
[i
] = copy
->int_values
[i
];
188 for (i
= 0; i
< LAST_UNITS
; i
++)
189 units_values
[i
] = copy
->units_values
[i
];
190 for (i
= 0; i
< LAST_STRING
; i
++)
191 string_values
[i
] = copy
->string_values
[i
];
192 issue_no
= copy
->issue_no
;
199 void statem::flush(FILE *fp
, statem
*compare
)
201 int_values
[MTSM_FI
].diff(fp
, "devtag:.fi",
202 compare
->int_values
[MTSM_FI
]);
203 int_values
[MTSM_RJ
].diff(fp
, "devtag:.rj",
204 compare
->int_values
[MTSM_RJ
]);
205 int_values
[MTSM_SP
].diff(fp
, "devtag:.sp",
206 compare
->int_values
[MTSM_SP
]);
207 units_values
[MTSM_IN
].diff(fp
, "devtag:.in",
208 compare
->units_values
[MTSM_IN
]);
209 units_values
[MTSM_LL
].diff(fp
, "devtag:.ll",
210 compare
->units_values
[MTSM_LL
]);
211 units_values
[MTSM_PO
].diff(fp
, "devtag:.po",
212 compare
->units_values
[MTSM_PO
]);
213 string_values
[MTSM_TA
].diff(fp
, "devtag:.ta",
214 compare
->string_values
[MTSM_TA
]);
215 units_values
[MTSM_TI
].diff(fp
, "devtag:.ti",
216 compare
->units_values
[MTSM_TI
]);
217 int_values
[MTSM_CE
].diff(fp
, "devtag:.ce",
218 compare
->int_values
[MTSM_CE
]);
219 bool_values
[MTSM_EOL
].diff(fp
, "devtag:.eol",
220 compare
->bool_values
[MTSM_EOL
]);
221 bool_values
[MTSM_BR
].diff(fp
, "devtag:.br",
222 compare
->bool_values
[MTSM_BR
]);
224 fprintf(stderr
, "compared state %d\n", compare
->issue_no
);
229 void statem::add_tag(int_value_state t
, int v
)
231 int_values
[t
].set(v
);
234 void statem::add_tag(units_value_state t
, hunits v
)
236 units_values
[t
].set(v
);
239 void statem::add_tag(bool_value_state t
)
241 bool_values
[t
].set(1);
244 void statem::add_tag(string_value_state t
, string v
)
246 string_values
[t
].set(v
);
249 void statem::add_tag_if_unknown(int_value_state t
, int v
)
251 int_values
[t
].set_if_unknown(v
);
254 void statem::sub_tag_ce()
256 int_values
[MTSM_CE
].unset();
260 * add_tag_ta - add the tab settings to the minimum troff state machine
263 void statem::add_tag_ta()
266 string s
= string("");
270 t
= curenv
->tabs
.distance_to_next_tab(l
, &d
);
275 s
+= as_string(l
.to_units());
279 s
+= as_string(l
.to_units());
283 s
+= as_string(l
.to_units());
288 } while (t
!= TAB_NONE
&& l
< curenv
->get_line_length());
290 string_values
[MTSM_TA
].set(s
);
294 void statem::update(statem
*older
, statem
*newer
, int_value_state t
)
296 if (newer
->int_values
[t
].differs(older
->int_values
[t
])
297 && !newer
->int_values
[t
].is_known
)
298 newer
->int_values
[t
].set(older
->int_values
[t
].value
);
301 void statem::update(statem
*older
, statem
*newer
, units_value_state t
)
303 if (newer
->units_values
[t
].differs(older
->units_values
[t
])
304 && !newer
->units_values
[t
].is_known
)
305 newer
->units_values
[t
].set(older
->units_values
[t
].value
);
308 void statem::update(statem
*older
, statem
*newer
, bool_value_state t
)
310 if (newer
->bool_values
[t
].differs(older
->bool_values
[t
])
311 && !newer
->bool_values
[t
].is_known
)
312 newer
->bool_values
[t
].set(older
->bool_values
[t
].value
);
315 void statem::update(statem
*older
, statem
*newer
, string_value_state t
)
317 if (newer
->string_values
[t
].differs(older
->string_values
[t
])
318 && !newer
->string_values
[t
].is_known
)
319 newer
->string_values
[t
].set(older
->string_values
[t
].value
);
322 void statem::merge(statem
*newer
, statem
*older
)
324 if (newer
== 0 || older
== 0)
326 update(older
, newer
, MTSM_EOL
);
327 update(older
, newer
, MTSM_BR
);
328 update(older
, newer
, MTSM_FI
);
329 update(older
, newer
, MTSM_LL
);
330 update(older
, newer
, MTSM_PO
);
331 update(older
, newer
, MTSM_RJ
);
332 update(older
, newer
, MTSM_SP
);
333 update(older
, newer
, MTSM_TA
);
334 update(older
, newer
, MTSM_TI
);
335 update(older
, newer
, MTSM_CE
);
343 stack::stack(statem
*s
, stack
*n
)
359 driver
= new statem();
370 * push_state - push the current troff state and use `n' as
371 * the new troff state.
374 void mtsm::push_state(statem
*n
)
377 #if defined(DEBUGGING)
379 fprintf(stderr
, "--> state %d pushed\n", n
->issue_no
) ; fflush(stderr
);
381 sp
= new stack(n
, sp
);
385 void mtsm::pop_state()
388 #if defined(DEBUGGING)
390 fprintf(stderr
, "--> state popped\n") ; fflush(stderr
);
393 fatal("empty state machine stack");
405 * inherit - scan the stack and collects inherited values.
408 void mtsm::inherit(statem
*s
, int reset_bool
)
410 if (sp
&& sp
->state
) {
411 if (s
->units_values
[MTSM_IN
].is_known
412 && sp
->state
->units_values
[MTSM_IN
].is_known
)
413 s
->units_values
[MTSM_IN
].value
+= sp
->state
->units_values
[MTSM_IN
].value
;
414 s
->update(sp
->state
, s
, MTSM_FI
);
415 s
->update(sp
->state
, s
, MTSM_LL
);
416 s
->update(sp
->state
, s
, MTSM_PO
);
417 s
->update(sp
->state
, s
, MTSM_RJ
);
418 s
->update(sp
->state
, s
, MTSM_TA
);
419 s
->update(sp
->state
, s
, MTSM_TI
);
420 s
->update(sp
->state
, s
, MTSM_CE
);
421 if (sp
->state
->bool_values
[MTSM_BR
].is_known
422 && sp
->state
->bool_values
[MTSM_BR
].value
) {
424 sp
->state
->bool_values
[MTSM_BR
].set(0);
425 s
->bool_values
[MTSM_BR
].set(1);
427 fprintf(stderr
, "inherited br from pushed state %d\n",
428 sp
->state
->issue_no
);
430 else if (s
->bool_values
[MTSM_BR
].is_known
431 && s
->bool_values
[MTSM_BR
].value
)
432 if (! s
->int_values
[MTSM_CE
].is_known
)
433 s
->bool_values
[MTSM_BR
].unset();
434 if (sp
->state
->bool_values
[MTSM_EOL
].is_known
435 && sp
->state
->bool_values
[MTSM_EOL
].value
) {
437 sp
->state
->bool_values
[MTSM_EOL
].set(0);
438 s
->bool_values
[MTSM_EOL
].set(1);
443 void mtsm::flush(FILE *fp
, statem
*s
, string tag_list
)
447 driver
->flush(fp
, s
);
448 // Set rj, ce, ti to unknown if they were known and
449 // we have seen an eol or br. This ensures that these values
450 // are emitted during the next glyph (as they step from n..0
452 if ((driver
->bool_values
[MTSM_EOL
].is_known
453 && driver
->bool_values
[MTSM_EOL
].value
)
454 || (driver
->bool_values
[MTSM_BR
].is_known
455 && driver
->bool_values
[MTSM_BR
].value
)) {
456 if (driver
->units_values
[MTSM_TI
].is_known
)
457 driver
->units_values
[MTSM_TI
].is_known
= 0;
458 if (driver
->int_values
[MTSM_RJ
].is_known
459 && driver
->int_values
[MTSM_RJ
].value
> 0)
460 driver
->int_values
[MTSM_RJ
].is_known
= 0;
461 if (driver
->int_values
[MTSM_CE
].is_known
462 && driver
->int_values
[MTSM_CE
].value
> 0)
463 driver
->int_values
[MTSM_CE
].is_known
= 0;
465 // reset the boolean values
466 driver
->bool_values
[MTSM_BR
].set(0);
467 driver
->bool_values
[MTSM_EOL
].set(0);
469 driver
->int_values
[MTSM_SP
].set(0);
470 // lastly write out any direct tag entries
471 if (tag_list
!= string("")) {
472 string t
= tag_list
+ '\0';
473 fputs(t
.contents(), fp
);
479 * display_state - dump out a synopsis of the state to stderr.
482 void statem::display_state()
484 fprintf(stderr
, " <state ");
485 if (bool_values
[MTSM_BR
].is_known
)
486 if (bool_values
[MTSM_BR
].value
)
487 fprintf(stderr
, "[br]");
489 fprintf(stderr
, "[!br]");
490 if (bool_values
[MTSM_EOL
].is_known
)
491 if (bool_values
[MTSM_EOL
].value
)
492 fprintf(stderr
, "[eol]");
494 fprintf(stderr
, "[!eol]");
495 if (int_values
[MTSM_SP
].is_known
)
496 if (int_values
[MTSM_SP
].value
)
497 fprintf(stderr
, "[sp %d]", int_values
[MTSM_SP
].value
);
499 fprintf(stderr
, "[!sp]");
500 fprintf(stderr
, ">");
504 int mtsm::has_changed(int_value_state t
, statem
*s
)
506 return driver
->int_values
[t
].differs(s
->int_values
[t
]);
509 int mtsm::has_changed(units_value_state t
, statem
*s
)
511 return driver
->units_values
[t
].differs(s
->units_values
[t
]);
514 int mtsm::has_changed(bool_value_state t
, statem
*s
)
516 return driver
->bool_values
[t
].differs(s
->bool_values
[t
]);
519 int mtsm::has_changed(string_value_state t
, statem
*s
)
521 return driver
->string_values
[t
].differs(s
->string_values
[t
]);
524 int mtsm::changed(statem
*s
)
526 if (s
== 0 || !is_html
)
530 int result
= has_changed(MTSM_EOL
, s
)
531 || has_changed(MTSM_BR
, s
)
532 || has_changed(MTSM_FI
, s
)
533 || has_changed(MTSM_IN
, s
)
534 || has_changed(MTSM_LL
, s
)
535 || has_changed(MTSM_PO
, s
)
536 || has_changed(MTSM_RJ
, s
)
537 || has_changed(MTSM_SP
, s
)
538 || has_changed(MTSM_TA
, s
)
539 || has_changed(MTSM_CE
, s
);
544 void mtsm::add_tag(FILE *fp
, string s
)
548 fputs(s
.contents(), fp
);
555 state_set::state_set()
556 : boolset(0), intset(0), unitsset(0), stringset(0)
560 state_set::~state_set()
564 void state_set::incl(bool_value_state b
)
566 boolset
|= 1 << (int)b
;
569 void state_set::incl(int_value_state i
)
571 intset
|= 1 << (int)i
;
574 void state_set::incl(units_value_state u
)
576 unitsset
|= 1 << (int)u
;
579 void state_set::incl(string_value_state s
)
581 stringset
|= 1 << (int)s
;
584 void state_set::excl(bool_value_state b
)
586 boolset
&= ~(1 << (int)b
);
589 void state_set::excl(int_value_state i
)
591 intset
&= ~(1 << (int)i
);
594 void state_set::excl(units_value_state u
)
596 unitsset
&= ~(1 << (int)u
);
599 void state_set::excl(string_value_state s
)
601 stringset
&= ~(1 << (int)s
);
604 int state_set::is_in(bool_value_state b
)
606 return (boolset
& (1 << (int)b
)) != 0;
609 int state_set::is_in(int_value_state i
)
611 return (intset
& (1 << (int)i
)) != 0;
614 int state_set::is_in(units_value_state u
)
616 return (unitsset
& (1 << (int)u
) != 0);
619 int state_set::is_in(string_value_state s
)
621 return (stringset
& (1 << (int)s
) != 0);
624 void state_set::add(units_value_state
, int n
)
629 units
state_set::val(units_value_state
)