1// -*- C++ -*-
2/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004
3   Free Software Foundation, Inc.
4     Written by James Clark (jjc@jclark.com)
5
6This file is part of groff.
7
8groff is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13groff is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License along
19with groff; see the file COPYING.  If not, write to the Free Software
20Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
21
22struct hyphen_list {
23  unsigned char hyphen;
24  unsigned char breakable;
25  unsigned char hyphenation_code;
26  hyphen_list *next;
27  hyphen_list(unsigned char code, hyphen_list *p = 0);
28};
29
30void hyphenate(hyphen_list *, unsigned);
31
32enum hyphenation_type { HYPHEN_MIDDLE, HYPHEN_BOUNDARY, HYPHEN_INHIBIT };
33
34class ascii_output_file;
35
36struct breakpoint;
37struct vertical_size;
38class charinfo;
39
40class macro;
41
42class troff_output_file;
43class tfont;
44class environment;
45
46class glyph_node;
47class diverted_space_node;
48class token_node;
49
50struct node {
51  node *next;
52  node *last;
53  statem *state;
54  statem *push_state;
55  int div_nest_level;
56  int is_special;
57  node();
58  node(node *);
59  node(node *, statem *, int);
60  node *add_char(charinfo *, environment *, hunits *, int *, node ** = 0);
61
62  virtual ~node();
63  virtual node *copy() = 0;
64  virtual int set_unformat_flag();
65  virtual int force_tprint() = 0;
66  virtual int is_tag() = 0;
67  virtual hunits width();
68  virtual hunits subscript_correction();
69  virtual hunits italic_correction();
70  virtual hunits left_italic_correction();
71  virtual hunits skew();
72  virtual int nspaces();
73  virtual int merge_space(hunits, hunits, hunits);
74  virtual vunits vertical_width();
75  virtual node *last_char_node();
76  virtual void vertical_extent(vunits *, vunits *);
77  virtual int character_type();
78  virtual void set_vertical_size(vertical_size *);
79  virtual int ends_sentence();
80  virtual node *merge_self(node *);
81  virtual node *add_discretionary_hyphen();
82  virtual node *add_self(node *, hyphen_list **);
83  virtual hyphen_list *get_hyphen_list(hyphen_list *, int *);
84  virtual void ascii_print(ascii_output_file *);
85  virtual void asciify(macro *);
86  virtual int discardable();
87  virtual void spread_space(int *, hunits *);
88  virtual void freeze_space();
89  virtual void is_escape_colon();
90  virtual breakpoint *get_breakpoints(hunits, int, breakpoint * = 0, int = 0);
91  virtual int nbreaks();
92  virtual void split(int, node **, node **);
93  virtual hyphenation_type get_hyphenation_type();
94  virtual int reread(int *);
95  virtual token_node *get_token_node();
96  virtual int overlaps_vertically();
97  virtual int overlaps_horizontally();
98  virtual units size();
99  virtual int interpret(macro *);
100
101  virtual node *merge_glyph_node(glyph_node *);
102  virtual tfont *get_tfont();
103  virtual color *get_glyph_color();
104  virtual color *get_fill_color();
105  virtual void tprint(troff_output_file *);
106  virtual void zero_width_tprint(troff_output_file *);
107
108  node *add_italic_correction(hunits *);
109
110  virtual int same(node *) = 0;
111  virtual const char *type() = 0;
112  virtual void debug_node();
113  virtual void debug_node_list();
114};
115
116inline node::node()
117: next(0), last(0), state(0), push_state(0), div_nest_level(0), is_special(0)
118{
119}
120
121inline node::node(node *n)
122: next(n), last(0), state(0), push_state(0), div_nest_level(0), is_special(0)
123{
124}
125
126inline node::node(node *n, statem *s, int divlevel)
127: next(n), last(0), push_state(0), div_nest_level(divlevel), is_special(0)
128{
129  if (s)
130    state = new statem(s);
131  else
132    state = 0;
133}
134
135inline node::~node()
136{
137}
138
139// 0 means it doesn't, 1 means it does, 2 means it's transparent
140
141int node_list_ends_sentence(node *);
142
143struct breakpoint {
144  breakpoint *next;
145  hunits width;
146  int nspaces;
147  node *nd;
148  int index;
149  char hyphenated;
150};
151
152class line_start_node : public node {
153public:
154  line_start_node() {}
155  node *copy() { return new line_start_node; }
156  int same(node *);
157  int force_tprint();
158  int is_tag();
159  const char *type();
160  void asciify(macro *);
161};
162
163class space_node : public node {
164private:
165#if 0
166  enum { BLOCK = 1024 };
167  static space_node *free_list;
168  void operator delete(void *);
169#endif
170protected:
171  hunits n;
172  char set;
173  char was_escape_colon;
174  color *col;			/* for grotty */
175  space_node(hunits, int, int, color *, statem *, int, node * = 0);
176public:
177  space_node(hunits, color *, statem *, int, node * = 0);
178  space_node(hunits, color *, node * = 0);
179#if 0
180  ~space_node();
181  void *operator new(size_t);
182#endif
183  node *copy();
184  int nspaces();
185  hunits width();
186  int discardable();
187  int merge_space(hunits, hunits, hunits);
188  void freeze_space();
189  void is_escape_colon();
190  void spread_space(int *, hunits *);
191  void tprint(troff_output_file *);
192  breakpoint *get_breakpoints(hunits, int, breakpoint * = 0, int = 0);
193  int nbreaks();
194  void split(int, node **, node **);
195  void ascii_print(ascii_output_file *);
196  int same(node *);
197  void asciify(macro *);
198  const char *type();
199  int force_tprint();
200  int is_tag();
201  hyphenation_type get_hyphenation_type();
202};
203
204struct width_list {
205  hunits width;
206  hunits sentence_width;
207  width_list *next;
208  width_list(hunits, hunits);
209  width_list(width_list *);
210};
211
212class word_space_node : public space_node {
213protected:
214  width_list *orig_width;
215  unsigned char unformat;
216  word_space_node(hunits, int, color *, width_list *, int, statem *, int,
217		  node * = 0);
218public:
219  word_space_node(hunits, color *, width_list *, node * = 0);
220  ~word_space_node();
221  node *copy();
222  int reread(int *);
223  int set_unformat_flag();
224  void tprint(troff_output_file *);
225  int same(node *);
226  void asciify(macro *);
227  const char *type();
228  int merge_space(hunits, hunits, hunits);
229  int force_tprint();
230  int is_tag();
231};
232
233class unbreakable_space_node : public word_space_node {
234  unbreakable_space_node(hunits, int, color *, statem *, int, node * = 0);
235public:
236  unbreakable_space_node(hunits, color *, node * = 0);
237  node *copy();
238  int reread(int *);
239  void tprint(troff_output_file *);
240  int same(node *);
241  void asciify(macro *);
242  const char *type();
243  int force_tprint();
244  int is_tag();
245  breakpoint *get_breakpoints(hunits, int, breakpoint * = 0, int = 0);
246  int nbreaks();
247  void split(int, node **, node **);
248  int merge_space(hunits, hunits, hunits);
249  node *add_self(node *, hyphen_list **);
250  hyphen_list *get_hyphen_list(hyphen_list *, int *);
251  hyphenation_type get_hyphenation_type();
252};
253
254class diverted_space_node : public node {
255public:
256  vunits n;
257  diverted_space_node(vunits, node * = 0);
258  diverted_space_node(vunits, statem *, int, node * = 0);
259  node *copy();
260  int reread(int *);
261  int same(node *);
262  const char *type();
263  int force_tprint();
264  int is_tag();
265};
266
267class diverted_copy_file_node : public node {
268  symbol filename;
269public:
270  vunits n;
271  diverted_copy_file_node(symbol, node * = 0);
272  diverted_copy_file_node(symbol, statem *, int, node * = 0);
273  node *copy();
274  int reread(int *);
275  int same(node *);
276  const char *type();
277  int force_tprint();
278  int is_tag();
279};
280
281class extra_size_node : public node {
282  vunits n;
283public:
284  extra_size_node(vunits);
285  extra_size_node(vunits, statem *, int);
286  void set_vertical_size(vertical_size *);
287  node *copy();
288  int same(node *);
289  const char *type();
290  int force_tprint();
291  int is_tag();
292};
293
294class vertical_size_node : public node {
295  vunits n;
296public:
297  vertical_size_node(vunits, statem *, int);
298  vertical_size_node(vunits);
299  void set_vertical_size(vertical_size *);
300  void asciify(macro *);
301  node *copy();
302  int set_unformat_flag();
303  int same(node *);
304  const char *type();
305  int force_tprint();
306  int is_tag();
307};
308
309class hmotion_node : public node {
310protected:
311  hunits n;
312  unsigned char was_tab;
313  unsigned char unformat;
314  color *col;			/* for grotty */
315public:
316  hmotion_node(hunits i, color *c, node *nxt = 0)
317    : node(nxt), n(i), was_tab(0), unformat(0), col(c) {}
318  hmotion_node(hunits i, color *c, statem *s, int divlevel, node *nxt = 0)
319    : node(nxt, s, divlevel), n(i), was_tab(0), unformat(0), col(c) {}
320  hmotion_node(hunits i, int flag1, int flag2, color *c, statem *s,
321	       int divlevel, node *nxt = 0)
322    : node(nxt, s, divlevel), n(i), was_tab(flag1), unformat(flag2),
323      col(c) {}
324  hmotion_node(hunits i, int flag1, int flag2, color *c, node *nxt = 0)
325    : node(nxt), n(i), was_tab(flag1), unformat(flag2), col(c) {}
326  node *copy();
327  int reread(int *);
328  int set_unformat_flag();
329  void asciify(macro *);
330  void tprint(troff_output_file *);
331  hunits width();
332  void ascii_print(ascii_output_file *);
333  int same(node *);
334  const char *type();
335  int force_tprint();
336  int is_tag();
337  node *add_self(node *, hyphen_list **);
338  hyphen_list *get_hyphen_list(hyphen_list *, int *);
339  hyphenation_type get_hyphenation_type();
340};
341
342class space_char_hmotion_node : public hmotion_node {
343public:
344  space_char_hmotion_node(hunits, color *, node * = 0);
345  space_char_hmotion_node(hunits, color *, statem *, int, node * = 0);
346  node *copy();
347  void ascii_print(ascii_output_file *);
348  void asciify(macro *);
349  void tprint(troff_output_file *);
350  int same(node *);
351  const char *type();
352  int force_tprint();
353  int is_tag();
354  node *add_self(node *, hyphen_list **);
355  hyphen_list *get_hyphen_list(hyphen_list *, int *);
356  hyphenation_type get_hyphenation_type();
357};
358
359class vmotion_node : public node {
360  vunits n;
361  color *col;			/* for grotty */
362public:
363  vmotion_node(vunits, color *);
364  vmotion_node(vunits, color *, statem *, int);
365  void tprint(troff_output_file *);
366  node *copy();
367  vunits vertical_width();
368  int same(node *);
369  const char *type();
370  int force_tprint();
371  int is_tag();
372};
373
374class hline_node : public node {
375  hunits x;
376  node *n;
377public:
378  hline_node(hunits, node *, node * = 0);
379  hline_node(hunits, node *, statem *, int, node * = 0);
380  ~hline_node();
381  node *copy();
382  hunits width();
383  void tprint(troff_output_file *);
384  int same(node *);
385  const char *type();
386  int force_tprint();
387  int is_tag();
388};
389
390class vline_node : public node {
391  vunits x;
392  node *n;
393public:
394  vline_node(vunits, node *, node * = 0);
395  vline_node(vunits, node *, statem *, int, node * = 0);
396  ~vline_node();
397  node *copy();
398  void tprint(troff_output_file *);
399  hunits width();
400  vunits vertical_width();
401  void vertical_extent(vunits *, vunits *);
402  int same(node *);
403  const char *type();
404  int force_tprint();
405  int is_tag();
406};
407
408class dummy_node : public node {
409public:
410  dummy_node(node *nd = 0) : node(nd) {}
411  node *copy();
412  int same(node *);
413  const char *type();
414  int force_tprint();
415  int is_tag();
416  hyphenation_type get_hyphenation_type();
417};
418
419class transparent_dummy_node : public node {
420public:
421  transparent_dummy_node(node *nd = 0) : node(nd) {}
422  node *copy();
423  int same(node *);
424  const char *type();
425  int force_tprint();
426  int is_tag();
427  int ends_sentence();
428  hyphenation_type get_hyphenation_type();
429};
430
431class zero_width_node : public node {
432  node *n;
433public:
434  zero_width_node(node *);
435  zero_width_node(node *, statem *, int);
436  ~zero_width_node();
437  node *copy();
438  void tprint(troff_output_file *);
439  int same(node *);
440  const char *type();
441  int force_tprint();
442  int is_tag();
443  void append(node *);
444  int character_type();
445  void vertical_extent(vunits *, vunits *);
446};
447
448class left_italic_corrected_node : public node {
449  node *n;
450  hunits x;
451public:
452  left_italic_corrected_node(node * = 0);
453  left_italic_corrected_node(statem *, int, node * = 0);
454  ~left_italic_corrected_node();
455  void tprint(troff_output_file *);
456  void ascii_print(ascii_output_file *);
457  void asciify(macro *);
458  node *copy();
459  int same(node *);
460  const char *type();
461  int force_tprint();
462  int is_tag();
463  hunits width();
464  node *last_char_node();
465  void vertical_extent(vunits *, vunits *);
466  int ends_sentence();
467  int overlaps_horizontally();
468  int overlaps_vertically();
469  hyphenation_type get_hyphenation_type();
470  tfont *get_tfont();
471  int character_type();
472  hunits skew();
473  hunits italic_correction();
474  hunits subscript_correction();
475  hyphen_list *get_hyphen_list(hyphen_list *, int *);
476  node *add_self(node *, hyphen_list **);
477  node *merge_glyph_node(glyph_node *);
478};
479
480class overstrike_node : public node {
481  node *list;
482  hunits max_width;
483public:
484  overstrike_node();
485  overstrike_node(statem *, int);
486  ~overstrike_node();
487  node *copy();
488  void tprint(troff_output_file *);
489  void overstrike(node *);	// add another node to be overstruck
490  hunits width();
491  int same(node *);
492  const char *type();
493  int force_tprint();
494  int is_tag();
495  node *add_self(node *, hyphen_list **);
496  hyphen_list *get_hyphen_list(hyphen_list *, int *);
497  hyphenation_type get_hyphenation_type();
498};
499
500class bracket_node : public node {
501  node *list;
502  hunits max_width;
503public:
504  bracket_node();
505  bracket_node(statem *, int);
506  ~bracket_node();
507  node *copy();
508  void tprint(troff_output_file *);
509  void bracket(node *);	// add another node to be overstruck
510  hunits width();
511  int same(node *);
512  const char *type();
513  int force_tprint();
514  int is_tag();
515};
516
517class special_node : public node {
518  macro mac;
519  tfont *tf;
520  color *gcol;
521  color *fcol;
522  int no_init_string;
523  void tprint_start(troff_output_file *);
524  void tprint_char(troff_output_file *, unsigned char);
525  void tprint_end(troff_output_file *);
526public:
527  special_node(const macro &, int = 0);
528  special_node(const macro &, tfont *, color *, color *, statem *, int,
529	       int = 0);
530  node *copy();
531  void tprint(troff_output_file *);
532  int same(node *);
533  const char *type();
534  int force_tprint();
535  int is_tag();
536  int ends_sentence();
537  tfont *get_tfont();
538};
539
540class suppress_node : public node {
541  int is_on;
542  int emit_limits;	// must we issue the extent of the area written out?
543  symbol filename;
544  char position;
545  int  image_id;
546public:
547  suppress_node(int, int);
548  suppress_node(symbol, char, int);
549  suppress_node(int, int, symbol, char, int, statem *, int);
550  suppress_node(int, int, symbol, char, int);
551  node *copy();
552  void tprint(troff_output_file *);
553  hunits width();
554  int same(node *);
555  const char *type();
556  int force_tprint();
557  int is_tag();
558private:
559  void put(troff_output_file *, const char *);
560};
561
562class tag_node : public node {
563public:
564  string tag_string;
565  int delayed;
566  tag_node();
567  tag_node(string, int);
568  tag_node(string, statem *, int, int);
569  node *copy();
570  void tprint(troff_output_file *);
571  int same(node *);
572  const char *type();
573  int force_tprint();
574  int is_tag();
575  int ends_sentence();
576};
577
578struct hvpair {
579  hunits h;
580  vunits v;
581  hvpair();
582};
583
584class draw_node : public node {
585  int npoints;
586  font_size sz;
587  color *gcol;
588  color *fcol;
589  char code;
590  hvpair *point;
591public:
592  draw_node(char, hvpair *, int, font_size, color *, color *);
593  draw_node(char, hvpair *, int, font_size, color *, color *, statem *, int);
594  ~draw_node();
595  hunits width();
596  vunits vertical_width();
597  node *copy();
598  void tprint(troff_output_file *);
599  int same(node *);
600  const char *type();
601  int force_tprint();
602  int is_tag();
603};
604
605class charinfo;
606node *make_node(charinfo *, environment *);
607int character_exists(charinfo *, environment *);
608
609int same_node_list(node *, node *);
610node *reverse_node_list(node *);
611void delete_node_list(node *);
612node *copy_node_list(node *);
613
614int get_bold_fontno(int);
615
616inline hyphen_list::hyphen_list(unsigned char code, hyphen_list *p)
617: hyphen(0), breakable(0), hyphenation_code(code), next(p)
618{
619}
620
621extern void read_desc();
622extern int mount_font(int, symbol, symbol = NULL_SYMBOL);
623extern int check_font(symbol, symbol);
624extern int check_style(symbol);
625extern void mount_style(int, symbol);
626extern int is_good_fontno(int);
627extern int symbol_fontno(symbol);
628extern int next_available_font_position();
629extern void init_size_table(int *);
630extern int get_underline_fontno();
631
632class output_file {
633  char make_g_plus_plus_shut_up;
634public:
635  output_file();
636  virtual ~output_file();
637  virtual void trailer(vunits);
638  virtual void flush() = 0;
639  virtual void transparent_char(unsigned char) = 0;
640  virtual void print_line(hunits x, vunits y, node *n,
641			  vunits before, vunits after, hunits width) = 0;
642  virtual void begin_page(int pageno, vunits page_length) = 0;
643  virtual void copy_file(hunits x, vunits y, const char *filename) = 0;
644  virtual int is_printing() = 0;
645  virtual void put_filename(const char *);
646  virtual void on();
647  virtual void off();
648#ifdef COLUMN
649  virtual void vjustify(vunits, symbol);
650#endif /* COLUMN */
651  mtsm state;
652};
653
654#ifndef POPEN_MISSING
655extern char *pipe_command;
656#endif
657
658extern output_file *the_output;
659extern void init_output();
660int in_output_page_list(int);
661
662class font_family {
663  int *map;
664  int map_size;
665public:
666  const symbol nm;
667  font_family(symbol);
668  ~font_family();
669  int make_definite(int);
670  static void invalidate_fontno(int);
671};
672
673font_family *lookup_family(symbol);
674symbol get_font_name(int, environment *);
675symbol get_style_name(int);
676extern search_path include_search_path;
677