4 /* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
5 Written by Gaius Mulley (gaius@glam.ac.uk)
7 This file is part of groff.
9 groff is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2, or (at your option) any later
14 groff is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License along
20 with groff; see the file COPYING. If not, write to the Free Software
21 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
25 extern int debug_state
;
29 #include "stringclass.h"
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
)) {
50 fputs(i_to_a(compare
.value
), fp
);
52 value
= compare
.value
;
59 void int_value::set(int v
)
65 void int_value::unset()
70 void int_value::set_if_unknown(int 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
)) {
96 value
= compare
.value
;
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
)) {
117 fputs(i_to_a(compare
.value
), fp
);
119 value
= compare
.value
;
126 void units_value::set(hunits v
)
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
)) {
153 fputs(compare
.value
.contents(), fp
);
155 value
= compare
.value
;
160 void string_value::set(string v
)
166 void string_value::unset()
171 int string_value::differs(string_value compare
)
173 return compare
.is_known
174 && (!is_known
|| value
!= compare
.value
);
179 issue_no
= no_of_statems
;
183 statem::statem(statem
*copy
)
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
;
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
]);
226 fprintf(stderr
, "compared state %d\n", compare
->issue_no
);
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()
268 string s
= string("");
272 t
= curenv
->tabs
.distance_to_next_tab(l
, &d
);
277 s
+= as_string(l
.to_units());
281 s
+= as_string(l
.to_units());
285 s
+= as_string(l
.to_units());
290 } while (t
!= TAB_NONE
&& l
< curenv
->get_line_length());
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)
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
);
345 stack::stack(statem
*s
, stack
*n
)
361 driver
= new statem();
372 * push_state - push the current troff state and use `n' as
373 * the new troff state.
376 void mtsm::push_state(statem
*n
)
379 #if defined(DEBUGGING)
381 fprintf(stderr
, "--> state %d pushed\n", n
->issue_no
) ; fflush(stderr
);
383 sp
= new stack(n
, sp
);
387 void mtsm::pop_state()
390 #if defined(DEBUGGING)
392 fprintf(stderr
, "--> state popped\n") ; fflush(stderr
);
395 fatal("empty state machine stack");
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
) {
426 sp
->state
->bool_values
[MTSM_BR
].set(0);
427 s
->bool_values
[MTSM_BR
].set(1);
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
) {
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
)
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
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);
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]");
491 fprintf(stderr
, "[!br]");
492 if (bool_values
[MTSM_EOL
].is_known
)
493 if (bool_values
[MTSM_EOL
].value
)
494 fprintf(stderr
, "[eol]");
496 fprintf(stderr
, "[!eol]");
497 if (int_values
[MTSM_SP
].is_known
)
498 if (int_values
[MTSM_SP
].value
)
499 fprintf(stderr
, "[sp %d]", int_values
[MTSM_SP
].value
);
501 fprintf(stderr
, "[!sp]");
502 fprintf(stderr
, ">");
506 int mtsm::has_changed(int_value_state t
, statem
*s
)
508 return driver
->int_values
[t
].differs(s
->int_values
[t
]);
511 int mtsm::has_changed(units_value_state t
, statem
*s
)
513 return driver
->units_values
[t
].differs(s
->units_values
[t
]);
516 int mtsm::has_changed(bool_value_state t
, statem
*s
)
518 return driver
->bool_values
[t
].differs(s
->bool_values
[t
]);
521 int mtsm::has_changed(string_value_state t
, statem
*s
)
523 return driver
->string_values
[t
].differs(s
->string_values
[t
]);
526 int mtsm::changed(statem
*s
)
528 if (s
== 0 || !is_html
)
532 int result
= has_changed(MTSM_EOL
, s
)
533 || has_changed(MTSM_BR
, s
)
534 || has_changed(MTSM_FI
, s
)
535 || has_changed(MTSM_IN
, s
)
536 || has_changed(MTSM_LL
, s
)
537 || has_changed(MTSM_PO
, s
)
538 || has_changed(MTSM_RJ
, s
)
539 || has_changed(MTSM_SP
, s
)
540 || has_changed(MTSM_TA
, s
)
541 || has_changed(MTSM_CE
, s
);
546 void mtsm::add_tag(FILE *fp
, string s
)
550 fputs(s
.contents(), fp
);
557 state_set::state_set()
558 : boolset(0), intset(0), unitsset(0), stringset(0)
562 state_set::~state_set()
566 void state_set::incl(bool_value_state b
)
568 boolset
|= 1 << (int)b
;
571 void state_set::incl(int_value_state i
)
573 intset
|= 1 << (int)i
;
576 void state_set::incl(units_value_state u
)
578 unitsset
|= 1 << (int)u
;
581 void state_set::incl(string_value_state s
)
583 stringset
|= 1 << (int)s
;
586 void state_set::excl(bool_value_state b
)
588 boolset
&= ~(1 << (int)b
);
591 void state_set::excl(int_value_state i
)
593 intset
&= ~(1 << (int)i
);
596 void state_set::excl(units_value_state u
)
598 unitsset
&= ~(1 << (int)u
);
601 void state_set::excl(string_value_state s
)
603 stringset
&= ~(1 << (int)s
);
606 int state_set::is_in(bool_value_state b
)
608 return (boolset
& (1 << (int)b
)) != 0;
611 int state_set::is_in(int_value_state i
)
613 return (intset
& (1 << (int)i
)) != 0;
616 int state_set::is_in(units_value_state u
)
618 return (unitsset
& (1 << (int)u
) != 0);
621 int state_set::is_in(string_value_state s
)
623 return (stringset
& (1 << (int)s
) != 0);
626 void state_set::add(units_value_state
, int n
)
631 units
state_set::val(units_value_state
)