1 /*	$NetBSD: node.cpp,v 1.2 2016/01/13 19:01:59 christos Exp $	*/
2 
3 // -*- C++ -*-
4 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
5    Free Software Foundation, Inc.
6      Written by James Clark (jjc@jclark.com)
7 
8 This file is part of groff.
9 
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
13 version.
14 
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 for more details.
19 
20 You should have received a copy of the GNU General Public License along
21 with groff; see the file COPYING.  If not, write to the Free Software
22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
23 
24 extern int debug_state;
25 
26 #include "troff.h"
27 
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 
32 #include "dictionary.h"
33 #include "hvunits.h"
34 #include "stringclass.h"
35 #include "mtsm.h"
36 #include "env.h"
37 #include "request.h"
38 #include "node.h"
39 #include "token.h"
40 #include "div.h"
41 #include "reg.h"
42 #include "charinfo.h"
43 #include "font.h"
44 #include "input.h"
45 #include "geometry.h"
46 
47 #include "nonposix.h"
48 
49 #ifdef _POSIX_VERSION
50 
51 #include <sys/wait.h>
52 
53 #else /* not _POSIX_VERSION */
54 
55 /* traditional Unix */
56 
57 #define WIFEXITED(s) (((s) & 0377) == 0)
58 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
59 #define WTERMSIG(s) ((s) & 0177)
60 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
61 #define WSTOPSIG(s) (((s) >> 8) & 0377)
62 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
63 
64 #endif /* not _POSIX_VERSION */
65 
66 // declarations to avoid friend name injections
67 class tfont;
68 class tfont_spec;
69 tfont *make_tfont(tfont_spec &);
70 
71 
72 /*
73  *  how many boundaries of images have been written? Useful for
74  *  debugging grohtml
75  */
76 
77 int image_no = 0;
78 static int suppress_start_page = 0;
79 
80 #define STORE_WIDTH 1
81 
82 symbol HYPHEN_SYMBOL("hy");
83 
84 // Character used when a hyphen is inserted at a line break.
85 static charinfo *soft_hyphen_char;
86 
87 enum constant_space_type {
88   CONSTANT_SPACE_NONE,
89   CONSTANT_SPACE_RELATIVE,
90   CONSTANT_SPACE_ABSOLUTE
91   };
92 
93 struct special_font_list {
94   int n;
95   special_font_list *next;
96 };
97 
98 special_font_list *global_special_fonts;
99 static int global_ligature_mode = 1;
100 static int global_kern_mode = 1;
101 
102 class track_kerning_function {
103   int non_zero;
104   units min_size;
105   hunits min_amount;
106   units max_size;
107   hunits max_amount;
108 public:
109   track_kerning_function();
110   track_kerning_function(units, hunits, units, hunits);
111   int operator==(const track_kerning_function &);
112   int operator!=(const track_kerning_function &);
113   hunits compute(int point_size);
114 };
115 
116 // embolden fontno when this is the current font
117 
118 struct conditional_bold {
119   conditional_bold *next;
120   int fontno;
121   hunits offset;
122   conditional_bold(int, hunits, conditional_bold * = 0);
123 };
124 
125 class font_info {
126   tfont *last_tfont;
127   int number;
128   font_size last_size;
129   int last_height;
130   int last_slant;
131   symbol internal_name;
132   symbol external_name;
133   font *fm;
134   char is_bold;
135   hunits bold_offset;
136   track_kerning_function track_kern;
137   constant_space_type is_constant_spaced;
138   units constant_space;
139   int last_ligature_mode;
140   int last_kern_mode;
141   conditional_bold *cond_bold_list;
142   void flush();
143 public:
144   special_font_list *sf;
145   font_info(symbol, int, symbol, font *);
146   int contains(charinfo *);
147   void set_bold(hunits);
148   void unbold();
149   void set_conditional_bold(int, hunits);
150   void conditional_unbold(int);
151   void set_track_kern(track_kerning_function &);
152   void set_constant_space(constant_space_type, units = 0);
153   int is_named(symbol);
154   symbol get_name();
155   tfont *get_tfont(font_size, int, int, int);
156   hunits get_space_width(font_size, int);
157   hunits get_narrow_space_width(font_size);
158   hunits get_half_narrow_space_width(font_size);
159   int get_bold(hunits *);
160   int is_special();
161   int is_style();
162   friend symbol get_font_name(int, environment *);
163   friend symbol get_style_name(int);
164 };
165 
166 class tfont_spec {
167 protected:
168   symbol name;
169   int input_position;
170   font *fm;
171   font_size size;
172   char is_bold;
173   char is_constant_spaced;
174   int ligature_mode;
175   int kern_mode;
176   hunits bold_offset;
177   hunits track_kern;			// add this to the width
178   hunits constant_space_width;
179   int height;
180   int slant;
181 public:
182   tfont_spec(symbol, int, font *, font_size, int, int);
tfont_spec(const tfont_spec & spec)183   tfont_spec(const tfont_spec &spec) { *this = spec; }
184   tfont_spec plain();
185   int operator==(const tfont_spec &);
186   friend tfont *font_info::get_tfont(font_size fs, int, int, int);
187 };
188 
189 class tfont : public tfont_spec {
190   static tfont *tfont_list;
191   tfont *next;
192   tfont *plain_version;
193 public:
194   tfont(tfont_spec &);
195   int contains(charinfo *);
196   hunits get_width(charinfo *c);
197   int get_bold(hunits *);
198   int get_constant_space(hunits *);
199   hunits get_track_kern();
200   tfont *get_plain();
201   font_size get_size();
202   symbol get_name();
203   charinfo *get_lig(charinfo *c1, charinfo *c2);
204   int get_kern(charinfo *c1, charinfo *c2, hunits *res);
205   int get_input_position();
206   int get_character_type(charinfo *);
207   int get_height();
208   int get_slant();
209   vunits get_char_height(charinfo *);
210   vunits get_char_depth(charinfo *);
211   hunits get_char_skew(charinfo *);
212   hunits get_italic_correction(charinfo *);
213   hunits get_left_italic_correction(charinfo *);
214   hunits get_subscript_correction(charinfo *);
215   friend tfont *make_tfont(tfont_spec &);
216 };
217 
env_definite_font(environment * env)218 inline int env_definite_font(environment *env)
219 {
220   return env->get_family()->make_definite(env->get_font());
221 }
222 
223 /* font_info functions */
224 
225 static font_info **font_table = 0;
226 static int font_table_size = 0;
227 
font_info(symbol nm,int n,symbol enm,font * f)228 font_info::font_info(symbol nm, int n, symbol enm, font *f)
229 : last_tfont(0), number(n), last_size(0),
230   internal_name(nm), external_name(enm), fm(f),
231   is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE), last_ligature_mode(1),
232   last_kern_mode(1), cond_bold_list(0), sf(0)
233 {
234 }
235 
contains(charinfo * ci)236 inline int font_info::contains(charinfo *ci)
237 {
238   return fm != 0 && fm->contains(ci->get_index());
239 }
240 
is_special()241 inline int font_info::is_special()
242 {
243   return fm != 0 && fm->is_special();
244 }
245 
is_style()246 inline int font_info::is_style()
247 {
248   return fm == 0;
249 }
250 
make_tfont(tfont_spec & spec)251 tfont *make_tfont(tfont_spec &spec)
252 {
253   for (tfont *p = tfont::tfont_list; p; p = p->next)
254     if (*p == spec)
255       return p;
256   return new tfont(spec);
257 }
258 
259 // this is the current_font, fontno is where we found the character,
260 // presumably a special font
261 
get_tfont(font_size fs,int height,int slant,int fontno)262 tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno)
263 {
264   if (last_tfont == 0 || fs != last_size
265       || height != last_height || slant != last_slant
266       || global_ligature_mode != last_ligature_mode
267       || global_kern_mode != last_kern_mode
268       || fontno != number) {
269 	font_info *f = font_table[fontno];
270 	tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant);
271 	for (conditional_bold *p = cond_bold_list; p; p = p->next)
272 	  if (p->fontno == fontno) {
273 	    spec.is_bold = 1;
274 	    spec.bold_offset = p->offset;
275 	    break;
276 	  }
277 	if (!spec.is_bold && is_bold) {
278 	  spec.is_bold = 1;
279 	  spec.bold_offset = bold_offset;
280 	}
281 	spec.track_kern = track_kern.compute(fs.to_scaled_points());
282 	spec.ligature_mode = global_ligature_mode;
283 	spec.kern_mode = global_kern_mode;
284 	switch (is_constant_spaced) {
285 	case CONSTANT_SPACE_NONE:
286 	  break;
287 	case CONSTANT_SPACE_ABSOLUTE:
288 	  spec.is_constant_spaced = 1;
289 	  spec.constant_space_width = constant_space;
290 	  break;
291 	case CONSTANT_SPACE_RELATIVE:
292 	  spec.is_constant_spaced = 1;
293 	  spec.constant_space_width
294 	    = scale(constant_space*fs.to_scaled_points(),
295 		    units_per_inch,
296 		    36*72*sizescale);
297 	  break;
298 	default:
299 	  assert(0);
300 	}
301 	if (fontno != number)
302 	  return make_tfont(spec);
303 	last_tfont = make_tfont(spec);
304 	last_size = fs;
305 	last_height = height;
306 	last_slant = slant;
307 	last_ligature_mode = global_ligature_mode;
308 	last_kern_mode = global_kern_mode;
309       }
310   return last_tfont;
311 }
312 
get_bold(hunits * res)313 int font_info::get_bold(hunits *res)
314 {
315   if (is_bold) {
316     *res = bold_offset;
317     return 1;
318   }
319   else
320     return 0;
321 }
322 
unbold()323 void font_info::unbold()
324 {
325   if (is_bold) {
326     is_bold = 0;
327     flush();
328   }
329 }
330 
set_bold(hunits offset)331 void font_info::set_bold(hunits offset)
332 {
333   if (!is_bold || offset != bold_offset) {
334     is_bold = 1;
335     bold_offset = offset;
336     flush();
337   }
338 }
339 
set_conditional_bold(int fontno,hunits offset)340 void font_info::set_conditional_bold(int fontno, hunits offset)
341 {
342   for (conditional_bold *p = cond_bold_list; p; p = p->next)
343     if (p->fontno == fontno) {
344       if (offset != p->offset) {
345 	p->offset = offset;
346 	flush();
347       }
348       return;
349     }
350   cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list);
351 }
352 
conditional_bold(int f,hunits h,conditional_bold * x)353 conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x)
354 : next(x), fontno(f), offset(h)
355 {
356 }
357 
conditional_unbold(int fontno)358 void font_info::conditional_unbold(int fontno)
359 {
360   for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next)
361     if ((*p)->fontno == fontno) {
362       conditional_bold *tem = *p;
363       *p = (*p)->next;
364       delete tem;
365       flush();
366       return;
367     }
368 }
369 
set_constant_space(constant_space_type type,units x)370 void font_info::set_constant_space(constant_space_type type, units x)
371 {
372   if (type != is_constant_spaced
373       || (type != CONSTANT_SPACE_NONE && x != constant_space)) {
374     flush();
375     is_constant_spaced = type;
376     constant_space = x;
377   }
378 }
379 
set_track_kern(track_kerning_function & tk)380 void font_info::set_track_kern(track_kerning_function &tk)
381 {
382   if (track_kern != tk) {
383     track_kern = tk;
384     flush();
385   }
386 }
387 
flush()388 void font_info::flush()
389 {
390   last_tfont = 0;
391 }
392 
is_named(symbol s)393 int font_info::is_named(symbol s)
394 {
395   return internal_name == s;
396 }
397 
get_name()398 symbol font_info::get_name()
399 {
400   return internal_name;
401 }
402 
get_font_name(int fontno,environment * env)403 symbol get_font_name(int fontno, environment *env)
404 {
405   symbol f = font_table[fontno]->get_name();
406   if (font_table[fontno]->is_style()) {
407     return concat(env->get_family()->nm, f);
408   }
409   return f;
410 }
411 
get_style_name(int fontno)412 symbol get_style_name(int fontno)
413 {
414   if (font_table[fontno]->is_style())
415     return font_table[fontno]->get_name();
416   else
417     return EMPTY_SYMBOL;
418 }
419 
get_space_width(font_size fs,int space_sz)420 hunits font_info::get_space_width(font_size fs, int space_sz)
421 {
422   if (is_constant_spaced == CONSTANT_SPACE_NONE)
423     return scale(hunits(fm->get_space_width(fs.to_scaled_points())),
424 			space_sz, 12);
425   else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE)
426     return constant_space;
427   else
428     return scale(constant_space*fs.to_scaled_points(),
429 		 units_per_inch, 36*72*sizescale);
430 }
431 
get_narrow_space_width(font_size fs)432 hunits font_info::get_narrow_space_width(font_size fs)
433 {
434   charinfo *ci = get_charinfo(symbol("|"));
435   if (fm->contains(ci->get_index()))
436     return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
437   else
438     return hunits(fs.to_units()/6);
439 }
440 
get_half_narrow_space_width(font_size fs)441 hunits font_info::get_half_narrow_space_width(font_size fs)
442 {
443   charinfo *ci = get_charinfo(symbol("^"));
444   if (fm->contains(ci->get_index()))
445     return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
446   else
447     return hunits(fs.to_units()/12);
448 }
449 
450 /* tfont */
451 
tfont_spec(symbol nm,int n,font * f,font_size s,int h,int sl)452 tfont_spec::tfont_spec(symbol nm, int n, font *f,
453 		       font_size s, int h, int sl)
454 : name(nm), input_position(n), fm(f), size(s),
455   is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
456   height(h), slant(sl)
457 {
458   if (height == size.to_scaled_points())
459     height = 0;
460 }
461 
operator ==(const tfont_spec & spec)462 int tfont_spec::operator==(const tfont_spec &spec)
463 {
464   if (fm == spec.fm
465       && size == spec.size
466       && input_position == spec.input_position
467       && name == spec.name
468       && height == spec.height
469       && slant == spec.slant
470       && (is_bold
471 	  ? (spec.is_bold && bold_offset == spec.bold_offset)
472 	  : !spec.is_bold)
473       && track_kern == spec.track_kern
474       && (is_constant_spaced
475 	  ? (spec.is_constant_spaced
476 	     && constant_space_width == spec.constant_space_width)
477 	  : !spec.is_constant_spaced)
478       && ligature_mode == spec.ligature_mode
479       && kern_mode == spec.kern_mode)
480     return 1;
481   else
482     return 0;
483 }
484 
plain()485 tfont_spec tfont_spec::plain()
486 {
487   return tfont_spec(name, input_position, fm, size, height, slant);
488 }
489 
get_width(charinfo * c)490 hunits tfont::get_width(charinfo *c)
491 {
492   if (is_constant_spaced)
493     return constant_space_width;
494   else if (is_bold)
495     return (hunits(fm->get_width(c->get_index(), size.to_scaled_points()))
496 	    + track_kern + bold_offset);
497   else
498     return (hunits(fm->get_width(c->get_index(), size.to_scaled_points()))
499 	    + track_kern);
500 }
501 
get_char_height(charinfo * c)502 vunits tfont::get_char_height(charinfo *c)
503 {
504   vunits v = fm->get_height(c->get_index(), size.to_scaled_points());
505   if (height != 0 && height != size.to_scaled_points())
506     return scale(v, height, size.to_scaled_points());
507   else
508     return v;
509 }
510 
get_char_depth(charinfo * c)511 vunits tfont::get_char_depth(charinfo *c)
512 {
513   vunits v = fm->get_depth(c->get_index(), size.to_scaled_points());
514   if (height != 0 && height != size.to_scaled_points())
515     return scale(v, height, size.to_scaled_points());
516   else
517     return v;
518 }
519 
get_char_skew(charinfo * c)520 hunits tfont::get_char_skew(charinfo *c)
521 {
522   return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant));
523 }
524 
get_italic_correction(charinfo * c)525 hunits tfont::get_italic_correction(charinfo *c)
526 {
527   return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points()));
528 }
529 
get_left_italic_correction(charinfo * c)530 hunits tfont::get_left_italic_correction(charinfo *c)
531 {
532   return hunits(fm->get_left_italic_correction(c->get_index(),
533 					       size.to_scaled_points()));
534 }
535 
get_subscript_correction(charinfo * c)536 hunits tfont::get_subscript_correction(charinfo *c)
537 {
538   return hunits(fm->get_subscript_correction(c->get_index(),
539 					     size.to_scaled_points()));
540 }
541 
get_input_position()542 inline int tfont::get_input_position()
543 {
544   return input_position;
545 }
546 
contains(charinfo * ci)547 inline int tfont::contains(charinfo *ci)
548 {
549   return fm->contains(ci->get_index());
550 }
551 
get_character_type(charinfo * ci)552 inline int tfont::get_character_type(charinfo *ci)
553 {
554   return fm->get_character_type(ci->get_index());
555 }
556 
get_bold(hunits * res)557 inline int tfont::get_bold(hunits *res)
558 {
559   if (is_bold) {
560     *res = bold_offset;
561     return 1;
562   }
563   else
564     return 0;
565 }
566 
get_constant_space(hunits * res)567 inline int tfont::get_constant_space(hunits *res)
568 {
569   if (is_constant_spaced) {
570     *res = constant_space_width;
571     return 1;
572   }
573   else
574     return 0;
575 }
576 
get_track_kern()577 inline hunits tfont::get_track_kern()
578 {
579   return track_kern;
580 }
581 
get_plain()582 inline tfont *tfont::get_plain()
583 {
584   return plain_version;
585 }
586 
get_size()587 inline font_size tfont::get_size()
588 {
589   return size;
590 }
591 
get_name()592 inline symbol tfont::get_name()
593 {
594   return name;
595 }
596 
get_height()597 inline int tfont::get_height()
598 {
599   return height;
600 }
601 
get_slant()602 inline int tfont::get_slant()
603 {
604   return slant;
605 }
606 
607 symbol SYMBOL_ff("ff");
608 symbol SYMBOL_fi("fi");
609 symbol SYMBOL_fl("fl");
610 symbol SYMBOL_Fi("Fi");
611 symbol SYMBOL_Fl("Fl");
612 
get_lig(charinfo * c1,charinfo * c2)613 charinfo *tfont::get_lig(charinfo *c1, charinfo *c2)
614 {
615   if (ligature_mode == 0)
616     return 0;
617   charinfo *ci = 0;
618   if (c1->get_ascii_code() == 'f') {
619     switch (c2->get_ascii_code()) {
620     case 'f':
621       if (fm->has_ligature(font::LIG_ff))
622 	ci = get_charinfo(SYMBOL_ff);
623       break;
624     case 'i':
625       if (fm->has_ligature(font::LIG_fi))
626 	ci = get_charinfo(SYMBOL_fi);
627       break;
628     case 'l':
629       if (fm->has_ligature(font::LIG_fl))
630 	ci = get_charinfo(SYMBOL_fl);
631       break;
632     }
633   }
634   else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) {
635     switch (c2->get_ascii_code()) {
636     case 'i':
637       if (fm->has_ligature(font::LIG_ffi))
638 	ci = get_charinfo(SYMBOL_Fi);
639       break;
640     case 'l':
641       if (fm->has_ligature(font::LIG_ffl))
642 	ci = get_charinfo(SYMBOL_Fl);
643       break;
644     }
645   }
646   if (ci != 0 && fm->contains(ci->get_index()))
647     return ci;
648   return 0;
649 }
650 
get_kern(charinfo * c1,charinfo * c2,hunits * res)651 inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res)
652 {
653   if (kern_mode == 0)
654     return 0;
655   else {
656     int n = fm->get_kern(c1->get_index(),
657 			 c2->get_index(),
658 			 size.to_scaled_points());
659     if (n) {
660       *res = hunits(n);
661       return 1;
662     }
663     else
664       return 0;
665   }
666 }
667 
668 tfont *tfont::tfont_list = 0;
669 
tfont(tfont_spec & spec)670 tfont::tfont(tfont_spec &spec) : tfont_spec(spec)
671 {
672   next = tfont_list;
673   tfont_list = this;
674   tfont_spec plain_spec = plain();
675   tfont *p;
676   for (p = tfont_list; p; p = p->next)
677     if (*p == plain_spec) {
678       plain_version = p;
679       break;
680     }
681   if (!p)
682     plain_version = new tfont(plain_spec);
683 }
684 
685 /* output_file */
686 
687 class real_output_file : public output_file {
688 #ifndef POPEN_MISSING
689   int piped;
690 #endif
691   int printing;        // decision via optional page list
692   int output_on;       // \O[0] or \O[1] escape calls
693   virtual void really_transparent_char(unsigned char) = 0;
694   virtual void really_print_line(hunits x, vunits y, node *n,
695 				 vunits before, vunits after, hunits width) = 0;
696   virtual void really_begin_page(int pageno, vunits page_length) = 0;
697   virtual void really_copy_file(hunits x, vunits y, const char *filename);
698   virtual void really_put_filename(const char *filename);
699   virtual void really_on();
700   virtual void really_off();
701 public:
702   FILE *fp;
703   real_output_file();
704   ~real_output_file();
705   void flush();
706   void transparent_char(unsigned char);
707   void print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
708   void begin_page(int pageno, vunits page_length);
709   void put_filename(const char *filename);
710   void on();
711   void off();
712   int is_on();
713   int is_printing();
714   void copy_file(hunits x, vunits y, const char *filename);
715 };
716 
717 class suppress_output_file : public real_output_file {
718 public:
719   suppress_output_file();
720   void really_transparent_char(unsigned char);
721   void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
722   void really_begin_page(int pageno, vunits page_length);
723 };
724 
725 class ascii_output_file : public real_output_file {
726 public:
727   ascii_output_file();
728   void really_transparent_char(unsigned char);
729   void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width);
730   void really_begin_page(int pageno, vunits page_length);
731   void outc(unsigned char c);
732   void outs(const char *s);
733 };
734 
outc(unsigned char c)735 void ascii_output_file::outc(unsigned char c)
736 {
737   fputc(c, fp);
738 }
739 
outs(const char * s)740 void ascii_output_file::outs(const char *s)
741 {
742   fputc('<', fp);
743   if (s)
744     fputs(s, fp);
745   fputc('>', fp);
746 }
747 
748 struct hvpair;
749 
750 class troff_output_file : public real_output_file {
751   units hpos;
752   units vpos;
753   units output_vpos;
754   units output_hpos;
755   int force_motion;
756   int current_size;
757   int current_slant;
758   int current_height;
759   tfont *current_tfont;
760   color *current_fill_color;
761   color *current_glyph_color;
762   int current_font_number;
763   symbol *font_position;
764   int nfont_positions;
765   enum { TBUF_SIZE = 256 };
766   char tbuf[TBUF_SIZE];
767   int tbuf_len;
768   int tbuf_kern;
769   int begun_page;
770   int cur_div_level;
771   string tag_list;
772   void do_motion();
773   void put(char c);
774   void put(unsigned char c);
775   void put(int i);
776   void put(unsigned int i);
777   void put(const char *s);
778   void set_font(tfont *tf);
779   void flush_tbuf();
780 public:
781   troff_output_file();
782   ~troff_output_file();
783   void trailer(vunits page_length);
784   void put_char(charinfo *, tfont *, color *, color *);
785   void put_char_width(charinfo *, tfont *, color *, color *, hunits, hunits);
786   void right(hunits);
787   void down(vunits);
788   void moveto(hunits, vunits);
789   void start_special(tfont *, color *, color *, int = 0);
790   void start_special();
791   void special_char(unsigned char c);
792   void end_special();
793   void word_marker();
794   void really_transparent_char(unsigned char c);
795   void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width);
796   void really_begin_page(int pageno, vunits page_length);
797   void really_copy_file(hunits x, vunits y, const char *filename);
798   void really_put_filename(const char *filename);
799   void really_on();
800   void really_off();
801   void draw(char, hvpair *, int, font_size, color *, color *);
802   void determine_line_limits (char code, hvpair *point, int npoints);
803   void check_charinfo(tfont *tf, charinfo *ci);
804   void glyph_color(color *c);
805   void fill_color(color *c);
get_hpos()806   int get_hpos() { return hpos; }
get_vpos()807   int get_vpos() { return vpos; }
808   void add_to_tag_list(string s);
809   friend void space_char_hmotion_node::tprint(troff_output_file *);
810   friend void unbreakable_space_node::tprint(troff_output_file *);
811 };
812 
put_string(const char * s,FILE * fp)813 static void put_string(const char *s, FILE *fp)
814 {
815   for (; *s != '\0'; ++s)
816     putc(*s, fp);
817 }
818 
put(char c)819 inline void troff_output_file::put(char c)
820 {
821   putc(c, fp);
822 }
823 
put(unsigned char c)824 inline void troff_output_file::put(unsigned char c)
825 {
826   putc(c, fp);
827 }
828 
put(const char * s)829 inline void troff_output_file::put(const char *s)
830 {
831   put_string(s, fp);
832 }
833 
put(int i)834 inline void troff_output_file::put(int i)
835 {
836   put_string(i_to_a(i), fp);
837 }
838 
put(unsigned int i)839 inline void troff_output_file::put(unsigned int i)
840 {
841   put_string(ui_to_a(i), fp);
842 }
843 
start_special(tfont * tf,color * gcol,color * fcol,int no_init_string)844 void troff_output_file::start_special(tfont *tf, color *gcol, color *fcol,
845 				      int no_init_string)
846 {
847   set_font(tf);
848   glyph_color(gcol);
849   fill_color(fcol);
850   flush_tbuf();
851   do_motion();
852   if (!no_init_string)
853     put("x X ");
854 }
855 
start_special()856 void troff_output_file::start_special()
857 {
858   flush_tbuf();
859   do_motion();
860   put("x X ");
861 }
862 
special_char(unsigned char c)863 void troff_output_file::special_char(unsigned char c)
864 {
865   put(c);
866   if (c == '\n')
867     put('+');
868 }
869 
end_special()870 void troff_output_file::end_special()
871 {
872   put('\n');
873 }
874 
moveto(hunits h,vunits v)875 inline void troff_output_file::moveto(hunits h, vunits v)
876 {
877   hpos = h.to_units();
878   vpos = v.to_units();
879 }
880 
really_print_line(hunits x,vunits y,node * n,vunits before,vunits after,hunits)881 void troff_output_file::really_print_line(hunits x, vunits y, node *n,
882 					  vunits before, vunits after, hunits)
883 {
884   moveto(x, y);
885   while (n != 0) {
886     // Check whether we should push the current troff state and use
887     // the state at the start of the invocation of this diversion.
888     if (n->div_nest_level > cur_div_level && n->push_state) {
889       state.push_state(n->push_state);
890       cur_div_level = n->div_nest_level;
891     }
892     // Has the current diversion level decreased?  Then we must pop the
893     // troff state.
894     while (n->div_nest_level < cur_div_level) {
895       state.pop_state();
896       cur_div_level = n->div_nest_level;
897     }
898     // Now check whether the state has changed.
899     if ((is_on() || n->force_tprint())
900 	&& (state.changed(n->state) || n->is_tag() || n->is_special)) {
901       flush_tbuf();
902       do_motion();
903       force_motion = 1;
904       flush();
905       state.flush(fp, n->state, tag_list);
906       tag_list = string("");
907       flush();
908     }
909     n->tprint(this);
910     n = n->next;
911   }
912   flush_tbuf();
913   // This ensures that transparent throughput will have a more predictable
914   // position.
915   do_motion();
916   force_motion = 1;
917   hpos = 0;
918   put('n');
919   put(before.to_units());
920   put(' ');
921   put(after.to_units());
922   put('\n');
923 }
924 
word_marker()925 inline void troff_output_file::word_marker()
926 {
927   flush_tbuf();
928   if (is_on())
929     put('w');
930 }
931 
right(hunits n)932 inline void troff_output_file::right(hunits n)
933 {
934   hpos += n.to_units();
935 }
936 
down(vunits n)937 inline void troff_output_file::down(vunits n)
938 {
939   vpos += n.to_units();
940 }
941 
do_motion()942 void troff_output_file::do_motion()
943 {
944   if (force_motion) {
945     put('V');
946     put(vpos);
947     put('\n');
948     put('H');
949     put(hpos);
950     put('\n');
951   }
952   else {
953     if (hpos != output_hpos) {
954       units n = hpos - output_hpos;
955       if (n > 0 && n < hpos) {
956 	put('h');
957 	put(n);
958       }
959       else {
960 	put('H');
961 	put(hpos);
962       }
963       put('\n');
964     }
965     if (vpos != output_vpos) {
966       units n = vpos - output_vpos;
967       if (n > 0 && n < vpos) {
968 	put('v');
969 	put(n);
970       }
971       else {
972 	put('V');
973 	put(vpos);
974       }
975       put('\n');
976     }
977   }
978   output_vpos = vpos;
979   output_hpos = hpos;
980   force_motion = 0;
981 }
982 
flush_tbuf()983 void troff_output_file::flush_tbuf()
984 {
985   if (!is_on()) {
986     tbuf_len = 0;
987     return;
988   }
989 
990   if (tbuf_len == 0)
991     return;
992   if (tbuf_kern == 0)
993     put('t');
994   else {
995     put('u');
996     put(tbuf_kern);
997     put(' ');
998   }
999   check_output_limits(hpos, vpos);
1000   check_output_limits(hpos, vpos - current_size);
1001 
1002   for (int i = 0; i < tbuf_len; i++)
1003     put(tbuf[i]);
1004   put('\n');
1005   tbuf_len = 0;
1006 }
1007 
check_charinfo(tfont * tf,charinfo * ci)1008 void troff_output_file::check_charinfo(tfont *tf, charinfo *ci)
1009 {
1010   if (!is_on())
1011     return;
1012 
1013   int height = tf->get_char_height(ci).to_units();
1014   int width = tf->get_width(ci).to_units()
1015 	      + tf->get_italic_correction(ci).to_units();
1016   int depth = tf->get_char_depth(ci).to_units();
1017   check_output_limits(output_hpos, output_vpos - height);
1018   check_output_limits(output_hpos + width, output_vpos + depth);
1019 }
1020 
put_char_width(charinfo * ci,tfont * tf,color * gcol,color * fcol,hunits w,hunits k)1021 void troff_output_file::put_char_width(charinfo *ci, tfont *tf,
1022 				       color *gcol, color *fcol,
1023 				       hunits w, hunits k)
1024 {
1025   int kk = k.to_units();
1026   if (!is_on()) {
1027     flush_tbuf();
1028     hpos += w.to_units() + kk;
1029     return;
1030   }
1031   set_font(tf);
1032   unsigned char c = ci->get_ascii_code();
1033   if (c == '\0') {
1034     glyph_color(gcol);
1035     fill_color(fcol);
1036     flush_tbuf();
1037     do_motion();
1038     check_charinfo(tf, ci);
1039     if (ci->numbered()) {
1040       put('N');
1041       put(ci->get_number());
1042     }
1043     else {
1044       put('C');
1045       const char *s = ci->nm.contents();
1046       if (s[1] == 0) {
1047 	put('\\');
1048 	put(s[0]);
1049       }
1050       else
1051 	put(s);
1052     }
1053     put('\n');
1054     hpos += w.to_units() + kk;
1055   }
1056   else if (tcommand_flag) {
1057     if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos
1058 	&& (!gcol || gcol == current_glyph_color)
1059 	&& (!fcol || fcol == current_fill_color)
1060 	&& kk == tbuf_kern
1061 	&& tbuf_len < TBUF_SIZE) {
1062       check_charinfo(tf, ci);
1063       tbuf[tbuf_len++] = c;
1064       output_hpos += w.to_units() + kk;
1065       hpos = output_hpos;
1066       return;
1067     }
1068     glyph_color(gcol);
1069     fill_color(fcol);
1070     flush_tbuf();
1071     do_motion();
1072     check_charinfo(tf, ci);
1073     tbuf[tbuf_len++] = c;
1074     output_hpos += w.to_units() + kk;
1075     tbuf_kern = kk;
1076     hpos = output_hpos;
1077   }
1078   else {
1079     // flush_tbuf();
1080     int n = hpos - output_hpos;
1081     check_charinfo(tf, ci);
1082     // check_output_limits(output_hpos, output_vpos);
1083     if (vpos == output_vpos
1084 	&& (!gcol || gcol == current_glyph_color)
1085 	&& (!fcol || fcol == current_fill_color)
1086 	&& n > 0 && n < 100 && !force_motion) {
1087       put(char(n/10 + '0'));
1088       put(char(n%10 + '0'));
1089       put(c);
1090       output_hpos = hpos;
1091     }
1092     else {
1093       glyph_color(gcol);
1094       fill_color(fcol);
1095       do_motion();
1096       put('c');
1097       put(c);
1098     }
1099     hpos += w.to_units() + kk;
1100   }
1101 }
1102 
put_char(charinfo * ci,tfont * tf,color * gcol,color * fcol)1103 void troff_output_file::put_char(charinfo *ci, tfont *tf,
1104 				 color *gcol, color *fcol)
1105 {
1106   flush_tbuf();
1107   if (!is_on())
1108     return;
1109   set_font(tf);
1110   unsigned char c = ci->get_ascii_code();
1111   if (c == '\0') {
1112     glyph_color(gcol);
1113     fill_color(fcol);
1114     flush_tbuf();
1115     do_motion();
1116     if (ci->numbered()) {
1117       put('N');
1118       put(ci->get_number());
1119     }
1120     else {
1121       put('C');
1122       const char *s = ci->nm.contents();
1123       if (s[1] == 0) {
1124 	put('\\');
1125 	put(s[0]);
1126       }
1127       else
1128 	put(s);
1129     }
1130     put('\n');
1131   }
1132   else {
1133     int n = hpos - output_hpos;
1134     if (vpos == output_vpos
1135 	&& (!gcol || gcol == current_glyph_color)
1136 	&& (!fcol || fcol == current_fill_color)
1137 	&& n > 0 && n < 100) {
1138       put(char(n/10 + '0'));
1139       put(char(n%10 + '0'));
1140       put(c);
1141       output_hpos = hpos;
1142     }
1143     else {
1144       glyph_color(gcol);
1145       fill_color(fcol);
1146       flush_tbuf();
1147       do_motion();
1148       put('c');
1149       put(c);
1150     }
1151   }
1152 }
1153 
1154 // set_font calls `flush_tbuf' if necessary.
1155 
set_font(tfont * tf)1156 void troff_output_file::set_font(tfont *tf)
1157 {
1158   if (current_tfont == tf)
1159     return;
1160   flush_tbuf();
1161   int n = tf->get_input_position();
1162   symbol nm = tf->get_name();
1163   if (n >= nfont_positions || font_position[n] != nm) {
1164     put("x font ");
1165     put(n);
1166     put(' ');
1167     put(nm.contents());
1168     put('\n');
1169     if (n >= nfont_positions) {
1170       int old_nfont_positions = nfont_positions;
1171       symbol *old_font_position = font_position;
1172       nfont_positions *= 3;
1173       nfont_positions /= 2;
1174       if (nfont_positions <= n)
1175 	nfont_positions = n + 10;
1176       font_position = new symbol[nfont_positions];
1177       memcpy(font_position, old_font_position,
1178 	     old_nfont_positions*sizeof(symbol));
1179       a_delete old_font_position;
1180     }
1181     font_position[n] = nm;
1182   }
1183   if (current_font_number != n) {
1184     put('f');
1185     put(n);
1186     put('\n');
1187     current_font_number = n;
1188   }
1189   int size = tf->get_size().to_scaled_points();
1190   if (current_size != size) {
1191     put('s');
1192     put(size);
1193     put('\n');
1194     current_size = size;
1195   }
1196   int slant = tf->get_slant();
1197   if (current_slant != slant) {
1198     put("x Slant ");
1199     put(slant);
1200     put('\n');
1201     current_slant = slant;
1202   }
1203   int height = tf->get_height();
1204   if (current_height != height) {
1205     put("x Height ");
1206     put(height == 0 ? current_size : height);
1207     put('\n');
1208     current_height = height;
1209   }
1210   current_tfont = tf;
1211 }
1212 
1213 // fill_color calls `flush_tbuf' and `do_motion' if necessary.
1214 
fill_color(color * col)1215 void troff_output_file::fill_color(color *col)
1216 {
1217   if (!col || current_fill_color == col)
1218     return;
1219   current_fill_color = col;
1220   if (!color_flag)
1221     return;
1222   flush_tbuf();
1223   do_motion();
1224   put("DF");
1225   unsigned int components[4];
1226   color_scheme cs;
1227   cs = col->get_components(components);
1228   switch (cs) {
1229   case DEFAULT:
1230     put('d');
1231     break;
1232   case RGB:
1233     put("r ");
1234     put(Red);
1235     put(' ');
1236     put(Green);
1237     put(' ');
1238     put(Blue);
1239     break;
1240   case CMY:
1241     put("c ");
1242     put(Cyan);
1243     put(' ');
1244     put(Magenta);
1245     put(' ');
1246     put(Yellow);
1247     break;
1248   case CMYK:
1249     put("k ");
1250     put(Cyan);
1251     put(' ');
1252     put(Magenta);
1253     put(' ');
1254     put(Yellow);
1255     put(' ');
1256     put(Black);
1257     break;
1258   case GRAY:
1259     put("g ");
1260     put(Gray);
1261     break;
1262   }
1263   put('\n');
1264 }
1265 
1266 // glyph_color calls `flush_tbuf' and `do_motion' if necessary.
1267 
glyph_color(color * col)1268 void troff_output_file::glyph_color(color *col)
1269 {
1270   if (!col || current_glyph_color == col)
1271     return;
1272   current_glyph_color = col;
1273   if (!color_flag)
1274     return;
1275   flush_tbuf();
1276   // grotty doesn't like a color command if the vertical position is zero.
1277   do_motion();
1278   put("m");
1279   unsigned int components[4];
1280   color_scheme cs;
1281   cs = col->get_components(components);
1282   switch (cs) {
1283   case DEFAULT:
1284     put('d');
1285     break;
1286   case RGB:
1287     put("r ");
1288     put(Red);
1289     put(' ');
1290     put(Green);
1291     put(' ');
1292     put(Blue);
1293     break;
1294   case CMY:
1295     put("c ");
1296     put(Cyan);
1297     put(' ');
1298     put(Magenta);
1299     put(' ');
1300     put(Yellow);
1301     break;
1302   case CMYK:
1303     put("k ");
1304     put(Cyan);
1305     put(' ');
1306     put(Magenta);
1307     put(' ');
1308     put(Yellow);
1309     put(' ');
1310     put(Black);
1311     break;
1312   case GRAY:
1313     put("g ");
1314     put(Gray);
1315     break;
1316   }
1317   put('\n');
1318 }
1319 
add_to_tag_list(string s)1320 void troff_output_file::add_to_tag_list(string s)
1321 {
1322   if (tag_list == string(""))
1323     tag_list = s;
1324   else {
1325     tag_list += string("\n");
1326     tag_list += s;
1327   }
1328 }
1329 
1330 // determine_line_limits - works out the smallest box which will contain
1331 //			   the entity, code, built from the point array.
determine_line_limits(char code,hvpair * point,int npoints)1332 void troff_output_file::determine_line_limits(char code, hvpair *point,
1333 					      int npoints)
1334 {
1335   int i, x, y;
1336 
1337   if (!is_on())
1338     return;
1339 
1340   switch (code) {
1341   case 'c':
1342   case 'C':
1343     // only the h field is used when defining a circle
1344     check_output_limits(output_hpos,
1345 			output_vpos - point[0].h.to_units()/2);
1346     check_output_limits(output_hpos + point[0].h.to_units(),
1347 			output_vpos + point[0].h.to_units()/2);
1348     break;
1349   case 'E':
1350   case 'e':
1351     check_output_limits(output_hpos,
1352 			output_vpos - point[0].v.to_units()/2);
1353     check_output_limits(output_hpos + point[0].h.to_units(),
1354 			output_vpos + point[0].v.to_units()/2);
1355     break;
1356   case 'P':
1357   case 'p':
1358     x = output_hpos;
1359     y = output_vpos;
1360     check_output_limits(x, y);
1361     for (i = 0; i < npoints; i++) {
1362       x += point[i].h.to_units();
1363       y += point[i].v.to_units();
1364       check_output_limits(x, y);
1365     }
1366     break;
1367   case 't':
1368     x = output_hpos;
1369     y = output_vpos;
1370     for (i = 0; i < npoints; i++) {
1371       x += point[i].h.to_units();
1372       y += point[i].v.to_units();
1373       check_output_limits(x, y);
1374     }
1375     break;
1376   case 'a':
1377     double c[2];
1378     int p[4];
1379     int minx, miny, maxx, maxy;
1380     x = output_hpos;
1381     y = output_vpos;
1382     p[0] = point[0].h.to_units();
1383     p[1] = point[0].v.to_units();
1384     p[2] = point[1].h.to_units();
1385     p[3] = point[1].v.to_units();
1386     if (adjust_arc_center(p, c)) {
1387       check_output_arc_limits(x, y,
1388 			      p[0], p[1], p[2], p[3],
1389 			      c[0], c[1],
1390 			      &minx, &maxx, &miny, &maxy);
1391       check_output_limits(minx, miny);
1392       check_output_limits(maxx, maxy);
1393       break;
1394     }
1395     // fall through
1396   case 'l':
1397     x = output_hpos;
1398     y = output_vpos;
1399     check_output_limits(x, y);
1400     for (i = 0; i < npoints; i++) {
1401       x += point[i].h.to_units();
1402       y += point[i].v.to_units();
1403       check_output_limits(x, y);
1404     }
1405     break;
1406   default:
1407     x = output_hpos;
1408     y = output_vpos;
1409     for (i = 0; i < npoints; i++) {
1410       x += point[i].h.to_units();
1411       y += point[i].v.to_units();
1412       check_output_limits(x, y);
1413     }
1414   }
1415 }
1416 
draw(char code,hvpair * point,int npoints,font_size fsize,color * gcol,color * fcol)1417 void troff_output_file::draw(char code, hvpair *point, int npoints,
1418 			     font_size fsize, color *gcol, color *fcol)
1419 {
1420   int i;
1421   glyph_color(gcol);
1422   fill_color(fcol);
1423   flush_tbuf();
1424   do_motion();
1425   if (is_on()) {
1426     int size = fsize.to_scaled_points();
1427     if (current_size != size) {
1428       put('s');
1429       put(size);
1430       put('\n');
1431       current_size = size;
1432       current_tfont = 0;
1433     }
1434     put('D');
1435     put(code);
1436     if (code == 'c') {
1437       put(' ');
1438       put(point[0].h.to_units());
1439     }
1440     else
1441       for (i = 0; i < npoints; i++) {
1442 	put(' ');
1443 	put(point[i].h.to_units());
1444 	put(' ');
1445 	put(point[i].v.to_units());
1446       }
1447     determine_line_limits(code, point, npoints);
1448   }
1449 
1450   for (i = 0; i < npoints; i++)
1451     output_hpos += point[i].h.to_units();
1452   hpos = output_hpos;
1453   if (code != 'e') {
1454     for (i = 0; i < npoints; i++)
1455       output_vpos += point[i].v.to_units();
1456     vpos = output_vpos;
1457   }
1458   if (is_on())
1459     put('\n');
1460 }
1461 
really_on()1462 void troff_output_file::really_on()
1463 {
1464   flush_tbuf();
1465   force_motion = 1;
1466   do_motion();
1467 }
1468 
really_off()1469 void troff_output_file::really_off()
1470 {
1471   flush_tbuf();
1472 }
1473 
really_put_filename(const char * filename)1474 void troff_output_file::really_put_filename(const char *filename)
1475 {
1476   flush_tbuf();
1477   put("F ");
1478   put(filename);
1479   put('\n');
1480 }
1481 
really_begin_page(int pageno,vunits page_length)1482 void troff_output_file::really_begin_page(int pageno, vunits page_length)
1483 {
1484   flush_tbuf();
1485   if (begun_page) {
1486     if (page_length > V0) {
1487       put('V');
1488       put(page_length.to_units());
1489       put('\n');
1490     }
1491   }
1492   else
1493     begun_page = 1;
1494   current_tfont = 0;
1495   current_font_number = -1;
1496   current_size = 0;
1497   // current_height = 0;
1498   // current_slant = 0;
1499   hpos = 0;
1500   vpos = 0;
1501   output_hpos = 0;
1502   output_vpos = 0;
1503   force_motion = 1;
1504   for (int i = 0; i < nfont_positions; i++)
1505     font_position[i] = NULL_SYMBOL;
1506   put('p');
1507   put(pageno);
1508   put('\n');
1509 }
1510 
really_copy_file(hunits x,vunits y,const char * filename)1511 void troff_output_file::really_copy_file(hunits x, vunits y,
1512 					 const char *filename)
1513 {
1514   moveto(x, y);
1515   flush_tbuf();
1516   do_motion();
1517   errno = 0;
1518   FILE *ifp = include_search_path.open_file_cautious(filename);
1519   if (ifp == 0)
1520     error("can't open `%1': %2", filename, strerror(errno));
1521   else {
1522     int c;
1523     while ((c = getc(ifp)) != EOF)
1524       put(char(c));
1525     fclose(ifp);
1526   }
1527   force_motion = 1;
1528   current_size = 0;
1529   current_tfont = 0;
1530   current_font_number = -1;
1531   for (int i = 0; i < nfont_positions; i++)
1532     font_position[i] = NULL_SYMBOL;
1533 }
1534 
really_transparent_char(unsigned char c)1535 void troff_output_file::really_transparent_char(unsigned char c)
1536 {
1537   put(c);
1538 }
1539 
~troff_output_file()1540 troff_output_file::~troff_output_file()
1541 {
1542   a_delete font_position;
1543 }
1544 
trailer(vunits page_length)1545 void troff_output_file::trailer(vunits page_length)
1546 {
1547   flush_tbuf();
1548   if (page_length > V0) {
1549     put("x trailer\n");
1550     put('V');
1551     put(page_length.to_units());
1552     put('\n');
1553   }
1554   put("x stop\n");
1555 }
1556 
troff_output_file()1557 troff_output_file::troff_output_file()
1558 : current_slant(0), current_height(0), current_fill_color(0),
1559   current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0),
1560   cur_div_level(0)
1561 {
1562   font_position = new symbol[nfont_positions];
1563   put("x T ");
1564   put(device);
1565   put('\n');
1566   put("x res ");
1567   put(units_per_inch);
1568   put(' ');
1569   put(hresolution);
1570   put(' ');
1571   put(vresolution);
1572   put('\n');
1573   put("x init\n");
1574 }
1575 
1576 /* output_file */
1577 
1578 output_file *the_output = 0;
1579 
output_file()1580 output_file::output_file()
1581 {
1582 }
1583 
~output_file()1584 output_file::~output_file()
1585 {
1586 }
1587 
trailer(vunits)1588 void output_file::trailer(vunits)
1589 {
1590 }
1591 
put_filename(const char *)1592 void output_file::put_filename(const char *)
1593 {
1594 }
1595 
on()1596 void output_file::on()
1597 {
1598 }
1599 
off()1600 void output_file::off()
1601 {
1602 }
1603 
real_output_file()1604 real_output_file::real_output_file()
1605 : printing(0), output_on(1)
1606 {
1607 #ifndef POPEN_MISSING
1608   if (pipe_command) {
1609     if ((fp = popen(pipe_command, POPEN_WT)) != 0) {
1610       piped = 1;
1611       return;
1612     }
1613     error("pipe open failed: %1", strerror(errno));
1614   }
1615   piped = 0;
1616 #endif /* not POPEN_MISSING */
1617   fp = stdout;
1618 }
1619 
~real_output_file()1620 real_output_file::~real_output_file()
1621 {
1622   if (!fp)
1623     return;
1624   // To avoid looping, set fp to 0 before calling fatal().
1625   if (ferror(fp) || fflush(fp) < 0) {
1626     fp = 0;
1627     fatal("error writing output file");
1628   }
1629 #ifndef POPEN_MISSING
1630   if (piped) {
1631     int result = pclose(fp);
1632     fp = 0;
1633     if (result < 0)
1634       fatal("pclose failed");
1635     if (!WIFEXITED(result))
1636       error("output process `%1' got fatal signal %2",
1637 	    pipe_command,
1638 	    WIFSIGNALED(result) ? WTERMSIG(result) : WSTOPSIG(result));
1639     else {
1640       int exit_status = WEXITSTATUS(result);
1641       if (exit_status != 0)
1642 	error("output process `%1' exited with status %2",
1643 	      pipe_command, exit_status);
1644     }
1645   }
1646   else
1647 #endif /* not POPEN MISSING */
1648   if (fclose(fp) < 0) {
1649     fp = 0;
1650     fatal("error closing output file");
1651   }
1652 }
1653 
flush()1654 void real_output_file::flush()
1655 {
1656   if (fflush(fp) < 0)
1657     fatal("error writing output file");
1658 }
1659 
is_printing()1660 int real_output_file::is_printing()
1661 {
1662   return printing;
1663 }
1664 
begin_page(int pageno,vunits page_length)1665 void real_output_file::begin_page(int pageno, vunits page_length)
1666 {
1667   printing = in_output_page_list(pageno);
1668   if (printing)
1669     really_begin_page(pageno, page_length);
1670 }
1671 
copy_file(hunits x,vunits y,const char * filename)1672 void real_output_file::copy_file(hunits x, vunits y, const char *filename)
1673 {
1674   if (printing && output_on)
1675     really_copy_file(x, y, filename);
1676   check_output_limits(x.to_units(), y.to_units());
1677 }
1678 
transparent_char(unsigned char c)1679 void real_output_file::transparent_char(unsigned char c)
1680 {
1681   if (printing && output_on)
1682     really_transparent_char(c);
1683 }
1684 
print_line(hunits x,vunits y,node * n,vunits before,vunits after,hunits width)1685 void real_output_file::print_line(hunits x, vunits y, node *n,
1686 			     vunits before, vunits after, hunits width)
1687 {
1688   if (printing)
1689     really_print_line(x, y, n, before, after, width);
1690   delete_node_list(n);
1691 }
1692 
really_copy_file(hunits,vunits,const char *)1693 void real_output_file::really_copy_file(hunits, vunits, const char *)
1694 {
1695   // do nothing
1696 }
1697 
put_filename(const char * filename)1698 void real_output_file::put_filename(const char *filename)
1699 {
1700   really_put_filename(filename);
1701 }
1702 
really_put_filename(const char *)1703 void real_output_file::really_put_filename(const char *)
1704 {
1705 }
1706 
on()1707 void real_output_file::on()
1708 {
1709   really_on();
1710   if (output_on == 0)
1711     output_on = 1;
1712 }
1713 
off()1714 void real_output_file::off()
1715 {
1716   really_off();
1717   output_on = 0;
1718 }
1719 
is_on()1720 int real_output_file::is_on()
1721 {
1722   return output_on;
1723 }
1724 
really_on()1725 void real_output_file::really_on()
1726 {
1727 }
1728 
really_off()1729 void real_output_file::really_off()
1730 {
1731 }
1732 
1733 /* ascii_output_file */
1734 
really_transparent_char(unsigned char c)1735 void ascii_output_file::really_transparent_char(unsigned char c)
1736 {
1737   putc(c, fp);
1738 }
1739 
really_print_line(hunits,vunits,node * n,vunits,vunits,hunits)1740 void ascii_output_file::really_print_line(hunits, vunits, node *n,
1741 					  vunits, vunits, hunits)
1742 {
1743   while (n != 0) {
1744     n->ascii_print(this);
1745     n = n->next;
1746   }
1747   fputc('\n', fp);
1748 }
1749 
really_begin_page(int,vunits)1750 void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/)
1751 {
1752   fputs("<beginning of page>\n", fp);
1753 }
1754 
ascii_output_file()1755 ascii_output_file::ascii_output_file()
1756 {
1757 }
1758 
1759 /* suppress_output_file */
1760 
suppress_output_file()1761 suppress_output_file::suppress_output_file()
1762 {
1763 }
1764 
really_print_line(hunits,vunits,node *,vunits,vunits,hunits)1765 void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits, hunits)
1766 {
1767 }
1768 
really_begin_page(int,vunits)1769 void suppress_output_file::really_begin_page(int, vunits)
1770 {
1771 }
1772 
really_transparent_char(unsigned char)1773 void suppress_output_file::really_transparent_char(unsigned char)
1774 {
1775 }
1776 
1777 /* glyphs, ligatures, kerns, discretionary breaks */
1778 
1779 class charinfo_node : public node {
1780 protected:
1781   charinfo *ci;
1782 public:
1783   charinfo_node(charinfo *, statem *, int, node * = 0);
1784   int ends_sentence();
1785   int overlaps_vertically();
1786   int overlaps_horizontally();
1787 };
1788 
charinfo_node(charinfo * c,statem * s,int pop,node * x)1789 charinfo_node::charinfo_node(charinfo *c, statem *s, int pop, node *x)
1790 : node(x, s, pop), ci(c)
1791 {
1792 }
1793 
ends_sentence()1794 int charinfo_node::ends_sentence()
1795 {
1796   if (ci->ends_sentence())
1797     return 1;
1798   else if (ci->transparent())
1799     return 2;
1800   else
1801     return 0;
1802 }
1803 
overlaps_horizontally()1804 int charinfo_node::overlaps_horizontally()
1805 {
1806   return ci->overlaps_horizontally();
1807 }
1808 
overlaps_vertically()1809 int charinfo_node::overlaps_vertically()
1810 {
1811   return ci->overlaps_vertically();
1812 }
1813 
1814 class glyph_node : public charinfo_node {
1815   static glyph_node *free_list;
1816 protected:
1817   tfont *tf;
1818   color *gcol;
1819   color *fcol;		/* this is needed for grotty */
1820 #ifdef STORE_WIDTH
1821   hunits wid;
1822   glyph_node(charinfo *, tfont *, color *, color *, hunits,
1823 	     statem *, int, node * = 0);
1824 #endif
1825 public:
1826   void *operator new(size_t);
1827   void operator delete(void *);
1828   glyph_node(charinfo *, tfont *, color *, color *,
1829 	     statem *, int, node * = 0);
~glyph_node()1830   ~glyph_node() {}
1831   node *copy();
1832   node *merge_glyph_node(glyph_node *);
1833   node *merge_self(node *);
1834   hunits width();
1835   node *last_char_node();
1836   units size();
1837   void vertical_extent(vunits *, vunits *);
1838   hunits subscript_correction();
1839   hunits italic_correction();
1840   hunits left_italic_correction();
1841   hunits skew();
1842   hyphenation_type get_hyphenation_type();
1843   tfont *get_tfont();
1844   color *get_glyph_color();
1845   color *get_fill_color();
1846   void tprint(troff_output_file *);
1847   void zero_width_tprint(troff_output_file *);
1848   hyphen_list *get_hyphen_list(hyphen_list *, int *);
1849   node *add_self(node *, hyphen_list **);
1850   void ascii_print(ascii_output_file *);
1851   void asciify(macro *);
1852   int character_type();
1853   int same(node *);
1854   const char *type();
1855   int force_tprint();
1856   int is_tag();
1857   void debug_node();
1858 };
1859 
1860 glyph_node *glyph_node::free_list = 0;
1861 
1862 class ligature_node : public glyph_node {
1863   node *n1;
1864   node *n2;
1865 #ifdef STORE_WIDTH
1866   ligature_node(charinfo *, tfont *, color *, color *, hunits,
1867 		node *, node *, statem *, int, node * = 0);
1868 #endif
1869 public:
1870   void *operator new(size_t);
1871   void operator delete(void *);
1872   ligature_node(charinfo *, tfont *, color *, color *,
1873 		node *, node *, statem *, int, node * = 0);
1874   ~ligature_node();
1875   node *copy();
1876   node *add_self(node *, hyphen_list **);
1877   hyphen_list *get_hyphen_list(hyphen_list *, int *);
1878   void ascii_print(ascii_output_file *);
1879   void asciify(macro *);
1880   int same(node *);
1881   const char *type();
1882   int force_tprint();
1883   int is_tag();
1884 };
1885 
1886 class kern_pair_node : public node {
1887   hunits amount;
1888   node *n1;
1889   node *n2;
1890 public:
1891   kern_pair_node(hunits, node *, node *, statem *, int, node * = 0);
1892   ~kern_pair_node();
1893   node *copy();
1894   node *merge_glyph_node(glyph_node *);
1895   node *add_self(node *, hyphen_list **);
1896   hyphen_list *get_hyphen_list(hyphen_list *, int *);
1897   node *add_discretionary_hyphen();
1898   hunits width();
1899   node *last_char_node();
1900   hunits italic_correction();
1901   hunits subscript_correction();
1902   void tprint(troff_output_file *);
1903   hyphenation_type get_hyphenation_type();
1904   int ends_sentence();
1905   void ascii_print(ascii_output_file *);
1906   void asciify(macro *);
1907   int same(node *);
1908   const char *type();
1909   int force_tprint();
1910   int is_tag();
1911   void vertical_extent(vunits *, vunits *);
1912 };
1913 
1914 class dbreak_node : public node {
1915   node *none;
1916   node *pre;
1917   node *post;
1918 public:
1919   dbreak_node(node *, node *, statem *, int, node * = 0);
1920   ~dbreak_node();
1921   node *copy();
1922   node *merge_glyph_node(glyph_node *);
1923   node *add_discretionary_hyphen();
1924   hunits width();
1925   node *last_char_node();
1926   hunits italic_correction();
1927   hunits subscript_correction();
1928   void tprint(troff_output_file *);
1929   breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0,
1930 			      int is_inner = 0);
1931   int nbreaks();
1932   int ends_sentence();
1933   void split(int, node **, node **);
1934   hyphenation_type get_hyphenation_type();
1935   void ascii_print(ascii_output_file *);
1936   void asciify(macro *);
1937   int same(node *);
1938   const char *type();
1939   int force_tprint();
1940   int is_tag();
1941 };
1942 
operator new(size_t n)1943 void *glyph_node::operator new(size_t n)
1944 {
1945   assert(n == sizeof(glyph_node));
1946   if (!free_list) {
1947     const int BLOCK = 1024;
1948     free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK];
1949     for (int i = 0; i < BLOCK - 1; i++)
1950       free_list[i].next = free_list + i + 1;
1951     free_list[BLOCK-1].next = 0;
1952   }
1953   glyph_node *p = free_list;
1954   free_list = (glyph_node *)(free_list->next);
1955   p->next = 0;
1956   return p;
1957 }
1958 
operator new(size_t n)1959 void *ligature_node::operator new(size_t n)
1960 {
1961   return new char[n];
1962 }
1963 
operator delete(void * p)1964 void glyph_node::operator delete(void *p)
1965 {
1966   if (p) {
1967     ((glyph_node *)p)->next = free_list;
1968     free_list = (glyph_node *)p;
1969   }
1970 }
1971 
operator delete(void * p)1972 void ligature_node::operator delete(void *p)
1973 {
1974   delete[] (char *)p;
1975 }
1976 
glyph_node(charinfo * c,tfont * t,color * gc,color * fc,statem * s,int pop,node * x)1977 glyph_node::glyph_node(charinfo *c, tfont *t, color *gc, color *fc,
1978 		       statem *s, int pop, node *x)
1979 : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc)
1980 {
1981 #ifdef STORE_WIDTH
1982   wid = tf->get_width(ci);
1983 #endif
1984 }
1985 
1986 #ifdef STORE_WIDTH
glyph_node(charinfo * c,tfont * t,color * gc,color * fc,hunits w,statem * s,int pop,node * x)1987 glyph_node::glyph_node(charinfo *c, tfont *t,
1988 		       color *gc, color *fc, hunits w,
1989 		       statem *s, int pop, node *x)
1990 : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc), wid(w)
1991 {
1992 }
1993 #endif
1994 
copy()1995 node *glyph_node::copy()
1996 {
1997 #ifdef STORE_WIDTH
1998   return new glyph_node(ci, tf, gcol, fcol, wid, state, div_nest_level);
1999 #else
2000   return new glyph_node(ci, tf, gcol, fcol, state, div_nest_level);
2001 #endif
2002 }
2003 
merge_self(node * nd)2004 node *glyph_node::merge_self(node *nd)
2005 {
2006   return nd->merge_glyph_node(this);
2007 }
2008 
character_type()2009 int glyph_node::character_type()
2010 {
2011   return tf->get_character_type(ci);
2012 }
2013 
add_self(node * n,hyphen_list ** p)2014 node *glyph_node::add_self(node *n, hyphen_list **p)
2015 {
2016   assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
2017   next = 0;
2018   node *nn;
2019   if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) {
2020     next = n;
2021     nn = this;
2022   }
2023   if ((*p)->hyphen)
2024     nn = nn->add_discretionary_hyphen();
2025   hyphen_list *pp = *p;
2026   *p = (*p)->next;
2027   delete pp;
2028   return nn;
2029 }
2030 
size()2031 units glyph_node::size()
2032 {
2033   return tf->get_size().to_units();
2034 }
2035 
get_hyphen_list(hyphen_list * tail,int * count)2036 hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail, int *count)
2037 {
2038   (*count)++;
2039   return new hyphen_list(ci->get_hyphenation_code(), tail);
2040 }
2041 
get_tfont()2042 tfont *node::get_tfont()
2043 {
2044   return 0;
2045 }
2046 
get_tfont()2047 tfont *glyph_node::get_tfont()
2048 {
2049   return tf;
2050 }
2051 
get_glyph_color()2052 color *node::get_glyph_color()
2053 {
2054   return 0;
2055 }
2056 
get_glyph_color()2057 color *glyph_node::get_glyph_color()
2058 {
2059   return gcol;
2060 }
2061 
get_fill_color()2062 color *node::get_fill_color()
2063 {
2064   return 0;
2065 }
2066 
get_fill_color()2067 color *glyph_node::get_fill_color()
2068 {
2069   return fcol;
2070 }
2071 
merge_glyph_node(glyph_node *)2072 node *node::merge_glyph_node(glyph_node *)
2073 {
2074   return 0;
2075 }
2076 
merge_glyph_node(glyph_node * gn)2077 node *glyph_node::merge_glyph_node(glyph_node *gn)
2078 {
2079   if (tf == gn->tf && gcol == gn->gcol && fcol == gn->fcol) {
2080     charinfo *lig;
2081     if ((lig = tf->get_lig(ci, gn->ci)) != 0) {
2082       node *next1 = next;
2083       next = 0;
2084       return new ligature_node(lig, tf, gcol, fcol, this, gn, state,
2085 			       gn->div_nest_level, next1);
2086     }
2087     hunits kern;
2088     if (tf->get_kern(ci, gn->ci, &kern)) {
2089       node *next1 = next;
2090       next = 0;
2091       return new kern_pair_node(kern, this, gn, state,
2092 				gn->div_nest_level, next1);
2093     }
2094   }
2095   return 0;
2096 }
2097 
2098 #ifdef STORE_WIDTH
2099 inline
2100 #endif
width()2101 hunits glyph_node::width()
2102 {
2103 #ifdef STORE_WIDTH
2104   return wid;
2105 #else
2106   return tf->get_width(ci);
2107 #endif
2108 }
2109 
last_char_node()2110 node *glyph_node::last_char_node()
2111 {
2112   return this;
2113 }
2114 
vertical_extent(vunits * min,vunits * max)2115 void glyph_node::vertical_extent(vunits *min, vunits *max)
2116 {
2117   *min = -tf->get_char_height(ci);
2118   *max = tf->get_char_depth(ci);
2119 }
2120 
skew()2121 hunits glyph_node::skew()
2122 {
2123   return tf->get_char_skew(ci);
2124 }
2125 
subscript_correction()2126 hunits glyph_node::subscript_correction()
2127 {
2128   return tf->get_subscript_correction(ci);
2129 }
2130 
italic_correction()2131 hunits glyph_node::italic_correction()
2132 {
2133   return tf->get_italic_correction(ci);
2134 }
2135 
left_italic_correction()2136 hunits glyph_node::left_italic_correction()
2137 {
2138   return tf->get_left_italic_correction(ci);
2139 }
2140 
get_hyphenation_type()2141 hyphenation_type glyph_node::get_hyphenation_type()
2142 {
2143   return HYPHEN_MIDDLE;
2144 }
2145 
ascii_print(ascii_output_file * ascii)2146 void glyph_node::ascii_print(ascii_output_file *ascii)
2147 {
2148   unsigned char c = ci->get_ascii_code();
2149   if (c != 0)
2150     ascii->outc(c);
2151   else
2152     ascii->outs(ci->nm.contents());
2153 }
2154 
debug_node()2155 void glyph_node::debug_node()
2156 {
2157   unsigned char c = ci->get_ascii_code();
2158   fprintf(stderr, "{ %s [", type());
2159   if (c)
2160     fprintf(stderr, "%c", c);
2161   else
2162     fprintf(stderr, "%s", ci->nm.contents());
2163   if (push_state)
2164     fprintf(stderr, " <push_state>");
2165   if (state)
2166     state->display_state();
2167   fprintf(stderr, " nest level %d", div_nest_level);
2168   fprintf(stderr, "]}\n");
2169   fflush(stderr);
2170 }
2171 
ligature_node(charinfo * c,tfont * t,color * gc,color * fc,node * gn1,node * gn2,statem * s,int pop,node * x)2172 ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
2173 			     node *gn1, node *gn2, statem *s,
2174 			     int pop, node *x)
2175 : glyph_node(c, t, gc, fc, s, pop, x), n1(gn1), n2(gn2)
2176 {
2177 }
2178 
2179 #ifdef STORE_WIDTH
ligature_node(charinfo * c,tfont * t,color * gc,color * fc,hunits w,node * gn1,node * gn2,statem * s,int pop,node * x)2180 ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
2181 			     hunits w, node *gn1, node *gn2, statem *s,
2182 			     int pop, node *x)
2183 : glyph_node(c, t, gc, fc, w, s, pop, x), n1(gn1), n2(gn2)
2184 {
2185 }
2186 #endif
2187 
~ligature_node()2188 ligature_node::~ligature_node()
2189 {
2190   delete n1;
2191   delete n2;
2192 }
2193 
copy()2194 node *ligature_node::copy()
2195 {
2196 #ifdef STORE_WIDTH
2197   return new ligature_node(ci, tf, gcol, fcol, wid, n1->copy(), n2->copy(),
2198 			   state, div_nest_level);
2199 #else
2200   return new ligature_node(ci, tf, gcol, fcol, n1->copy(), n2->copy(),
2201 			   state, div_nest_level);
2202 #endif
2203 }
2204 
ascii_print(ascii_output_file * ascii)2205 void ligature_node::ascii_print(ascii_output_file *ascii)
2206 {
2207   n1->ascii_print(ascii);
2208   n2->ascii_print(ascii);
2209 }
2210 
get_hyphen_list(hyphen_list * tail,int * count)2211 hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail, int *count)
2212 {
2213   hyphen_list *hl = n2->get_hyphen_list(tail, count);
2214   return n1->get_hyphen_list(hl, count);
2215 }
2216 
add_self(node * n,hyphen_list ** p)2217 node *ligature_node::add_self(node *n, hyphen_list **p)
2218 {
2219   n = n1->add_self(n, p);
2220   n = n2->add_self(n, p);
2221   n1 = n2 = 0;
2222   delete this;
2223   return n;
2224 }
2225 
kern_pair_node(hunits n,node * first,node * second,statem * s,int pop,node * x)2226 kern_pair_node::kern_pair_node(hunits n, node *first, node *second,
2227 			       statem* s, int pop, node *x)
2228 : node(x, s, pop), amount(n), n1(first), n2(second)
2229 {
2230 }
2231 
dbreak_node(node * n,node * p,statem * s,int pop,node * x)2232 dbreak_node::dbreak_node(node *n, node *p, statem *s, int pop, node *x)
2233 : node(x, s, pop), none(n), pre(p), post(0)
2234 {
2235 }
2236 
merge_glyph_node(glyph_node * gn)2237 node *dbreak_node::merge_glyph_node(glyph_node *gn)
2238 {
2239   glyph_node *gn2 = (glyph_node *)gn->copy();
2240   node *new_none = none ? none->merge_glyph_node(gn) : 0;
2241   node *new_post = post ? post->merge_glyph_node(gn2) : 0;
2242   if (new_none == 0 && new_post == 0) {
2243     delete gn2;
2244     return 0;
2245   }
2246   if (new_none != 0)
2247     none = new_none;
2248   else {
2249     gn->next = none;
2250     none = gn;
2251   }
2252   if (new_post != 0)
2253     post = new_post;
2254   else {
2255     gn2->next = post;
2256     post = gn2;
2257   }
2258   return this;
2259 }
2260 
merge_glyph_node(glyph_node * gn)2261 node *kern_pair_node::merge_glyph_node(glyph_node *gn)
2262 {
2263   node *nd = n2->merge_glyph_node(gn);
2264   if (nd == 0)
2265     return 0;
2266   n2 = nd;
2267   nd = n2->merge_self(n1);
2268   if (nd) {
2269     nd->next = next;
2270     n1 = 0;
2271     n2 = 0;
2272     delete this;
2273     return nd;
2274   }
2275   return this;
2276 }
2277 
italic_correction()2278 hunits kern_pair_node::italic_correction()
2279 {
2280   return n2->italic_correction();
2281 }
2282 
subscript_correction()2283 hunits kern_pair_node::subscript_correction()
2284 {
2285   return n2->subscript_correction();
2286 }
2287 
vertical_extent(vunits * min,vunits * max)2288 void kern_pair_node::vertical_extent(vunits *min, vunits *max)
2289 {
2290   n1->vertical_extent(min, max);
2291   vunits min2, max2;
2292   n2->vertical_extent(&min2, &max2);
2293   if (min2 < *min)
2294     *min = min2;
2295   if (max2 > *max)
2296     *max = max2;
2297 }
2298 
add_discretionary_hyphen()2299 node *kern_pair_node::add_discretionary_hyphen()
2300 {
2301   tfont *tf = n2->get_tfont();
2302   if (tf) {
2303     if (tf->contains(soft_hyphen_char)) {
2304       color *gcol = n2->get_glyph_color();
2305       color *fcol = n2->get_fill_color();
2306       node *next1 = next;
2307       next = 0;
2308       node *n = copy();
2309       glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol,
2310 				      state, div_nest_level);
2311       node *nn = n->merge_glyph_node(gn);
2312       if (nn == 0) {
2313 	gn->next = n;
2314 	nn = gn;
2315       }
2316       return new dbreak_node(this, nn, state, div_nest_level, next1);
2317     }
2318   }
2319   return this;
2320 }
2321 
~kern_pair_node()2322 kern_pair_node::~kern_pair_node()
2323 {
2324   if (n1 != 0)
2325     delete n1;
2326   if (n2 != 0)
2327     delete n2;
2328 }
2329 
~dbreak_node()2330 dbreak_node::~dbreak_node()
2331 {
2332   delete_node_list(pre);
2333   delete_node_list(post);
2334   delete_node_list(none);
2335 }
2336 
copy()2337 node *kern_pair_node::copy()
2338 {
2339   return new kern_pair_node(amount, n1->copy(), n2->copy(), state,
2340 			    div_nest_level);
2341 }
2342 
copy_node_list(node * n)2343 node *copy_node_list(node *n)
2344 {
2345   node *p = 0;
2346   while (n != 0) {
2347     node *nn = n->copy();
2348     nn->next = p;
2349     p = nn;
2350     n = n->next;
2351   }
2352   while (p != 0) {
2353     node *pp = p->next;
2354     p->next = n;
2355     n = p;
2356     p = pp;
2357   }
2358   return n;
2359 }
2360 
delete_node_list(node * n)2361 void delete_node_list(node *n)
2362 {
2363   while (n != 0) {
2364     node *tem = n;
2365     n = n->next;
2366     delete tem;
2367   }
2368 }
2369 
copy()2370 node *dbreak_node::copy()
2371 {
2372   dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre),
2373 				   state, div_nest_level);
2374   p->post = copy_node_list(post);
2375   return p;
2376 }
2377 
get_hyphen_list(hyphen_list * tail,int *)2378 hyphen_list *node::get_hyphen_list(hyphen_list *tail, int *)
2379 {
2380   return tail;
2381 }
2382 
get_hyphen_list(hyphen_list * tail,int * count)2383 hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail, int *count)
2384 {
2385   hyphen_list *hl = n2->get_hyphen_list(tail, count);
2386   return n1->get_hyphen_list(hl, count);
2387 }
2388 
2389 class hyphen_inhibitor_node : public node {
2390 public:
2391   hyphen_inhibitor_node(node * = 0);
2392   node *copy();
2393   int same(node *);
2394   const char *type();
2395   int force_tprint();
2396   int is_tag();
2397   hyphenation_type get_hyphenation_type();
2398 };
2399 
hyphen_inhibitor_node(node * nd)2400 hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd)
2401 {
2402 }
2403 
copy()2404 node *hyphen_inhibitor_node::copy()
2405 {
2406   return new hyphen_inhibitor_node;
2407 }
2408 
same(node *)2409 int hyphen_inhibitor_node::same(node *)
2410 {
2411   return 1;
2412 }
2413 
type()2414 const char *hyphen_inhibitor_node::type()
2415 {
2416   return "hyphen_inhibitor_node";
2417 }
2418 
force_tprint()2419 int hyphen_inhibitor_node::force_tprint()
2420 {
2421   return 0;
2422 }
2423 
is_tag()2424 int hyphen_inhibitor_node::is_tag()
2425 {
2426   return 0;
2427 }
2428 
get_hyphenation_type()2429 hyphenation_type hyphen_inhibitor_node::get_hyphenation_type()
2430 {
2431   return HYPHEN_INHIBIT;
2432 }
2433 
2434 /* add_discretionary_hyphen methods */
2435 
add_discretionary_hyphen()2436 node *dbreak_node::add_discretionary_hyphen()
2437 {
2438   if (post)
2439     post = post->add_discretionary_hyphen();
2440   if (none)
2441     none = none->add_discretionary_hyphen();
2442   return this;
2443 }
2444 
add_discretionary_hyphen()2445 node *node::add_discretionary_hyphen()
2446 {
2447   tfont *tf = get_tfont();
2448   if (!tf)
2449     return new hyphen_inhibitor_node(this);
2450   if (tf->contains(soft_hyphen_char)) {
2451     color *gcol = get_glyph_color();
2452     color *fcol = get_fill_color();
2453     node *next1 = next;
2454     next = 0;
2455     node *n = copy();
2456     glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol,
2457 				    state, div_nest_level);
2458     node *n1 = n->merge_glyph_node(gn);
2459     if (n1 == 0) {
2460       gn->next = n;
2461       n1 = gn;
2462     }
2463     return new dbreak_node(this, n1, state, div_nest_level, next1);
2464   }
2465   return this;
2466 }
2467 
merge_self(node *)2468 node *node::merge_self(node *)
2469 {
2470   return 0;
2471 }
2472 
add_self(node * n,hyphen_list **)2473 node *node::add_self(node *n, hyphen_list ** /*p*/)
2474 {
2475   next = n;
2476   return this;
2477 }
2478 
add_self(node * n,hyphen_list ** p)2479 node *kern_pair_node::add_self(node *n, hyphen_list **p)
2480 {
2481   n = n1->add_self(n, p);
2482   n = n2->add_self(n, p);
2483   n1 = n2 = 0;
2484   delete this;
2485   return n;
2486 }
2487 
width()2488 hunits node::width()
2489 {
2490   return H0;
2491 }
2492 
last_char_node()2493 node *node::last_char_node()
2494 {
2495   return 0;
2496 }
2497 
force_tprint()2498 int node::force_tprint()
2499 {
2500   return 0;
2501 }
2502 
is_tag()2503 int node::is_tag()
2504 {
2505   return 0;
2506 }
2507 
width()2508 hunits hmotion_node::width()
2509 {
2510   return n;
2511 }
2512 
size()2513 units node::size()
2514 {
2515   return points_to_units(10);
2516 }
2517 
debug_node()2518 void node::debug_node()
2519 {
2520   fprintf(stderr, "{ %s ", type());
2521   if (push_state)
2522     fprintf(stderr, " <push_state>");
2523   if (state)
2524     fprintf(stderr, " <state>");
2525   fprintf(stderr, " nest level %d", div_nest_level);
2526   fprintf(stderr, " }\n");
2527   fflush(stderr);
2528 }
2529 
debug_node_list()2530 void node::debug_node_list()
2531 {
2532   node *n = next;
2533 
2534   debug_node();
2535   while (n != 0) {
2536     n->debug_node();
2537     n = n->next;
2538   }
2539 }
2540 
width()2541 hunits kern_pair_node::width()
2542 {
2543   return n1->width() + n2->width() + amount;
2544 }
2545 
last_char_node()2546 node *kern_pair_node::last_char_node()
2547 {
2548   node *nd = n2->last_char_node();
2549   if (nd)
2550     return nd;
2551   return n1->last_char_node();
2552 }
2553 
width()2554 hunits dbreak_node::width()
2555 {
2556   hunits x = H0;
2557   for (node *n = none; n != 0; n = n->next)
2558     x += n->width();
2559   return x;
2560 }
2561 
last_char_node()2562 node *dbreak_node::last_char_node()
2563 {
2564   for (node *n = none; n; n = n->next) {
2565     node *last_node = n->last_char_node();
2566     if (last_node)
2567       return last_node;
2568   }
2569   return 0;
2570 }
2571 
italic_correction()2572 hunits dbreak_node::italic_correction()
2573 {
2574   return none ? none->italic_correction() : H0;
2575 }
2576 
subscript_correction()2577 hunits dbreak_node::subscript_correction()
2578 {
2579   return none ? none->subscript_correction() : H0;
2580 }
2581 
2582 class italic_corrected_node : public node {
2583   node *n;
2584   hunits x;
2585 public:
2586   italic_corrected_node(node *, hunits, statem *, int, node * = 0);
2587   ~italic_corrected_node();
2588   node *copy();
2589   void ascii_print(ascii_output_file *);
2590   void asciify(macro *);
2591   hunits width();
2592   node *last_char_node();
2593   void vertical_extent(vunits *, vunits *);
2594   int ends_sentence();
2595   int overlaps_horizontally();
2596   int overlaps_vertically();
2597   int same(node *);
2598   hyphenation_type get_hyphenation_type();
2599   tfont *get_tfont();
2600   hyphen_list *get_hyphen_list(hyphen_list *, int *);
2601   int character_type();
2602   void tprint(troff_output_file *);
2603   hunits subscript_correction();
2604   hunits skew();
2605   node *add_self(node *, hyphen_list **);
2606   const char *type();
2607   int force_tprint();
2608   int is_tag();
2609 };
2610 
add_italic_correction(hunits * wd)2611 node *node::add_italic_correction(hunits *wd)
2612 {
2613   hunits ic = italic_correction();
2614   if (ic.is_zero())
2615     return this;
2616   else {
2617     node *next1 = next;
2618     next = 0;
2619     *wd += ic;
2620     return new italic_corrected_node(this, ic, state, div_nest_level, next1);
2621   }
2622 }
2623 
italic_corrected_node(node * nn,hunits xx,statem * s,int pop,node * p)2624 italic_corrected_node::italic_corrected_node(node *nn, hunits xx, statem *s,
2625 					     int pop, node *p)
2626 : node(p, s, pop), n(nn), x(xx)
2627 {
2628   assert(n != 0);
2629 }
2630 
~italic_corrected_node()2631 italic_corrected_node::~italic_corrected_node()
2632 {
2633   delete n;
2634 }
2635 
copy()2636 node *italic_corrected_node::copy()
2637 {
2638   return new italic_corrected_node(n->copy(), x, state, div_nest_level);
2639 }
2640 
width()2641 hunits italic_corrected_node::width()
2642 {
2643   return n->width() + x;
2644 }
2645 
vertical_extent(vunits * min,vunits * max)2646 void italic_corrected_node::vertical_extent(vunits *min, vunits *max)
2647 {
2648   n->vertical_extent(min, max);
2649 }
2650 
tprint(troff_output_file * out)2651 void italic_corrected_node::tprint(troff_output_file *out)
2652 {
2653   n->tprint(out);
2654   out->right(x);
2655 }
2656 
skew()2657 hunits italic_corrected_node::skew()
2658 {
2659   return n->skew() - x/2;
2660 }
2661 
subscript_correction()2662 hunits italic_corrected_node::subscript_correction()
2663 {
2664   return n->subscript_correction() - x;
2665 }
2666 
ascii_print(ascii_output_file * out)2667 void italic_corrected_node::ascii_print(ascii_output_file *out)
2668 {
2669   n->ascii_print(out);
2670 }
2671 
ends_sentence()2672 int italic_corrected_node::ends_sentence()
2673 {
2674   return n->ends_sentence();
2675 }
2676 
overlaps_horizontally()2677 int italic_corrected_node::overlaps_horizontally()
2678 {
2679   return n->overlaps_horizontally();
2680 }
2681 
overlaps_vertically()2682 int italic_corrected_node::overlaps_vertically()
2683 {
2684   return n->overlaps_vertically();
2685 }
2686 
last_char_node()2687 node *italic_corrected_node::last_char_node()
2688 {
2689   return n->last_char_node();
2690 }
2691 
get_tfont()2692 tfont *italic_corrected_node::get_tfont()
2693 {
2694   return n->get_tfont();
2695 }
2696 
get_hyphenation_type()2697 hyphenation_type italic_corrected_node::get_hyphenation_type()
2698 {
2699   return n->get_hyphenation_type();
2700 }
2701 
add_self(node * nd,hyphen_list ** p)2702 node *italic_corrected_node::add_self(node *nd, hyphen_list **p)
2703 {
2704   nd = n->add_self(nd, p);
2705   hunits not_interested;
2706   nd = nd->add_italic_correction(&not_interested);
2707   n = 0;
2708   delete this;
2709   return nd;
2710 }
2711 
get_hyphen_list(hyphen_list * tail,int * count)2712 hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail,
2713 						    int *count)
2714 {
2715   return n->get_hyphen_list(tail, count);
2716 }
2717 
character_type()2718 int italic_corrected_node::character_type()
2719 {
2720   return n->character_type();
2721 }
2722 
2723 class break_char_node : public node {
2724   node *ch;
2725   char break_code;
2726   color *col;
2727 public:
2728   break_char_node(node *, int, color *, node * = 0);
2729   break_char_node(node *, int, color *, statem *, int, node * = 0);
2730   ~break_char_node();
2731   node *copy();
2732   hunits width();
2733   vunits vertical_width();
2734   node *last_char_node();
2735   int character_type();
2736   int ends_sentence();
2737   node *add_self(node *, hyphen_list **);
2738   hyphen_list *get_hyphen_list(hyphen_list *, int *);
2739   void tprint(troff_output_file *);
2740   void zero_width_tprint(troff_output_file *);
2741   void ascii_print(ascii_output_file *);
2742   void asciify(macro *);
2743   hyphenation_type get_hyphenation_type();
2744   int overlaps_vertically();
2745   int overlaps_horizontally();
2746   units size();
2747   tfont *get_tfont();
2748   int same(node *);
2749   const char *type();
2750   int force_tprint();
2751   int is_tag();
2752 };
2753 
break_char_node(node * n,int bc,color * c,node * x)2754 break_char_node::break_char_node(node *n, int bc, color *c, node *x)
2755 : node(x), ch(n), break_code(bc), col(c)
2756 {
2757 }
2758 
break_char_node(node * n,int bc,color * c,statem * s,int pop,node * x)2759 break_char_node::break_char_node(node *n, int bc, color *c, statem *s,
2760 				 int pop, node *x)
2761 : node(x, s, pop), ch(n), break_code(bc), col(c)
2762 {
2763 }
2764 
~break_char_node()2765 break_char_node::~break_char_node()
2766 {
2767   delete ch;
2768 }
2769 
copy()2770 node *break_char_node::copy()
2771 {
2772   return new break_char_node(ch->copy(), break_code, col, state,
2773 			     div_nest_level);
2774 }
2775 
width()2776 hunits break_char_node::width()
2777 {
2778   return ch->width();
2779 }
2780 
vertical_width()2781 vunits break_char_node::vertical_width()
2782 {
2783   return ch->vertical_width();
2784 }
2785 
last_char_node()2786 node *break_char_node::last_char_node()
2787 {
2788   return ch->last_char_node();
2789 }
2790 
character_type()2791 int break_char_node::character_type()
2792 {
2793   return ch->character_type();
2794 }
2795 
ends_sentence()2796 int break_char_node::ends_sentence()
2797 {
2798   return ch->ends_sentence();
2799 }
2800 
add_self(node * n,hyphen_list ** p)2801 node *break_char_node::add_self(node *n, hyphen_list **p)
2802 {
2803   assert((*p)->hyphenation_code == 0);
2804   if ((*p)->breakable && (break_code & 1)) {
2805     n = new space_node(H0, col, n);
2806     n->freeze_space();
2807   }
2808   next = n;
2809   n = this;
2810   if ((*p)->breakable && (break_code & 2)) {
2811     n = new space_node(H0, col, n);
2812     n->freeze_space();
2813   }
2814   hyphen_list *pp = *p;
2815   *p = (*p)->next;
2816   delete pp;
2817   return n;
2818 }
2819 
get_hyphen_list(hyphen_list * tail,int *)2820 hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail, int *)
2821 {
2822   return new hyphen_list(0, tail);
2823 }
2824 
get_hyphenation_type()2825 hyphenation_type break_char_node::get_hyphenation_type()
2826 {
2827   return HYPHEN_MIDDLE;
2828 }
2829 
ascii_print(ascii_output_file * ascii)2830 void break_char_node::ascii_print(ascii_output_file *ascii)
2831 {
2832   ch->ascii_print(ascii);
2833 }
2834 
overlaps_vertically()2835 int break_char_node::overlaps_vertically()
2836 {
2837   return ch->overlaps_vertically();
2838 }
2839 
overlaps_horizontally()2840 int break_char_node::overlaps_horizontally()
2841 {
2842   return ch->overlaps_horizontally();
2843 }
2844 
size()2845 units break_char_node::size()
2846 {
2847   return ch->size();
2848 }
2849 
get_tfont()2850 tfont *break_char_node::get_tfont()
2851 {
2852   return ch->get_tfont();
2853 }
2854 
copy()2855 node *extra_size_node::copy()
2856 {
2857   return new extra_size_node(n, state, div_nest_level);
2858 }
2859 
extra_size_node(vunits i,statem * s,int pop)2860 extra_size_node::extra_size_node(vunits i, statem *s, int pop)
2861 : node(0, s, pop), n(i)
2862 {
2863 }
2864 
extra_size_node(vunits i)2865 extra_size_node::extra_size_node(vunits i)
2866 : n(i)
2867 {
2868 }
2869 
copy()2870 node *vertical_size_node::copy()
2871 {
2872   return new vertical_size_node(n, state, div_nest_level);
2873 }
2874 
vertical_size_node(vunits i,statem * s,int pop)2875 vertical_size_node::vertical_size_node(vunits i, statem *s, int pop)
2876 : node(0, s, pop), n(i)
2877 {
2878 }
2879 
vertical_size_node(vunits i)2880 vertical_size_node::vertical_size_node(vunits i)
2881 : n(i)
2882 {
2883 }
2884 
copy()2885 node *hmotion_node::copy()
2886 {
2887   return new hmotion_node(n, was_tab, unformat, col, state, div_nest_level);
2888 }
2889 
copy()2890 node *space_char_hmotion_node::copy()
2891 {
2892   return new space_char_hmotion_node(n, col, state, div_nest_level);
2893 }
2894 
vmotion_node(vunits i,color * c)2895 vmotion_node::vmotion_node(vunits i, color *c)
2896 : n(i), col(c)
2897 {
2898 }
2899 
vmotion_node(vunits i,color * c,statem * s,int pop)2900 vmotion_node::vmotion_node(vunits i, color *c, statem *s, int pop)
2901 : node(0, s, pop), n(i), col(c)
2902 {
2903 }
2904 
copy()2905 node *vmotion_node::copy()
2906 {
2907   return new vmotion_node(n, col, state, div_nest_level);
2908 }
2909 
copy()2910 node *dummy_node::copy()
2911 {
2912   return new dummy_node;
2913 }
2914 
copy()2915 node *transparent_dummy_node::copy()
2916 {
2917   return new transparent_dummy_node;
2918 }
2919 
~hline_node()2920 hline_node::~hline_node()
2921 {
2922   if (n)
2923     delete n;
2924 }
2925 
hline_node(hunits i,node * c,node * nxt)2926 hline_node::hline_node(hunits i, node *c, node *nxt)
2927 : node(nxt), x(i), n(c)
2928 {
2929 }
2930 
hline_node(hunits i,node * c,statem * s,int pop,node * nxt)2931 hline_node::hline_node(hunits i, node *c, statem *s, int pop, node *nxt)
2932 : node(nxt, s, pop), x(i), n(c)
2933 {
2934 }
2935 
copy()2936 node *hline_node::copy()
2937 {
2938   return new hline_node(x, n ? n->copy() : 0, state, div_nest_level);
2939 }
2940 
width()2941 hunits hline_node::width()
2942 {
2943   return x < H0 ? H0 : x;
2944 }
2945 
vline_node(vunits i,node * c,node * nxt)2946 vline_node::vline_node(vunits i, node *c, node *nxt)
2947 : node(nxt), x(i), n(c)
2948 {
2949 }
2950 
vline_node(vunits i,node * c,statem * s,int pop,node * nxt)2951 vline_node::vline_node(vunits i, node *c, statem *s, int pop, node *nxt)
2952 : node(nxt, s, pop), x(i), n(c)
2953 {
2954 }
2955 
~vline_node()2956 vline_node::~vline_node()
2957 {
2958   if (n)
2959     delete n;
2960 }
2961 
copy()2962 node *vline_node::copy()
2963 {
2964   return new vline_node(x, n ? n->copy() : 0, state, div_nest_level);
2965 }
2966 
width()2967 hunits vline_node::width()
2968 {
2969   return n == 0 ? H0 : n->width();
2970 }
2971 
zero_width_node(node * nd,statem * s,int pop)2972 zero_width_node::zero_width_node(node *nd, statem *s, int pop)
2973 : node(0, s, pop), n(nd)
2974 {
2975 }
2976 
zero_width_node(node * nd)2977 zero_width_node::zero_width_node(node *nd)
2978 : n(nd)
2979 {
2980 }
2981 
~zero_width_node()2982 zero_width_node::~zero_width_node()
2983 {
2984   delete_node_list(n);
2985 }
2986 
copy()2987 node *zero_width_node::copy()
2988 {
2989   return new zero_width_node(copy_node_list(n), state, div_nest_level);
2990 }
2991 
node_list_character_type(node * p)2992 int node_list_character_type(node *p)
2993 {
2994   int t = 0;
2995   for (; p; p = p->next)
2996     t |= p->character_type();
2997   return t;
2998 }
2999 
character_type()3000 int zero_width_node::character_type()
3001 {
3002   return node_list_character_type(n);
3003 }
3004 
node_list_vertical_extent(node * p,vunits * min,vunits * max)3005 void node_list_vertical_extent(node *p, vunits *min, vunits *max)
3006 {
3007   *min = V0;
3008   *max = V0;
3009   vunits cur_vpos = V0;
3010   vunits v1, v2;
3011   for (; p; p = p->next) {
3012     p->vertical_extent(&v1, &v2);
3013     v1 += cur_vpos;
3014     if (v1 < *min)
3015       *min = v1;
3016     v2 += cur_vpos;
3017     if (v2 > *max)
3018       *max = v2;
3019     cur_vpos += p->vertical_width();
3020   }
3021 }
3022 
vertical_extent(vunits * min,vunits * max)3023 void zero_width_node::vertical_extent(vunits *min, vunits *max)
3024 {
3025   node_list_vertical_extent(n, min, max);
3026 }
3027 
overstrike_node()3028 overstrike_node::overstrike_node()
3029 : list(0), max_width(H0)
3030 {
3031 }
3032 
overstrike_node(statem * s,int pop)3033 overstrike_node::overstrike_node(statem *s, int pop)
3034 : node(0, s, pop), list(0), max_width(H0)
3035 {
3036 }
3037 
~overstrike_node()3038 overstrike_node::~overstrike_node()
3039 {
3040   delete_node_list(list);
3041 }
3042 
copy()3043 node *overstrike_node::copy()
3044 {
3045   overstrike_node *on = new overstrike_node(state, div_nest_level);
3046   for (node *tem = list; tem; tem = tem->next)
3047     on->overstrike(tem->copy());
3048   return on;
3049 }
3050 
overstrike(node * n)3051 void overstrike_node::overstrike(node *n)
3052 {
3053   if (n == 0)
3054     return;
3055   hunits w = n->width();
3056   if (w > max_width)
3057     max_width = w;
3058   node **p;
3059   for (p = &list; *p; p = &(*p)->next)
3060     ;
3061   n->next = 0;
3062   *p = n;
3063 }
3064 
width()3065 hunits overstrike_node::width()
3066 {
3067   return max_width;
3068 }
3069 
bracket_node()3070 bracket_node::bracket_node()
3071 : list(0), max_width(H0)
3072 {
3073 }
3074 
bracket_node(statem * s,int pop)3075 bracket_node::bracket_node(statem *s, int pop)
3076 : node(0, s, pop), list(0), max_width(H0)
3077 {
3078 }
3079 
~bracket_node()3080 bracket_node::~bracket_node()
3081 {
3082   delete_node_list(list);
3083 }
3084 
copy()3085 node *bracket_node::copy()
3086 {
3087   bracket_node *on = new bracket_node(state, div_nest_level);
3088   node *last_node = 0;
3089   node *tem;
3090   if (list)
3091     list->last = 0;
3092   for (tem = list; tem; tem = tem->next) {
3093     if (tem->next)
3094       tem->next->last = tem;
3095     last_node = tem;
3096   }
3097   for (tem = last_node; tem; tem = tem->last)
3098     on->bracket(tem->copy());
3099   return on;
3100 }
3101 
bracket(node * n)3102 void bracket_node::bracket(node *n)
3103 {
3104   if (n == 0)
3105     return;
3106   hunits w = n->width();
3107   if (w > max_width)
3108     max_width = w;
3109   n->next = list;
3110   list = n;
3111 }
3112 
width()3113 hunits bracket_node::width()
3114 {
3115   return max_width;
3116 }
3117 
nspaces()3118 int node::nspaces()
3119 {
3120   return 0;
3121 }
3122 
merge_space(hunits,hunits,hunits)3123 int node::merge_space(hunits, hunits, hunits)
3124 {
3125   return 0;
3126 }
3127 
3128 #if 0
3129 space_node *space_node::free_list = 0;
3130 
3131 void *space_node::operator new(size_t n)
3132 {
3133   assert(n == sizeof(space_node));
3134   if (!free_list) {
3135     free_list = (space_node *)new char[sizeof(space_node)*BLOCK];
3136     for (int i = 0; i < BLOCK - 1; i++)
3137       free_list[i].next = free_list + i + 1;
3138     free_list[BLOCK-1].next = 0;
3139   }
3140   space_node *p = free_list;
3141   free_list = (space_node *)(free_list->next);
3142   p->next = 0;
3143   return p;
3144 }
3145 
3146 inline void space_node::operator delete(void *p)
3147 {
3148   if (p) {
3149     ((space_node *)p)->next = free_list;
3150     free_list = (space_node *)p;
3151   }
3152 }
3153 #endif
3154 
space_node(hunits nn,color * c,node * p)3155 space_node::space_node(hunits nn, color *c, node *p)
3156 : node(p, 0, 0), n(nn), set(0), was_escape_colon(0), col(c)
3157 {
3158 }
3159 
space_node(hunits nn,color * c,statem * s,int pop,node * p)3160 space_node::space_node(hunits nn, color *c, statem *s, int pop, node *p)
3161 : node(p, s, pop), n(nn), set(0), was_escape_colon(0), col(c)
3162 {
3163 }
3164 
space_node(hunits nn,int s,int flag,color * c,statem * st,int pop,node * p)3165 space_node::space_node(hunits nn, int s, int flag, color *c, statem *st,
3166 		       int pop, node *p)
3167 : node(p, st, pop), n(nn), set(s), was_escape_colon(flag), col(c)
3168 {
3169 }
3170 
3171 #if 0
3172 space_node::~space_node()
3173 {
3174 }
3175 #endif
3176 
copy()3177 node *space_node::copy()
3178 {
3179   return new space_node(n, set, was_escape_colon, col, state, div_nest_level);
3180 }
3181 
force_tprint()3182 int space_node::force_tprint()
3183 {
3184   return 0;
3185 }
3186 
is_tag()3187 int space_node::is_tag()
3188 {
3189   return 0;
3190 }
3191 
nspaces()3192 int space_node::nspaces()
3193 {
3194   return set ? 0 : 1;
3195 }
3196 
merge_space(hunits h,hunits,hunits)3197 int space_node::merge_space(hunits h, hunits, hunits)
3198 {
3199   n += h;
3200   return 1;
3201 }
3202 
width()3203 hunits space_node::width()
3204 {
3205   return n;
3206 }
3207 
spread_space(int *,hunits *)3208 void node::spread_space(int*, hunits*)
3209 {
3210 }
3211 
spread_space(int * n_spaces,hunits * desired_space)3212 void space_node::spread_space(int *n_spaces, hunits *desired_space)
3213 {
3214   if (!set) {
3215     assert(*n_spaces > 0);
3216     if (*n_spaces == 1) {
3217       n += *desired_space;
3218       *desired_space = H0;
3219     }
3220     else {
3221       hunits extra = *desired_space / *n_spaces;
3222       *desired_space -= extra;
3223       n += extra;
3224     }
3225     *n_spaces -= 1;
3226     set = 1;
3227   }
3228 }
3229 
freeze_space()3230 void node::freeze_space()
3231 {
3232 }
3233 
freeze_space()3234 void space_node::freeze_space()
3235 {
3236   set = 1;
3237 }
3238 
is_escape_colon()3239 void node::is_escape_colon()
3240 {
3241 }
3242 
is_escape_colon()3243 void space_node::is_escape_colon()
3244 {
3245   was_escape_colon = 1;
3246 }
3247 
diverted_space_node(vunits d,statem * s,int pop,node * p)3248 diverted_space_node::diverted_space_node(vunits d, statem *s, int pop,
3249 					 node *p)
3250 : node(p, s, pop), n(d)
3251 {
3252 }
3253 
diverted_space_node(vunits d,node * p)3254 diverted_space_node::diverted_space_node(vunits d, node *p)
3255 : node(p), n(d)
3256 {
3257 }
3258 
copy()3259 node *diverted_space_node::copy()
3260 {
3261   return new diverted_space_node(n, state, div_nest_level);
3262 }
3263 
diverted_copy_file_node(symbol s,statem * st,int pop,node * p)3264 diverted_copy_file_node::diverted_copy_file_node(symbol s, statem *st,
3265 						 int pop, node *p)
3266 : node(p, st, pop), filename(s)
3267 {
3268 }
3269 
diverted_copy_file_node(symbol s,node * p)3270 diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p)
3271 : node(p), filename(s)
3272 {
3273 }
3274 
copy()3275 node *diverted_copy_file_node::copy()
3276 {
3277   return new diverted_copy_file_node(filename, state, div_nest_level);
3278 }
3279 
ends_sentence()3280 int node::ends_sentence()
3281 {
3282   return 0;
3283 }
3284 
ends_sentence()3285 int kern_pair_node::ends_sentence()
3286 {
3287   switch (n2->ends_sentence()) {
3288   case 0:
3289     return 0;
3290   case 1:
3291     return 1;
3292   case 2:
3293     break;
3294   default:
3295     assert(0);
3296   }
3297   return n1->ends_sentence();
3298 }
3299 
node_list_ends_sentence(node * n)3300 int node_list_ends_sentence(node *n)
3301 {
3302   for (; n != 0; n = n->next)
3303     switch (n->ends_sentence()) {
3304     case 0:
3305       return 0;
3306     case 1:
3307       return 1;
3308     case 2:
3309       break;
3310     default:
3311       assert(0);
3312     }
3313   return 2;
3314 }
3315 
ends_sentence()3316 int dbreak_node::ends_sentence()
3317 {
3318   return node_list_ends_sentence(none);
3319 }
3320 
overlaps_horizontally()3321 int node::overlaps_horizontally()
3322 {
3323   return 0;
3324 }
3325 
overlaps_vertically()3326 int node::overlaps_vertically()
3327 {
3328   return 0;
3329 }
3330 
discardable()3331 int node::discardable()
3332 {
3333   return 0;
3334 }
3335 
discardable()3336 int space_node::discardable()
3337 {
3338   return set ? 0 : 1;
3339 }
3340 
vertical_width()3341 vunits node::vertical_width()
3342 {
3343   return V0;
3344 }
3345 
vertical_width()3346 vunits vline_node::vertical_width()
3347 {
3348   return x;
3349 }
3350 
vertical_width()3351 vunits vmotion_node::vertical_width()
3352 {
3353   return n;
3354 }
3355 
set_unformat_flag()3356 int node::set_unformat_flag()
3357 {
3358   return 1;
3359 }
3360 
character_type()3361 int node::character_type()
3362 {
3363   return 0;
3364 }
3365 
subscript_correction()3366 hunits node::subscript_correction()
3367 {
3368   return H0;
3369 }
3370 
italic_correction()3371 hunits node::italic_correction()
3372 {
3373   return H0;
3374 }
3375 
left_italic_correction()3376 hunits node::left_italic_correction()
3377 {
3378   return H0;
3379 }
3380 
skew()3381 hunits node::skew()
3382 {
3383   return H0;
3384 }
3385 
3386 /* vertical_extent methods */
3387 
vertical_extent(vunits * min,vunits * max)3388 void node::vertical_extent(vunits *min, vunits *max)
3389 {
3390   vunits v = vertical_width();
3391   if (v < V0) {
3392     *min = v;
3393     *max = V0;
3394   }
3395   else {
3396     *max = v;
3397     *min = V0;
3398   }
3399 }
3400 
vertical_extent(vunits * min,vunits * max)3401 void vline_node::vertical_extent(vunits *min, vunits *max)
3402 {
3403   if (n == 0)
3404     node::vertical_extent(min, max);
3405   else {
3406     vunits cmin, cmax;
3407     n->vertical_extent(&cmin, &cmax);
3408     vunits h = n->size();
3409     if (x < V0) {
3410       if (-x < h) {
3411 	*min = x;
3412 	*max = V0;
3413       }
3414       else {
3415 	// we print the first character and then move up, so
3416 	*max = cmax;
3417 	// we print the last character and then move up h
3418 	*min = cmin + h;
3419 	if (*min > V0)
3420 	  *min = V0;
3421 	*min += x;
3422       }
3423     }
3424     else {
3425       if (x < h) {
3426 	*max = x;
3427 	*min = V0;
3428       }
3429       else {
3430 	// we move down by h and then print the first character, so
3431 	*min = cmin + h;
3432 	if (*min > V0)
3433 	  *min = V0;
3434 	*max = x + cmax;
3435       }
3436     }
3437   }
3438 }
3439 
3440 /* ascii_print methods */
3441 
ascii_print_reverse_node_list(ascii_output_file * ascii,node * n)3442 static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n)
3443 {
3444   if (n == 0)
3445     return;
3446   ascii_print_reverse_node_list(ascii, n->next);
3447   n->ascii_print(ascii);
3448 }
3449 
ascii_print(ascii_output_file * ascii)3450 void dbreak_node::ascii_print(ascii_output_file *ascii)
3451 {
3452   ascii_print_reverse_node_list(ascii, none);
3453 }
3454 
ascii_print(ascii_output_file * ascii)3455 void kern_pair_node::ascii_print(ascii_output_file *ascii)
3456 {
3457   n1->ascii_print(ascii);
3458   n2->ascii_print(ascii);
3459 }
3460 
ascii_print(ascii_output_file *)3461 void node::ascii_print(ascii_output_file *)
3462 {
3463 }
3464 
ascii_print(ascii_output_file * ascii)3465 void space_node::ascii_print(ascii_output_file *ascii)
3466 {
3467   if (!n.is_zero())
3468     ascii->outc(' ');
3469 }
3470 
ascii_print(ascii_output_file * ascii)3471 void hmotion_node::ascii_print(ascii_output_file *ascii)
3472 {
3473   // this is pretty arbitrary
3474   if (n >= points_to_units(2))
3475     ascii->outc(' ');
3476 }
3477 
ascii_print(ascii_output_file * ascii)3478 void space_char_hmotion_node::ascii_print(ascii_output_file *ascii)
3479 {
3480   ascii->outc(' ');
3481 }
3482 
3483 /* asciify methods */
3484 
asciify(macro * m)3485 void node::asciify(macro *m)
3486 {
3487   m->append(this);
3488 }
3489 
asciify(macro * m)3490 void glyph_node::asciify(macro *m)
3491 {
3492   unsigned char c = ci->get_asciify_code();
3493   if (c == 0)
3494     c = ci->get_ascii_code();
3495   if (c != 0) {
3496     m->append(c);
3497     delete this;
3498   }
3499   else
3500     m->append(this);
3501 }
3502 
asciify(macro * m)3503 void kern_pair_node::asciify(macro *m)
3504 {
3505   n1->asciify(m);
3506   n2->asciify(m);
3507   n1 = n2 = 0;
3508   delete this;
3509 }
3510 
asciify_reverse_node_list(macro * m,node * n)3511 static void asciify_reverse_node_list(macro *m, node *n)
3512 {
3513   if (n == 0)
3514     return;
3515   asciify_reverse_node_list(m, n->next);
3516   n->asciify(m);
3517 }
3518 
asciify(macro * m)3519 void dbreak_node::asciify(macro *m)
3520 {
3521   asciify_reverse_node_list(m, none);
3522   none = 0;
3523   delete this;
3524 }
3525 
asciify(macro * m)3526 void ligature_node::asciify(macro *m)
3527 {
3528   n1->asciify(m);
3529   n2->asciify(m);
3530   n1 = n2 = 0;
3531   delete this;
3532 }
3533 
asciify(macro * m)3534 void break_char_node::asciify(macro *m)
3535 {
3536   ch->asciify(m);
3537   ch = 0;
3538   delete this;
3539 }
3540 
asciify(macro * m)3541 void italic_corrected_node::asciify(macro *m)
3542 {
3543   n->asciify(m);
3544   n = 0;
3545   delete this;
3546 }
3547 
asciify(macro * m)3548 void left_italic_corrected_node::asciify(macro *m)
3549 {
3550   if (n) {
3551     n->asciify(m);
3552     n = 0;
3553   }
3554   delete this;
3555 }
3556 
asciify(macro * m)3557 void hmotion_node::asciify(macro *m)
3558 {
3559   if (was_tab) {
3560     m->append('\t');
3561     delete this;
3562   }
3563   else
3564     m->append(this);
3565 }
3566 
space_char_hmotion_node(hunits i,color * c,statem * s,int pop,node * nxt)3567 space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c,
3568 						 statem *s, int pop,
3569 						 node *nxt)
3570 : hmotion_node(i, c, s, pop, nxt)
3571 {
3572 }
3573 
space_char_hmotion_node(hunits i,color * c,node * nxt)3574 space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c,
3575  						 node *nxt)
3576 : hmotion_node(i, c, 0, 0, nxt)
3577 {
3578 }
3579 
asciify(macro * m)3580 void space_char_hmotion_node::asciify(macro *m)
3581 {
3582   m->append(ESCAPE_SPACE);
3583   delete this;
3584 }
3585 
asciify(macro * m)3586 void space_node::asciify(macro *m)
3587 {
3588   if (was_escape_colon) {
3589     m->append(ESCAPE_COLON);
3590     delete this;
3591   }
3592   else
3593     m->append(this);
3594 }
3595 
asciify(macro * m)3596 void word_space_node::asciify(macro *m)
3597 {
3598   for (width_list *w = orig_width; w; w = w->next)
3599     m->append(' ');
3600   delete this;
3601 }
3602 
asciify(macro * m)3603 void unbreakable_space_node::asciify(macro *m)
3604 {
3605   m->append(ESCAPE_TILDE);
3606   delete this;
3607 }
3608 
asciify(macro *)3609 void line_start_node::asciify(macro *)
3610 {
3611   delete this;
3612 }
3613 
asciify(macro *)3614 void vertical_size_node::asciify(macro *)
3615 {
3616   delete this;
3617 }
3618 
get_breakpoints(hunits,int,breakpoint * rest,int)3619 breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/,
3620 				  breakpoint *rest, int /*is_inner*/)
3621 {
3622   return rest;
3623 }
3624 
nbreaks()3625 int node::nbreaks()
3626 {
3627   return 0;
3628 }
3629 
get_breakpoints(hunits wd,int ns,breakpoint * rest,int is_inner)3630 breakpoint *space_node::get_breakpoints(hunits wd, int ns,
3631 					breakpoint *rest, int is_inner)
3632 {
3633   if (next && next->discardable())
3634     return rest;
3635   breakpoint *bp = new breakpoint;
3636   bp->next = rest;
3637   bp->width = wd;
3638   bp->nspaces = ns;
3639   bp->hyphenated = 0;
3640   if (is_inner) {
3641     assert(rest != 0);
3642     bp->index = rest->index + 1;
3643     bp->nd = rest->nd;
3644   }
3645   else {
3646     bp->nd = this;
3647     bp->index = 0;
3648   }
3649   return bp;
3650 }
3651 
nbreaks()3652 int space_node::nbreaks()
3653 {
3654   if (next && next->discardable())
3655     return 0;
3656   else
3657     return 1;
3658 }
3659 
node_list_get_breakpoints(node * p,hunits * widthp,int ns,breakpoint * rest)3660 static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp,
3661 					     int ns, breakpoint *rest)
3662 {
3663   if (p != 0) {
3664     rest = p->get_breakpoints(*widthp,
3665 			      ns,
3666 			      node_list_get_breakpoints(p->next, widthp, ns,
3667 							rest),
3668 			      1);
3669     *widthp += p->width();
3670   }
3671   return rest;
3672 }
3673 
get_breakpoints(hunits wd,int ns,breakpoint * rest,int is_inner)3674 breakpoint *dbreak_node::get_breakpoints(hunits wd, int ns,
3675 					 breakpoint *rest, int is_inner)
3676 {
3677   breakpoint *bp = new breakpoint;
3678   bp->next = rest;
3679   bp->width = wd;
3680   for (node *tem = pre; tem != 0; tem = tem->next)
3681     bp->width += tem->width();
3682   bp->nspaces = ns;
3683   bp->hyphenated = 1;
3684   if (is_inner) {
3685     assert(rest != 0);
3686     bp->index = rest->index + 1;
3687     bp->nd = rest->nd;
3688   }
3689   else {
3690     bp->nd = this;
3691     bp->index = 0;
3692   }
3693   return node_list_get_breakpoints(none, &wd, ns, bp);
3694 }
3695 
nbreaks()3696 int dbreak_node::nbreaks()
3697 {
3698   int i = 1;
3699   for (node *tem = none; tem != 0; tem = tem->next)
3700     i += tem->nbreaks();
3701   return i;
3702 }
3703 
split(int,node **,node **)3704 void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/)
3705 {
3706   assert(0);
3707 }
3708 
split(int where,node ** pre,node ** post)3709 void space_node::split(int where, node **pre, node **post)
3710 {
3711   assert(where == 0);
3712   *pre = next;
3713   *post = 0;
3714   delete this;
3715 }
3716 
node_list_split(node * p,int * wherep,node ** prep,node ** postp)3717 static void node_list_split(node *p, int *wherep, node **prep, node **postp)
3718 {
3719   if (p == 0)
3720     return;
3721   int nb = p->nbreaks();
3722   node_list_split(p->next, wherep, prep, postp);
3723   if (*wherep < 0) {
3724     p->next = *postp;
3725     *postp = p;
3726   }
3727   else if (*wherep < nb) {
3728     p->next = *prep;
3729     p->split(*wherep, prep, postp);
3730   }
3731   else {
3732     p->next = *prep;
3733     *prep = p;
3734   }
3735   *wherep -= nb;
3736 }
3737 
split(int where,node ** prep,node ** postp)3738 void dbreak_node::split(int where, node **prep, node **postp)
3739 {
3740   assert(where >= 0);
3741   if (where == 0) {
3742     *postp = post;
3743     post = 0;
3744     if (pre == 0)
3745       *prep = next;
3746     else {
3747       node *tem;
3748       for (tem = pre; tem->next != 0; tem = tem->next)
3749 	;
3750       tem->next = next;
3751       *prep = pre;
3752     }
3753     pre = 0;
3754     delete this;
3755   }
3756   else {
3757     *prep = next;
3758     where -= 1;
3759     node_list_split(none, &where, prep, postp);
3760     none = 0;
3761     delete this;
3762   }
3763 }
3764 
get_hyphenation_type()3765 hyphenation_type node::get_hyphenation_type()
3766 {
3767   return HYPHEN_BOUNDARY;
3768 }
3769 
get_hyphenation_type()3770 hyphenation_type dbreak_node::get_hyphenation_type()
3771 {
3772   return HYPHEN_INHIBIT;
3773 }
3774 
get_hyphenation_type()3775 hyphenation_type kern_pair_node::get_hyphenation_type()
3776 {
3777   return HYPHEN_MIDDLE;
3778 }
3779 
get_hyphenation_type()3780 hyphenation_type dummy_node::get_hyphenation_type()
3781 {
3782   return HYPHEN_MIDDLE;
3783 }
3784 
get_hyphenation_type()3785 hyphenation_type transparent_dummy_node::get_hyphenation_type()
3786 {
3787   return HYPHEN_MIDDLE;
3788 }
3789 
get_hyphenation_type()3790 hyphenation_type hmotion_node::get_hyphenation_type()
3791 {
3792   return HYPHEN_MIDDLE;
3793 }
3794 
get_hyphenation_type()3795 hyphenation_type space_char_hmotion_node::get_hyphenation_type()
3796 {
3797   return HYPHEN_MIDDLE;
3798 }
3799 
get_hyphenation_type()3800 hyphenation_type overstrike_node::get_hyphenation_type()
3801 {
3802   return HYPHEN_MIDDLE;
3803 }
3804 
get_hyphenation_type()3805 hyphenation_type space_node::get_hyphenation_type()
3806 {
3807   if (was_escape_colon)
3808     return HYPHEN_MIDDLE;
3809   return HYPHEN_BOUNDARY;
3810 }
3811 
get_hyphenation_type()3812 hyphenation_type unbreakable_space_node::get_hyphenation_type()
3813 {
3814   return HYPHEN_MIDDLE;
3815 }
3816 
interpret(macro *)3817 int node::interpret(macro *)
3818 {
3819   return 0;
3820 }
3821 
special_node(const macro & m,int n)3822 special_node::special_node(const macro &m, int n)
3823 : mac(m), no_init_string(n)
3824 {
3825   font_size fs = curenv->get_font_size();
3826   int char_height = curenv->get_char_height();
3827   int char_slant = curenv->get_char_slant();
3828   int fontno = env_definite_font(curenv);
3829   tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fontno);
3830   if (curenv->is_composite())
3831     tf = tf->get_plain();
3832   gcol = curenv->get_glyph_color();
3833   fcol = curenv->get_fill_color();
3834   is_special = 1;
3835 }
3836 
special_node(const macro & m,tfont * t,color * gc,color * fc,statem * s,int pop,int n)3837 special_node::special_node(const macro &m, tfont *t,
3838 			   color *gc, color *fc,
3839 			   statem *s, int pop,
3840 			   int n)
3841 : node(0, s, pop), mac(m), tf(t), gcol(gc), fcol(fc), no_init_string(n)
3842 {
3843   is_special = 1;
3844 }
3845 
same(node * n)3846 int special_node::same(node *n)
3847 {
3848   return mac == ((special_node *)n)->mac
3849 	 && tf == ((special_node *)n)->tf
3850 	 && gcol == ((special_node *)n)->gcol
3851 	 && fcol == ((special_node *)n)->fcol
3852 	 && no_init_string == ((special_node *)n)->no_init_string;
3853 }
3854 
type()3855 const char *special_node::type()
3856 {
3857   return "special_node";
3858 }
3859 
ends_sentence()3860 int special_node::ends_sentence()
3861 {
3862   return 2;
3863 }
3864 
force_tprint()3865 int special_node::force_tprint()
3866 {
3867   return 0;
3868 }
3869 
is_tag()3870 int special_node::is_tag()
3871 {
3872   return 0;
3873 }
3874 
copy()3875 node *special_node::copy()
3876 {
3877   return new special_node(mac, tf, gcol, fcol, state, div_nest_level,
3878 			  no_init_string);
3879 }
3880 
tprint_start(troff_output_file * out)3881 void special_node::tprint_start(troff_output_file *out)
3882 {
3883   out->start_special(tf, gcol, fcol, no_init_string);
3884 }
3885 
tprint_char(troff_output_file * out,unsigned char c)3886 void special_node::tprint_char(troff_output_file *out, unsigned char c)
3887 {
3888   out->special_char(c);
3889 }
3890 
tprint_end(troff_output_file * out)3891 void special_node::tprint_end(troff_output_file *out)
3892 {
3893   out->end_special();
3894 }
3895 
get_tfont()3896 tfont *special_node::get_tfont()
3897 {
3898   return tf;
3899 }
3900 
3901 /* suppress_node */
3902 
suppress_node(int on_or_off,int issue_limits)3903 suppress_node::suppress_node(int on_or_off, int issue_limits)
3904 : is_on(on_or_off), emit_limits(issue_limits), filename(0), position(0),
3905   image_id(0)
3906 {
3907 }
3908 
suppress_node(symbol f,char p,int id)3909 suppress_node::suppress_node(symbol f, char p, int id)
3910 : is_on(2), emit_limits(0), filename(f), position(p), image_id(id)
3911 {
3912   is_special = 1;
3913 }
3914 
suppress_node(int issue_limits,int on_or_off,symbol f,char p,int id,statem * s,int pop)3915 suppress_node::suppress_node(int issue_limits, int on_or_off,
3916 			     symbol f, char p, int id,
3917 			     statem *s, int pop)
3918 : node(0, s, pop), is_on(on_or_off), emit_limits(issue_limits), filename(f),
3919   position(p), image_id(id)
3920 {
3921 }
3922 
same(node * n)3923 int suppress_node::same(node *n)
3924 {
3925   return ((is_on == ((suppress_node *)n)->is_on)
3926 	  && (emit_limits == ((suppress_node *)n)->emit_limits)
3927 	  && (filename == ((suppress_node *)n)->filename)
3928 	  && (position == ((suppress_node *)n)->position)
3929 	  && (image_id == ((suppress_node *)n)->image_id));
3930 }
3931 
type()3932 const char *suppress_node::type()
3933 {
3934   return "suppress_node";
3935 }
3936 
copy()3937 node *suppress_node::copy()
3938 {
3939   return new suppress_node(emit_limits, is_on, filename, position, image_id,
3940 			   state, div_nest_level);
3941 }
3942 
3943 /* tag_node */
3944 
tag_node()3945 tag_node::tag_node()
3946 : delayed(0)
3947 {
3948   is_special = 1;
3949 }
3950 
tag_node(string s,int delay)3951 tag_node::tag_node(string s, int delay)
3952 : tag_string(s), delayed(delay)
3953 {
3954   is_special = !delay;
3955 }
3956 
tag_node(string s,statem * st,int pop,int delay)3957 tag_node::tag_node(string s, statem *st, int pop, int delay)
3958 : node(0, st, pop), tag_string(s), delayed(delay)
3959 {
3960   is_special = !delay;
3961 }
3962 
copy()3963 node *tag_node::copy()
3964 {
3965   return new tag_node(tag_string, state, div_nest_level, delayed);
3966 }
3967 
tprint(troff_output_file * out)3968 void tag_node::tprint(troff_output_file *out)
3969 {
3970   if (delayed)
3971     out->add_to_tag_list(tag_string);
3972   else
3973     out->state.add_tag(out->fp, tag_string);
3974 }
3975 
same(node * nd)3976 int tag_node::same(node *nd)
3977 {
3978   return tag_string == ((tag_node *)nd)->tag_string
3979 	 && delayed == ((tag_node *)nd)->delayed;
3980 }
3981 
type()3982 const char *tag_node::type()
3983 {
3984   return "tag_node";
3985 }
3986 
force_tprint()3987 int tag_node::force_tprint()
3988 {
3989   return !delayed;
3990 }
3991 
is_tag()3992 int tag_node::is_tag()
3993 {
3994   return !delayed;
3995 }
3996 
ends_sentence()3997 int tag_node::ends_sentence()
3998 {
3999   return 2;
4000 }
4001 
get_reg_int(const char * p)4002 int get_reg_int(const char *p)
4003 {
4004   reg *r = (reg *)number_reg_dictionary.lookup(p);
4005   units prev_value;
4006   if (r && (r->get_value(&prev_value)))
4007     return (int)prev_value;
4008   else
4009     warning(WARN_REG, "number register `%1' not defined", p);
4010   return 0;
4011 }
4012 
get_reg_str(const char * p)4013 const char *get_reg_str(const char *p)
4014 {
4015   reg *r = (reg *)number_reg_dictionary.lookup(p);
4016   if (r)
4017     return r->get_string();
4018   else
4019     warning(WARN_REG, "register `%1' not defined", p);
4020   return 0;
4021 }
4022 
put(troff_output_file * out,const char * s)4023 void suppress_node::put(troff_output_file *out, const char *s)
4024 {
4025   int i = 0;
4026   while (s[i] != (char)0) {
4027     out->special_char(s[i]);
4028     i++;
4029   }
4030 }
4031 
4032 /*
4033  *  We need to remember the start of the image and its name.
4034  */
4035 
4036 static char last_position = 0;
4037 static const char *last_image_filename = 0;
4038 static int last_image_id = 0;
4039 
min(int a,int b)4040 inline int min(int a, int b)
4041 {
4042   return a < b ? a : b;
4043 }
4044 
4045 /*
4046  *  tprint - if (is_on == 2)
4047  *               remember current position (l, r, c, i) and filename
4048  *           else
4049  *               if (emit_limits)
4050  *                   if (html)
4051  *                      emit image tag
4052  *                   else
4053  *                      emit postscript bounds for image
4054  *               else
4055  *                  if (suppress boolean differs from current state)
4056  *                      alter state
4057  *                  reset registers
4058  *                  record current page
4059  *                  set low water mark.
4060  */
4061 
tprint(troff_output_file * out)4062 void suppress_node::tprint(troff_output_file *out)
4063 {
4064   int current_page = topdiv->get_page_number();
4065   // firstly check to see whether this suppress node contains
4066   // an image filename & position.
4067   if (is_on == 2) {
4068     // remember position and filename
4069     last_position = position;
4070     char *tem = (char *)last_image_filename;
4071     last_image_filename = strsave(filename.contents());
4072     if (tem)
4073       a_delete tem;
4074     last_image_id = image_id;
4075     // printf("start of image and page = %d\n", current_page);
4076   }
4077   else {
4078     // now check whether the suppress node requires us to issue limits.
4079     if (emit_limits) {
4080       char name[8192];
4081       // remember that the filename will contain a %d in which the
4082       // last_image_id is placed
4083       if (last_image_filename == (char *) 0)
4084 	*name = '\0';
4085       else
4086 	sprintf(name, last_image_filename, last_image_id);
4087       if (is_html) {
4088 	switch (last_position) {
4089 	case 'c':
4090 	  out->start_special();
4091 	  put(out, "devtag:.centered-image");
4092 	  break;
4093 	case 'r':
4094 	  out->start_special();
4095 	  put(out, "devtag:.right-image");
4096 	  break;
4097 	case 'l':
4098 	  out->start_special();
4099 	  put(out, "devtag:.left-image");
4100 	  break;
4101 	case 'i':
4102 	  ;
4103 	default:
4104 	  ;
4105 	}
4106 	out->end_special();
4107 	out->start_special();
4108 	put(out, "devtag:.auto-image ");
4109 	put(out, name);
4110 	out->end_special();
4111       }
4112       else {
4113 	// postscript (or other device)
4114 	if (suppress_start_page > 0 && current_page != suppress_start_page)
4115 	  error("suppression limit registers span more than one page;\n"
4116 	        "image description %1 will be wrong", image_no);
4117 	// if (topdiv->get_page_number() != suppress_start_page)
4118 	//  fprintf(stderr, "end of image and topdiv page = %d   and  suppress_start_page = %d\n",
4119 	//	  topdiv->get_page_number(), suppress_start_page);
4120 
4121 	// remember that the filename will contain a %d in which the
4122 	// image_no is placed
4123 	fprintf(stderr,
4124 		"grohtml-info:page %d  %d  %d  %d  %d  %d  %s  %d  %d  %s\n",
4125 		topdiv->get_page_number(),
4126 		get_reg_int("opminx"), get_reg_int("opminy"),
4127 		get_reg_int("opmaxx"), get_reg_int("opmaxy"),
4128 		// page offset + line length
4129 		get_reg_int(".o") + get_reg_int(".l"),
4130 		name, hresolution, vresolution, get_reg_str(".F"));
4131 	fflush(stderr);
4132       }
4133     }
4134     else {
4135       if (is_on) {
4136 	out->on();
4137 	// lastly we reset the output registers
4138 	reset_output_registers();
4139       }
4140       else
4141 	out->off();
4142       suppress_start_page = current_page;
4143     }
4144   }
4145 }
4146 
force_tprint()4147 int suppress_node::force_tprint()
4148 {
4149   return is_on;
4150 }
4151 
is_tag()4152 int suppress_node::is_tag()
4153 {
4154   return is_on;
4155 }
4156 
width()4157 hunits suppress_node::width()
4158 {
4159   return H0;
4160 }
4161 
4162 /* composite_node */
4163 
4164 class composite_node : public charinfo_node {
4165   node *n;
4166   tfont *tf;
4167 public:
4168   composite_node(node *, charinfo *, tfont *, statem *, int, node * = 0);
4169   ~composite_node();
4170   node *copy();
4171   hunits width();
4172   node *last_char_node();
4173   units size();
4174   void tprint(troff_output_file *);
4175   hyphenation_type get_hyphenation_type();
4176   void ascii_print(ascii_output_file *);
4177   void asciify(macro *);
4178   hyphen_list *get_hyphen_list(hyphen_list *, int *);
4179   node *add_self(node *, hyphen_list **);
4180   tfont *get_tfont();
4181   int same(node *);
4182   const char *type();
4183   int force_tprint();
4184   int is_tag();
4185   void vertical_extent(vunits *, vunits *);
4186   vunits vertical_width();
4187 };
4188 
composite_node(node * p,charinfo * c,tfont * t,statem * s,int pop,node * x)4189 composite_node::composite_node(node *p, charinfo *c, tfont *t, statem *s,
4190 			       int pop, node *x)
4191 : charinfo_node(c, s, pop, x), n(p), tf(t)
4192 {
4193 }
4194 
~composite_node()4195 composite_node::~composite_node()
4196 {
4197   delete_node_list(n);
4198 }
4199 
copy()4200 node *composite_node::copy()
4201 {
4202   return new composite_node(copy_node_list(n), ci, tf, state, div_nest_level);
4203 }
4204 
width()4205 hunits composite_node::width()
4206 {
4207   hunits x;
4208   if (tf->get_constant_space(&x))
4209     return x;
4210   x = H0;
4211   for (node *tem = n; tem; tem = tem->next)
4212     x += tem->width();
4213   hunits offset;
4214   if (tf->get_bold(&offset))
4215     x += offset;
4216   x += tf->get_track_kern();
4217   return x;
4218 }
4219 
last_char_node()4220 node *composite_node::last_char_node()
4221 {
4222   return this;
4223 }
4224 
vertical_width()4225 vunits composite_node::vertical_width()
4226 {
4227   vunits v = V0;
4228   for (node *tem = n; tem; tem = tem->next)
4229     v += tem->vertical_width();
4230   return v;
4231 }
4232 
size()4233 units composite_node::size()
4234 {
4235   return tf->get_size().to_units();
4236 }
4237 
get_hyphenation_type()4238 hyphenation_type composite_node::get_hyphenation_type()
4239 {
4240   return HYPHEN_MIDDLE;
4241 }
4242 
asciify(macro * m)4243 void composite_node::asciify(macro *m)
4244 {
4245   unsigned char c = ci->get_asciify_code();
4246   if (c == 0)
4247     c = ci->get_ascii_code();
4248   if (c != 0) {
4249     m->append(c);
4250     delete this;
4251   }
4252   else
4253     m->append(this);
4254 }
4255 
ascii_print(ascii_output_file * ascii)4256 void composite_node::ascii_print(ascii_output_file *ascii)
4257 {
4258   unsigned char c = ci->get_ascii_code();
4259   if (c != 0)
4260     ascii->outc(c);
4261   else
4262     ascii->outs(ci->nm.contents());
4263 
4264 }
4265 
get_hyphen_list(hyphen_list * tail,int * count)4266 hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail, int *count)
4267 {
4268   (*count)++;
4269   return new hyphen_list(ci->get_hyphenation_code(), tail);
4270 }
4271 
add_self(node * nn,hyphen_list ** p)4272 node *composite_node::add_self(node *nn, hyphen_list **p)
4273 {
4274   assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
4275   next = nn;
4276   nn = this;
4277   if ((*p)->hyphen)
4278     nn = nn->add_discretionary_hyphen();
4279   hyphen_list *pp = *p;
4280   *p = (*p)->next;
4281   delete pp;
4282   return nn;
4283 }
4284 
get_tfont()4285 tfont *composite_node::get_tfont()
4286 {
4287   return tf;
4288 }
4289 
reverse_node_list(node * n)4290 node *reverse_node_list(node *n)
4291 {
4292   node *r = 0;
4293   while (n) {
4294     node *tem = n;
4295     n = n->next;
4296     tem->next = r;
4297     r = tem;
4298   }
4299   return r;
4300 }
4301 
vertical_extent(vunits * minimum,vunits * maximum)4302 void composite_node::vertical_extent(vunits *minimum, vunits *maximum)
4303 {
4304   n = reverse_node_list(n);
4305   node_list_vertical_extent(n, minimum, maximum);
4306   n = reverse_node_list(n);
4307 }
4308 
width_list(hunits w,hunits s)4309 width_list::width_list(hunits w, hunits s)
4310 : width(w), sentence_width(s), next(0)
4311 {
4312 }
4313 
width_list(width_list * w)4314 width_list::width_list(width_list *w)
4315 : width(w->width), sentence_width(w->sentence_width), next(0)
4316 {
4317 }
4318 
word_space_node(hunits d,color * c,width_list * w,node * x)4319 word_space_node::word_space_node(hunits d, color *c, width_list *w, node *x)
4320 : space_node(d, c, x), orig_width(w), unformat(0)
4321 {
4322 }
4323 
word_space_node(hunits d,int s,color * c,width_list * w,int flag,statem * st,int pop,node * x)4324 word_space_node::word_space_node(hunits d, int s, color *c, width_list *w,
4325 				 int flag, statem *st, int pop, node *x)
4326 : space_node(d, s, 0, c, st, pop, x), orig_width(w), unformat(flag)
4327 {
4328 }
4329 
~word_space_node()4330 word_space_node::~word_space_node()
4331 {
4332   width_list *w = orig_width;
4333   while (w != 0) {
4334     width_list *tmp = w;
4335     w = w->next;
4336     delete tmp;
4337   }
4338 }
4339 
copy()4340 node *word_space_node::copy()
4341 {
4342   assert(orig_width != 0);
4343   width_list *w_old_curr = orig_width;
4344   width_list *w_new_curr = new width_list(w_old_curr);
4345   width_list *w_new = w_new_curr;
4346   w_old_curr = w_old_curr->next;
4347   while (w_old_curr != 0) {
4348     w_new_curr->next = new width_list(w_old_curr);
4349     w_new_curr = w_new_curr->next;
4350     w_old_curr = w_old_curr->next;
4351   }
4352   return new word_space_node(n, set, col, w_new, unformat, state,
4353 			     div_nest_level);
4354 }
4355 
set_unformat_flag()4356 int word_space_node::set_unformat_flag()
4357 {
4358   unformat = 1;
4359   return 1;
4360 }
4361 
tprint(troff_output_file * out)4362 void word_space_node::tprint(troff_output_file *out)
4363 {
4364   out->fill_color(col);
4365   out->word_marker();
4366   out->right(n);
4367 }
4368 
merge_space(hunits h,hunits sw,hunits ssw)4369 int word_space_node::merge_space(hunits h, hunits sw, hunits ssw)
4370 {
4371   n += h;
4372   assert(orig_width != 0);
4373   width_list *w = orig_width;
4374   for (; w->next; w = w->next)
4375     ;
4376   w->next = new width_list(sw, ssw);
4377   return 1;
4378 }
4379 
unbreakable_space_node(hunits d,color * c,node * x)4380 unbreakable_space_node::unbreakable_space_node(hunits d, color *c, node *x)
4381 : word_space_node(d, c, 0, x)
4382 {
4383 }
4384 
unbreakable_space_node(hunits d,int s,color * c,statem * st,int pop,node * x)4385 unbreakable_space_node::unbreakable_space_node(hunits d, int s,
4386 					       color *c, statem *st, int pop,
4387 					       node *x)
4388 : word_space_node(d, s, c, 0, 0, st, pop, x)
4389 {
4390 }
4391 
copy()4392 node *unbreakable_space_node::copy()
4393 {
4394   return new unbreakable_space_node(n, set, col, state, div_nest_level);
4395 }
4396 
force_tprint()4397 int unbreakable_space_node::force_tprint()
4398 {
4399   return 0;
4400 }
4401 
is_tag()4402 int unbreakable_space_node::is_tag()
4403 {
4404   return 0;
4405 }
4406 
get_breakpoints(hunits,int,breakpoint * rest,int)4407 breakpoint *unbreakable_space_node::get_breakpoints(hunits, int,
4408 						    breakpoint *rest, int)
4409 {
4410   return rest;
4411 }
4412 
nbreaks()4413 int unbreakable_space_node::nbreaks()
4414 {
4415   return 0;
4416 }
4417 
split(int,node **,node **)4418 void unbreakable_space_node::split(int, node **, node **)
4419 {
4420   assert(0);
4421 }
4422 
merge_space(hunits,hunits,hunits)4423 int unbreakable_space_node::merge_space(hunits, hunits, hunits)
4424 {
4425   return 0;
4426 }
4427 
hvpair()4428 hvpair::hvpair()
4429 {
4430 }
4431 
draw_node(char c,hvpair * p,int np,font_size s,color * gc,color * fc)4432 draw_node::draw_node(char c, hvpair *p, int np, font_size s,
4433 		     color *gc, color *fc)
4434 : npoints(np), sz(s), gcol(gc), fcol(fc), code(c)
4435 {
4436   point = new hvpair[npoints];
4437   for (int i = 0; i < npoints; i++)
4438     point[i] = p[i];
4439 }
4440 
draw_node(char c,hvpair * p,int np,font_size s,color * gc,color * fc,statem * st,int pop)4441 draw_node::draw_node(char c, hvpair *p, int np, font_size s,
4442 		     color *gc, color *fc, statem *st, int pop)
4443 : node(0, st, pop), npoints(np), sz(s), gcol(gc), fcol(fc), code(c)
4444 {
4445   point = new hvpair[npoints];
4446   for (int i = 0; i < npoints; i++)
4447     point[i] = p[i];
4448 }
4449 
same(node * n)4450 int draw_node::same(node *n)
4451 {
4452   draw_node *nd = (draw_node *)n;
4453   if (code != nd->code || npoints != nd->npoints || sz != nd->sz
4454       || gcol != nd->gcol || fcol != nd->fcol)
4455     return 0;
4456   for (int i = 0; i < npoints; i++)
4457     if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v)
4458       return 0;
4459   return 1;
4460 }
4461 
type()4462 const char *draw_node::type()
4463 {
4464   return "draw_node";
4465 }
4466 
force_tprint()4467 int draw_node::force_tprint()
4468 {
4469   return 0;
4470 }
4471 
is_tag()4472 int draw_node::is_tag()
4473 {
4474   return 0;
4475 }
4476 
~draw_node()4477 draw_node::~draw_node()
4478 {
4479   if (point)
4480     a_delete point;
4481 }
4482 
width()4483 hunits draw_node::width()
4484 {
4485   hunits x = H0;
4486   for (int i = 0; i < npoints; i++)
4487     x += point[i].h;
4488   return x;
4489 }
4490 
vertical_width()4491 vunits draw_node::vertical_width()
4492 {
4493   if (code == 'e')
4494     return V0;
4495   vunits x = V0;
4496   for (int i = 0; i < npoints; i++)
4497     x += point[i].v;
4498   return x;
4499 }
4500 
copy()4501 node *draw_node::copy()
4502 {
4503   return new draw_node(code, point, npoints, sz, gcol, fcol, state,
4504 		       div_nest_level);
4505 }
4506 
tprint(troff_output_file * out)4507 void draw_node::tprint(troff_output_file *out)
4508 {
4509   out->draw(code, point, npoints, sz, gcol, fcol);
4510 }
4511 
4512 /* tprint methods */
4513 
tprint(troff_output_file * out)4514 void glyph_node::tprint(troff_output_file *out)
4515 {
4516   tfont *ptf = tf->get_plain();
4517   if (ptf == tf)
4518     out->put_char_width(ci, ptf, gcol, fcol, width(), H0);
4519   else {
4520     hunits offset;
4521     int bold = tf->get_bold(&offset);
4522     hunits w = ptf->get_width(ci);
4523     hunits k = H0;
4524     hunits x;
4525     int cs = tf->get_constant_space(&x);
4526     if (cs) {
4527       x -= w;
4528       if (bold)
4529 	x -= offset;
4530       hunits x2 = x/2;
4531       out->right(x2);
4532       k = x - x2;
4533     }
4534     else
4535       k = tf->get_track_kern();
4536     if (bold) {
4537       out->put_char(ci, ptf, gcol, fcol);
4538       out->right(offset);
4539     }
4540     out->put_char_width(ci, ptf, gcol, fcol, w, k);
4541   }
4542 }
4543 
zero_width_tprint(troff_output_file * out)4544 void glyph_node::zero_width_tprint(troff_output_file *out)
4545 {
4546   tfont *ptf = tf->get_plain();
4547   hunits offset;
4548   int bold = tf->get_bold(&offset);
4549   hunits x;
4550   int cs = tf->get_constant_space(&x);
4551   if (cs) {
4552     x -= ptf->get_width(ci);
4553     if (bold)
4554       x -= offset;
4555     x = x/2;
4556     out->right(x);
4557   }
4558   out->put_char(ci, ptf, gcol, fcol);
4559   if (bold) {
4560     out->right(offset);
4561     out->put_char(ci, ptf, gcol, fcol);
4562     out->right(-offset);
4563   }
4564   if (cs)
4565     out->right(-x);
4566 }
4567 
tprint(troff_output_file * t)4568 void break_char_node::tprint(troff_output_file *t)
4569 {
4570   ch->tprint(t);
4571 }
4572 
zero_width_tprint(troff_output_file * t)4573 void break_char_node::zero_width_tprint(troff_output_file *t)
4574 {
4575   ch->zero_width_tprint(t);
4576 }
4577 
tprint(troff_output_file * out)4578 void hline_node::tprint(troff_output_file *out)
4579 {
4580   if (x < H0) {
4581     out->right(x);
4582     x = -x;
4583   }
4584   if (n == 0) {
4585     out->right(x);
4586     return;
4587   }
4588   hunits w = n->width();
4589   if (w <= H0) {
4590     error("horizontal line drawing character must have positive width");
4591     out->right(x);
4592     return;
4593   }
4594   int i = int(x/w);
4595   if (i == 0) {
4596     hunits xx = x - w;
4597     hunits xx2 = xx/2;
4598     out->right(xx2);
4599     if (out->is_on())
4600       n->tprint(out);
4601     out->right(xx - xx2);
4602   }
4603   else {
4604     hunits rem = x - w*i;
4605     if (rem > H0) {
4606       if (n->overlaps_horizontally()) {
4607 	if (out->is_on())
4608 	  n->tprint(out);
4609 	out->right(rem - w);
4610       }
4611       else
4612 	out->right(rem);
4613     }
4614     while (--i >= 0)
4615       if (out->is_on())
4616 	n->tprint(out);
4617   }
4618 }
4619 
tprint(troff_output_file * out)4620 void vline_node::tprint(troff_output_file *out)
4621 {
4622   if (n == 0) {
4623     out->down(x);
4624     return;
4625   }
4626   vunits h = n->size();
4627   int overlaps = n->overlaps_vertically();
4628   vunits y = x;
4629   if (y < V0) {
4630     y = -y;
4631     int i = y / h;
4632     vunits rem = y - i*h;
4633     if (i == 0) {
4634       out->right(n->width());
4635       out->down(-rem);
4636     }
4637     else {
4638       while (--i > 0) {
4639 	n->zero_width_tprint(out);
4640 	out->down(-h);
4641       }
4642       if (overlaps) {
4643 	n->zero_width_tprint(out);
4644 	out->down(-rem);
4645 	if (out->is_on())
4646 	  n->tprint(out);
4647 	out->down(-h);
4648       }
4649       else {
4650 	if (out->is_on())
4651 	  n->tprint(out);
4652 	out->down(-h - rem);
4653       }
4654     }
4655   }
4656   else {
4657     int i = y / h;
4658     vunits rem = y - i*h;
4659     if (i == 0) {
4660       out->down(rem);
4661       out->right(n->width());
4662     }
4663     else {
4664       out->down(h);
4665       if (overlaps)
4666 	n->zero_width_tprint(out);
4667       out->down(rem);
4668       while (--i > 0) {
4669 	n->zero_width_tprint(out);
4670 	out->down(h);
4671       }
4672       if (out->is_on())
4673 	n->tprint(out);
4674     }
4675   }
4676 }
4677 
tprint(troff_output_file * out)4678 void zero_width_node::tprint(troff_output_file *out)
4679 {
4680   if (!n)
4681     return;
4682   if (!n->next) {
4683     n->zero_width_tprint(out);
4684     return;
4685   }
4686   int hpos = out->get_hpos();
4687   int vpos = out->get_vpos();
4688   node *tem = n;
4689   while (tem) {
4690     tem->tprint(out);
4691     tem = tem->next;
4692   }
4693   out->moveto(hpos, vpos);
4694 }
4695 
tprint(troff_output_file * out)4696 void overstrike_node::tprint(troff_output_file *out)
4697 {
4698   hunits pos = H0;
4699   for (node *tem = list; tem; tem = tem->next) {
4700     hunits x = (max_width - tem->width())/2;
4701     out->right(x - pos);
4702     pos = x;
4703     tem->zero_width_tprint(out);
4704   }
4705   out->right(max_width - pos);
4706 }
4707 
tprint(troff_output_file * out)4708 void bracket_node::tprint(troff_output_file *out)
4709 {
4710   if (list == 0)
4711     return;
4712   int npieces = 0;
4713   node *tem;
4714   for (tem = list; tem; tem = tem->next)
4715     ++npieces;
4716   vunits h = list->size();
4717   vunits totalh = h*npieces;
4718   vunits y = (totalh - h)/2;
4719   out->down(y);
4720   for (tem = list; tem; tem = tem->next) {
4721     tem->zero_width_tprint(out);
4722     out->down(-h);
4723   }
4724   out->right(max_width);
4725   out->down(totalh - y);
4726 }
4727 
tprint(troff_output_file *)4728 void node::tprint(troff_output_file *)
4729 {
4730 }
4731 
zero_width_tprint(troff_output_file * out)4732 void node::zero_width_tprint(troff_output_file *out)
4733 {
4734   int hpos = out->get_hpos();
4735   int vpos = out->get_vpos();
4736   tprint(out);
4737   out->moveto(hpos, vpos);
4738 }
4739 
tprint(troff_output_file * out)4740 void space_node::tprint(troff_output_file *out)
4741 {
4742   out->fill_color(col);
4743   out->right(n);
4744 }
4745 
tprint(troff_output_file * out)4746 void hmotion_node::tprint(troff_output_file *out)
4747 {
4748   out->fill_color(col);
4749   out->right(n);
4750 }
4751 
tprint(troff_output_file * out)4752 void space_char_hmotion_node::tprint(troff_output_file *out)
4753 {
4754   out->fill_color(col);
4755   if (is_html) {
4756     // we emit the space width as a negative glyph index
4757     out->flush_tbuf();
4758     out->do_motion();
4759     out->put('N');
4760     out->put(-n.to_units());
4761     out->put('\n');
4762   }
4763   out->right(n);
4764 }
4765 
tprint(troff_output_file * out)4766 void vmotion_node::tprint(troff_output_file *out)
4767 {
4768   out->fill_color(col);
4769   out->down(n);
4770 }
4771 
tprint(troff_output_file * out)4772 void kern_pair_node::tprint(troff_output_file *out)
4773 {
4774   n1->tprint(out);
4775   out->right(amount);
4776   n2->tprint(out);
4777 }
4778 
tprint_reverse_node_list(troff_output_file * out,node * n)4779 static void tprint_reverse_node_list(troff_output_file *out, node *n)
4780 {
4781   if (n == 0)
4782     return;
4783   tprint_reverse_node_list(out, n->next);
4784   n->tprint(out);
4785 }
4786 
tprint(troff_output_file * out)4787 void dbreak_node::tprint(troff_output_file *out)
4788 {
4789   tprint_reverse_node_list(out, none);
4790 }
4791 
tprint(troff_output_file * out)4792 void composite_node::tprint(troff_output_file *out)
4793 {
4794   hunits bold_offset;
4795   int is_bold = tf->get_bold(&bold_offset);
4796   hunits track_kern = tf->get_track_kern();
4797   hunits constant_space;
4798   int is_constant_spaced = tf->get_constant_space(&constant_space);
4799   hunits x = H0;
4800   if (is_constant_spaced) {
4801     x = constant_space;
4802     for (node *tem = n; tem; tem = tem->next)
4803       x -= tem->width();
4804     if (is_bold)
4805       x -= bold_offset;
4806     hunits x2 = x/2;
4807     out->right(x2);
4808     x -= x2;
4809   }
4810   if (is_bold) {
4811     int hpos = out->get_hpos();
4812     int vpos = out->get_vpos();
4813     tprint_reverse_node_list(out, n);
4814     out->moveto(hpos, vpos);
4815     out->right(bold_offset);
4816   }
4817   tprint_reverse_node_list(out, n);
4818   if (is_constant_spaced)
4819     out->right(x);
4820   else
4821     out->right(track_kern);
4822 }
4823 
make_composite_node(charinfo * s,environment * env)4824 node *make_composite_node(charinfo *s, environment *env)
4825 {
4826   int fontno = env_definite_font(env);
4827   if (fontno < 0) {
4828     error("no current font");
4829     return 0;
4830   }
4831   assert(fontno < font_table_size && font_table[fontno] != 0);
4832   node *n = charinfo_to_node_list(s, env);
4833   font_size fs = env->get_font_size();
4834   int char_height = env->get_char_height();
4835   int char_slant = env->get_char_slant();
4836   tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant,
4837 					    fontno);
4838   if (env->is_composite())
4839     tf = tf->get_plain();
4840   return new composite_node(n, s, tf, 0, 0, 0);
4841 }
4842 
make_glyph_node(charinfo * s,environment * env,int no_error_message=0)4843 node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0)
4844 {
4845   int fontno = env_definite_font(env);
4846   if (fontno < 0) {
4847     error("no current font");
4848     return 0;
4849   }
4850   assert(fontno < font_table_size && font_table[fontno] != 0);
4851   int fn = fontno;
4852   int found = font_table[fontno]->contains(s);
4853   if (!found) {
4854     macro *mac = s->get_macro();
4855     if (mac && s->is_fallback())
4856       return make_composite_node(s, env);
4857     if (s->numbered()) {
4858       if (!no_error_message)
4859 	warning(WARN_CHAR, "can't find numbered character %1",
4860 		s->get_number());
4861       return 0;
4862     }
4863     special_font_list *sf = font_table[fontno]->sf;
4864     while (sf != 0 && !found) {
4865       fn = sf->n;
4866       if (font_table[fn])
4867 	found = font_table[fn]->contains(s);
4868       sf = sf->next;
4869     }
4870     if (!found) {
4871       symbol f = font_table[fontno]->get_name();
4872       string gl(f.contents());
4873       gl += ' ';
4874       gl += s->nm.contents();
4875       gl += '\0';
4876       charinfo *ci = get_charinfo(symbol(gl.contents()));
4877       if (ci && ci->get_macro())
4878 	return make_composite_node(ci, env);
4879     }
4880     if (!found) {
4881       sf = global_special_fonts;
4882       while (sf != 0 && !found) {
4883 	fn = sf->n;
4884 	if (font_table[fn])
4885 	  found = font_table[fn]->contains(s);
4886 	sf = sf->next;
4887       }
4888     }
4889     if (!found)
4890       if (mac && s->is_special())
4891 	return make_composite_node(s, env);
4892     if (!found) {
4893       for (fn = 0; fn < font_table_size; fn++)
4894 	if (font_table[fn]
4895 	    && font_table[fn]->is_special()
4896 	    && font_table[fn]->contains(s)) {
4897 	  found = 1;
4898 	  break;
4899 	}
4900     }
4901     if (!found) {
4902       if (!no_error_message && s->first_time_not_found()) {
4903 	unsigned char input_code = s->get_ascii_code();
4904 	if (input_code != 0) {
4905 	  if (csgraph(input_code))
4906 	    warning(WARN_CHAR, "can't find character `%1'", input_code);
4907 	  else
4908 	    warning(WARN_CHAR, "can't find character with input code %1",
4909 		    int(input_code));
4910 	}
4911 	else if (s->nm.contents())
4912 	  warning(WARN_CHAR, "can't find special character `%1'",
4913 		  s->nm.contents());
4914       }
4915       return 0;
4916     }
4917   }
4918   font_size fs = env->get_font_size();
4919   int char_height = env->get_char_height();
4920   int char_slant = env->get_char_slant();
4921   tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn);
4922   if (env->is_composite())
4923     tf = tf->get_plain();
4924   color *gcol = env->get_glyph_color();
4925   color *fcol = env->get_fill_color();
4926   return new glyph_node(s, tf, gcol, fcol, 0, 0);
4927 }
4928 
make_node(charinfo * ci,environment * env)4929 node *make_node(charinfo *ci, environment *env)
4930 {
4931   switch (ci->get_special_translation()) {
4932   case charinfo::TRANSLATE_SPACE:
4933     return new space_char_hmotion_node(env->get_space_width(),
4934 				       env->get_fill_color());
4935   case charinfo::TRANSLATE_STRETCHABLE_SPACE:
4936     return new unbreakable_space_node(env->get_space_width(),
4937 				      env->get_fill_color());
4938   case charinfo::TRANSLATE_DUMMY:
4939     return new dummy_node;
4940   case charinfo::TRANSLATE_HYPHEN_INDICATOR:
4941     error("translation to \\% ignored in this context");
4942     break;
4943   }
4944   charinfo *tem = ci->get_translation();
4945   if (tem)
4946     ci = tem;
4947   macro *mac = ci->get_macro();
4948   if (mac && ci->is_normal())
4949     return make_composite_node(ci, env);
4950   else
4951     return make_glyph_node(ci, env);
4952 }
4953 
character_exists(charinfo * ci,environment * env)4954 int character_exists(charinfo *ci, environment *env)
4955 {
4956   if (ci->get_special_translation() != charinfo::TRANSLATE_NONE)
4957     return 1;
4958   charinfo *tem = ci->get_translation();
4959   if (tem)
4960     ci = tem;
4961   if (ci->get_macro())
4962     return 1;
4963   node *nd = make_glyph_node(ci, env, 1);
4964   if (nd) {
4965     delete nd;
4966     return 1;
4967   }
4968   return 0;
4969 }
4970 
add_char(charinfo * ci,environment * env,hunits * widthp,int * spacep,node ** glyph_comp_np)4971 node *node::add_char(charinfo *ci, environment *env,
4972 		     hunits *widthp, int *spacep, node **glyph_comp_np)
4973 {
4974   node *res;
4975   switch (ci->get_special_translation()) {
4976   case charinfo::TRANSLATE_SPACE:
4977     res = new space_char_hmotion_node(env->get_space_width(),
4978 				      env->get_fill_color(), this);
4979     *widthp += res->width();
4980     return res;
4981   case charinfo::TRANSLATE_STRETCHABLE_SPACE:
4982     res = new unbreakable_space_node(env->get_space_width(),
4983 				     env->get_fill_color(), this);
4984     res->freeze_space();
4985     *widthp += res->width();
4986     *spacep += res->nspaces();
4987     return res;
4988   case charinfo::TRANSLATE_DUMMY:
4989     return new dummy_node(this);
4990   case charinfo::TRANSLATE_HYPHEN_INDICATOR:
4991     return add_discretionary_hyphen();
4992   }
4993   charinfo *tem = ci->get_translation();
4994   if (tem)
4995     ci = tem;
4996   macro *mac = ci->get_macro();
4997   if (mac && ci->is_normal()) {
4998     res = make_composite_node(ci, env);
4999     if (res) {
5000       res->next = this;
5001       *widthp += res->width();
5002       if (glyph_comp_np)
5003 	*glyph_comp_np = res;
5004     }
5005     else {
5006       if (glyph_comp_np)
5007 	*glyph_comp_np = res;
5008       return this;
5009     }
5010   }
5011   else {
5012     node *gn = make_glyph_node(ci, env);
5013     if (gn == 0)
5014       return this;
5015     else {
5016       hunits old_width = width();
5017       node *p = gn->merge_self(this);
5018       if (p == 0) {
5019 	*widthp += gn->width();
5020 	gn->next = this;
5021 	res = gn;
5022       }
5023       else {
5024 	*widthp += p->width() - old_width;
5025 	res = p;
5026       }
5027       if (glyph_comp_np)
5028 	*glyph_comp_np = res;
5029     }
5030   }
5031   int break_code = 0;
5032   if (ci->can_break_before())
5033     break_code = 1;
5034   if (ci->can_break_after())
5035     break_code |= 2;
5036   if (break_code) {
5037     node *next1 = res->next;
5038     res->next = 0;
5039     res = new break_char_node(res, break_code, env->get_fill_color(), next1);
5040   }
5041   return res;
5042 }
5043 
5044 #ifdef __GNUG__
5045 inline
5046 #endif
same_node(node * n1,node * n2)5047 int same_node(node *n1, node *n2)
5048 {
5049   if (n1 != 0) {
5050     if (n2 != 0)
5051       return n1->type() == n2->type() && n1->same(n2);
5052     else
5053       return 0;
5054   }
5055   else
5056     return n2 == 0;
5057 }
5058 
same_node_list(node * n1,node * n2)5059 int same_node_list(node *n1, node *n2)
5060 {
5061   while (n1 && n2) {
5062     if (n1->type() != n2->type() || !n1->same(n2))
5063       return 0;
5064     n1 = n1->next;
5065     n2 = n2->next;
5066   }
5067   return !n1 && !n2;
5068 }
5069 
same(node * nd)5070 int extra_size_node::same(node *nd)
5071 {
5072   return n == ((extra_size_node *)nd)->n;
5073 }
5074 
type()5075 const char *extra_size_node::type()
5076 {
5077   return "extra_size_node";
5078 }
5079 
force_tprint()5080 int extra_size_node::force_tprint()
5081 {
5082   return 0;
5083 }
5084 
is_tag()5085 int extra_size_node::is_tag()
5086 {
5087   return 0;
5088 }
5089 
same(node * nd)5090 int vertical_size_node::same(node *nd)
5091 {
5092   return n == ((vertical_size_node *)nd)->n;
5093 }
5094 
type()5095 const char *vertical_size_node::type()
5096 {
5097   return "vertical_size_node";
5098 }
5099 
set_unformat_flag()5100 int vertical_size_node::set_unformat_flag()
5101 {
5102   return 0;
5103 }
5104 
force_tprint()5105 int vertical_size_node::force_tprint()
5106 {
5107   return 0;
5108 }
5109 
is_tag()5110 int vertical_size_node::is_tag()
5111 {
5112   return 0;
5113 }
5114 
same(node * nd)5115 int hmotion_node::same(node *nd)
5116 {
5117   return n == ((hmotion_node *)nd)->n
5118 	 && col == ((hmotion_node *)nd)->col;
5119 }
5120 
type()5121 const char *hmotion_node::type()
5122 {
5123   return "hmotion_node";
5124 }
5125 
set_unformat_flag()5126 int hmotion_node::set_unformat_flag()
5127 {
5128   unformat = 1;
5129   return 1;
5130 }
5131 
force_tprint()5132 int hmotion_node::force_tprint()
5133 {
5134   return 0;
5135 }
5136 
is_tag()5137 int hmotion_node::is_tag()
5138 {
5139   return 0;
5140 }
5141 
add_self(node * nd,hyphen_list ** p)5142 node *hmotion_node::add_self(node *nd, hyphen_list **p)
5143 {
5144   next = nd;
5145   hyphen_list *pp = *p;
5146   *p = (*p)->next;
5147   delete pp;
5148   return this;
5149 }
5150 
get_hyphen_list(hyphen_list * tail,int *)5151 hyphen_list *hmotion_node::get_hyphen_list(hyphen_list *tail, int *)
5152 {
5153   return new hyphen_list(0, tail);
5154 }
5155 
same(node * nd)5156 int space_char_hmotion_node::same(node *nd)
5157 {
5158   return n == ((space_char_hmotion_node *)nd)->n
5159 	 && col == ((space_char_hmotion_node *)nd)->col;
5160 }
5161 
type()5162 const char *space_char_hmotion_node::type()
5163 {
5164   return "space_char_hmotion_node";
5165 }
5166 
force_tprint()5167 int space_char_hmotion_node::force_tprint()
5168 {
5169   return 0;
5170 }
5171 
is_tag()5172 int space_char_hmotion_node::is_tag()
5173 {
5174   return 0;
5175 }
5176 
add_self(node * nd,hyphen_list ** p)5177 node *space_char_hmotion_node::add_self(node *nd, hyphen_list **p)
5178 {
5179   next = nd;
5180   hyphen_list *pp = *p;
5181   *p = (*p)->next;
5182   delete pp;
5183   return this;
5184 }
5185 
get_hyphen_list(hyphen_list * tail,int *)5186 hyphen_list *space_char_hmotion_node::get_hyphen_list(hyphen_list *tail,
5187 						      int *)
5188 {
5189   return new hyphen_list(0, tail);
5190 }
5191 
same(node * nd)5192 int vmotion_node::same(node *nd)
5193 {
5194   return n == ((vmotion_node *)nd)->n
5195 	 && col == ((vmotion_node *)nd)->col;
5196 }
5197 
type()5198 const char *vmotion_node::type()
5199 {
5200   return "vmotion_node";
5201 }
5202 
force_tprint()5203 int vmotion_node::force_tprint()
5204 {
5205   return 0;
5206 }
5207 
is_tag()5208 int vmotion_node::is_tag()
5209 {
5210   return 0;
5211 }
5212 
same(node * nd)5213 int hline_node::same(node *nd)
5214 {
5215   return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n);
5216 }
5217 
type()5218 const char *hline_node::type()
5219 {
5220   return "hline_node";
5221 }
5222 
force_tprint()5223 int hline_node::force_tprint()
5224 {
5225   return 0;
5226 }
5227 
is_tag()5228 int hline_node::is_tag()
5229 {
5230   return 0;
5231 }
5232 
same(node * nd)5233 int vline_node::same(node *nd)
5234 {
5235   return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n);
5236 }
5237 
type()5238 const char *vline_node::type()
5239 {
5240   return "vline_node";
5241 }
5242 
force_tprint()5243 int vline_node::force_tprint()
5244 {
5245   return 0;
5246 }
5247 
is_tag()5248 int vline_node::is_tag()
5249 {
5250   return 0;
5251 }
5252 
same(node *)5253 int dummy_node::same(node * /*nd*/)
5254 {
5255   return 1;
5256 }
5257 
type()5258 const char *dummy_node::type()
5259 {
5260   return "dummy_node";
5261 }
5262 
force_tprint()5263 int dummy_node::force_tprint()
5264 {
5265   return 0;
5266 }
5267 
is_tag()5268 int dummy_node::is_tag()
5269 {
5270   return 0;
5271 }
5272 
same(node *)5273 int transparent_dummy_node::same(node * /*nd*/)
5274 {
5275   return 1;
5276 }
5277 
type()5278 const char *transparent_dummy_node::type()
5279 {
5280   return "transparent_dummy_node";
5281 }
5282 
force_tprint()5283 int transparent_dummy_node::force_tprint()
5284 {
5285   return 0;
5286 }
5287 
is_tag()5288 int transparent_dummy_node::is_tag()
5289 {
5290   return 0;
5291 }
5292 
ends_sentence()5293 int transparent_dummy_node::ends_sentence()
5294 {
5295   return 2;
5296 }
5297 
same(node * nd)5298 int zero_width_node::same(node *nd)
5299 {
5300   return same_node_list(n, ((zero_width_node *)nd)->n);
5301 }
5302 
type()5303 const char *zero_width_node::type()
5304 {
5305   return "zero_width_node";
5306 }
5307 
force_tprint()5308 int zero_width_node::force_tprint()
5309 {
5310   return 0;
5311 }
5312 
is_tag()5313 int zero_width_node::is_tag()
5314 {
5315   return 0;
5316 }
5317 
same(node * nd)5318 int italic_corrected_node::same(node *nd)
5319 {
5320   return (x == ((italic_corrected_node *)nd)->x
5321 	  && same_node(n, ((italic_corrected_node *)nd)->n));
5322 }
5323 
type()5324 const char *italic_corrected_node::type()
5325 {
5326   return "italic_corrected_node";
5327 }
5328 
force_tprint()5329 int italic_corrected_node::force_tprint()
5330 {
5331   return 0;
5332 }
5333 
is_tag()5334 int italic_corrected_node::is_tag()
5335 {
5336   return 0;
5337 }
5338 
left_italic_corrected_node(node * xx)5339 left_italic_corrected_node::left_italic_corrected_node(node *xx)
5340 : node(xx), n(0)
5341 {
5342 }
5343 
left_italic_corrected_node(statem * s,int pop,node * xx)5344 left_italic_corrected_node::left_italic_corrected_node(statem *s, int pop,
5345 						       node *xx)
5346 : node(xx, s, pop), n(0)
5347 {
5348 }
5349 
~left_italic_corrected_node()5350 left_italic_corrected_node::~left_italic_corrected_node()
5351 {
5352   delete n;
5353 }
5354 
merge_glyph_node(glyph_node * gn)5355 node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn)
5356 {
5357   if (n == 0) {
5358     hunits lic = gn->left_italic_correction();
5359     if (!lic.is_zero()) {
5360       x = lic;
5361       n = gn;
5362       return this;
5363     }
5364   }
5365   else {
5366     node *nd = n->merge_glyph_node(gn);
5367     if (nd) {
5368       n = nd;
5369       x = n->left_italic_correction();
5370       return this;
5371     }
5372   }
5373   return 0;
5374 }
5375 
copy()5376 node *left_italic_corrected_node::copy()
5377 {
5378   left_italic_corrected_node *nd =
5379     new left_italic_corrected_node(state, div_nest_level);
5380   if (n) {
5381     nd->n = n->copy();
5382     nd->x = x;
5383   }
5384   return nd;
5385 }
5386 
tprint(troff_output_file * out)5387 void left_italic_corrected_node::tprint(troff_output_file *out)
5388 {
5389   if (n) {
5390     out->right(x);
5391     n->tprint(out);
5392   }
5393 }
5394 
type()5395 const char *left_italic_corrected_node::type()
5396 {
5397   return "left_italic_corrected_node";
5398 }
5399 
force_tprint()5400 int left_italic_corrected_node::force_tprint()
5401 {
5402   return 0;
5403 }
5404 
is_tag()5405 int left_italic_corrected_node::is_tag()
5406 {
5407   return 0;
5408 }
5409 
same(node * nd)5410 int left_italic_corrected_node::same(node *nd)
5411 {
5412   return (x == ((left_italic_corrected_node *)nd)->x
5413 	  && same_node(n, ((left_italic_corrected_node *)nd)->n));
5414 }
5415 
ascii_print(ascii_output_file * out)5416 void left_italic_corrected_node::ascii_print(ascii_output_file *out)
5417 {
5418   if (n)
5419     n->ascii_print(out);
5420 }
5421 
width()5422 hunits left_italic_corrected_node::width()
5423 {
5424   return n ? n->width() + x : H0;
5425 }
5426 
vertical_extent(vunits * minimum,vunits * maximum)5427 void left_italic_corrected_node::vertical_extent(vunits *minimum,
5428 						 vunits *maximum)
5429 {
5430   if (n)
5431     n->vertical_extent(minimum, maximum);
5432   else
5433     node::vertical_extent(minimum, maximum);
5434 }
5435 
skew()5436 hunits left_italic_corrected_node::skew()
5437 {
5438   return n ? n->skew() + x/2 : H0;
5439 }
5440 
subscript_correction()5441 hunits left_italic_corrected_node::subscript_correction()
5442 {
5443   return n ? n->subscript_correction() : H0;
5444 }
5445 
italic_correction()5446 hunits left_italic_corrected_node::italic_correction()
5447 {
5448   return n ? n->italic_correction() : H0;
5449 }
5450 
ends_sentence()5451 int left_italic_corrected_node::ends_sentence()
5452 {
5453   return n ? n->ends_sentence() : 0;
5454 }
5455 
overlaps_horizontally()5456 int left_italic_corrected_node::overlaps_horizontally()
5457 {
5458   return n ? n->overlaps_horizontally() : 0;
5459 }
5460 
overlaps_vertically()5461 int left_italic_corrected_node::overlaps_vertically()
5462 {
5463   return n ? n->overlaps_vertically() : 0;
5464 }
5465 
last_char_node()5466 node *left_italic_corrected_node::last_char_node()
5467 {
5468   return n ? n->last_char_node() : 0;
5469 }
5470 
get_tfont()5471 tfont *left_italic_corrected_node::get_tfont()
5472 {
5473   return n ? n->get_tfont() : 0;
5474 }
5475 
get_hyphenation_type()5476 hyphenation_type left_italic_corrected_node::get_hyphenation_type()
5477 {
5478   if (n)
5479     return n->get_hyphenation_type();
5480   else
5481     return HYPHEN_MIDDLE;
5482 }
5483 
get_hyphen_list(hyphen_list * tail,int * count)5484 hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail,
5485 							 int *count)
5486 {
5487   return n ? n->get_hyphen_list(tail, count) : tail;
5488 }
5489 
add_self(node * nd,hyphen_list ** p)5490 node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p)
5491 {
5492   if (n) {
5493     nd = new left_italic_corrected_node(state, div_nest_level, nd);
5494     nd = n->add_self(nd, p);
5495     n = 0;
5496     delete this;
5497   }
5498   return nd;
5499 }
5500 
character_type()5501 int left_italic_corrected_node::character_type()
5502 {
5503   return n ? n->character_type() : 0;
5504 }
5505 
same(node * nd)5506 int overstrike_node::same(node *nd)
5507 {
5508   return same_node_list(list, ((overstrike_node *)nd)->list);
5509 }
5510 
type()5511 const char *overstrike_node::type()
5512 {
5513   return "overstrike_node";
5514 }
5515 
force_tprint()5516 int overstrike_node::force_tprint()
5517 {
5518   return 0;
5519 }
5520 
is_tag()5521 int overstrike_node::is_tag()
5522 {
5523   return 0;
5524 }
5525 
add_self(node * n,hyphen_list ** p)5526 node *overstrike_node::add_self(node *n, hyphen_list **p)
5527 {
5528   next = n;
5529   hyphen_list *pp = *p;
5530   *p = (*p)->next;
5531   delete pp;
5532   return this;
5533 }
5534 
get_hyphen_list(hyphen_list * tail,int *)5535 hyphen_list *overstrike_node::get_hyphen_list(hyphen_list *tail, int *)
5536 {
5537   return new hyphen_list(0, tail);
5538 }
5539 
same(node * nd)5540 int bracket_node::same(node *nd)
5541 {
5542   return same_node_list(list, ((bracket_node *)nd)->list);
5543 }
5544 
type()5545 const char *bracket_node::type()
5546 {
5547   return "bracket_node";
5548 }
5549 
force_tprint()5550 int bracket_node::force_tprint()
5551 {
5552   return 0;
5553 }
5554 
is_tag()5555 int bracket_node::is_tag()
5556 {
5557   return 0;
5558 }
5559 
same(node * nd)5560 int composite_node::same(node *nd)
5561 {
5562   return ci == ((composite_node *)nd)->ci
5563     && same_node_list(n, ((composite_node *)nd)->n);
5564 }
5565 
type()5566 const char *composite_node::type()
5567 {
5568   return "composite_node";
5569 }
5570 
force_tprint()5571 int composite_node::force_tprint()
5572 {
5573   return 0;
5574 }
5575 
is_tag()5576 int composite_node::is_tag()
5577 {
5578   return 0;
5579 }
5580 
same(node * nd)5581 int glyph_node::same(node *nd)
5582 {
5583   return ci == ((glyph_node *)nd)->ci
5584 	 && tf == ((glyph_node *)nd)->tf
5585 	 && gcol == ((glyph_node *)nd)->gcol
5586 	 && fcol == ((glyph_node *)nd)->fcol;
5587 }
5588 
type()5589 const char *glyph_node::type()
5590 {
5591   return "glyph_node";
5592 }
5593 
force_tprint()5594 int glyph_node::force_tprint()
5595 {
5596   return 0;
5597 }
5598 
is_tag()5599 int glyph_node::is_tag()
5600 {
5601   return 0;
5602 }
5603 
same(node * nd)5604 int ligature_node::same(node *nd)
5605 {
5606   return (same_node(n1, ((ligature_node *)nd)->n1)
5607 	  && same_node(n2, ((ligature_node *)nd)->n2)
5608 	  && glyph_node::same(nd));
5609 }
5610 
type()5611 const char *ligature_node::type()
5612 {
5613   return "ligature_node";
5614 }
5615 
force_tprint()5616 int ligature_node::force_tprint()
5617 {
5618   return 0;
5619 }
5620 
is_tag()5621 int ligature_node::is_tag()
5622 {
5623   return 0;
5624 }
5625 
same(node * nd)5626 int kern_pair_node::same(node *nd)
5627 {
5628   return (amount == ((kern_pair_node *)nd)->amount
5629 	  && same_node(n1, ((kern_pair_node *)nd)->n1)
5630 	  && same_node(n2, ((kern_pair_node *)nd)->n2));
5631 }
5632 
type()5633 const char *kern_pair_node::type()
5634 {
5635   return "kern_pair_node";
5636 }
5637 
force_tprint()5638 int kern_pair_node::force_tprint()
5639 {
5640   return 0;
5641 }
5642 
is_tag()5643 int kern_pair_node::is_tag()
5644 {
5645   return 0;
5646 }
5647 
same(node * nd)5648 int dbreak_node::same(node *nd)
5649 {
5650   return (same_node_list(none, ((dbreak_node *)nd)->none)
5651 	  && same_node_list(pre, ((dbreak_node *)nd)->pre)
5652 	  && same_node_list(post, ((dbreak_node *)nd)->post));
5653 }
5654 
type()5655 const char *dbreak_node::type()
5656 {
5657   return "dbreak_node";
5658 }
5659 
force_tprint()5660 int dbreak_node::force_tprint()
5661 {
5662   return 0;
5663 }
5664 
is_tag()5665 int dbreak_node::is_tag()
5666 {
5667   return 0;
5668 }
5669 
same(node * nd)5670 int break_char_node::same(node *nd)
5671 {
5672   return break_code == ((break_char_node *)nd)->break_code
5673 	 && col == ((break_char_node *)nd)->col
5674 	 && same_node(ch, ((break_char_node *)nd)->ch);
5675 }
5676 
type()5677 const char *break_char_node::type()
5678 {
5679   return "break_char_node";
5680 }
5681 
force_tprint()5682 int break_char_node::force_tprint()
5683 {
5684   return 0;
5685 }
5686 
is_tag()5687 int break_char_node::is_tag()
5688 {
5689   return 0;
5690 }
5691 
same(node *)5692 int line_start_node::same(node * /*nd*/)
5693 {
5694   return 1;
5695 }
5696 
type()5697 const char *line_start_node::type()
5698 {
5699   return "line_start_node";
5700 }
5701 
force_tprint()5702 int line_start_node::force_tprint()
5703 {
5704   return 0;
5705 }
5706 
is_tag()5707 int line_start_node::is_tag()
5708 {
5709   return 0;
5710 }
5711 
same(node * nd)5712 int space_node::same(node *nd)
5713 {
5714   return n == ((space_node *)nd)->n
5715 	      && set == ((space_node *)nd)->set
5716 	      && col == ((space_node *)nd)->col;
5717 }
5718 
type()5719 const char *space_node::type()
5720 {
5721   return "space_node";
5722 }
5723 
same(node * nd)5724 int word_space_node::same(node *nd)
5725 {
5726   return n == ((word_space_node *)nd)->n
5727 	 && set == ((word_space_node *)nd)->set
5728 	 && col == ((word_space_node *)nd)->col;
5729 }
5730 
type()5731 const char *word_space_node::type()
5732 {
5733   return "word_space_node";
5734 }
5735 
force_tprint()5736 int word_space_node::force_tprint()
5737 {
5738   return 0;
5739 }
5740 
is_tag()5741 int word_space_node::is_tag()
5742 {
5743   return 0;
5744 }
5745 
tprint(troff_output_file * out)5746 void unbreakable_space_node::tprint(troff_output_file *out)
5747 {
5748   out->fill_color(col);
5749   if (is_html) {
5750     // we emit the space width as a negative glyph index
5751     out->flush_tbuf();
5752     out->do_motion();
5753     out->put('N');
5754     out->put(-n.to_units());
5755     out->put('\n');
5756   }
5757   out->right(n);
5758 }
5759 
same(node * nd)5760 int unbreakable_space_node::same(node *nd)
5761 {
5762   return n == ((unbreakable_space_node *)nd)->n
5763 	 && set == ((unbreakable_space_node *)nd)->set
5764 	 && col == ((unbreakable_space_node *)nd)->col;
5765 }
5766 
type()5767 const char *unbreakable_space_node::type()
5768 {
5769   return "unbreakable_space_node";
5770 }
5771 
add_self(node * nd,hyphen_list ** p)5772 node *unbreakable_space_node::add_self(node *nd, hyphen_list **p)
5773 {
5774   next = nd;
5775   hyphen_list *pp = *p;
5776   *p = (*p)->next;
5777   delete pp;
5778   return this;
5779 }
5780 
get_hyphen_list(hyphen_list * tail,int *)5781 hyphen_list *unbreakable_space_node::get_hyphen_list(hyphen_list *tail, int *)
5782 {
5783   return new hyphen_list(0, tail);
5784 }
5785 
same(node * nd)5786 int diverted_space_node::same(node *nd)
5787 {
5788   return n == ((diverted_space_node *)nd)->n;
5789 }
5790 
type()5791 const char *diverted_space_node::type()
5792 {
5793   return "diverted_space_node";
5794 }
5795 
force_tprint()5796 int diverted_space_node::force_tprint()
5797 {
5798   return 0;
5799 }
5800 
is_tag()5801 int diverted_space_node::is_tag()
5802 {
5803   return 0;
5804 }
5805 
same(node * nd)5806 int diverted_copy_file_node::same(node *nd)
5807 {
5808   return filename == ((diverted_copy_file_node *)nd)->filename;
5809 }
5810 
type()5811 const char *diverted_copy_file_node::type()
5812 {
5813   return "diverted_copy_file_node";
5814 }
5815 
force_tprint()5816 int diverted_copy_file_node::force_tprint()
5817 {
5818   return 0;
5819 }
5820 
is_tag()5821 int diverted_copy_file_node::is_tag()
5822 {
5823   return 0;
5824 }
5825 
5826 // Grow the font_table so that its size is > n.
5827 
grow_font_table(int n)5828 static void grow_font_table(int n)
5829 {
5830   assert(n >= font_table_size);
5831   font_info **old_font_table = font_table;
5832   int old_font_table_size = font_table_size;
5833   font_table_size = font_table_size ? (font_table_size*3)/2 : 10;
5834   if (font_table_size <= n)
5835     font_table_size = n + 10;
5836   font_table = new font_info *[font_table_size];
5837   if (old_font_table_size)
5838     memcpy(font_table, old_font_table,
5839 	   old_font_table_size*sizeof(font_info *));
5840   a_delete old_font_table;
5841   for (int i = old_font_table_size; i < font_table_size; i++)
5842     font_table[i] = 0;
5843 }
5844 
5845 dictionary font_translation_dictionary(17);
5846 
get_font_translation(symbol nm)5847 static symbol get_font_translation(symbol nm)
5848 {
5849   void *p = font_translation_dictionary.lookup(nm);
5850   return p ? symbol((char *)p) : nm;
5851 }
5852 
5853 dictionary font_dictionary(50);
5854 
mount_font_no_translate(int n,symbol name,symbol external_name,int check_only=0)5855 static int mount_font_no_translate(int n, symbol name, symbol external_name,
5856 				   int check_only = 0)
5857 {
5858   assert(n >= 0);
5859   // We store the address of this char in font_dictionary to indicate
5860   // that we've previously tried to mount the font and failed.
5861   static char a_char;
5862   font *fm = 0;
5863   void *p = font_dictionary.lookup(external_name);
5864   if (p == 0) {
5865     int not_found;
5866     fm = font::load_font(external_name.contents(), &not_found, check_only);
5867     if (check_only)
5868       return fm != 0;
5869     if (!fm) {
5870       if (not_found)
5871 	warning(WARN_FONT, "can't find font `%1'", external_name.contents());
5872       (void)font_dictionary.lookup(external_name, &a_char);
5873       return 0;
5874     }
5875     (void)font_dictionary.lookup(name, fm);
5876   }
5877   else if (p == &a_char) {
5878 #if 0
5879     error("invalid font `%1'", external_name.contents());
5880 #endif
5881     return 0;
5882   }
5883   else
5884     fm = (font*)p;
5885   if (check_only)
5886     return 1;
5887   if (n >= font_table_size) {
5888     if (n - font_table_size > 1000) {
5889       error("font position too much larger than first unused position");
5890       return 0;
5891     }
5892     grow_font_table(n);
5893   }
5894   else if (font_table[n] != 0)
5895     delete font_table[n];
5896   font_table[n] = new font_info(name, n, external_name, fm);
5897   font_family::invalidate_fontno(n);
5898   return 1;
5899 }
5900 
mount_font(int n,symbol name,symbol external_name)5901 int mount_font(int n, symbol name, symbol external_name)
5902 {
5903   assert(n >= 0);
5904   name = get_font_translation(name);
5905   if (external_name.is_null())
5906     external_name = name;
5907   else
5908     external_name = get_font_translation(external_name);
5909   return mount_font_no_translate(n, name, external_name);
5910 }
5911 
check_font(symbol fam,symbol name)5912 int check_font(symbol fam, symbol name)
5913 {
5914   if (check_style(name))
5915     name = concat(fam, name);
5916   return mount_font_no_translate(0, name, name, 1);
5917 }
5918 
check_style(symbol s)5919 int check_style(symbol s)
5920 {
5921   int i = symbol_fontno(s);
5922   return i < 0 ? 0 : font_table[i]->is_style();
5923 }
5924 
mount_style(int n,symbol name)5925 void mount_style(int n, symbol name)
5926 {
5927   assert(n >= 0);
5928   if (n >= font_table_size) {
5929     if (n - font_table_size > 1000) {
5930       error("font position too much larger than first unused position");
5931       return;
5932     }
5933     grow_font_table(n);
5934   }
5935   else if (font_table[n] != 0)
5936     delete font_table[n];
5937   font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0);
5938   font_family::invalidate_fontno(n);
5939 }
5940 
5941 /* global functions */
5942 
font_translate()5943 void font_translate()
5944 {
5945   symbol from = get_name(1);
5946   if (!from.is_null()) {
5947     symbol to = get_name();
5948     if (to.is_null() || from == to)
5949       font_translation_dictionary.remove(from);
5950     else
5951       (void)font_translation_dictionary.lookup(from, (void *)to.contents());
5952   }
5953   skip_line();
5954 }
5955 
font_position()5956 void font_position()
5957 {
5958   int n;
5959   if (get_integer(&n)) {
5960     if (n < 0)
5961       error("negative font position");
5962     else {
5963       symbol internal_name = get_name(1);
5964       if (!internal_name.is_null()) {
5965 	symbol external_name = get_long_name();
5966 	mount_font(n, internal_name, external_name); // ignore error
5967       }
5968     }
5969   }
5970   skip_line();
5971 }
5972 
font_family(symbol s)5973 font_family::font_family(symbol s)
5974 : map_size(10), nm(s)
5975 {
5976   map = new int[map_size];
5977   for (int i = 0; i < map_size; i++)
5978     map[i] = -1;
5979 }
5980 
~font_family()5981 font_family::~font_family()
5982 {
5983   a_delete map;
5984 }
5985 
make_definite(int i)5986 int font_family::make_definite(int i)
5987 {
5988   if (i >= 0) {
5989     if (i < map_size && map[i] >= 0)
5990       return map[i];
5991     else {
5992       if (i < font_table_size && font_table[i] != 0) {
5993 	if (i >= map_size) {
5994 	  int old_map_size = map_size;
5995 	  int *old_map = map;
5996 	  map_size *= 3;
5997 	  map_size /= 2;
5998 	  if (i >= map_size)
5999 	    map_size = i + 10;
6000 	  map = new int[map_size];
6001 	  memcpy(map, old_map, old_map_size*sizeof(int));
6002 	  a_delete old_map;
6003 	  for (int j = old_map_size; j < map_size; j++)
6004 	    map[j] = -1;
6005 	}
6006 	if (font_table[i]->is_style()) {
6007 	  symbol sty = font_table[i]->get_name();
6008 	  symbol f = concat(nm, sty);
6009 	  int n;
6010 	  // don't use symbol_fontno, because that might return a style
6011 	  // and because we don't want to translate the name
6012 	  for (n = 0; n < font_table_size; n++)
6013 	    if (font_table[n] != 0 && font_table[n]->is_named(f)
6014 		&& !font_table[n]->is_style())
6015 	      break;
6016 	  if (n >= font_table_size) {
6017 	    n = next_available_font_position();
6018 	    if (!mount_font_no_translate(n, f, f))
6019 	      return -1;
6020 	  }
6021 	  return map[i] = n;
6022 	}
6023 	else
6024 	  return map[i] = i;
6025       }
6026       else
6027 	return -1;
6028     }
6029   }
6030   else
6031     return -1;
6032 }
6033 
6034 dictionary family_dictionary(5);
6035 
lookup_family(symbol nm)6036 font_family *lookup_family(symbol nm)
6037 {
6038   font_family *f = (font_family *)family_dictionary.lookup(nm);
6039   if (!f) {
6040     f = new font_family(nm);
6041     (void)family_dictionary.lookup(nm, f);
6042   }
6043   return f;
6044 }
6045 
invalidate_fontno(int n)6046 void font_family::invalidate_fontno(int n)
6047 {
6048   assert(n >= 0 && n < font_table_size);
6049   dictionary_iterator iter(family_dictionary);
6050   symbol nam;
6051   font_family *fam;
6052   while (iter.get(&nam, (void **)&fam)) {
6053     int mapsize = fam->map_size;
6054     if (n < mapsize)
6055       fam->map[n] = -1;
6056     for (int i = 0; i < mapsize; i++)
6057       if (fam->map[i] == n)
6058 	fam->map[i] = -1;
6059   }
6060 }
6061 
style()6062 void style()
6063 {
6064   int n;
6065   if (get_integer(&n)) {
6066     if (n < 0)
6067       error("negative font position");
6068     else {
6069       symbol internal_name = get_name(1);
6070       if (!internal_name.is_null())
6071 	mount_style(n, internal_name);
6072     }
6073   }
6074   skip_line();
6075 }
6076 
get_fontno()6077 static int get_fontno()
6078 {
6079   int n;
6080   tok.skip();
6081   if (tok.delimiter()) {
6082     symbol s = get_name(1);
6083     if (!s.is_null()) {
6084       n = symbol_fontno(s);
6085       if (n < 0) {
6086 	n = next_available_font_position();
6087 	if (!mount_font(n, s))
6088 	  return -1;
6089       }
6090       return curenv->get_family()->make_definite(n);
6091     }
6092   }
6093   else if (get_integer(&n)) {
6094     if (n < 0 || n >= font_table_size || font_table[n] == 0)
6095       error("bad font number");
6096     else
6097       return curenv->get_family()->make_definite(n);
6098   }
6099   return -1;
6100 }
6101 
6102 static int underline_fontno = 2;
6103 
underline_font()6104 void underline_font()
6105 {
6106   int n = get_fontno();
6107   if (n >= 0)
6108     underline_fontno = n;
6109   skip_line();
6110 }
6111 
get_underline_fontno()6112 int get_underline_fontno()
6113 {
6114   return underline_fontno;
6115 }
6116 
define_font_special_character()6117 void define_font_special_character()
6118 {
6119   int n = get_fontno();
6120   if (n < 0) {
6121     skip_line();
6122     return;
6123   }
6124   symbol f = font_table[n]->get_name();
6125   do_define_character(CHAR_FONT_SPECIAL, f.contents());
6126 }
6127 
remove_font_special_character()6128 void remove_font_special_character()
6129 {
6130   int n = get_fontno();
6131   if (n < 0) {
6132     skip_line();
6133     return;
6134   }
6135   symbol f = font_table[n]->get_name();
6136   while (!tok.newline() && !tok.eof()) {
6137     if (!tok.space() && !tok.tab()) {
6138       charinfo *s = tok.get_char(1);
6139       string gl(f.contents());
6140       gl += ' ';
6141       gl += s->nm.contents();
6142       gl += '\0';
6143       charinfo *ci = get_charinfo(symbol(gl.contents()));
6144       if (!ci)
6145 	break;
6146       macro *m = ci->set_macro(0);
6147       if (m)
6148 	delete m;
6149     }
6150     tok.next();
6151   }
6152   skip_line();
6153 }
6154 
read_special_fonts(special_font_list ** sp)6155 static void read_special_fonts(special_font_list **sp)
6156 {
6157   special_font_list *s = *sp;
6158   *sp = 0;
6159   while (s != 0) {
6160     special_font_list *tem = s;
6161     s = s->next;
6162     delete tem;
6163   }
6164   special_font_list **p = sp;
6165   while (has_arg()) {
6166     int i = get_fontno();
6167     if (i >= 0) {
6168       special_font_list *tem = new special_font_list;
6169       tem->n = i;
6170       tem->next = 0;
6171       *p = tem;
6172       p = &(tem->next);
6173     }
6174   }
6175 }
6176 
font_special_request()6177 void font_special_request()
6178 {
6179   int n = get_fontno();
6180   if (n >= 0)
6181     read_special_fonts(&font_table[n]->sf);
6182   skip_line();
6183 }
6184 
special_request()6185 void special_request()
6186 {
6187   read_special_fonts(&global_special_fonts);
6188   skip_line();
6189 }
6190 
next_available_font_position()6191 int next_available_font_position()
6192 {
6193   int i;
6194   for (i = 1; i < font_table_size && font_table[i] != 0; i++)
6195     ;
6196   return i;
6197 }
6198 
symbol_fontno(symbol s)6199 int symbol_fontno(symbol s)
6200 {
6201   s = get_font_translation(s);
6202   for (int i = 0; i < font_table_size; i++)
6203     if (font_table[i] != 0 && font_table[i]->is_named(s))
6204       return i;
6205   return -1;
6206 }
6207 
is_good_fontno(int n)6208 int is_good_fontno(int n)
6209 {
6210   return n >= 0 && n < font_table_size && font_table[n] != 0;
6211 }
6212 
get_bold_fontno(int n)6213 int get_bold_fontno(int n)
6214 {
6215   if (n >= 0 && n < font_table_size && font_table[n] != 0) {
6216     hunits offset;
6217     if (font_table[n]->get_bold(&offset))
6218       return offset.to_units() + 1;
6219     else
6220       return 0;
6221   }
6222   else
6223     return 0;
6224 }
6225 
env_digit_width(environment * env)6226 hunits env_digit_width(environment *env)
6227 {
6228   node *n = make_glyph_node(charset_table['0'], env);
6229   if (n) {
6230     hunits x = n->width();
6231     delete n;
6232     return x;
6233   }
6234   else
6235     return H0;
6236 }
6237 
env_space_width(environment * env)6238 hunits env_space_width(environment *env)
6239 {
6240   int fn = env_definite_font(env);
6241   font_size fs = env->get_font_size();
6242   if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6243     return scale(fs.to_units()/3, env->get_space_size(), 12);
6244   else
6245     return font_table[fn]->get_space_width(fs, env->get_space_size());
6246 }
6247 
env_sentence_space_width(environment * env)6248 hunits env_sentence_space_width(environment *env)
6249 {
6250   int fn = env_definite_font(env);
6251   font_size fs = env->get_font_size();
6252   if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6253     return scale(fs.to_units()/3, env->get_sentence_space_size(), 12);
6254   else
6255     return font_table[fn]->get_space_width(fs, env->get_sentence_space_size());
6256 }
6257 
env_half_narrow_space_width(environment * env)6258 hunits env_half_narrow_space_width(environment *env)
6259 {
6260   int fn = env_definite_font(env);
6261   font_size fs = env->get_font_size();
6262   if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6263     return 0;
6264   else
6265     return font_table[fn]->get_half_narrow_space_width(fs);
6266 }
6267 
env_narrow_space_width(environment * env)6268 hunits env_narrow_space_width(environment *env)
6269 {
6270   int fn = env_definite_font(env);
6271   font_size fs = env->get_font_size();
6272   if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
6273     return 0;
6274   else
6275     return font_table[fn]->get_narrow_space_width(fs);
6276 }
6277 
bold_font()6278 void bold_font()
6279 {
6280   int n = get_fontno();
6281   if (n >= 0) {
6282     if (has_arg()) {
6283       if (tok.delimiter()) {
6284 	int f = get_fontno();
6285 	if (f >= 0) {
6286 	  units offset;
6287 	  if (has_arg() && get_number(&offset, 'u') && offset >= 1)
6288 	    font_table[f]->set_conditional_bold(n, hunits(offset - 1));
6289 	  else
6290 	    font_table[f]->conditional_unbold(n);
6291 	}
6292       }
6293       else {
6294 	units offset;
6295 	if (get_number(&offset, 'u') && offset >= 1)
6296 	  font_table[n]->set_bold(hunits(offset - 1));
6297 	else
6298 	  font_table[n]->unbold();
6299       }
6300     }
6301     else
6302       font_table[n]->unbold();
6303   }
6304   skip_line();
6305 }
6306 
track_kerning_function()6307 track_kerning_function::track_kerning_function() : non_zero(0)
6308 {
6309 }
6310 
track_kerning_function(int min_s,hunits min_a,int max_s,hunits max_a)6311 track_kerning_function::track_kerning_function(int min_s, hunits min_a,
6312 					       int max_s, hunits max_a)
6313 : non_zero(1), min_size(min_s), min_amount(min_a), max_size(max_s),
6314   max_amount(max_a)
6315 {
6316 }
6317 
operator ==(const track_kerning_function & tk)6318 int track_kerning_function::operator==(const track_kerning_function &tk)
6319 {
6320   if (non_zero)
6321     return (tk.non_zero
6322 	    && min_size == tk.min_size
6323 	    && min_amount == tk.min_amount
6324 	    && max_size == tk.max_size
6325 	    && max_amount == tk.max_amount);
6326   else
6327     return !tk.non_zero;
6328 }
6329 
operator !=(const track_kerning_function & tk)6330 int track_kerning_function::operator!=(const track_kerning_function &tk)
6331 {
6332   if (non_zero)
6333     return (!tk.non_zero
6334 	    || min_size != tk.min_size
6335 	    || min_amount != tk.min_amount
6336 	    || max_size != tk.max_size
6337 	    || max_amount != tk.max_amount);
6338   else
6339     return tk.non_zero;
6340 }
6341 
compute(int size)6342 hunits track_kerning_function::compute(int size)
6343 {
6344   if (non_zero) {
6345     if (max_size <= min_size)
6346       return min_amount;
6347     else if (size <= min_size)
6348       return min_amount;
6349     else if (size >= max_size)
6350       return max_amount;
6351     else
6352       return (scale(max_amount, size - min_size, max_size - min_size)
6353 	      + scale(min_amount, max_size - size, max_size - min_size));
6354   }
6355   else
6356     return H0;
6357 }
6358 
track_kern()6359 void track_kern()
6360 {
6361   int n = get_fontno();
6362   if (n >= 0) {
6363     int min_s, max_s;
6364     hunits min_a, max_a;
6365     if (has_arg()
6366 	&& get_number(&min_s, 'z')
6367 	&& get_hunits(&min_a, 'p')
6368 	&& get_number(&max_s, 'z')
6369 	&& get_hunits(&max_a, 'p')) {
6370       track_kerning_function tk(min_s, min_a, max_s, max_a);
6371       font_table[n]->set_track_kern(tk);
6372     }
6373     else {
6374       track_kerning_function tk;
6375       font_table[n]->set_track_kern(tk);
6376     }
6377   }
6378   skip_line();
6379 }
6380 
constant_space()6381 void constant_space()
6382 {
6383   int n = get_fontno();
6384   if (n >= 0) {
6385     int x, y;
6386     if (!has_arg() || !get_integer(&x))
6387       font_table[n]->set_constant_space(CONSTANT_SPACE_NONE);
6388     else {
6389       if (!has_arg() || !get_number(&y, 'z'))
6390 	font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x);
6391       else
6392 	font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE,
6393 					  scale(y*x,
6394 						units_per_inch,
6395 						36*72*sizescale));
6396     }
6397   }
6398   skip_line();
6399 }
6400 
ligature()6401 void ligature()
6402 {
6403   int lig;
6404   if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2)
6405     global_ligature_mode = lig;
6406   else
6407     global_ligature_mode = 1;
6408   skip_line();
6409 }
6410 
kern_request()6411 void kern_request()
6412 {
6413   int k;
6414   if (has_arg() && get_integer(&k))
6415     global_kern_mode = k != 0;
6416   else
6417     global_kern_mode = 1;
6418   skip_line();
6419 }
6420 
set_soft_hyphen_char()6421 void set_soft_hyphen_char()
6422 {
6423   soft_hyphen_char = get_optional_char();
6424   if (!soft_hyphen_char)
6425     soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
6426   skip_line();
6427 }
6428 
init_output()6429 void init_output()
6430 {
6431   if (suppress_output_flag)
6432     the_output = new suppress_output_file;
6433   else if (ascii_output_flag)
6434     the_output = new ascii_output_file;
6435   else
6436     the_output = new troff_output_file;
6437 }
6438 
6439 class next_available_font_position_reg : public reg {
6440 public:
6441   const char *get_string();
6442 };
6443 
get_string()6444 const char *next_available_font_position_reg::get_string()
6445 {
6446   return i_to_a(next_available_font_position());
6447 }
6448 
6449 class printing_reg : public reg {
6450 public:
6451   const char *get_string();
6452 };
6453 
get_string()6454 const char *printing_reg::get_string()
6455 {
6456   if (the_output)
6457     return the_output->is_printing() ? "1" : "0";
6458   else
6459     return "0";
6460 }
6461 
init_node_requests()6462 void init_node_requests()
6463 {
6464   init_request("bd", bold_font);
6465   init_request("cs", constant_space);
6466   init_request("fp", font_position);
6467   init_request("fschar", define_font_special_character);
6468   init_request("fspecial", font_special_request);
6469   init_request("ftr", font_translate);
6470   init_request("kern", kern_request);
6471   init_request("lg", ligature);
6472   init_request("rfschar", remove_font_special_character);
6473   init_request("shc", set_soft_hyphen_char);
6474   init_request("special", special_request);
6475   init_request("sty", style);
6476   init_request("tkf", track_kern);
6477   init_request("uf", underline_font);
6478   number_reg_dictionary.define(".fp", new next_available_font_position_reg);
6479   number_reg_dictionary.define(".kern",
6480 			       new constant_int_reg(&global_kern_mode));
6481   number_reg_dictionary.define(".lg",
6482 			       new constant_int_reg(&global_ligature_mode));
6483   number_reg_dictionary.define(".P", new printing_reg);
6484   soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
6485 }
6486