2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
27 #include "dictionary.h"
43 #else /* not _POSIX_VERSION */
45 /* traditional Unix */
47 #define WIFEXITED(s) (((s) & 0377) == 0)
48 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
49 #define WTERMSIG(s) ((s) & 0177)
50 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
51 #define WSTOPSIG(s) (((s) >> 8) & 0377)
52 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
54 #endif /* not _POSIX_VERSION */
58 symbol
HYPHEN_SYMBOL("hy");
60 // Character used when a hyphen is inserted at a line break.
61 static charinfo
*soft_hyphen_char
;
63 enum constant_space_type
{
65 CONSTANT_SPACE_RELATIVE
,
66 CONSTANT_SPACE_ABSOLUTE
69 struct special_font_list
{
71 special_font_list
*next
;
74 special_font_list
*global_special_fonts
;
75 static int global_ligature_mode
= 1;
76 static int global_kern_mode
= 1;
78 class track_kerning_function
{
85 track_kerning_function();
86 track_kerning_function(units
, hunits
, units
, hunits
);
87 int operator==(const track_kerning_function
&);
88 int operator!=(const track_kerning_function
&);
89 hunits
compute(int point_size
);
92 // embolden fontno when this is the current font
94 struct conditional_bold
{
95 conditional_bold
*next
;
98 conditional_bold(int, hunits
, conditional_bold
* = 0);
109 symbol internal_name
;
110 symbol external_name
;
114 track_kerning_function track_kern
;
115 constant_space_type is_constant_spaced
;
116 units constant_space
;
117 int last_ligature_mode
;
119 conditional_bold
*cond_bold_list
;
122 special_font_list
*sf
;
124 font_info(symbol nm
, int n
, symbol enm
, font
*f
);
125 int contains(charinfo
*);
126 void set_bold(hunits
);
128 void set_conditional_bold(int, hunits
);
129 void conditional_unbold(int);
130 void set_track_kern(track_kerning_function
&);
131 void set_constant_space(constant_space_type
, units
= 0);
132 int is_named(symbol
);
134 tfont
*get_tfont(font_size
, int, int, int);
135 hunits
get_space_width(font_size
, int);
136 hunits
get_narrow_space_width(font_size
);
137 hunits
get_half_narrow_space_width(font_size
);
138 int get_bold(hunits
*);
150 char is_constant_spaced
;
154 hunits track_kern
; // add this to the width
155 hunits constant_space_width
;
159 tfont_spec(symbol nm
, int pos
, font
*, font_size
, int, int);
160 tfont_spec(const tfont_spec
&spec
) { *this = spec
; }
162 int operator==(const tfont_spec
&);
163 friend tfont
*font_info::get_tfont(font_size fs
, int, int, int);
166 class tfont
: public tfont_spec
{
167 static tfont
*tfont_list
;
169 tfont
*plain_version
;
172 int contains(charinfo
*);
173 hunits
get_width(charinfo
*c
);
174 int get_bold(hunits
*);
175 int get_constant_space(hunits
*);
176 hunits
get_track_kern();
178 font_size
get_size();
180 charinfo
*get_lig(charinfo
*c1
, charinfo
*c2
);
181 int get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
);
182 int get_input_position();
183 int get_character_type(charinfo
*);
186 vunits
get_char_height(charinfo
*);
187 vunits
get_char_depth(charinfo
*);
188 hunits
get_char_skew(charinfo
*);
189 hunits
get_italic_correction(charinfo
*);
190 hunits
get_left_italic_correction(charinfo
*);
191 hunits
get_subscript_correction(charinfo
*);
192 friend tfont
*make_tfont(tfont_spec
&);
195 inline int env_definite_font(environment
*env
)
197 return env
->get_family()->make_definite(env
->get_font());
200 /* font_info functions */
202 static font_info
**font_table
= 0;
203 static int font_table_size
= 0;
205 font_info::font_info(symbol nm
, int n
, symbol enm
, font
*f
)
206 : last_tfont(0), number(n
), last_size(0),
207 internal_name(nm
), external_name(enm
), fm(f
),
208 is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE
), last_ligature_mode(1),
209 last_kern_mode(1), cond_bold_list(0), sf(0)
213 inline int font_info::contains(charinfo
*ci
)
215 return fm
!= 0 && fm
->contains(ci
->get_index());
218 inline int font_info::is_special()
220 return fm
!= 0 && fm
->is_special();
223 inline int font_info::is_style()
228 // this is the current_font, fontno is where we found the character,
229 // presumably a special font
231 tfont
*font_info::get_tfont(font_size fs
, int height
, int slant
, int fontno
)
233 if (last_tfont
== 0 || fs
!= last_size
234 || height
!= last_height
|| slant
!= last_slant
235 || global_ligature_mode
!= last_ligature_mode
236 || global_kern_mode
!= last_kern_mode
237 || fontno
!= number
) {
238 font_info
*f
= font_table
[fontno
];
239 tfont_spec
spec(f
->external_name
, f
->number
, f
->fm
, fs
, height
, slant
);
240 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
241 if (p
->fontno
== fontno
) {
243 spec
.bold_offset
= p
->offset
;
246 if (!spec
.is_bold
&& is_bold
) {
248 spec
.bold_offset
= bold_offset
;
250 spec
.track_kern
= track_kern
.compute(fs
.to_scaled_points());
251 spec
.ligature_mode
= global_ligature_mode
;
252 spec
.kern_mode
= global_kern_mode
;
253 switch (is_constant_spaced
) {
254 case CONSTANT_SPACE_NONE
:
256 case CONSTANT_SPACE_ABSOLUTE
:
257 spec
.is_constant_spaced
= 1;
258 spec
.constant_space_width
= constant_space
;
260 case CONSTANT_SPACE_RELATIVE
:
261 spec
.is_constant_spaced
= 1;
262 spec
.constant_space_width
263 = scale(constant_space
*fs
.to_scaled_points(),
270 if (fontno
!= number
)
271 return make_tfont(spec
);
272 last_tfont
= make_tfont(spec
);
274 last_height
= height
;
276 last_ligature_mode
= global_ligature_mode
;
277 last_kern_mode
= global_kern_mode
;
282 int font_info::get_bold(hunits
*res
)
292 void font_info::unbold()
300 void font_info::set_bold(hunits offset
)
302 if (!is_bold
|| offset
!= bold_offset
) {
304 bold_offset
= offset
;
309 void font_info::set_conditional_bold(int fontno
, hunits offset
)
311 for (conditional_bold
*p
= cond_bold_list
; p
; p
= p
->next
)
312 if (p
->fontno
== fontno
) {
313 if (offset
!= p
->offset
) {
319 cond_bold_list
= new conditional_bold(fontno
, offset
, cond_bold_list
);
322 conditional_bold::conditional_bold(int f
, hunits h
, conditional_bold
*x
)
323 : next(x
), fontno(f
), offset(h
)
327 void font_info::conditional_unbold(int fontno
)
329 for (conditional_bold
**p
= &cond_bold_list
; *p
; p
= &(*p
)->next
)
330 if ((*p
)->fontno
== fontno
) {
331 conditional_bold
*tem
= *p
;
339 void font_info::set_constant_space(constant_space_type type
, units x
)
341 if (type
!= is_constant_spaced
342 || (type
!= CONSTANT_SPACE_NONE
&& x
!= constant_space
)) {
344 is_constant_spaced
= type
;
349 void font_info::set_track_kern(track_kerning_function
&tk
)
351 if (track_kern
!= tk
) {
357 void font_info::flush()
362 int font_info::is_named(symbol s
)
364 return internal_name
== s
;
367 symbol
font_info::get_name()
369 return internal_name
;
372 hunits
font_info::get_space_width(font_size fs
, int space_size
)
374 if (is_constant_spaced
== CONSTANT_SPACE_NONE
)
375 return scale(hunits(fm
->get_space_width(fs
.to_scaled_points())),
377 else if (is_constant_spaced
== CONSTANT_SPACE_ABSOLUTE
)
378 return constant_space
;
380 return scale(constant_space
*fs
.to_scaled_points(),
381 units_per_inch
, 36*72*sizescale
);
384 hunits
font_info::get_narrow_space_width(font_size fs
)
386 charinfo
*ci
= get_charinfo(symbol("|"));
387 if (fm
->contains(ci
->get_index()))
388 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
390 return hunits(fs
.to_units()/6);
393 hunits
font_info::get_half_narrow_space_width(font_size fs
)
395 charinfo
*ci
= get_charinfo(symbol("^"));
396 if (fm
->contains(ci
->get_index()))
397 return hunits(fm
->get_width(ci
->get_index(), fs
.to_scaled_points()));
399 return hunits(fs
.to_units()/12);
404 tfont_spec::tfont_spec(symbol nm
, int n
, font
*f
,
405 font_size s
, int h
, int sl
)
406 : name(nm
), input_position(n
), fm(f
), size(s
),
407 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
410 if (height
== size
.to_scaled_points())
414 int tfont_spec::operator==(const tfont_spec
&spec
)
418 && input_position
== spec
.input_position
420 && height
== spec
.height
421 && slant
== spec
.slant
423 ? (spec
.is_bold
&& bold_offset
== spec
.bold_offset
)
425 && track_kern
== spec
.track_kern
426 && (is_constant_spaced
427 ? (spec
.is_constant_spaced
428 && constant_space_width
== spec
.constant_space_width
)
429 : !spec
.is_constant_spaced
)
430 && ligature_mode
== spec
.ligature_mode
431 && kern_mode
== spec
.kern_mode
)
437 tfont_spec
tfont_spec::plain()
439 return tfont_spec(name
, input_position
, fm
, size
, height
, slant
);
442 hunits
tfont::get_width(charinfo
*c
)
444 if (is_constant_spaced
)
445 return constant_space_width
;
447 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points()))
448 + track_kern
+ bold_offset
);
450 return (hunits(fm
->get_width(c
->get_index(), size
.to_scaled_points())) + track_kern
);
453 vunits
tfont::get_char_height(charinfo
*c
)
455 vunits v
= fm
->get_height(c
->get_index(), size
.to_scaled_points());
456 if (height
!= 0 && height
!= size
.to_scaled_points())
457 return scale(v
, height
, size
.to_scaled_points());
462 vunits
tfont::get_char_depth(charinfo
*c
)
464 vunits v
= fm
->get_depth(c
->get_index(), size
.to_scaled_points());
465 if (height
!= 0 && height
!= size
.to_scaled_points())
466 return scale(v
, height
, size
.to_scaled_points());
471 hunits
tfont::get_char_skew(charinfo
*c
)
473 return hunits(fm
->get_skew(c
->get_index(), size
.to_scaled_points(), slant
));
476 hunits
tfont::get_italic_correction(charinfo
*c
)
478 return hunits(fm
->get_italic_correction(c
->get_index(), size
.to_scaled_points()));
481 hunits
tfont::get_left_italic_correction(charinfo
*c
)
483 return hunits(fm
->get_left_italic_correction(c
->get_index(),
484 size
.to_scaled_points()));
487 hunits
tfont::get_subscript_correction(charinfo
*c
)
489 return hunits(fm
->get_subscript_correction(c
->get_index(),
490 size
.to_scaled_points()));
493 inline int tfont::get_input_position()
495 return input_position
;
498 inline int tfont::contains(charinfo
*ci
)
500 return fm
->contains(ci
->get_index());
503 inline int tfont::get_character_type(charinfo
*ci
)
505 return fm
->get_character_type(ci
->get_index());
508 inline int tfont::get_bold(hunits
*res
)
518 inline int tfont::get_constant_space(hunits
*res
)
520 if (is_constant_spaced
) {
521 *res
= constant_space_width
;
528 inline hunits
tfont::get_track_kern()
533 inline tfont
*tfont::get_plain()
535 return plain_version
;
538 inline font_size
tfont::get_size()
543 inline symbol
tfont::get_name()
548 inline int tfont::get_height()
553 inline int tfont::get_slant()
558 symbol
SYMBOL_ff("ff");
559 symbol
SYMBOL_fi("fi");
560 symbol
SYMBOL_fl("fl");
561 symbol
SYMBOL_Fi("Fi");
562 symbol
SYMBOL_Fl("Fl");
564 charinfo
*tfont::get_lig(charinfo
*c1
, charinfo
*c2
)
566 if (ligature_mode
== 0)
569 if (c1
->get_ascii_code() == 'f') {
570 switch (c2
->get_ascii_code()) {
572 if (fm
->has_ligature(font::LIG_ff
))
573 ci
= get_charinfo(SYMBOL_ff
);
576 if (fm
->has_ligature(font::LIG_fi
))
577 ci
= get_charinfo(SYMBOL_fi
);
580 if (fm
->has_ligature(font::LIG_fl
))
581 ci
= get_charinfo(SYMBOL_fl
);
585 else if (ligature_mode
!= 2 && c1
->nm
== SYMBOL_ff
) {
586 switch (c2
->get_ascii_code()) {
588 if (fm
->has_ligature(font::LIG_ffi
))
589 ci
= get_charinfo(SYMBOL_Fi
);
592 if (fm
->has_ligature(font::LIG_ffl
))
593 ci
= get_charinfo(SYMBOL_Fl
);
597 if (ci
!= 0 && fm
->contains(ci
->get_index()))
602 inline int tfont::get_kern(charinfo
*c1
, charinfo
*c2
, hunits
*res
)
607 int n
= fm
->get_kern(c1
->get_index(),
609 size
.to_scaled_points());
619 tfont
*make_tfont(tfont_spec
&spec
)
621 for (tfont
*p
= tfont::tfont_list
; p
; p
= p
->next
)
624 return new tfont(spec
);
627 tfont
*tfont::tfont_list
= 0;
629 tfont::tfont(tfont_spec
&spec
) : tfont_spec(spec
)
633 tfont_spec plain_spec
= plain();
635 for (p
= tfont_list
; p
; p
= p
->next
)
636 if (*p
== plain_spec
) {
641 plain_version
= new tfont(plain_spec
);
646 class real_output_file
: public output_file
{
647 #ifndef POPEN_MISSING
651 virtual void really_transparent_char(unsigned char) = 0;
652 virtual void really_print_line(hunits x
, vunits y
, node
*n
,
653 vunits before
, vunits after
) = 0;
654 virtual void really_begin_page(int pageno
, vunits page_length
) = 0;
655 virtual void really_copy_file(hunits x
, vunits y
, const char *filename
);
656 virtual void really_put_filename(const char *filename
);
663 void transparent_char(unsigned char);
664 void print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
);
665 void begin_page(int pageno
, vunits page_length
);
666 void put_filename(const char *filename
);
668 void copy_file(hunits x
, vunits y
, const char *filename
);
671 class suppress_output_file
: public real_output_file
{
673 suppress_output_file();
674 void really_transparent_char(unsigned char);
675 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
);
676 void really_begin_page(int pageno
, vunits page_length
);
679 class ascii_output_file
: public real_output_file
{
682 void really_transparent_char(unsigned char);
683 void really_print_line(hunits x
, vunits y
, node
*n
, vunits
, vunits
);
684 void really_begin_page(int pageno
, vunits page_length
);
685 void outc(unsigned char c
);
686 void outs(const char *s
);
689 void ascii_output_file::outc(unsigned char c
)
694 void ascii_output_file::outs(const char *s
)
704 class troff_output_file
: public real_output_file
{
713 tfont
*current_tfont
;
714 int current_font_number
;
715 symbol
*font_position
;
717 enum { TBUF_SIZE
= 256 };
718 char tbuf
[TBUF_SIZE
];
724 void put(unsigned char c
);
726 void put(const char *s
);
727 void set_font(tfont
*tf
);
731 ~troff_output_file();
732 void trailer(vunits page_length
);
733 void put_char(charinfo
*ci
, tfont
*tf
);
734 void put_char_width(charinfo
*ci
, tfont
*tf
, hunits w
, hunits k
);
737 void moveto(hunits
, vunits
);
738 void start_special();
739 void special_char(unsigned char c
);
742 void really_transparent_char(unsigned char c
);
743 void really_print_line(hunits x
, vunits y
, node
*n
, vunits before
, vunits after
);
744 void really_begin_page(int pageno
, vunits page_length
);
745 void really_copy_file(hunits x
, vunits y
, const char *filename
);
746 void really_put_filename(const char *filename
);
747 void draw(char, hvpair
*, int, font_size
);
748 int get_hpos() { return hpos
; }
749 int get_vpos() { return vpos
; }
752 static void put_string(const char *s
, FILE *fp
)
754 for (; *s
!= '\0'; ++s
)
758 inline void troff_output_file::put(char c
)
763 inline void troff_output_file::put(unsigned char c
)
768 inline void troff_output_file::put(const char *s
)
773 inline void troff_output_file::put(int i
)
775 put_string(i_to_a(i
), fp
);
778 void troff_output_file::start_special()
785 void troff_output_file::special_char(unsigned char c
)
792 void troff_output_file::end_special()
797 inline void troff_output_file::moveto(hunits h
, vunits v
)
803 void troff_output_file::really_print_line(hunits x
, vunits y
, node
*n
,
804 vunits before
, vunits after
)
812 // This ensures that transparent throughput will have a more predictable
818 put(before
.to_units());
820 put(after
.to_units());
824 inline void troff_output_file::word_marker()
830 inline void troff_output_file::right(hunits n
)
832 hpos
+= n
.to_units();
835 inline void troff_output_file::down(vunits n
)
837 vpos
+= n
.to_units();
840 void troff_output_file::do_motion()
851 if (hpos
!= output_hpos
) {
852 units n
= hpos
- output_hpos
;
853 if (n
> 0 && n
< hpos
) {
863 if (vpos
!= output_vpos
) {
864 units n
= vpos
- output_vpos
;
865 if (n
> 0 && n
< vpos
) {
881 void troff_output_file::flush_tbuf()
892 for (int i
= 0; i
< tbuf_len
; i
++)
898 void troff_output_file::put_char_width(charinfo
*ci
, tfont
*tf
, hunits w
,
901 if (tf
!= current_tfont
) {
905 char c
= ci
->get_ascii_code();
906 int kk
= k
.to_units();
910 if (ci
->numbered()) {
912 put(ci
->get_number());
916 const char *s
= ci
->nm
.contents();
925 hpos
+= w
.to_units() + kk
;
927 else if (tcommand_flag
) {
928 if (tbuf_len
> 0 && hpos
== output_hpos
&& vpos
== output_vpos
930 && tbuf_len
< TBUF_SIZE
) {
931 tbuf
[tbuf_len
++] = c
;
932 output_hpos
+= w
.to_units() + kk
;
938 tbuf
[tbuf_len
++] = c
;
939 output_hpos
+= w
.to_units() + kk
;
945 int n
= hpos
- output_hpos
;
946 if (vpos
== output_vpos
&& n
> 0 && n
< 100 && !force_motion
) {
947 put(char(n
/10 + '0'));
948 put(char(n
%10 + '0'));
957 hpos
+= w
.to_units() + kk
;
961 void troff_output_file::put_char(charinfo
*ci
, tfont
*tf
)
964 if (tf
!= current_tfont
)
966 char c
= ci
->get_ascii_code();
969 if (ci
->numbered()) {
971 put(ci
->get_number());
975 const char *s
= ci
->nm
.contents();
986 int n
= hpos
- output_hpos
;
987 if (vpos
== output_vpos
&& n
> 0 && n
< 100) {
988 put(char(n
/10 + '0'));
989 put(char(n
%10 + '0'));
1001 void troff_output_file::set_font(tfont
*tf
)
1003 if (current_tfont
== tf
)
1005 int n
= tf
->get_input_position();
1006 symbol nm
= tf
->get_name();
1007 if (n
>= nfont_positions
|| font_position
[n
] != nm
) {
1013 if (n
>= nfont_positions
) {
1014 int old_nfont_positions
= nfont_positions
;
1015 symbol
*old_font_position
= font_position
;
1016 nfont_positions
*= 3;
1017 nfont_positions
/= 2;
1018 if (nfont_positions
<= n
)
1019 nfont_positions
= n
+ 10;
1020 font_position
= new symbol
[nfont_positions
];
1021 memcpy(font_position
, old_font_position
,
1022 old_nfont_positions
*sizeof(symbol
));
1023 a_delete old_font_position
;
1025 font_position
[n
] = nm
;
1027 if (current_font_number
!= n
) {
1031 current_font_number
= n
;
1033 int size
= tf
->get_size().to_scaled_points();
1034 if (current_size
!= size
) {
1038 current_size
= size
;
1040 int slant
= tf
->get_slant();
1041 if (current_slant
!= slant
) {
1045 current_slant
= slant
;
1047 int height
= tf
->get_height();
1048 if (current_height
!= height
) {
1050 put(height
== 0 ? current_size
: height
);
1052 current_height
= height
;
1057 void troff_output_file::draw(char code
, hvpair
*point
, int npoints
,
1062 int size
= fsize
.to_scaled_points();
1063 if (current_size
!= size
) {
1067 current_size
= size
;
1075 put(point
[0].h
.to_units());
1078 for (i
= 0; i
< npoints
; i
++) {
1080 put(point
[i
].h
.to_units());
1082 put(point
[i
].v
.to_units());
1084 for (i
= 0; i
< npoints
; i
++)
1085 output_hpos
+= point
[i
].h
.to_units();
1088 for (i
= 0; i
< npoints
; i
++)
1089 output_vpos
+= point
[i
].v
.to_units();
1095 void troff_output_file::really_put_filename(const char *filename
)
1103 void troff_output_file::really_begin_page(int pageno
, vunits page_length
)
1107 if (page_length
> V0
) {
1109 put(page_length
.to_units());
1116 current_font_number
= -1;
1118 // current_height = 0;
1119 // current_slant = 0;
1125 for (int i
= 0; i
< nfont_positions
; i
++)
1126 font_position
[i
] = NULL_SYMBOL
;
1132 void troff_output_file::really_copy_file(hunits x
, vunits y
, const char *filename
)
1138 FILE *ifp
= fopen(filename
, "r");
1140 error("can't open `%1': %2", filename
, strerror(errno
));
1143 while ((c
= getc(ifp
)) != EOF
)
1150 current_font_number
= -1;
1151 for (int i
= 0; i
< nfont_positions
; i
++)
1152 font_position
[i
] = NULL_SYMBOL
;
1155 void troff_output_file::really_transparent_char(unsigned char c
)
1160 troff_output_file::~troff_output_file()
1162 a_delete font_position
;
1165 void troff_output_file::trailer(vunits page_length
)
1168 if (page_length
> V0
) {
1171 put(page_length
.to_units());
1177 troff_output_file::troff_output_file()
1178 : current_slant(0), current_height(0), nfont_positions(10), tbuf_len(0),
1181 font_position
= new symbol
[nfont_positions
];
1186 put(units_per_inch
);
1197 output_file
*the_output
= 0;
1199 output_file::output_file()
1203 output_file::~output_file()
1207 void output_file::trailer(vunits
)
1212 void output_file::put_filename(const char *filename
)
1216 real_output_file::real_output_file()
1219 #ifndef POPEN_MISSING
1221 if ((fp
= popen(pipe_command
, POPEN_WT
)) != 0) {
1225 error("pipe open failed: %1", strerror(errno
));
1228 #endif /* not POPEN_MISSING */
1232 real_output_file::~real_output_file()
1236 // To avoid looping, set fp to 0 before calling fatal().
1237 if (ferror(fp
) || fflush(fp
) < 0) {
1239 fatal("error writing output file");
1241 #ifndef POPEN_MISSING
1243 int result
= pclose(fp
);
1246 fatal("pclose failed");
1247 if (!WIFEXITED(result
))
1248 error("output process `%1' got fatal signal %2",
1250 WIFSIGNALED(result
) ? WTERMSIG(result
) : WSTOPSIG(result
));
1252 int exit_status
= WEXITSTATUS(result
);
1253 if (exit_status
!= 0)
1254 error("output process `%1' exited with status %2",
1255 pipe_command
, exit_status
);
1259 #endif /* not POPEN MISSING */
1260 if (fclose(fp
) < 0) {
1262 fatal("error closing output file");
1266 void real_output_file::flush()
1269 fatal("error writing output file");
1272 int real_output_file::is_printing()
1277 void real_output_file::begin_page(int pageno
, vunits page_length
)
1279 printing
= in_output_page_list(pageno
);
1281 really_begin_page(pageno
, page_length
);
1284 void real_output_file::copy_file(hunits x
, vunits y
, const char *filename
)
1287 really_copy_file(x
, y
, filename
);
1290 void real_output_file::transparent_char(unsigned char c
)
1293 really_transparent_char(c
);
1296 void real_output_file::print_line(hunits x
, vunits y
, node
*n
,
1297 vunits before
, vunits after
)
1300 really_print_line(x
, y
, n
, before
, after
);
1301 delete_node_list(n
);
1304 void real_output_file::really_copy_file(hunits
, vunits
, const char *)
1309 void real_output_file::put_filename(const char *filename
)
1311 really_put_filename(filename
);
1314 void real_output_file::really_put_filename(const char *filename
)
1318 /* ascii_output_file */
1320 void ascii_output_file::really_transparent_char(unsigned char c
)
1325 void ascii_output_file::really_print_line(hunits
, vunits
, node
*n
, vunits
, vunits
)
1328 n
->ascii_print(this);
1334 void ascii_output_file::really_begin_page(int /*pageno*/, vunits
/*page_length*/)
1336 fputs("<beginning of page>\n", fp
);
1339 ascii_output_file::ascii_output_file()
1343 /* suppress_output_file */
1345 suppress_output_file::suppress_output_file()
1349 void suppress_output_file::really_print_line(hunits
, vunits
, node
*, vunits
, vunits
)
1353 void suppress_output_file::really_begin_page(int, vunits
)
1357 void suppress_output_file::really_transparent_char(unsigned char)
1361 /* glyphs, ligatures, kerns, discretionary breaks */
1363 class charinfo_node
: public node
{
1367 charinfo_node(charinfo
*, node
* = 0);
1368 int ends_sentence();
1369 int overlaps_vertically();
1370 int overlaps_horizontally();
1373 charinfo_node::charinfo_node(charinfo
*c
, node
*x
)
1378 int charinfo_node::ends_sentence()
1380 if (ci
->ends_sentence())
1382 else if (ci
->transparent())
1388 int charinfo_node::overlaps_horizontally()
1390 return ci
->overlaps_horizontally();
1393 int charinfo_node::overlaps_vertically()
1395 return ci
->overlaps_vertically();
1398 class glyph_node
: public charinfo_node
{
1399 static glyph_node
*free_list
;
1404 glyph_node(charinfo
*, tfont
*, hunits
, node
* = 0);
1407 void *operator new(size_t);
1408 void operator delete(void *);
1409 glyph_node(charinfo
*, tfont
*, node
* = 0);
1412 node
*merge_glyph_node(glyph_node
*);
1413 node
*merge_self(node
*);
1415 node
*last_char_node();
1417 void vertical_extent(vunits
*, vunits
*);
1418 hunits
subscript_correction();
1419 hunits
italic_correction();
1420 hunits
left_italic_correction();
1422 hyphenation_type
get_hyphenation_type();
1424 void tprint(troff_output_file
*);
1425 void zero_width_tprint(troff_output_file
*);
1426 hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
1427 node
*add_self(node
*, hyphen_list
**);
1428 void ascii_print(ascii_output_file
*);
1429 void asciify(macro
*);
1430 int character_type();
1435 glyph_node
*glyph_node::free_list
= 0;
1437 class ligature_node
: public glyph_node
{
1441 ligature_node(charinfo
*, tfont
*, hunits
, node
*gn1
, node
*gn2
, node
*x
= 0);
1444 void *operator new(size_t);
1445 void operator delete(void *);
1446 ligature_node(charinfo
*, tfont
*, node
*gn1
, node
*gn2
, node
*x
= 0);
1449 node
*add_self(node
*, hyphen_list
**);
1450 hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
1451 void ascii_print(ascii_output_file
*);
1452 void asciify(macro
*);
1457 class kern_pair_node
: public node
{
1462 kern_pair_node(hunits n
, node
*first
, node
*second
, node
*x
= 0);
1465 node
*merge_glyph_node(glyph_node
*);
1466 node
*add_self(node
*, hyphen_list
**);
1467 hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
1468 node
*add_discretionary_hyphen();
1470 node
*last_char_node();
1471 hunits
italic_correction();
1472 hunits
subscript_correction();
1473 void tprint(troff_output_file
*);
1474 hyphenation_type
get_hyphenation_type();
1475 int ends_sentence();
1476 void ascii_print(ascii_output_file
*);
1477 void asciify(macro
*);
1480 void vertical_extent(vunits
*, vunits
*);
1483 class dbreak_node
: public node
{
1488 dbreak_node(node
*n
, node
*p
, node
*x
= 0);
1491 node
*merge_glyph_node(glyph_node
*);
1492 node
*add_discretionary_hyphen();
1494 node
*last_char_node();
1495 hunits
italic_correction();
1496 hunits
subscript_correction();
1497 void tprint(troff_output_file
*);
1498 breakpoint
*get_breakpoints(hunits width
, int ns
, breakpoint
*rest
= 0,
1501 int ends_sentence();
1502 void split(int, node
**, node
**);
1503 hyphenation_type
get_hyphenation_type();
1504 void ascii_print(ascii_output_file
*);
1505 void asciify(macro
*);
1510 void *glyph_node::operator new(size_t n
)
1512 assert(n
== sizeof(glyph_node
));
1514 const int BLOCK
= 1024;
1515 free_list
= (glyph_node
*)new char[sizeof(glyph_node
)*BLOCK
];
1516 for (int i
= 0; i
< BLOCK
- 1; i
++)
1517 free_list
[i
].next
= free_list
+ i
+ 1;
1518 free_list
[BLOCK
-1].next
= 0;
1520 glyph_node
*p
= free_list
;
1521 free_list
= (glyph_node
*)(free_list
->next
);
1526 void *ligature_node::operator new(size_t n
)
1531 void glyph_node::operator delete(void *p
)
1534 ((glyph_node
*)p
)->next
= free_list
;
1535 free_list
= (glyph_node
*)p
;
1539 void ligature_node::operator delete(void *p
)
1544 glyph_node::glyph_node(charinfo
*c
, tfont
*t
, node
*x
)
1545 : charinfo_node(c
, x
), tf(t
)
1548 wid
= tf
->get_width(ci
);
1553 glyph_node::glyph_node(charinfo
*c
, tfont
*t
, hunits w
, node
*x
)
1554 : charinfo_node(c
, x
), tf(t
), wid(w
)
1559 node
*glyph_node::copy()
1562 return new glyph_node(ci
, tf
, wid
);
1564 return new glyph_node(ci
, tf
);
1568 node
*glyph_node::merge_self(node
*nd
)
1570 return nd
->merge_glyph_node(this);
1573 int glyph_node::character_type()
1575 return tf
->get_character_type(ci
);
1578 node
*glyph_node::add_self(node
*n
, hyphen_list
**p
)
1580 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
1583 if (n
== 0 || (nn
= n
->merge_glyph_node(this)) == 0) {
1588 nn
= nn
->add_discretionary_hyphen();
1589 hyphen_list
*pp
= *p
;
1595 units
glyph_node::size()
1597 return tf
->get_size().to_units();
1600 hyphen_list
*glyph_node::get_hyphen_list(hyphen_list
*tail
)
1602 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
1606 tfont
*node::get_tfont()
1611 tfont
*glyph_node::get_tfont()
1616 node
*node::merge_glyph_node(glyph_node
* /*gn*/)
1621 node
*glyph_node::merge_glyph_node(glyph_node
*gn
)
1625 if ((lig
= tf
->get_lig(ci
, gn
->ci
)) != 0) {
1628 return new ligature_node(lig
, tf
, this, gn
, next1
);
1631 if (tf
->get_kern(ci
, gn
->ci
, &kern
)) {
1634 return new kern_pair_node(kern
, this, gn
, next1
);
1643 hunits
glyph_node::width()
1648 return tf
->get_width(ci
);
1652 node
*glyph_node::last_char_node()
1657 void glyph_node::vertical_extent(vunits
*min
, vunits
*max
)
1659 *min
= -tf
->get_char_height(ci
);
1660 *max
= tf
->get_char_depth(ci
);
1663 hunits
glyph_node::skew()
1665 return tf
->get_char_skew(ci
);
1668 hunits
glyph_node::subscript_correction()
1670 return tf
->get_subscript_correction(ci
);
1673 hunits
glyph_node::italic_correction()
1675 return tf
->get_italic_correction(ci
);
1678 hunits
glyph_node::left_italic_correction()
1680 return tf
->get_left_italic_correction(ci
);
1683 hyphenation_type
glyph_node::get_hyphenation_type()
1685 return HYPHEN_MIDDLE
;
1688 void glyph_node::ascii_print(ascii_output_file
*ascii
)
1690 unsigned char c
= ci
->get_ascii_code();
1694 ascii
->outs(ci
->nm
.contents());
1697 ligature_node::ligature_node(charinfo
*c
, tfont
*t
,
1698 node
*gn1
, node
*gn2
, node
*x
)
1699 : glyph_node(c
, t
, x
), n1(gn1
), n2(gn2
)
1704 ligature_node::ligature_node(charinfo
*c
, tfont
*t
, hunits w
,
1705 node
*gn1
, node
*gn2
, node
*x
)
1706 : glyph_node(c
, t
, w
, x
), n1(gn1
), n2(gn2
)
1711 ligature_node::~ligature_node()
1717 node
*ligature_node::copy()
1720 return new ligature_node(ci
, tf
, wid
, n1
->copy(), n2
->copy());
1722 return new ligature_node(ci
, tf
, n1
->copy(), n2
->copy());
1726 void ligature_node::ascii_print(ascii_output_file
*ascii
)
1728 n1
->ascii_print(ascii
);
1729 n2
->ascii_print(ascii
);
1732 hyphen_list
*ligature_node::get_hyphen_list(hyphen_list
*tail
)
1734 return n1
->get_hyphen_list(n2
->get_hyphen_list(tail
));
1737 node
*ligature_node::add_self(node
*n
, hyphen_list
**p
)
1739 n
= n1
->add_self(n
, p
);
1740 n
= n2
->add_self(n
, p
);
1746 kern_pair_node::kern_pair_node(hunits n
, node
*first
, node
*second
, node
*x
)
1747 : node(x
), amount(n
), n1(first
), n2(second
)
1751 dbreak_node::dbreak_node(node
*n
, node
*p
, node
*x
)
1752 : node(x
), none(n
), pre(p
), post(0)
1756 node
*dbreak_node::merge_glyph_node(glyph_node
*gn
)
1758 glyph_node
*gn2
= (glyph_node
*)gn
->copy();
1759 node
*new_none
= none
? none
->merge_glyph_node(gn
) : 0;
1760 node
*new_post
= post
? post
->merge_glyph_node(gn2
) : 0;
1761 if (new_none
== 0 && new_post
== 0) {
1780 node
*kern_pair_node::merge_glyph_node(glyph_node
*gn
)
1782 node
*nd
= n2
->merge_glyph_node(gn
);
1786 nd
= n2
->merge_self(n1
);
1798 hunits
kern_pair_node::italic_correction()
1800 return n2
->italic_correction();
1803 hunits
kern_pair_node::subscript_correction()
1805 return n2
->subscript_correction();
1808 void kern_pair_node::vertical_extent(vunits
*min
, vunits
*max
)
1810 n1
->vertical_extent(min
, max
);
1812 n2
->vertical_extent(&min2
, &max2
);
1819 node
*kern_pair_node::add_discretionary_hyphen()
1821 tfont
*tf
= n2
->get_tfont();
1823 if (tf
->contains(soft_hyphen_char
)) {
1827 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
);
1828 node
*nn
= n
->merge_glyph_node(gn
);
1833 return new dbreak_node(this, nn
, next1
);
1840 kern_pair_node::~kern_pair_node()
1848 dbreak_node::~dbreak_node()
1850 delete_node_list(pre
);
1851 delete_node_list(post
);
1852 delete_node_list(none
);
1855 node
*kern_pair_node::copy()
1857 return new kern_pair_node(amount
, n1
->copy(), n2
->copy());
1860 node
*copy_node_list(node
*n
)
1864 node
*nn
= n
->copy();
1878 void delete_node_list(node
*n
)
1887 node
*dbreak_node::copy()
1889 dbreak_node
*p
= new dbreak_node(copy_node_list(none
), copy_node_list(pre
));
1890 p
->post
= copy_node_list(post
);
1894 hyphen_list
*node::get_hyphen_list(hyphen_list
*tail
)
1900 hyphen_list
*kern_pair_node::get_hyphen_list(hyphen_list
*tail
)
1902 return n1
->get_hyphen_list(n2
->get_hyphen_list(tail
));
1905 class hyphen_inhibitor_node
: public node
{
1907 hyphen_inhibitor_node(node
*nd
= 0);
1911 hyphenation_type
get_hyphenation_type();
1914 hyphen_inhibitor_node::hyphen_inhibitor_node(node
*nd
) : node(nd
)
1918 node
*hyphen_inhibitor_node::copy()
1920 return new hyphen_inhibitor_node
;
1923 int hyphen_inhibitor_node::same(node
*)
1928 const char *hyphen_inhibitor_node::type()
1930 return "hyphen_inhibitor_node";
1933 hyphenation_type
hyphen_inhibitor_node::get_hyphenation_type()
1935 return HYPHEN_INHIBIT
;
1938 /* add_discretionary_hyphen methods */
1940 node
*dbreak_node::add_discretionary_hyphen()
1943 post
= post
->add_discretionary_hyphen();
1945 none
= none
->add_discretionary_hyphen();
1950 node
*node::add_discretionary_hyphen()
1952 tfont
*tf
= get_tfont();
1954 return new hyphen_inhibitor_node(this);
1955 if (tf
->contains(soft_hyphen_char
)) {
1959 glyph_node
*gn
= new glyph_node(soft_hyphen_char
, tf
);
1960 node
*n1
= n
->merge_glyph_node(gn
);
1965 return new dbreak_node(this, n1
, next1
);
1971 node
*node::merge_self(node
*)
1976 node
*node::add_self(node
*n
, hyphen_list
** /*p*/)
1982 node
*kern_pair_node::add_self(node
*n
, hyphen_list
**p
)
1984 n
= n1
->add_self(n
, p
);
1985 n
= n2
->add_self(n
, p
);
1992 hunits
node::width()
1997 node
*node::last_char_node()
2002 hunits
hmotion_node::width()
2009 return points_to_units(10);
2012 hunits
kern_pair_node::width()
2014 return n1
->width() + n2
->width() + amount
;
2017 node
*kern_pair_node::last_char_node()
2019 node
*nd
= n2
->last_char_node();
2022 return n1
->last_char_node();
2025 hunits
dbreak_node::width()
2028 for (node
*n
= none
; n
!= 0; n
= n
->next
)
2033 node
*dbreak_node::last_char_node()
2035 for (node
*n
= none
; n
; n
= n
->next
) {
2036 node
*last
= n
->last_char_node();
2043 hunits
dbreak_node::italic_correction()
2045 return none
? none
->italic_correction() : H0
;
2048 hunits
dbreak_node::subscript_correction()
2050 return none
? none
->subscript_correction() : H0
;
2053 class italic_corrected_node
: public node
{
2057 italic_corrected_node(node
*, hunits
, node
* = 0);
2058 ~italic_corrected_node();
2060 void ascii_print(ascii_output_file
*);
2061 void asciify(macro
*m
);
2063 node
*last_char_node();
2064 void vertical_extent(vunits
*, vunits
*);
2065 int ends_sentence();
2066 int overlaps_horizontally();
2067 int overlaps_vertically();
2069 hyphenation_type
get_hyphenation_type();
2071 hyphen_list
*get_hyphen_list(hyphen_list
*ss
= 0);
2072 int character_type();
2073 void tprint(troff_output_file
*);
2074 hunits
subscript_correction();
2076 node
*add_self(node
*, hyphen_list
**);
2080 node
*node::add_italic_correction(hunits
*width
)
2082 hunits ic
= italic_correction();
2089 return new italic_corrected_node(this, ic
, next1
);
2093 italic_corrected_node::italic_corrected_node(node
*nn
, hunits xx
, node
*p
)
2094 : node(p
), n(nn
), x(xx
)
2099 italic_corrected_node::~italic_corrected_node()
2104 node
*italic_corrected_node::copy()
2106 return new italic_corrected_node(n
->copy(), x
);
2109 hunits
italic_corrected_node::width()
2111 return n
->width() + x
;
2114 void italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
2116 n
->vertical_extent(min
, max
);
2119 void italic_corrected_node::tprint(troff_output_file
*out
)
2125 hunits
italic_corrected_node::skew()
2127 return n
->skew() - x
/2;
2130 hunits
italic_corrected_node::subscript_correction()
2132 return n
->subscript_correction() - x
;
2135 void italic_corrected_node::ascii_print(ascii_output_file
*out
)
2137 n
->ascii_print(out
);
2140 int italic_corrected_node::ends_sentence()
2142 return n
->ends_sentence();
2145 int italic_corrected_node::overlaps_horizontally()
2147 return n
->overlaps_horizontally();
2150 int italic_corrected_node::overlaps_vertically()
2152 return n
->overlaps_vertically();
2155 node
*italic_corrected_node::last_char_node()
2157 return n
->last_char_node();
2160 tfont
*italic_corrected_node::get_tfont()
2162 return n
->get_tfont();
2165 hyphenation_type
italic_corrected_node::get_hyphenation_type()
2167 return n
->get_hyphenation_type();
2170 node
*italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
2172 nd
= n
->add_self(nd
, p
);
2173 hunits not_interested
;
2174 nd
= nd
->add_italic_correction(¬_interested
);
2180 hyphen_list
*italic_corrected_node::get_hyphen_list(hyphen_list
*tail
)
2182 return n
->get_hyphen_list(tail
);
2185 int italic_corrected_node::character_type()
2187 return n
->character_type();
2190 class break_char_node
: public node
{
2194 break_char_node(node
*, int, node
* = 0);
2198 vunits
vertical_width();
2199 node
*last_char_node();
2200 int character_type();
2201 int ends_sentence();
2202 node
*add_self(node
*, hyphen_list
**);
2203 hyphen_list
*get_hyphen_list(hyphen_list
*s
= 0);
2204 void tprint(troff_output_file
*);
2205 void zero_width_tprint(troff_output_file
*);
2206 void ascii_print(ascii_output_file
*);
2207 void asciify(macro
*m
);
2208 hyphenation_type
get_hyphenation_type();
2209 int overlaps_vertically();
2210 int overlaps_horizontally();
2217 break_char_node::break_char_node(node
*n
, int c
, node
*x
)
2218 : node(x
), ch(n
), break_code(c
)
2222 break_char_node::~break_char_node()
2227 node
*break_char_node::copy()
2229 return new break_char_node(ch
->copy(), break_code
);
2232 hunits
break_char_node::width()
2237 vunits
break_char_node::vertical_width()
2239 return ch
->vertical_width();
2242 node
*break_char_node::last_char_node()
2244 return ch
->last_char_node();
2247 int break_char_node::character_type()
2249 return ch
->character_type();
2252 int break_char_node::ends_sentence()
2254 return ch
->ends_sentence();
2257 node
*break_char_node::add_self(node
*n
, hyphen_list
**p
)
2259 assert((*p
)->hyphenation_code
== 0);
2260 if ((*p
)->breakable
&& (break_code
& 1)) {
2261 n
= new space_node(H0
, n
);
2266 if ((*p
)->breakable
&& (break_code
& 2)) {
2267 n
= new space_node(H0
, n
);
2270 hyphen_list
*pp
= *p
;
2276 hyphen_list
*break_char_node::get_hyphen_list(hyphen_list
*tail
)
2278 return new hyphen_list(0, tail
);
2281 hyphenation_type
break_char_node::get_hyphenation_type()
2283 return HYPHEN_MIDDLE
;
2286 void break_char_node::ascii_print(ascii_output_file
*ascii
)
2288 ch
->ascii_print(ascii
);
2291 int break_char_node::overlaps_vertically()
2293 return ch
->overlaps_vertically();
2296 int break_char_node::overlaps_horizontally()
2298 return ch
->overlaps_horizontally();
2301 units
break_char_node::size()
2306 tfont
*break_char_node::get_tfont()
2308 return ch
->get_tfont();
2311 node
*extra_size_node::copy()
2313 return new extra_size_node(n
);
2316 node
*vertical_size_node::copy()
2318 return new vertical_size_node(n
);
2321 node
*hmotion_node::copy()
2323 return new hmotion_node(n
);
2326 node
*space_char_hmotion_node::copy()
2328 return new space_char_hmotion_node(n
);
2331 node
*vmotion_node::copy()
2333 return new vmotion_node(n
);
2336 node
*dummy_node::copy()
2338 return new dummy_node
;
2341 node
*transparent_dummy_node::copy()
2343 return new transparent_dummy_node
;
2346 hline_node::~hline_node()
2352 node
*hline_node::copy()
2354 return new hline_node(x
, n
? n
->copy() : 0);
2357 hunits
hline_node::width()
2359 return x
< H0
? H0
: x
;
2363 vline_node::~vline_node()
2369 node
*vline_node::copy()
2371 return new vline_node(x
, n
? n
->copy() : 0);
2374 hunits
vline_node::width()
2376 return n
== 0 ? H0
: n
->width();
2380 zero_width_node::zero_width_node(node
*nd
) : n(nd
)
2384 zero_width_node::~zero_width_node()
2386 delete_node_list(n
);
2389 node
*zero_width_node::copy()
2391 return new zero_width_node(copy_node_list(n
));
2394 int node_list_character_type(node
*p
)
2397 for (; p
; p
= p
->next
)
2398 t
|= p
->character_type();
2402 int zero_width_node::character_type()
2404 return node_list_character_type(n
);
2407 void node_list_vertical_extent(node
*p
, vunits
*min
, vunits
*max
)
2411 vunits cur_vpos
= V0
;
2413 for (; p
; p
= p
->next
) {
2414 p
->vertical_extent(&v1
, &v2
);
2421 cur_vpos
+= p
->vertical_width();
2425 void zero_width_node::vertical_extent(vunits
*min
, vunits
*max
)
2427 node_list_vertical_extent(n
, min
, max
);
2430 overstrike_node::overstrike_node() : list(0), max_width(H0
)
2434 overstrike_node::~overstrike_node()
2436 delete_node_list(list
);
2439 node
*overstrike_node::copy()
2441 overstrike_node
*on
= new overstrike_node
;
2442 for (node
*tem
= list
; tem
; tem
= tem
->next
)
2443 on
->overstrike(tem
->copy());
2447 void overstrike_node::overstrike(node
*n
)
2451 hunits w
= n
->width();
2455 for (p
= &list
; *p
; p
= &(*p
)->next
)
2461 hunits
overstrike_node::width()
2466 bracket_node::bracket_node() : list(0), max_width(H0
)
2470 bracket_node::~bracket_node()
2472 delete_node_list(list
);
2475 node
*bracket_node::copy()
2477 bracket_node
*on
= new bracket_node
;
2480 for (tem
= list
; tem
; tem
= tem
->next
) {
2482 tem
->next
->last
= tem
;
2485 for (tem
= last
; tem
; tem
= tem
->last
)
2486 on
->bracket(tem
->copy());
2491 void bracket_node::bracket(node
*n
)
2495 hunits w
= n
->width();
2502 hunits
bracket_node::width()
2512 int node::merge_space(hunits
)
2518 space_node
*space_node::free_list
= 0;
2520 void *space_node::operator new(size_t n
)
2522 assert(n
== sizeof(space_node
));
2524 free_list
= (space_node
*)new char[sizeof(space_node
)*BLOCK
];
2525 for (int i
= 0; i
< BLOCK
- 1; i
++)
2526 free_list
[i
].next
= free_list
+ i
+ 1;
2527 free_list
[BLOCK
-1].next
= 0;
2529 space_node
*p
= free_list
;
2530 free_list
= (space_node
*)(free_list
->next
);
2535 inline void space_node::operator delete(void *p
)
2538 ((space_node
*)p
)->next
= free_list
;
2539 free_list
= (space_node
*)p
;
2544 space_node::space_node(hunits nn
, node
*p
) : node(p
), n(nn
), set(0)
2548 space_node::space_node(hunits nn
, int s
, node
*p
) : node(p
), n(nn
), set(s
)
2553 space_node::~space_node()
2558 node
*space_node::copy()
2560 return new space_node(n
, set
);
2563 int space_node::nspaces()
2568 int space_node::merge_space(hunits h
)
2574 hunits
space_node::width()
2579 void node::spread_space(int*, hunits
*)
2583 void space_node::spread_space(int *nspaces
, hunits
*desired_space
)
2586 assert(*nspaces
> 0);
2587 if (*nspaces
== 1) {
2588 n
+= *desired_space
;
2589 *desired_space
= H0
;
2592 hunits extra
= *desired_space
/ *nspaces
;
2593 *desired_space
-= extra
;
2601 void node::freeze_space()
2605 void space_node::freeze_space()
2610 diverted_space_node::diverted_space_node(vunits d
, node
*p
)
2615 node
*diverted_space_node::copy()
2617 return new diverted_space_node(n
);
2620 diverted_copy_file_node::diverted_copy_file_node(symbol s
, node
*p
)
2621 : node(p
), filename(s
)
2625 node
*diverted_copy_file_node::copy()
2627 return new diverted_copy_file_node(filename
);
2630 int node::ends_sentence()
2635 int kern_pair_node::ends_sentence()
2637 switch (n2
->ends_sentence()) {
2647 return n1
->ends_sentence();
2650 int node_list_ends_sentence(node
*n
)
2652 for (; n
!= 0; n
= n
->next
)
2653 switch (n
->ends_sentence()) {
2667 int dbreak_node::ends_sentence()
2669 return node_list_ends_sentence(none
);
2673 int node::overlaps_horizontally()
2678 int node::overlaps_vertically()
2683 int node::discardable()
2688 int space_node::discardable()
2694 vunits
node::vertical_width()
2699 vunits
vline_node::vertical_width()
2704 vunits
vmotion_node::vertical_width()
2709 int node::character_type()
2714 hunits
node::subscript_correction()
2719 hunits
node::italic_correction()
2724 hunits
node::left_italic_correction()
2735 /* vertical_extent methods */
2737 void node::vertical_extent(vunits
*min
, vunits
*max
)
2739 vunits v
= vertical_width();
2750 void vline_node::vertical_extent(vunits
*min
, vunits
*max
)
2753 node::vertical_extent(min
, max
);
2756 n
->vertical_extent(&cmin
, &cmax
);
2757 vunits h
= n
->size();
2764 // we print the first character and then move up, so
2766 // we print the last character and then move up h
2779 // we move down by h and then print the first character, so
2789 /* ascii_print methods */
2792 static void ascii_print_reverse_node_list(ascii_output_file
*ascii
, node
*n
)
2796 ascii_print_reverse_node_list(ascii
, n
->next
);
2797 n
->ascii_print(ascii
);
2800 void dbreak_node::ascii_print(ascii_output_file
*ascii
)
2802 ascii_print_reverse_node_list(ascii
, none
);
2805 void kern_pair_node::ascii_print(ascii_output_file
*ascii
)
2807 n1
->ascii_print(ascii
);
2808 n2
->ascii_print(ascii
);
2812 void node::ascii_print(ascii_output_file
*)
2816 void space_node::ascii_print(ascii_output_file
*ascii
)
2822 void hmotion_node::ascii_print(ascii_output_file
*ascii
)
2824 // this is pretty arbitrary
2825 if (n
>= points_to_units(2))
2829 void space_char_hmotion_node::ascii_print(ascii_output_file
*ascii
)
2834 /* asciify methods */
2836 void node::asciify(macro
*m
)
2841 void glyph_node::asciify(macro
*m
)
2843 unsigned char c
= ci
->get_ascii_code();
2852 void kern_pair_node::asciify(macro
*m
)
2860 static void asciify_reverse_node_list(macro
*m
, node
*n
)
2864 asciify_reverse_node_list(m
, n
->next
);
2868 void dbreak_node::asciify(macro
*m
)
2870 asciify_reverse_node_list(m
, none
);
2875 void ligature_node::asciify(macro
*m
)
2883 void break_char_node::asciify(macro
*m
)
2890 void italic_corrected_node::asciify(macro
*m
)
2897 void left_italic_corrected_node::asciify(macro
*m
)
2906 space_char_hmotion_node::space_char_hmotion_node(hunits i
, node
*next
)
2907 : hmotion_node(i
, next
)
2911 void space_char_hmotion_node::asciify(macro
*m
)
2917 void line_start_node::asciify(macro
*)
2922 void vertical_size_node::asciify(macro
*)
2927 breakpoint
*node::get_breakpoints(hunits
/*width*/, int /*nspaces*/,
2928 breakpoint
*rest
, int /*is_inner*/)
2938 breakpoint
*space_node::get_breakpoints(hunits width
, int ns
, breakpoint
*rest
,
2941 if (next
->discardable())
2943 breakpoint
*bp
= new breakpoint
;
2950 bp
->index
= rest
->index
+ 1;
2960 int space_node::nbreaks()
2962 if (next
->discardable())
2968 static breakpoint
*node_list_get_breakpoints(node
*p
, hunits
*widthp
,
2969 int ns
, breakpoint
*rest
)
2972 rest
= p
->get_breakpoints(*widthp
,
2974 node_list_get_breakpoints(p
->next
, widthp
, ns
,
2977 *widthp
+= p
->width();
2983 breakpoint
*dbreak_node::get_breakpoints(hunits width
, int ns
,
2984 breakpoint
*rest
, int is_inner
)
2986 breakpoint
*bp
= new breakpoint
;
2989 for (node
*tem
= pre
; tem
!= 0; tem
= tem
->next
)
2990 bp
->width
+= tem
->width();
2995 bp
->index
= rest
->index
+ 1;
3002 return node_list_get_breakpoints(none
, &width
, ns
, bp
);
3005 int dbreak_node::nbreaks()
3008 for (node
*tem
= none
; tem
!= 0; tem
= tem
->next
)
3009 i
+= tem
->nbreaks();
3013 void node::split(int /*where*/, node
** /*prep*/, node
** /*postp*/)
3018 void space_node::split(int where
, node
**pre
, node
**post
)
3026 static void node_list_split(node
*p
, int *wherep
, node
**prep
, node
**postp
)
3030 int nb
= p
->nbreaks();
3031 node_list_split(p
->next
, wherep
, prep
, postp
);
3036 else if (*wherep
< nb
) {
3038 p
->split(*wherep
, prep
, postp
);
3047 void dbreak_node::split(int where
, node
**prep
, node
**postp
)
3057 for (tem
= pre
; tem
->next
!= 0; tem
= tem
->next
)
3068 node_list_split(none
, &where
, prep
, postp
);
3075 hyphenation_type
node::get_hyphenation_type()
3077 return HYPHEN_BOUNDARY
;
3081 hyphenation_type
dbreak_node::get_hyphenation_type()
3083 return HYPHEN_INHIBIT
;
3086 hyphenation_type
kern_pair_node::get_hyphenation_type()
3088 return HYPHEN_MIDDLE
;
3091 hyphenation_type
dummy_node::get_hyphenation_type()
3093 return HYPHEN_MIDDLE
;
3096 hyphenation_type
transparent_dummy_node::get_hyphenation_type()
3098 return HYPHEN_MIDDLE
;
3101 int node::interpret(macro
*)
3106 special_node::special_node(const macro
&m
)
3111 int special_node::same(node
*n
)
3113 return mac
== ((special_node
*)n
)->mac
;
3116 const char *special_node::type()
3118 return "special_node";
3121 node
*special_node::copy()
3123 return new special_node(mac
);
3126 void special_node::tprint_start(troff_output_file
*out
)
3128 out
->start_special();
3131 void special_node::tprint_char(troff_output_file
*out
, unsigned char c
)
3133 out
->special_char(c
);
3136 void special_node::tprint_end(troff_output_file
*out
)
3141 /* composite_node */
3143 class composite_node
: public charinfo_node
{
3147 composite_node(node
*, charinfo
*, tfont
*, node
* = 0);
3151 node
*last_char_node();
3153 void tprint(troff_output_file
*);
3154 hyphenation_type
get_hyphenation_type();
3155 void ascii_print(ascii_output_file
*);
3156 void asciify(macro
*);
3157 hyphen_list
*get_hyphen_list(hyphen_list
*tail
);
3158 node
*add_self(node
*, hyphen_list
**);
3162 void vertical_extent(vunits
*, vunits
*);
3163 vunits
vertical_width();
3166 composite_node::composite_node(node
*p
, charinfo
*c
, tfont
*t
, node
*x
)
3167 : charinfo_node(c
, x
), n(p
), tf(t
)
3171 composite_node::~composite_node()
3173 delete_node_list(n
);
3176 node
*composite_node::copy()
3178 return new composite_node(copy_node_list(n
), ci
, tf
);
3181 hunits
composite_node::width()
3184 if (tf
->get_constant_space(&x
))
3187 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3190 if (tf
->get_bold(&offset
))
3192 x
+= tf
->get_track_kern();
3196 node
*composite_node::last_char_node()
3201 vunits
composite_node::vertical_width()
3204 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3205 v
+= tem
->vertical_width();
3209 units
composite_node::size()
3211 return tf
->get_size().to_units();
3214 hyphenation_type
composite_node::get_hyphenation_type()
3216 return HYPHEN_MIDDLE
;
3219 void composite_node::asciify(macro
*m
)
3221 unsigned char c
= ci
->get_ascii_code();
3230 void composite_node::ascii_print(ascii_output_file
*ascii
)
3232 unsigned char c
= ci
->get_ascii_code();
3236 ascii
->outs(ci
->nm
.contents());
3240 hyphen_list
*composite_node::get_hyphen_list(hyphen_list
*tail
)
3242 return new hyphen_list(ci
->get_hyphenation_code(), tail
);
3246 node
*composite_node::add_self(node
*nn
, hyphen_list
**p
)
3248 assert(ci
->get_hyphenation_code() == (*p
)->hyphenation_code
);
3252 nn
= nn
->add_discretionary_hyphen();
3253 hyphen_list
*pp
= *p
;
3259 tfont
*composite_node::get_tfont()
3264 node
*reverse_node_list(node
*n
)
3276 void composite_node::vertical_extent(vunits
*min
, vunits
*max
)
3278 n
= reverse_node_list(n
);
3279 node_list_vertical_extent(n
, min
, max
);
3280 n
= reverse_node_list(n
);
3283 word_space_node::word_space_node(hunits d
, node
*x
) : space_node(d
, x
)
3287 word_space_node::word_space_node(hunits d
, int s
, node
*x
)
3288 : space_node(d
, s
, x
)
3292 node
*word_space_node::copy()
3294 return new word_space_node(n
, set
);
3297 void word_space_node::tprint(troff_output_file
*out
)
3300 space_node::tprint(out
);
3303 unbreakable_space_node::unbreakable_space_node(hunits d
, node
*x
)
3304 : word_space_node(d
, x
)
3308 unbreakable_space_node::unbreakable_space_node(hunits d
, int s
, node
*x
)
3309 : word_space_node(d
, s
, x
)
3313 node
*unbreakable_space_node::copy()
3315 return new unbreakable_space_node(n
, set
);
3318 breakpoint
*unbreakable_space_node::get_breakpoints(hunits
, int,
3319 breakpoint
*rest
, int)
3324 int unbreakable_space_node::nbreaks()
3329 void unbreakable_space_node::split(int, node
**, node
**)
3334 int unbreakable_space_node::merge_space(hunits
)
3343 draw_node::draw_node(char c
, hvpair
*p
, int np
, font_size s
)
3344 : npoints(np
), sz(s
), code(c
)
3346 point
= new hvpair
[npoints
];
3347 for (int i
= 0; i
< npoints
; i
++)
3351 int draw_node::same(node
*n
)
3353 draw_node
*nd
= (draw_node
*)n
;
3354 if (code
!= nd
->code
|| npoints
!= nd
->npoints
|| sz
!= nd
->sz
)
3356 for (int i
= 0; i
< npoints
; i
++)
3357 if (point
[i
].h
!= nd
->point
[i
].h
|| point
[i
].v
!= nd
->point
[i
].v
)
3362 const char *draw_node::type()
3367 draw_node::~draw_node()
3373 hunits
draw_node::width()
3376 for (int i
= 0; i
< npoints
; i
++)
3381 vunits
draw_node::vertical_width()
3386 for (int i
= 0; i
< npoints
; i
++)
3391 node
*draw_node::copy()
3393 return new draw_node(code
, point
, npoints
, sz
);
3396 void draw_node::tprint(troff_output_file
*out
)
3398 out
->draw(code
, point
, npoints
, sz
);
3401 /* tprint methods */
3403 void glyph_node::tprint(troff_output_file
*out
)
3405 tfont
*ptf
= tf
->get_plain();
3407 out
->put_char_width(ci
, ptf
, width(), H0
);
3410 int bold
= tf
->get_bold(&offset
);
3411 hunits w
= ptf
->get_width(ci
);
3414 int cs
= tf
->get_constant_space(&x
);
3424 k
= tf
->get_track_kern();
3426 out
->put_char(ci
, ptf
);
3429 out
->put_char_width(ci
, ptf
, w
, k
);
3433 void glyph_node::zero_width_tprint(troff_output_file
*out
)
3435 tfont
*ptf
= tf
->get_plain();
3437 int bold
= tf
->get_bold(&offset
);
3439 int cs
= tf
->get_constant_space(&x
);
3441 x
-= ptf
->get_width(ci
);
3447 out
->put_char(ci
, ptf
);
3450 out
->put_char(ci
, ptf
);
3451 out
->right(-offset
);
3457 void break_char_node::tprint(troff_output_file
*t
)
3462 void break_char_node::zero_width_tprint(troff_output_file
*t
)
3464 ch
->zero_width_tprint(t
);
3467 void hline_node::tprint(troff_output_file
*out
)
3477 hunits w
= n
->width();
3479 error("horizontal line drawing character must have positive width");
3489 out
->right(xx
- xx2
);
3492 hunits rem
= x
- w
*i
;
3494 if (n
->overlaps_horizontally()) {
3496 out
->right(rem
- w
);
3505 void vline_node::tprint(troff_output_file
*out
)
3511 vunits h
= n
->size();
3512 int overlaps
= n
->overlaps_vertically();
3517 vunits rem
= y
- i
*h
;
3519 out
->right(n
->width());
3524 n
->zero_width_tprint(out
);
3528 n
->zero_width_tprint(out
);
3535 out
->down(-h
- rem
);
3541 vunits rem
= y
- i
*h
;
3544 out
->right(n
->width());
3549 n
->zero_width_tprint(out
);
3552 n
->zero_width_tprint(out
);
3560 void zero_width_node::tprint(troff_output_file
*out
)
3565 n
->zero_width_tprint(out
);
3568 int hpos
= out
->get_hpos();
3569 int vpos
= out
->get_vpos();
3575 out
->moveto(hpos
, vpos
);
3578 void overstrike_node::tprint(troff_output_file
*out
)
3581 for (node
*tem
= list
; tem
; tem
= tem
->next
) {
3582 hunits x
= (max_width
- tem
->width())/2;
3583 out
->right(x
- pos
);
3585 tem
->zero_width_tprint(out
);
3587 out
->right(max_width
- pos
);
3590 void bracket_node::tprint(troff_output_file
*out
)
3596 for (tem
= list
; tem
; tem
= tem
->next
)
3598 vunits h
= list
->size();
3599 vunits totalh
= h
*npieces
;
3600 vunits y
= (totalh
- h
)/2;
3602 for (tem
= list
; tem
; tem
= tem
->next
) {
3603 tem
->zero_width_tprint(out
);
3606 out
->right(max_width
);
3607 out
->down(totalh
- y
);
3610 void node::tprint(troff_output_file
*)
3614 void node::zero_width_tprint(troff_output_file
*out
)
3616 int hpos
= out
->get_hpos();
3617 int vpos
= out
->get_vpos();
3619 out
->moveto(hpos
, vpos
);
3622 void space_node::tprint(troff_output_file
*out
)
3627 void hmotion_node::tprint(troff_output_file
*out
)
3632 void vmotion_node::tprint(troff_output_file
*out
)
3637 void kern_pair_node::tprint(troff_output_file
*out
)
3644 static void tprint_reverse_node_list(troff_output_file
*out
, node
*n
)
3648 tprint_reverse_node_list(out
, n
->next
);
3652 void dbreak_node::tprint(troff_output_file
*out
)
3654 tprint_reverse_node_list(out
, none
);
3657 void composite_node::tprint(troff_output_file
*out
)
3660 int is_bold
= tf
->get_bold(&bold_offset
);
3661 hunits track_kern
= tf
->get_track_kern();
3662 hunits constant_space
;
3663 int is_constant_spaced
= tf
->get_constant_space(&constant_space
);
3665 if (is_constant_spaced
) {
3667 for (node
*tem
= n
; tem
; tem
= tem
->next
)
3676 int hpos
= out
->get_hpos();
3677 int vpos
= out
->get_vpos();
3678 tprint_reverse_node_list(out
, n
);
3679 out
->moveto(hpos
, vpos
);
3680 out
->right(bold_offset
);
3682 tprint_reverse_node_list(out
, n
);
3683 if (is_constant_spaced
)
3686 out
->right(track_kern
);
3689 node
*make_composite_node(charinfo
*s
, environment
*env
)
3691 int fontno
= env_definite_font(env
);
3693 error("no current font");
3696 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
3697 node
*n
= charinfo_to_node_list(s
, env
);
3698 font_size fs
= env
->get_font_size();
3699 int char_height
= env
->get_char_height();
3700 int char_slant
= env
->get_char_slant();
3701 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
,
3703 if (env
->is_composite())
3704 tf
= tf
->get_plain();
3705 return new composite_node(n
, s
, tf
);
3708 node
*make_glyph_node(charinfo
*s
, environment
*env
, int no_error_message
= 0)
3710 int fontno
= env_definite_font(env
);
3712 error("no current font");
3715 assert(fontno
< font_table_size
&& font_table
[fontno
] != 0);
3717 int found
= font_table
[fontno
]->contains(s
);
3719 if (s
->numbered()) {
3720 if (!no_error_message
)
3721 warning(WARN_CHAR
, "can't find numbered character %1",
3725 special_font_list
*sf
= font_table
[fontno
]->sf
;
3726 while (sf
!= 0 && !found
) {
3729 found
= font_table
[fn
]->contains(s
);
3733 sf
= global_special_fonts
;
3734 while (sf
!= 0 && !found
) {
3737 found
= font_table
[fn
]->contains(s
);
3743 && global_special_fonts
== 0 && font_table
[fontno
]->sf
== 0
3746 for (fn
= 0; fn
< font_table_size
; fn
++)
3748 && font_table
[fn
]->is_special()
3749 && font_table
[fn
]->contains(s
)) {
3755 if (!no_error_message
&& s
->first_time_not_found()) {
3756 unsigned char input_code
= s
->get_ascii_code();
3757 if (input_code
!= 0) {
3758 if (csgraph(input_code
))
3759 warning(WARN_CHAR
, "can't find character `%1'", input_code
);
3761 warning(WARN_CHAR
, "can't find character with input code %1",
3765 warning(WARN_CHAR
, "can't find special character `%1'",
3771 font_size fs
= env
->get_font_size();
3772 int char_height
= env
->get_char_height();
3773 int char_slant
= env
->get_char_slant();
3774 tfont
*tf
= font_table
[fontno
]->get_tfont(fs
, char_height
, char_slant
, fn
);
3775 if (env
->is_composite())
3776 tf
= tf
->get_plain();
3777 return new glyph_node(s
, tf
);
3780 node
*make_node(charinfo
*ci
, environment
*env
)
3782 switch (ci
->get_special_translation()) {
3783 case charinfo::TRANSLATE_SPACE
:
3784 return new space_char_hmotion_node(env
->get_space_width());
3785 case charinfo::TRANSLATE_DUMMY
:
3786 return new dummy_node
;
3787 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
3788 error("translation to \\% ignored in this context");
3791 charinfo
*tem
= ci
->get_translation();
3794 macro
*mac
= ci
->get_macro();
3796 return make_composite_node(ci
, env
);
3798 return make_glyph_node(ci
, env
);
3801 int character_exists(charinfo
*ci
, environment
*env
)
3803 if (ci
->get_special_translation() != charinfo::TRANSLATE_NONE
)
3805 charinfo
*tem
= ci
->get_translation();
3808 if (ci
->get_macro())
3810 node
*nd
= make_glyph_node(ci
, env
, 1);
3818 node
*node::add_char(charinfo
*ci
, environment
*env
, hunits
*widthp
)
3821 switch (ci
->get_special_translation()) {
3822 case charinfo::TRANSLATE_SPACE
:
3823 res
= new space_char_hmotion_node(env
->get_space_width(), this);
3824 *widthp
+= res
->width();
3826 case charinfo::TRANSLATE_DUMMY
:
3827 return new dummy_node(this);
3828 case charinfo::TRANSLATE_HYPHEN_INDICATOR
:
3829 return add_discretionary_hyphen();
3831 charinfo
*tem
= ci
->get_translation();
3834 macro
*mac
= ci
->get_macro();
3836 res
= make_composite_node(ci
, env
);
3839 *widthp
+= res
->width();
3845 node
*gn
= make_glyph_node(ci
, env
);
3849 hunits old_width
= width();
3850 node
*p
= gn
->merge_self(this);
3852 *widthp
+= gn
->width();
3857 *widthp
+= p
->width() - old_width
;
3863 if (ci
->can_break_before())
3865 if (ci
->can_break_after())
3868 node
*next1
= res
->next
;
3870 res
= new break_char_node(res
, break_code
, next1
);
3879 int same_node(node
*n1
, node
*n2
)
3883 return n1
->type() == n2
->type() && n1
->same(n2
);
3891 int same_node_list(node
*n1
, node
*n2
)
3894 if (n1
->type() != n2
->type() || !n1
->same(n2
))
3902 int extra_size_node::same(node
*nd
)
3904 return n
== ((extra_size_node
*)nd
)->n
;
3907 const char *extra_size_node::type()
3909 return "extra_size_node";
3912 int vertical_size_node::same(node
*nd
)
3914 return n
== ((vertical_size_node
*)nd
)->n
;
3917 const char *vertical_size_node::type()
3919 return "vertical_size_node";
3922 int hmotion_node::same(node
*nd
)
3924 return n
== ((hmotion_node
*)nd
)->n
;
3927 const char *hmotion_node::type()
3929 return "hmotion_node";
3932 int space_char_hmotion_node::same(node
*nd
)
3934 return n
== ((space_char_hmotion_node
*)nd
)->n
;
3937 const char *space_char_hmotion_node::type()
3939 return "space_char_hmotion_node";
3942 int vmotion_node::same(node
*nd
)
3944 return n
== ((vmotion_node
*)nd
)->n
;
3947 const char *vmotion_node::type()
3949 return "vmotion_node";
3952 int hline_node::same(node
*nd
)
3954 return x
== ((hline_node
*)nd
)->x
&& same_node(n
, ((hline_node
*)nd
)->n
);
3957 const char *hline_node::type()
3959 return "hline_node";
3962 int vline_node::same(node
*nd
)
3964 return x
== ((vline_node
*)nd
)->x
&& same_node(n
, ((vline_node
*)nd
)->n
);
3967 const char *vline_node::type()
3969 return "vline_node";
3972 int dummy_node::same(node
* /*nd*/)
3977 const char *dummy_node::type()
3979 return "dummy_node";
3982 int transparent_dummy_node::same(node
* /*nd*/)
3987 const char *transparent_dummy_node::type()
3989 return "transparent_dummy_node";
3992 int transparent_dummy_node::ends_sentence()
3997 int zero_width_node::same(node
*nd
)
3999 return same_node_list(n
, ((zero_width_node
*)nd
)->n
);
4002 const char *zero_width_node::type()
4004 return "zero_width_node";
4007 int italic_corrected_node::same(node
*nd
)
4009 return (x
== ((italic_corrected_node
*)nd
)->x
4010 && same_node(n
, ((italic_corrected_node
*)nd
)->n
));
4013 const char *italic_corrected_node::type()
4015 return "italic_corrected_node";
4019 left_italic_corrected_node::left_italic_corrected_node(node
*x
)
4024 left_italic_corrected_node::~left_italic_corrected_node()
4029 node
*left_italic_corrected_node::merge_glyph_node(glyph_node
*gn
)
4032 hunits lic
= gn
->left_italic_correction();
4033 if (!lic
.is_zero()) {
4040 node
*nd
= n
->merge_glyph_node(gn
);
4043 x
= n
->left_italic_correction();
4050 node
*left_italic_corrected_node::copy()
4052 left_italic_corrected_node
*nd
= new left_italic_corrected_node
;
4060 void left_italic_corrected_node::tprint(troff_output_file
*out
)
4068 const char *left_italic_corrected_node::type()
4070 return "left_italic_corrected_node";
4073 int left_italic_corrected_node::same(node
*nd
)
4075 return (x
== ((left_italic_corrected_node
*)nd
)->x
4076 && same_node(n
, ((left_italic_corrected_node
*)nd
)->n
));
4079 void left_italic_corrected_node::ascii_print(ascii_output_file
*out
)
4082 n
->ascii_print(out
);
4085 hunits
left_italic_corrected_node::width()
4087 return n
? n
->width() + x
: H0
;
4090 void left_italic_corrected_node::vertical_extent(vunits
*min
, vunits
*max
)
4093 n
->vertical_extent(min
, max
);
4095 node::vertical_extent(min
, max
);
4098 hunits
left_italic_corrected_node::skew()
4100 return n
? n
->skew() + x
/2 : H0
;
4103 hunits
left_italic_corrected_node::subscript_correction()
4105 return n
? n
->subscript_correction() : H0
;
4108 hunits
left_italic_corrected_node::italic_correction()
4110 return n
? n
->italic_correction() : H0
;
4113 int left_italic_corrected_node::ends_sentence()
4115 return n
? n
->ends_sentence() : 0;
4118 int left_italic_corrected_node::overlaps_horizontally()
4120 return n
? n
->overlaps_horizontally() : 0;
4123 int left_italic_corrected_node::overlaps_vertically()
4125 return n
? n
->overlaps_vertically() : 0;
4128 node
*left_italic_corrected_node::last_char_node()
4130 return n
? n
->last_char_node() : 0;
4133 tfont
*left_italic_corrected_node::get_tfont()
4135 return n
? n
->get_tfont() : 0;
4138 hyphenation_type
left_italic_corrected_node::get_hyphenation_type()
4141 return n
->get_hyphenation_type();
4143 return HYPHEN_MIDDLE
;
4146 hyphen_list
*left_italic_corrected_node::get_hyphen_list(hyphen_list
*tail
)
4148 return n
? n
->get_hyphen_list(tail
) : tail
;
4151 node
*left_italic_corrected_node::add_self(node
*nd
, hyphen_list
**p
)
4154 nd
= new left_italic_corrected_node(nd
);
4155 nd
= n
->add_self(nd
, p
);
4162 int left_italic_corrected_node::character_type()
4164 return n
? n
->character_type() : 0;
4167 int overstrike_node::same(node
*nd
)
4169 return same_node_list(list
, ((overstrike_node
*)nd
)->list
);
4172 const char *overstrike_node::type()
4174 return "overstrike_node";
4177 int bracket_node::same(node
*nd
)
4179 return same_node_list(list
, ((bracket_node
*)nd
)->list
);
4182 const char *bracket_node::type()
4184 return "bracket_node";
4187 int composite_node::same(node
*nd
)
4189 return ci
== ((composite_node
*)nd
)->ci
4190 && same_node_list(n
, ((composite_node
*)nd
)->n
);
4193 const char *composite_node::type()
4195 return "composite_node";
4198 int glyph_node::same(node
*nd
)
4200 return ci
== ((glyph_node
*)nd
)->ci
&& tf
== ((glyph_node
*)nd
)->tf
;
4203 const char *glyph_node::type()
4205 return "glyph_node";
4208 int ligature_node::same(node
*nd
)
4210 return (same_node(n1
, ((ligature_node
*)nd
)->n1
)
4211 && same_node(n2
, ((ligature_node
*)nd
)->n2
)
4212 && glyph_node::same(nd
));
4215 const char *ligature_node::type()
4217 return "ligature_node";
4220 int kern_pair_node::same(node
*nd
)
4222 return (amount
== ((kern_pair_node
*)nd
)->amount
4223 && same_node(n1
, ((kern_pair_node
*)nd
)->n1
)
4224 && same_node(n2
, ((kern_pair_node
*)nd
)->n2
));
4227 const char *kern_pair_node::type()
4229 return "kern_pair_node";
4232 int dbreak_node::same(node
*nd
)
4234 return (same_node_list(none
, ((dbreak_node
*)nd
)->none
)
4235 && same_node_list(pre
, ((dbreak_node
*)nd
)->pre
)
4236 && same_node_list(post
, ((dbreak_node
*)nd
)->post
));
4239 const char *dbreak_node::type()
4241 return "dbreak_node";
4244 int break_char_node::same(node
*nd
)
4246 return (break_code
== ((break_char_node
*)nd
)->break_code
4247 && same_node(ch
, ((break_char_node
*)nd
)->ch
));
4250 const char *break_char_node::type()
4252 return "break_char_node";
4255 int line_start_node::same(node
* /*nd*/)
4260 const char *line_start_node::type()
4262 return "line_start_node";
4265 int space_node::same(node
*nd
)
4267 return n
== ((space_node
*)nd
)->n
&& set
== ((space_node
*)nd
)->set
;
4270 const char *space_node::type()
4272 return "space_node";
4275 int word_space_node::same(node
*nd
)
4277 return (n
== ((word_space_node
*)nd
)->n
4278 && set
== ((word_space_node
*)nd
)->set
);
4281 const char *word_space_node::type()
4283 return "word_space_node";
4286 int unbreakable_space_node::same(node
*nd
)
4288 return (n
== ((unbreakable_space_node
*)nd
)->n
4289 && set
== ((unbreakable_space_node
*)nd
)->set
);
4292 const char *unbreakable_space_node::type()
4294 return "unbreakable_space_node";
4297 int diverted_space_node::same(node
*nd
)
4299 return n
== ((diverted_space_node
*)nd
)->n
;
4302 const char *diverted_space_node::type()
4304 return "diverted_space_node";
4307 int diverted_copy_file_node::same(node
*nd
)
4309 return filename
== ((diverted_copy_file_node
*)nd
)->filename
;
4312 const char *diverted_copy_file_node::type()
4314 return "diverted_copy_file_node";
4317 // Grow the font_table so that its size is > n.
4319 static void grow_font_table(int n
)
4321 assert(n
>= font_table_size
);
4322 font_info
**old_font_table
= font_table
;
4323 int old_font_table_size
= font_table_size
;
4324 font_table_size
= font_table_size
? (font_table_size
*3)/2 : 10;
4325 if (font_table_size
<= n
)
4326 font_table_size
= n
+ 10;
4327 font_table
= new font_info
*[font_table_size
];
4328 if (old_font_table_size
)
4329 memcpy(font_table
, old_font_table
,
4330 old_font_table_size
*sizeof(font_info
*));
4331 a_delete old_font_table
;
4332 for (int i
= old_font_table_size
; i
< font_table_size
; i
++)
4336 dictionary
font_translation_dictionary(17);
4338 static symbol
get_font_translation(symbol nm
)
4340 void *p
= font_translation_dictionary
.lookup(nm
);
4341 return p
? symbol((char *)p
) : nm
;
4344 dictionary
font_dictionary(50);
4346 static int mount_font_no_translate(int n
, symbol name
, symbol external_name
)
4349 // We store the address of this char in font_dictionary to indicate
4350 // that we've previously tried to mount the font and failed.
4353 void *p
= font_dictionary
.lookup(external_name
);
4356 fm
= font::load_font(external_name
.contents(), ¬_found
);
4359 warning(WARN_FONT
, "can't find font `%1'", external_name
.contents());
4360 font_dictionary
.lookup(external_name
, &a_char
);
4363 font_dictionary
.lookup(name
, fm
);
4365 else if (p
== &a_char
) {
4367 error("invalid font `%1'", external_name
.contents());
4373 if (n
>= font_table_size
) {
4374 if (n
- font_table_size
> 1000) {
4375 error("font position too much larger than first unused position");
4380 else if (font_table
[n
] != 0)
4381 delete font_table
[n
];
4382 font_table
[n
] = new font_info(name
, n
, external_name
, fm
);
4383 font_family::invalidate_fontno(n
);
4387 int mount_font(int n
, symbol name
, symbol external_name
)
4390 name
= get_font_translation(name
);
4391 if (external_name
.is_null())
4392 external_name
= name
;
4394 external_name
= get_font_translation(external_name
);
4395 return mount_font_no_translate(n
, name
, external_name
);
4398 void mount_style(int n
, symbol name
)
4401 if (n
>= font_table_size
) {
4402 if (n
- font_table_size
> 1000) {
4403 error("font position too much larger than first unused position");
4408 else if (font_table
[n
] != 0)
4409 delete font_table
[n
];
4410 font_table
[n
] = new font_info(get_font_translation(name
), n
, NULL_SYMBOL
, 0);
4411 font_family::invalidate_fontno(n
);
4414 /* global functions */
4416 void font_translate()
4418 symbol from
= get_name(1);
4419 if (!from
.is_null()) {
4420 symbol to
= get_name();
4421 if (to
.is_null() || from
== to
)
4422 font_translation_dictionary
.remove(from
);
4424 font_translation_dictionary
.lookup(from
, (void *)to
.contents());
4429 void font_position()
4432 if (get_integer(&n
)) {
4434 error("negative font position");
4436 symbol internal_name
= get_name(1);
4437 if (!internal_name
.is_null()) {
4438 symbol external_name
= get_long_name(0);
4439 mount_font(n
, internal_name
, external_name
); // ignore error
4446 font_family::font_family(symbol s
)
4447 : map_size(10), nm(s
)
4449 map
= new int[map_size
];
4450 for (int i
= 0; i
< map_size
; i
++)
4454 font_family::~font_family()
4459 int font_family::make_definite(int i
)
4462 if (i
< map_size
&& map
[i
] >= 0)
4465 if (i
< font_table_size
&& font_table
[i
] != 0) {
4466 if (i
>= map_size
) {
4467 int old_map_size
= map_size
;
4473 map
= new int[map_size
];
4474 memcpy(map
, old_map
, old_map_size
*sizeof(int));
4476 for (int j
= old_map_size
; j
< map_size
; j
++)
4479 if (font_table
[i
]->is_style()) {
4480 symbol sty
= font_table
[i
]->get_name();
4481 symbol f
= concat(nm
, sty
);
4483 // don't use symbol_fontno, because that might return a style
4484 // and because we don't want to translate the name
4485 for (n
= 0; n
< font_table_size
; n
++)
4486 if (font_table
[n
] != 0 && font_table
[n
]->is_named(f
)
4487 && !font_table
[n
]->is_style())
4489 if (n
>= font_table_size
) {
4490 n
= next_available_font_position();
4491 if (!mount_font_no_translate(n
, f
, f
))
4507 dictionary
family_dictionary(5);
4509 font_family
*lookup_family(symbol nm
)
4511 font_family
*f
= (font_family
*)family_dictionary
.lookup(nm
);
4513 f
= new font_family(nm
);
4514 (void)family_dictionary
.lookup(nm
, f
);
4519 void font_family::invalidate_fontno(int n
)
4521 assert(n
>= 0 && n
< font_table_size
);
4522 dictionary_iterator
iter(family_dictionary
);
4525 while (iter
.get(&nm
, (void **)&fam
)) {
4526 int map_size
= fam
->map_size
;
4529 for (int i
= 0; i
< map_size
; i
++)
4530 if (fam
->map
[i
] == n
)
4538 if (get_integer(&n
)) {
4540 error("negative font position");
4542 symbol internal_name
= get_name(1);
4543 if (!internal_name
.is_null())
4544 mount_style(n
, internal_name
);
4550 static int get_fontno()
4554 if (tok
.delimiter()) {
4555 symbol s
= get_name(1);
4557 n
= symbol_fontno(s
);
4559 n
= next_available_font_position();
4560 if (!mount_font(n
, s
))
4563 return curenv
->get_family()->make_definite(n
);
4566 else if (get_integer(&n
)) {
4567 if (n
< 0 || n
>= font_table_size
|| font_table
[n
] == 0)
4568 error("bad font number");
4570 return curenv
->get_family()->make_definite(n
);
4575 static int underline_fontno
= 2;
4577 void underline_font()
4579 int n
= get_fontno();
4581 underline_fontno
= n
;
4585 int get_underline_fontno()
4587 return underline_fontno
;
4590 static void read_special_fonts(special_font_list
**sp
)
4592 special_font_list
*s
= *sp
;
4595 special_font_list
*tem
= s
;
4599 special_font_list
**p
= sp
;
4601 int i
= get_fontno();
4603 special_font_list
*tem
= new special_font_list
;
4612 void font_special_request()
4614 int n
= get_fontno();
4616 read_special_fonts(&font_table
[n
]->sf
);
4621 void special_request()
4623 read_special_fonts(&global_special_fonts
);
4627 int next_available_font_position()
4630 for (i
= 1; i
< font_table_size
&& font_table
[i
] != 0; i
++)
4635 int symbol_fontno(symbol s
)
4637 s
= get_font_translation(s
);
4638 for (int i
= 0; i
< font_table_size
; i
++)
4639 if (font_table
[i
] != 0 && font_table
[i
]->is_named(s
))
4644 int is_good_fontno(int n
)
4646 return n
>= 0 && n
< font_table_size
&& font_table
[n
] != NULL
;
4649 int get_bold_fontno(int n
)
4651 if (n
>= 0 && n
< font_table_size
&& font_table
[n
] != 0) {
4653 if (font_table
[n
]->get_bold(&offset
))
4654 return offset
.to_units() + 1;
4662 hunits
env_digit_width(environment
*env
)
4664 node
*n
= make_glyph_node(charset_table
['0'], env
);
4666 hunits x
= n
->width();
4674 hunits
env_space_width(environment
*env
)
4676 int fn
= env_definite_font(env
);
4677 font_size fs
= env
->get_font_size();
4678 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
4679 return scale(fs
.to_units()/3, env
->get_space_size(), 12);
4681 return font_table
[fn
]->get_space_width(fs
, env
->get_space_size());
4684 hunits
env_sentence_space_width(environment
*env
)
4686 int fn
= env_definite_font(env
);
4687 font_size fs
= env
->get_font_size();
4688 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
4689 return scale(fs
.to_units()/3, env
->get_sentence_space_size(), 12);
4691 return font_table
[fn
]->get_space_width(fs
, env
->get_sentence_space_size());
4694 hunits
env_half_narrow_space_width(environment
*env
)
4696 int fn
= env_definite_font(env
);
4697 font_size fs
= env
->get_font_size();
4698 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
4701 return font_table
[fn
]->get_half_narrow_space_width(fs
);
4704 hunits
env_narrow_space_width(environment
*env
)
4706 int fn
= env_definite_font(env
);
4707 font_size fs
= env
->get_font_size();
4708 if (fn
< 0 || fn
>= font_table_size
|| font_table
[fn
] == 0)
4711 return font_table
[fn
]->get_narrow_space_width(fs
);
4716 int n
= get_fontno();
4719 if (tok
.delimiter()) {
4720 int f
= get_fontno();
4723 if (has_arg() && get_number(&offset
, 'u') && offset
>= 1)
4724 font_table
[f
]->set_conditional_bold(n
, hunits(offset
- 1));
4726 font_table
[f
]->conditional_unbold(n
);
4731 if (get_number(&offset
, 'u') && offset
>= 1)
4732 font_table
[n
]->set_bold(hunits(offset
- 1));
4734 font_table
[n
]->unbold();
4738 font_table
[n
]->unbold();
4743 track_kerning_function::track_kerning_function() : non_zero(0)
4747 track_kerning_function::track_kerning_function(int min_s
, hunits min_a
,
4748 int max_s
, hunits max_a
)
4750 min_size(min_s
), min_amount(min_a
),
4751 max_size(max_s
), max_amount(max_a
)
4755 int track_kerning_function::operator==(const track_kerning_function
&tk
)
4759 && min_size
== tk
.min_size
4760 && min_amount
== tk
.min_amount
4761 && max_size
== tk
.max_size
4762 && max_amount
== tk
.max_amount
);
4764 return !tk
.non_zero
;
4767 int track_kerning_function::operator!=(const track_kerning_function
&tk
)
4770 return (!tk
.non_zero
4771 || min_size
!= tk
.min_size
4772 || min_amount
!= tk
.min_amount
4773 || max_size
!= tk
.max_size
4774 || max_amount
!= tk
.max_amount
);
4779 hunits
track_kerning_function::compute(int size
)
4782 if (max_size
<= min_size
)
4784 else if (size
<= min_size
)
4786 else if (size
>= max_size
)
4789 return (scale(max_amount
, size
- min_size
, max_size
- min_size
)
4790 + scale(min_amount
, max_size
- size
, max_size
- min_size
));
4798 int n
= get_fontno();
4801 hunits min_a
, max_a
;
4803 && get_number(&min_s
, 'z')
4804 && get_hunits(&min_a
, 'p')
4805 && get_number(&max_s
, 'z')
4806 && get_hunits(&max_a
, 'p')) {
4807 track_kerning_function
tk(min_s
, min_a
, max_s
, max_a
);
4808 font_table
[n
]->set_track_kern(tk
);
4811 track_kerning_function tk
;
4812 font_table
[n
]->set_track_kern(tk
);
4818 void constant_space()
4820 int n
= get_fontno();
4823 if (!has_arg() || !get_integer(&x
))
4824 font_table
[n
]->set_constant_space(CONSTANT_SPACE_NONE
);
4826 if (!has_arg() || !get_number(&y
, 'z'))
4827 font_table
[n
]->set_constant_space(CONSTANT_SPACE_RELATIVE
, x
);
4829 font_table
[n
]->set_constant_space(CONSTANT_SPACE_ABSOLUTE
,
4841 if (has_arg() && get_integer(&lig
) && lig
>= 0 && lig
<= 2)
4842 global_ligature_mode
= lig
;
4844 global_ligature_mode
= 1;
4851 if (has_arg() && get_integer(&k
))
4852 global_kern_mode
= k
!= 0;
4854 global_kern_mode
= 1;
4858 void set_soft_hyphen_char()
4860 soft_hyphen_char
= get_optional_char();
4861 if (!soft_hyphen_char
)
4862 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);
4868 if (suppress_output_flag
)
4869 the_output
= new suppress_output_file
;
4870 else if (ascii_output_flag
)
4871 the_output
= new ascii_output_file
;
4873 the_output
= new troff_output_file
;
4876 class next_available_font_position_reg
: public reg
{
4878 const char *get_string();
4881 const char *next_available_font_position_reg::get_string()
4883 return i_to_a(next_available_font_position());
4886 class printing_reg
: public reg
{
4888 const char *get_string();
4891 const char *printing_reg::get_string()
4894 return the_output
->is_printing() ? "1" : "0";
4899 void init_node_requests()
4901 init_request("fp", font_position
);
4902 init_request("sty", style
);
4903 init_request("cs", constant_space
);
4904 init_request("bd", bold_font
);
4905 init_request("uf", underline_font
);
4906 init_request("lg", ligature
);
4907 init_request("kern", kern_request
);
4908 init_request("tkf", track_kern
);
4909 init_request("special", special_request
);
4910 init_request("fspecial", font_special_request
);
4911 init_request("ftr", font_translate
);
4912 init_request("shc", set_soft_hyphen_char
);
4913 number_reg_dictionary
.define(".fp", new next_available_font_position_reg
);
4914 number_reg_dictionary
.define(".kern",
4915 new constant_int_reg(&global_kern_mode
));
4916 number_reg_dictionary
.define(".lg",
4917 new constant_int_reg(&global_ligature_mode
));
4918 number_reg_dictionary
.define(".P", new printing_reg
);
4919 soft_hyphen_char
= get_charinfo(HYPHEN_SYMBOL
);