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(¬_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(), ¬_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