summaryrefslogtreecommitdiffstats
path: root/contrib/groff/src/roff/troff
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/groff/src/roff/troff')
-rw-r--r--contrib/groff/src/roff/troff/Makefile.sub20
-rw-r--r--contrib/groff/src/roff/troff/TODO3
-rw-r--r--contrib/groff/src/roff/troff/charinfo.h38
-rw-r--r--contrib/groff/src/roff/troff/dictionary.cc2
-rw-r--r--contrib/groff/src/roff/troff/div.cc23
-rw-r--r--contrib/groff/src/roff/troff/div.h2
-rw-r--r--contrib/groff/src/roff/troff/env.cc607
-rw-r--r--contrib/groff/src/roff/troff/env.h33
-rw-r--r--contrib/groff/src/roff/troff/input.cc1685
-rw-r--r--contrib/groff/src/roff/troff/node.cc650
-rw-r--r--contrib/groff/src/roff/troff/node.h51
-rw-r--r--contrib/groff/src/roff/troff/number.cc9
-rw-r--r--contrib/groff/src/roff/troff/request.h10
-rw-r--r--contrib/groff/src/roff/troff/symbol.cc14
-rw-r--r--contrib/groff/src/roff/troff/symbol.h9
-rw-r--r--contrib/groff/src/roff/troff/token.h21
-rw-r--r--contrib/groff/src/roff/troff/troff.h18
-rw-r--r--contrib/groff/src/roff/troff/troff.man2595
18 files changed, 2691 insertions, 3099 deletions
diff --git a/contrib/groff/src/roff/troff/Makefile.sub b/contrib/groff/src/roff/troff/Makefile.sub
index e883959..e889cdd 100644
--- a/contrib/groff/src/roff/troff/Makefile.sub
+++ b/contrib/groff/src/roff/troff/Makefile.sub
@@ -1,17 +1,17 @@
-PROG=troff
+PROG=troff$(EXEEXT)
MAN1=troff.n
XLIBS=$(LIBGROFF)
MLIB=$(LIBM)
OBJS=\
- env.o \
- node.o \
- input.o \
- div.o \
- symbol.o \
- dictionary.o \
- reg.o \
- number.o \
- majorminor.o
+ env.$(OBJEXT) \
+ node.$(OBJEXT) \
+ input.$(OBJEXT) \
+ div.$(OBJEXT) \
+ symbol.$(OBJEXT) \
+ dictionary.$(OBJEXT) \
+ reg.$(OBJEXT) \
+ number.$(OBJEXT) \
+ majorminor.$(OBJEXT)
CCSRCS=\
$(srcdir)/env.cc \
$(srcdir)/node.cc \
diff --git a/contrib/groff/src/roff/troff/TODO b/contrib/groff/src/roff/troff/TODO
index 6660597..49aa0eb 100644
--- a/contrib/groff/src/roff/troff/TODO
+++ b/contrib/groff/src/roff/troff/TODO
@@ -83,9 +83,6 @@ Then is you ask for R at pointsize 16, groff will first look for
R.display and then R. Probably necessary to be able to specify a
separate unitwidth for each sizesuffix (eg. for X).
-Variant of `.it' for which a line interrupted with \c counts as one
-input line.
-
Make it possible to suppress hyphenation on a word-by-word basis.
(Perhaps store hyphenation flags in tfont.)
diff --git a/contrib/groff/src/roff/troff/charinfo.h b/contrib/groff/src/roff/troff/charinfo.h
index a4ecd57..b907ae4 100644
--- a/contrib/groff/src/roff/troff/charinfo.h
+++ b/contrib/groff/src/roff/troff/charinfo.h
@@ -1,5 +1,6 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
+ Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -30,9 +31,13 @@ class charinfo {
unsigned char hyphenation_code;
unsigned char flags;
unsigned char ascii_code;
+ unsigned char asciify_code;
char not_found;
- char transparent_translate; // non-zero means translation applies to
+ char transparent_translate; // non-zero means translation applies
// to transparent throughput
+ char translate_input; // non-zero means that asciify_code is
+ // active for .asciify (set by .trin)
+ char fallback;
public:
enum {
ENDS_SENTENCE = 1,
@@ -61,19 +66,24 @@ public:
int transparent();
unsigned char get_hyphenation_code();
unsigned char get_ascii_code();
+ unsigned char get_asciify_code();
void set_hyphenation_code(unsigned char);
void set_ascii_code(unsigned char);
+ void set_asciify_code(unsigned char);
+ void set_translation_input();
+ int get_translation_input();
charinfo *get_translation(int = 0);
- void set_translation(charinfo *, int);
+ void set_translation(charinfo *, int, int);
void set_flags(unsigned char);
void set_special_translation(int, int);
int get_special_translation(int = 0);
- macro *set_macro(macro *);
+ macro *set_macro(macro *, int = 0);
macro *get_macro();
int first_time_not_found();
void set_number(int);
int get_number();
int numbered();
+ int is_fallback();
symbol *get_symbol();
};
@@ -116,6 +126,11 @@ inline int charinfo::numbered()
return flags & NUMBERED;
}
+inline int charinfo::is_fallback()
+{
+ return fallback;
+}
+
inline charinfo *charinfo::get_translation(int transparent_throughput)
{
return (transparent_throughput && !transparent_translate
@@ -133,6 +148,11 @@ inline unsigned char charinfo::get_ascii_code()
return ascii_code;
}
+inline unsigned char charinfo::get_asciify_code()
+{
+ return (translate_input ? asciify_code : 0);
+}
+
inline void charinfo::set_flags(unsigned char c)
{
flags = c;
@@ -143,6 +163,16 @@ inline int charinfo::get_index()
return index;
}
+inline void charinfo::set_translation_input()
+{
+ translate_input = 1;
+}
+
+inline int charinfo::get_translation_input()
+{
+ return translate_input;
+}
+
inline int charinfo::get_special_translation(int transparent_throughput)
{
return (transparent_throughput && !transparent_translate
diff --git a/contrib/groff/src/roff/troff/dictionary.cc b/contrib/groff/src/roff/troff/dictionary.cc
index bca3845..a70ebb0 100644
--- a/contrib/groff/src/roff/troff/dictionary.cc
+++ b/contrib/groff/src/roff/troff/dictionary.cc
@@ -138,7 +138,7 @@ int dictionary_iterator::get(symbol *sp, void **vp)
}
object_dictionary_iterator::object_dictionary_iterator(object_dictionary &od)
- : di(od.d)
+: di(od.d)
{
}
diff --git a/contrib/groff/src/roff/troff/div.cc b/contrib/groff/src/roff/troff/div.cc
index c885ca8..14c7399 100644
--- a/contrib/groff/src/roff/troff/div.cc
+++ b/contrib/groff/src/roff/troff/div.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
@@ -410,7 +410,7 @@ void top_level_diversion::output(node *nd, int retain_size,
void top_level_diversion::transparent_output(unsigned char c)
{
if (before_first_page && begin_page())
- // This can only happen with the transparent() request.
+ // This can only happen with the .output request.
fatal("sorry, I didn't manage to begin the first page in time: use an explicit .br request");
const char *s = asciify(c);
while (*s)
@@ -467,7 +467,7 @@ void top_level_diversion::space(vunits n, int forced)
}
trap::trap(symbol s, vunits n, trap *p)
- : next(p), position(n), nm(s)
+: next(p), position(n), nm(s)
{
}
@@ -641,7 +641,7 @@ void page_offset()
n = topdiv->prev_page_offset;
topdiv->prev_page_offset = topdiv->page_offset;
topdiv->page_offset = n;
- curenv->add_html_tag(".po", n.to_units());
+ curenv->add_html_tag(0, ".po", n.to_units());
skip_line();
}
@@ -760,7 +760,7 @@ void space_request()
else
// The line might have had line spacing that was truncated.
truncated_space += n;
- curenv->add_html_tag(".sp", n.to_units());
+ curenv->add_html_tag(1, ".sp", n.to_units());
tok.next();
}
@@ -769,7 +769,7 @@ void blank_line()
curenv->do_break();
if (!trap_sprung_flag && !curdiv->no_space_mode) {
curdiv->space(curenv->get_vertical_spacing());
- curenv->add_html_tag(".sp", 1);
+ curenv->add_html_tag(1, ".sp", 1);
} else
truncated_space += curenv->get_vertical_spacing();
}
@@ -791,8 +791,13 @@ void need_space()
void page_number()
{
int n;
- if (has_arg() && get_integer(&n, topdiv->get_page_number()))
- topdiv->set_next_page_number(n);
+
+ // the ps4html register is set if we are using -Tps
+ // to generate images for html
+ reg *r = (reg *)number_reg_dictionary.lookup("ps4html");
+ if (r == NULL)
+ if (has_arg() && get_integer(&n, topdiv->get_page_number()))
+ topdiv->set_next_page_number(n);
skip_line();
}
@@ -828,7 +833,7 @@ void flush_output()
curenv->do_break();
if (the_output)
the_output->flush();
- curenv->add_html_tag(".fl");
+ curenv->add_html_tag(1, ".fl");
tok.next();
}
diff --git a/contrib/groff/src/roff/troff/div.h b/contrib/groff/src/roff/troff/div.h
index 3b726c3..31b9af3 100644
--- a/contrib/groff/src/roff/troff/div.h
+++ b/contrib/groff/src/roff/troff/div.h
@@ -152,5 +152,7 @@ void push_page_ejector();
void continue_page_eject();
void handle_first_page_transition();
void blank_line();
+void begin_page();
+void end_diversions();
extern void cleanup_and_exit(int);
diff --git a/contrib/groff/src/roff/troff/env.cc b/contrib/groff/src/roff/troff/env.cc
index c0743441..40c9e3c 100644
--- a/contrib/groff/src/roff/troff/env.cc
+++ b/contrib/groff/src/roff/troff/env.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
@@ -31,6 +31,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "reg.h"
#include "charinfo.h"
#include "macropath.h"
+#include "input.h"
#include <math.h>
symbol default_family("T");
@@ -299,7 +300,8 @@ node *environment::make_char_node(charinfo *ci)
void environment::add_node(node *n)
{
- assert(n != 0);
+ if (n == 0)
+ return;
if (current_tab || current_field)
n->freeze_space();
if (interrupted) {
@@ -392,7 +394,7 @@ void environment::space_newline()
width_total += x;
return;
}
- add_node(new word_space_node(x, w));
+ add_node(new word_space_node(x, get_fill_color(), w));
possibly_break_line(0, spread_flag);
spread_flag = 0;
}
@@ -426,6 +428,7 @@ void environment::space(hunits space_width, hunits sentence_space_width)
return;
}
add_node(new word_space_node(x,
+ get_fill_color(),
new width_list(space_width,
sentence_space_width)));
possibly_break_line(0, spread_flag);
@@ -438,7 +441,7 @@ void environment::set_font(symbol nm)
{
if (interrupted)
return;
- if (nm == symbol("P")) {
+ if (nm == symbol("P") || nm.is_empty()) {
if (family->make_definite(prev_fontno) < 0)
return;
int tem = fontno;
@@ -479,7 +482,9 @@ void environment::set_font(int n)
void environment::set_family(symbol fam)
{
- if (fam.is_null()) {
+ if (interrupted)
+ return;
+ if (fam.is_null() || fam.is_empty()) {
if (prev_family->make_definite(fontno) < 0)
return;
font_family *tem = family;
@@ -532,6 +537,42 @@ void environment::set_char_slant(int n)
char_slant = n;
}
+color *environment::get_prev_glyph_color()
+{
+ return prev_glyph_color;
+}
+
+color *environment::get_glyph_color()
+{
+ return glyph_color;
+}
+
+color *environment::get_prev_fill_color()
+{
+ return prev_fill_color;
+}
+
+color *environment::get_fill_color()
+{
+ return fill_color;
+}
+
+void environment::set_glyph_color(color *c)
+{
+ if (interrupted)
+ return;
+ curenv->prev_glyph_color = curenv->glyph_color;
+ curenv->glyph_color = c;
+}
+
+void environment::set_fill_color(color *c)
+{
+ if (interrupted)
+ return;
+ curenv->prev_fill_color = curenv->fill_color;
+ curenv->fill_color = c;
+}
+
environment::environment(symbol nm)
: dummy(0),
prev_line_length((units_per_inch*13)/2),
@@ -565,6 +606,7 @@ environment::environment(symbol nm)
underline_lines(0),
underline_spaces(0),
input_trap_count(0),
+ continued_input_trap(0),
line(0),
prev_text_length(0),
width_total(0),
@@ -597,9 +639,12 @@ environment::environment(symbol nm)
#ifdef WIDOW_CONTROL
widow_control(0),
#endif /* WIDOW_CONTROL */
- need_eol(0),
ignore_next_eol(0),
emitted_node(0),
+ glyph_color(&default_color),
+ prev_glyph_color(&default_color),
+ fill_color(&default_color),
+ prev_fill_color(&default_color),
name(nm),
control_char('.'),
no_break_control_char('\''),
@@ -651,6 +696,7 @@ environment::environment(const environment *e)
underline_lines(0),
underline_spaces(0),
input_trap_count(0),
+ continued_input_trap(0),
line(0),
prev_text_length(e->prev_text_length),
width_total(0),
@@ -683,8 +729,12 @@ environment::environment(const environment *e)
#ifdef WIDOW_CONTROL
widow_control(e->widow_control),
#endif /* WIDOW_CONTROL */
- need_eol(0),
ignore_next_eol(0),
+ emitted_node(0),
+ glyph_color(e->glyph_color),
+ prev_glyph_color(e->prev_glyph_color),
+ fill_color(e->fill_color),
+ prev_fill_color(e->prev_fill_color),
name(e->name), // so that eg `.if "\n[.ev]"0"' works
control_char(e->control_char),
no_break_control_char(e->no_break_control_char),
@@ -725,6 +775,7 @@ void environment::copy(const environment *e)
underline_lines = 0;
underline_spaces = 0;
input_trap_count = 0;
+ continued_input_trap = 0;
prev_text_length = e->prev_text_length;
width_total = 0;
space_total = 0;
@@ -765,6 +816,12 @@ void environment::copy(const environment *e)
hyphenation_space = e->hyphenation_space;
hyphenation_margin = e->hyphenation_margin;
composite = 0;
+ ignore_next_eol = e->ignore_next_eol;
+ emitted_node = e->emitted_node;
+ glyph_color= e->glyph_color;
+ prev_glyph_color = e->prev_glyph_color;
+ fill_color = e->fill_color;
+ prev_fill_color = e->prev_fill_color;
}
environment::~environment()
@@ -1107,13 +1164,54 @@ void point_size()
if (n <= 0)
n = 1;
curenv->set_size(n);
- curenv->add_html_tag(".ps", n);
+ curenv->add_html_tag(1, ".ps", n);
}
else
curenv->set_size(0);
skip_line();
}
+void override_sizes()
+{
+ int n = 16;
+ int *sizes = new int[n];
+ int i = 0;
+ char *buf = read_string();
+ if (!buf)
+ return;
+ char *p = strtok(buf, " \t");
+ for (;;) {
+ if (!p)
+ break;
+ int lower, upper;
+ switch (sscanf(p, "%d-%d", &lower, &upper)) {
+ case 1:
+ upper = lower;
+ // fall through
+ case 2:
+ if (lower <= upper && lower >= 0)
+ break;
+ // fall through
+ default:
+ warning(WARN_RANGE, "bad size range `%1'", p);
+ return;
+ }
+ if (i + 2 > n) {
+ int *old_sizes = sizes;
+ sizes = new int[n*2];
+ memcpy(sizes, old_sizes, n*sizeof(int));
+ n *= 2;
+ a_delete old_sizes;
+ }
+ sizes[i++] = lower;
+ if (lower == 0)
+ break;
+ sizes[i++] = upper;
+ p = strtok(0, " \t");
+ }
+ font_size::init_size_table(sizes);
+}
+
void space_size()
{
int n;
@@ -1134,7 +1232,8 @@ void fill()
if (break_flag)
curenv->do_break();
curenv->fill = 1;
- curenv->add_html_tag(".fi");
+ curenv->add_html_tag(1, ".fi");
+ curenv->add_html_tag(0, ".br");
tok.next();
}
@@ -1144,11 +1243,10 @@ void no_fill()
tok.next();
if (break_flag)
curenv->do_break();
-
curenv->fill = 0;
- curenv->add_html_tag(".nf");
- curenv->ignore_next_eol = 1;
- curenv->add_html_tag(".po", topdiv->get_page_offset().to_units());
+ curenv->add_html_tag(1, ".nf");
+ curenv->add_html_tag(0, ".br");
+ curenv->add_html_tag(0, ".po", topdiv->get_page_offset().to_units());
tok.next();
}
@@ -1165,7 +1263,7 @@ void center()
curenv->do_break();
curenv->right_justify_lines = 0;
curenv->center_lines = n;
- curenv->add_html_tag(".ce", n);
+ curenv->add_html_tag(1, ".ce", n);
tok.next();
}
@@ -1182,7 +1280,7 @@ void right_justify()
curenv->do_break();
curenv->center_lines = 0;
curenv->right_justify_lines = n;
- curenv->add_html_tag(".rj", n);
+ curenv->add_html_tag(1, ".rj", n);
tok.next();
}
@@ -1199,7 +1297,7 @@ void line_length()
temp = curenv->prev_line_length;
curenv->prev_line_length = curenv->line_length;
curenv->line_length = temp;
- curenv->add_html_tag(".ll", temp.to_units());
+ curenv->add_html_tag(1, ".ll", temp.to_units());
skip_line();
}
@@ -1286,7 +1384,8 @@ void indent()
curenv->have_temporary_indent = 0;
curenv->prev_indent = curenv->indent;
curenv->indent = temp;
- curenv->add_html_tag(".in", temp.to_units());
+ if (break_flag)
+ curenv->add_html_tag(1, ".in", temp.to_units());
tok.next();
}
@@ -1307,7 +1406,7 @@ void temporary_indent()
if (!err) {
curenv->temporary_indent = temp;
curenv->have_temporary_indent = 1;
- curenv->add_html_tag(".ti", temp.to_units());
+ curenv->add_html_tag(1, ".ti", temp.to_units());
}
tok.next();
}
@@ -1562,6 +1661,11 @@ void environment::newline()
if (x > H0)
saved_indent += x/2;
to_be_output = line;
+ if (is_html) {
+ node *n = make_html_tag("eol.ce");
+ n->next = to_be_output;
+ to_be_output = n;
+ }
to_be_output_width = width_total;
line = 0;
}
@@ -1583,12 +1687,21 @@ void environment::newline()
}
input_line_start = line == 0 ? H0 : width_total;
if (to_be_output) {
+ if (is_html && !fill) {
+ if (curdiv == topdiv) {
+ node *n = make_html_tag("eol");
+
+ n->next = to_be_output;
+ to_be_output = n;
+ }
+ }
output_line(to_be_output, to_be_output_width);
hyphen_line_count = 0;
}
if (input_trap_count > 0) {
- if (--input_trap_count == 0)
- spring_trap(input_trap);
+ if (!(continued_input_trap && prev_line_interrupted))
+ if (--input_trap_count == 0)
+ spring_trap(input_trap);
}
}
@@ -1598,7 +1711,7 @@ void environment::output_line(node *n, hunits width)
if (margin_character_flags) {
hunits d = line_length + margin_character_distance - saved_indent - width;
if (d > 0) {
- n = new hmotion_node(d, n);
+ n = new hmotion_node(d, get_fill_color(), n);
width += d;
}
margin_character_flags &= ~MARGIN_CHARACTER_NEXT;
@@ -1621,7 +1734,7 @@ void environment::output_line(node *n, hunits width)
n = tem;
}
if (!saved_indent.is_zero())
- nn = new hmotion_node(saved_indent, nn);
+ nn = new hmotion_node(saved_indent, get_fill_color(), nn);
width += saved_indent;
if (no_number_count > 0)
--no_number_count;
@@ -1629,11 +1742,11 @@ void environment::output_line(node *n, hunits width)
hunits w = (line_number_digit_width
*(3+line_number_indent+number_text_separation));
if (next_line_number % line_number_multiple != 0)
- nn = new hmotion_node(w, nn);
+ nn = new hmotion_node(w, get_fill_color(), nn);
else {
hunits x = w;
- nn = new hmotion_node(number_text_separation*line_number_digit_width,
- nn);
+ nn = new hmotion_node(number_text_separation * line_number_digit_width,
+ get_fill_color(), nn);
x -= number_text_separation*line_number_digit_width;
char buf[30];
sprintf(buf, "%3d", next_line_number);
@@ -1646,7 +1759,7 @@ void environment::output_line(node *n, hunits width)
gn->next = nn;
nn = gn;
}
- nn = new hmotion_node(x, nn);
+ nn = new hmotion_node(x, get_fill_color(), nn);
}
width += w;
++next_line_number;
@@ -1789,7 +1902,7 @@ breakpoint *environment::choose_breakpoint()
}
if (best_bp) {
if (!best_bp_fits)
- warning(WARN_BREAK, "can't break line");
+ output_warning(WARN_BREAK, "can't break line");
return best_bp;
}
return 0;
@@ -1875,6 +1988,14 @@ static void distribute_space(node *n, int nspaces, hunits desired_space,
static int reverse = 0;
if (force_reverse || reverse)
n = node_list_reverse(n);
+ if (!force_reverse && nspaces > 0 && spread_limit >= 0
+ && desired_space.to_units() > 0) {
+ hunits em = curenv->get_size();
+ double Ems = (double)desired_space.to_units() / nspaces
+ / (em.is_zero() ? hresolution : em.to_units());
+ if (Ems > spread_limit)
+ output_warning(WARN_BREAK, "spreading %1m per space", Ems);
+ }
for (node *tem = n; tem; tem = tem->next)
tem->spread_space(&nspaces, &desired_space);
if (force_reverse || reverse)
@@ -1909,6 +2030,9 @@ void environment::possibly_break_line(int start_here, int forced)
case ADJUST_BOTH:
if (bp->nspaces != 0)
extra_space_width = target_text_length - bp->width;
+ else if (bp->width > 0 && target_text_length > 0
+ && target_text_length > bp->width)
+ output_warning(WARN_BREAK, "cannot adjust line");
break;
case ADJUST_CENTER:
saved_indent += (target_text_length - bp->width)/2;
@@ -2013,32 +2137,15 @@ void environment::final_break()
}
/*
- * add_html_tag_eol - add an end of line tag if appropriate.
- */
-
-void environment::add_html_tag_eol()
-{
- if (is_html) {
- if (ignore_next_eol > 0)
- ignore_next_eol--;
- else if (need_eol > 0) {
- need_eol--;
- add_html_tag("eol");
- }
- else if (!fill && emitted_node) {
- add_html_tag("eol");
- emitted_node = 0;
- }
- }
-}
-
-/*
* add_html_tag - emits a special html-tag: to help post-grohtml understand
* the key troff commands
*/
-void environment::add_html_tag(const char *name)
+void environment::add_html_tag(int force, const char *name)
{
+ if (!force && (curdiv != topdiv))
+ return;
+
if (is_html) {
/*
* need to emit tag for post-grohtml
@@ -2049,9 +2156,11 @@ void environment::add_html_tag(const char *name)
macro *m = new macro;
m->append_str("html-tag:");
for (const char *p = name; *p; p++)
- if (!illegal_input_char((unsigned char)*p))
+ if (!invalid_input_char((unsigned char)*p))
m->append(*p);
- add_node(new special_node(*m));
+ curdiv->output(new special_node(*m), 1, 0, 0, 0);
+ if (strcmp(name, ".nf") == 0)
+ curenv->ignore_next_eol = 1;
}
}
@@ -2061,18 +2170,12 @@ void environment::add_html_tag(const char *name)
* of i.
*/
-void environment::add_html_tag(const char *name, int i)
+void environment::add_html_tag(int force, const char *name, int i)
{
- if (is_html) {
- if (strcmp(name, ".ce") == 0) {
- if (i == 0)
- need_eol = 0;
- else {
- need_eol = i;
- ignore_next_eol = 1; // since the .ce creates an eol
- }
- }
+ if (!force && (curdiv != topdiv))
+ return;
+ if (is_html) {
/*
* need to emit tag for post-grohtml
* but we check to see whether we can emit specials
@@ -2082,13 +2185,12 @@ void environment::add_html_tag(const char *name, int i)
macro *m = new macro;
m->append_str("html-tag:");
for (const char *p = name; *p; p++)
- if (!illegal_input_char((unsigned char)*p))
+ if (!invalid_input_char((unsigned char)*p))
m->append(*p);
m->append(' ');
m->append_int(i);
- // output_pending_lines();
- output(new special_node(*m), !fill, 0, 0, 0);
- // output_pending_lines();
+ node *n = new special_node(*m);
+ curdiv->output(n, 1, 0, 0, 0);
}
}
@@ -2096,8 +2198,11 @@ void environment::add_html_tag(const char *name, int i)
* add_html_tag_tabs - emits the tab settings for post-grohtml
*/
-void environment::add_html_tag_tabs()
+void environment::add_html_tag_tabs(int force)
{
+ if (!force && (curdiv != topdiv))
+ return;
+
if (is_html) {
/*
* need to emit tag for post-grohtml
@@ -2115,24 +2220,62 @@ void environment::add_html_tag_tabs()
switch (t) {
case TAB_LEFT:
m->append_str(" L ");
- m->append_int(d.to_units());
+ m->append_int(l.to_units());
break;
case TAB_CENTER:
m->append_str(" C ");
- m->append_int(d.to_units());
+ m->append_int(l.to_units());
break;
case TAB_RIGHT:
m->append_str(" R ");
- m->append_int(d.to_units());
+ m->append_int(l.to_units());
break;
case TAB_NONE:
break;
}
} while ((t != TAB_NONE) && (l < get_line_length()));
- output_pending_lines();
- output(new special_node(*m), !fill, 0, 0, 0);
- output_pending_lines();
+ curdiv->output(new special_node(*m), 1, 0, 0, 0);
+ }
+}
+
+node *environment::make_html_tag(const char *name, int i)
+{
+ if (is_html) {
+ /*
+ * need to emit tag for post-grohtml
+ * but we check to see whether we can emit specials
+ */
+ if (curdiv == topdiv && topdiv->before_first_page)
+ topdiv->begin_page();
+ macro *m = new macro;
+ m->append_str("html-tag:");
+ for (const char *p = name; *p; p++)
+ if (!invalid_input_char((unsigned char)*p))
+ m->append(*p);
+ m->append(' ');
+ m->append_int(i);
+ return new special_node(*m);
}
+ return 0;
+}
+
+node *environment::make_html_tag(const char *name)
+{
+ if (is_html) {
+ /*
+ * need to emit tag for post-grohtml
+ * but we check to see whether we can emit specials
+ */
+ if (curdiv == topdiv && topdiv->before_first_page)
+ topdiv->begin_page();
+ macro *m = new macro;
+ m->append_str("html-tag:");
+ for (const char *p = name; *p; p++)
+ if (!invalid_input_char((unsigned char)*p))
+ m->append(*p);
+ return new special_node(*m);
+ }
+ return 0;
}
void environment::do_break(int spread)
@@ -2144,7 +2287,8 @@ void environment::do_break(int spread)
if (current_tab)
wrap_up_tab();
if (line) {
- line = new space_node(H0, line); // this is so that hyphenation works
+ // this is so that hyphenation works
+ line = new space_node(H0, get_fill_color(), line);
space_total++;
possibly_break_line(0, spread);
}
@@ -2191,7 +2335,7 @@ void do_break_request(int spread)
tok.next();
if (break_flag) {
curenv->do_break(spread);
- curenv->add_html_tag(".br");
+ curenv->add_html_tag(0, ".br");
}
tok.next();
}
@@ -2228,6 +2372,10 @@ void title()
curenv->char_slant = env.char_slant;
curenv->fontno = env.fontno;
curenv->prev_fontno = env.prev_fontno;
+ curenv->glyph_color = env.glyph_color;
+ curenv->prev_glyph_color = env.prev_glyph_color;
+ curenv->fill_color = env.fill_color;
+ curenv->prev_fill_color = env.prev_fill_color;
node *n = 0;
node *p = part[2];
while (p != 0) {
@@ -2239,7 +2387,7 @@ void title()
hunits title_length(curenv->title_length);
hunits f = title_length - part_width[1];
hunits f2 = f/2;
- n = new hmotion_node(f2 - part_width[2], n);
+ n = new hmotion_node(f2 - part_width[2], curenv->get_fill_color(), n);
p = part[1];
while (p != 0) {
node *tem = p;
@@ -2247,7 +2395,7 @@ void title()
tem->next = n;
n = tem;
}
- n = new hmotion_node(f - f2 - part_width[0], n);
+ n = new hmotion_node(f - f2 - part_width[0], curenv->get_fill_color(), n);
p = part[0];
while (p != 0) {
node *tem = p;
@@ -2302,9 +2450,11 @@ void no_adjust()
skip_line();
}
-void input_trap()
+void do_input_trap(int continued)
{
curenv->input_trap_count = 0;
+ if (continued)
+ curenv->continued_input_trap = 1;
int n;
if (has_arg() && get_integer(&n)) {
if (n <= 0)
@@ -2321,6 +2471,16 @@ void input_trap()
skip_line();
}
+void input_trap()
+{
+ do_input_trap(0);
+}
+
+void input_trap_continued()
+{
+ do_input_trap(1);
+}
+
/* tabs */
// must not be R or C or L or a legitimate part of a number expression
@@ -2371,7 +2531,7 @@ tab::tab(hunits x, tab_type t) : next(0), pos(x), type(t)
}
tab_stops::tab_stops(hunits distance, tab_type type)
- : initial_list(0)
+: initial_list(0)
{
repeated_list = new tab(distance, type);
}
@@ -2383,12 +2543,21 @@ tab_stops::~tab_stops()
tab_type tab_stops::distance_to_next_tab(hunits curpos, hunits *distance)
{
+ hunits nextpos;
+
+ return distance_to_next_tab(curpos, distance, &nextpos);
+}
+
+tab_type tab_stops::distance_to_next_tab(hunits curpos, hunits *distance,
+ hunits *nextpos)
+{
hunits lastpos = 0;
tab *tem;
for (tem = initial_list; tem && tem->pos <= curpos; tem = tem->next)
lastpos = tem->pos;
if (tem) {
*distance = tem->pos - curpos;
+ *nextpos = tem->pos;
return tem->type;
}
if (repeated_list == 0)
@@ -2399,6 +2568,7 @@ tab_type tab_stops::distance_to_next_tab(hunits curpos, hunits *distance)
lastpos = tem->pos;
if (tem) {
*distance = tem->pos + base - curpos;
+ *nextpos = tem->pos + base;
return tem->type;
}
assert(lastpos > 0);
@@ -2476,7 +2646,7 @@ tab_stops::tab_stops() : initial_list(0), repeated_list(0)
}
tab_stops::tab_stops(const tab_stops &ts)
- : initial_list(0), repeated_list(0)
+: initial_list(0), repeated_list(0)
{
tab **p = &initial_list;
tab *t = ts.initial_list;
@@ -2573,7 +2743,7 @@ void set_tabs()
}
}
curenv->tabs = tabs;
- curenv->add_html_tag_tabs();
+ curenv->add_html_tag_tabs(1);
skip_line();
}
@@ -2605,6 +2775,14 @@ tab_type environment::distance_to_next_tab(hunits *distance)
: curenv->tabs.distance_to_next_tab(get_input_line_position(), distance);
}
+tab_type environment::distance_to_next_tab(hunits *distance, hunits *leftpos)
+{
+ return line_tabs
+ ? curenv->tabs.distance_to_next_tab(get_text_length(), distance, leftpos)
+ : curenv->tabs.distance_to_next_tab(get_input_line_position(), distance,
+ leftpos);
+}
+
void field_characters()
{
field_delimiter_char = get_optional_char();
@@ -2683,7 +2861,7 @@ node *environment::make_tab_node(hunits d, node *next)
leader_node = 0;
}
if (!leader_node)
- return new hmotion_node(d, 1, 0, next);
+ return new hmotion_node(d, 1, 0, get_fill_color(), next);
node *n = new hline_node(d, leader_node, next);
leader_node = 0;
return n;
@@ -2692,31 +2870,34 @@ node *environment::make_tab_node(hunits d, node *next)
void environment::handle_tab(int is_leader)
{
hunits d;
+ hunits abs;
if (current_tab)
wrap_up_tab();
charinfo *ci = is_leader ? leader_char : tab_char;
delete leader_node;
leader_node = ci ? make_char_node(ci) : 0;
- tab_type t = distance_to_next_tab(&d);
+ tab_type t = distance_to_next_tab(&d, &abs);
switch (t) {
case TAB_NONE:
return;
case TAB_LEFT:
- add_html_tag("tab left");
add_node(make_tab_node(d));
+ add_node(make_html_tag("tab L", abs.to_units()));
return;
case TAB_RIGHT:
+ add_node(make_html_tag("tab R", abs.to_units()));
+ break;
case TAB_CENTER:
- add_html_tag("tab center");
- tab_width = 0;
- tab_distance = d;
- tab_contents = 0;
- current_tab = t;
- tab_field_spaces = 0;
- return;
+ add_node(make_html_tag("tab C", abs.to_units()));
+ break;
default:
assert(0);
}
+ tab_width = 0;
+ tab_distance = d;
+ tab_contents = 0;
+ current_tab = t;
+ tab_field_spaces = 0;
}
void environment::start_field()
@@ -2792,13 +2973,13 @@ void environment::wrap_up_field()
void environment::add_padding()
{
if (current_tab) {
- tab_contents = new space_node(H0, tab_contents);
+ tab_contents = new space_node(H0, get_fill_color(), tab_contents);
tab_field_spaces++;
}
else {
if (line == 0)
start_line();
- line = new space_node(H0, line);
+ line = new space_node(H0, get_fill_color(), line);
field_spaces++;
}
}
@@ -2921,6 +3102,12 @@ const char *environment::get_font_family_string()
return family->nm.contents();
}
+const char *environment::get_font_name_string()
+{
+ symbol f = get_font_name(fontno, this);
+ return f.contents();
+}
+
const char *environment::get_name_string()
{
return name.contents();
@@ -3001,12 +3188,14 @@ const char *environment::get_requested_point_size_string()
void init_env_requests()
{
init_request("it", input_trap);
+ init_request("itc", input_trap_continued);
init_request("ad", adjust);
init_request("na", no_adjust);
init_request("ev", environment_switch);
init_request("evc", environment_copy);
init_request("lt", title_length);
init_request("ps", point_size);
+ init_request("sizes", override_sizes);
init_request("ft", font_change);
init_request("fam", family_change);
init_request("ss", space_size);
@@ -3070,6 +3259,7 @@ void init_env_requests()
init_int_env_reg(".ss", get_space_size);
init_int_env_reg(".sss", get_sentence_space_size);
init_string_env_reg(".fam", get_font_family_string);
+ init_string_env_reg(".fn", get_font_name_string);
init_string_env_reg(".ev", get_name_string);
init_int_env_reg(".hy", get_hyphenation_flags);
init_int_env_reg(".hlm", get_hyphen_line_max);
@@ -3118,14 +3308,15 @@ class hyphen_trie : private trie {
void do_match(int i, void *v);
void do_delete(void *v);
void insert_pattern(const char *pat, int patlen, int *num);
+ void insert_hyphenation(dictionary ex, const char *pat, int patlen);
+ int hpf_getc(FILE *f);
public:
hyphen_trie() {}
~hyphen_trie() {}
void hyphenate(const char *word, int len, int *hyphens);
- void read_patterns_file(const char *name);
+ void read_patterns_file(const char *name, int append, dictionary ex);
};
-
struct hyphenation_language {
symbol name;
dictionary exceptions;
@@ -3150,7 +3341,8 @@ static void set_hyphenation_language()
skip_line();
}
-const int WORD_MAX = 1024;
+const int WORD_MAX = 256; // we use unsigned char for offsets in
+ // hyphenation exceptions
static void hyphen_word()
{
@@ -3189,7 +3381,7 @@ static void hyphen_word()
pos[npos] = 0;
buf[i] = 0;
unsigned char *tem = new unsigned char[npos + 1];
- memcpy(tem, pos, npos+1);
+ memcpy(tem, pos, npos + 1);
tem = (unsigned char *)current_language->exceptions.lookup(symbol(buf),
tem);
if (tem)
@@ -3290,6 +3482,33 @@ void hyphen_trie::insert_pattern(const char *pat, int patlen, int *num)
insert(pat, patlen, op);
}
+void hyphen_trie::insert_hyphenation(dictionary ex, const char *pat,
+ int patlen)
+{
+ char buf[WORD_MAX + 1];
+ unsigned char pos[WORD_MAX + 2];
+ int i = 0, j = 0;
+ int npos = 0;
+ while (j < patlen) {
+ unsigned char c = pat[j++];
+ if (c == '-') {
+ if (i > 0 && (npos == 0 || pos[npos - 1] != i))
+ pos[npos++] = i;
+ }
+ else
+ buf[i++] = hpf_code_table[c];
+ }
+ if (i > 0) {
+ pos[npos] = 0;
+ buf[i] = 0;
+ unsigned char *tem = new unsigned char[npos + 1];
+ memcpy(tem, pos, npos + 1);
+ tem = (unsigned char *)ex.lookup(symbol(buf), tem);
+ if (tem)
+ a_delete tem;
+ }
+}
+
void hyphen_trie::hyphenate(const char *word, int len, int *hyphens)
{
int j;
@@ -3324,10 +3543,78 @@ void hyphen_trie::do_delete(void *v)
delete tem;
}
}
-
-void hyphen_trie::read_patterns_file(const char *name)
+
+/* We use very simple rules to parse TeX's hyphenation patterns.
+
+ . `%' starts a comment even if preceded by `\'.
+
+ . No support for digraphs and like `\$'.
+
+ . `^^xx' (`x' is 0-9 or a-f), and `^^x' (character code of `x' in the
+ range 0-127) are recognized; other use of `^' causes an error.
+
+ . No macro expansion.
+
+ . We check for the expression `\patterns{...}' (possibly with
+ whitespace before and after the braces). Everything between the
+ braces is taken as hyphenation patterns. Consequently, `{' and `}'
+ are not allowed in patterns.
+
+ . Similarly, `\hyphenation{...}' gives a list of hyphenation
+ exceptions.
+
+ . `\endinput' is recognized also.
+
+ . For backwards compatibility, if `\patterns' is missing, the
+ whole file is treated as a list of hyphenation patterns (only
+ recognizing `%' as the start of a comment.
+
+*/
+
+int hyphen_trie::hpf_getc(FILE *f)
+{
+ int c = getc(f);
+ int c1;
+ int cc = 0;
+ if (c != '^')
+ return c;
+ c = getc(f);
+ if (c != '^')
+ goto fail;
+ c = getc(f);
+ c1 = getc(f);
+ if (((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))
+ && ((c1 >= '0' && c1 <= '9') || (c1 >= 'a' && c1 <= 'f'))) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else
+ c = c - 'a' + 10;
+ if (c1 >= '0' && c1 <= '9')
+ c1 -= '0';
+ else
+ c1 = c1 - 'a' + 10;
+ cc = c * 16 + c1;
+ }
+ else {
+ ungetc(c1, f);
+ if (c >= 0 && c <= 63)
+ cc = c + 64;
+ else if (c >= 64 && c <= 127)
+ cc = c - 64;
+ else
+ goto fail;
+ }
+ return cc;
+fail:
+ error("invalid ^, ^^x, or ^^xx character in hyphenation patterns file");
+ return c;
+}
+
+void hyphen_trie::read_patterns_file(const char *name, int append,
+ dictionary ex)
{
- clear();
+ if (!append)
+ clear();
char buf[WORD_MAX];
int num[WORD_MAX+1];
errno = 0;
@@ -3337,32 +3624,111 @@ void hyphen_trie::read_patterns_file(const char *name)
error("can't find hyphenation patterns file `%1'", name);
return;
}
- int c = getc(fp);
+ int c = hpf_getc(fp);
+ int have_patterns = 0; // we've seen \patterns
+ int final_pattern = 0; // 1 if we have a trailing closing brace
+ int have_hyphenation = 0; // we've seen \hyphenation
+ int final_hyphenation = 0; // 1 if we have a trailing closing brace
+ int have_keyword = 0; // we've seen either \patterns or \hyphenation
+ int traditional = 0; // don't handle \patterns
for (;;) {
for (;;) {
- if (c == '%') {
+ if (c == '%') { // skip comments
do {
c = getc(fp);
} while (c != EOF && c != '\n');
}
if (c == EOF || !csspace(c))
break;
- c = getc(fp);
+ c = hpf_getc(fp);
+ }
+ if (c == EOF) {
+ if (have_keyword || traditional) // we are done
+ break;
+ else { // rescan file in `traditional' mode
+ rewind(fp);
+ traditional = 1;
+ c = hpf_getc(fp);
+ continue;
+ }
}
- if (c == EOF)
- break;
int i = 0;
num[0] = 0;
- do {
- if (csdigit(c))
- num[i] = c - '0';
- else {
- buf[i++] = c;
- num[i] = 0;
+ if (!(c == '{' || c == '}')) { // skip braces at line start
+ do { // scan patterns
+ if (csdigit(c))
+ num[i] = c - '0';
+ else {
+ buf[i++] = c;
+ num[i] = 0;
+ }
+ c = hpf_getc(fp);
+ } while (i < WORD_MAX && c != EOF && !csspace(c)
+ && c != '%' && c != '{' && c != '}');
+ }
+ if (!traditional) {
+ if (i >= 9 && !strncmp(buf + i - 9, "\\patterns", 9)) {
+ while (csspace(c))
+ c = hpf_getc(fp);
+ if (c == '{') {
+ if (have_patterns || have_hyphenation)
+ error("`{' not allowed inside of \\patterns or \\hyphenation");
+ else {
+ have_patterns = 1;
+ have_keyword = 1;
+ }
+ c = hpf_getc(fp);
+ continue;
+ }
+ }
+ else if (i >= 12 && !strncmp(buf + i - 12, "\\hyphenation", 12)) {
+ while (csspace(c))
+ c = hpf_getc(fp);
+ if (c == '{') {
+ if (have_patterns || have_hyphenation)
+ error("`{' not allowed inside of \\patterns or \\hyphenation");
+ else {
+ have_hyphenation = 1;
+ have_keyword = 1;
+ }
+ c = hpf_getc(fp);
+ continue;
+ }
+ }
+ else if (strstr(buf, "\\endinput")) {
+ if (have_patterns || have_hyphenation)
+ error("found \\endinput inside of %1 group",
+ have_patterns ? "\\patterns" : "\\hyphenation");
+ break;
+ }
+ else if (c == '}') {
+ if (have_patterns) {
+ have_patterns = 0;
+ if (i > 0)
+ final_pattern = 1;
+ }
+ else if (have_hyphenation) {
+ have_hyphenation = 0;
+ if (i > 0)
+ final_hyphenation = 1;
+ }
+ c = hpf_getc(fp);
}
- c = getc(fp);
- } while (i < WORD_MAX && c != EOF && !csspace(c) && c != '%');
- insert_pattern(buf, i, num);
+ else if (c == '{') // skipped if not starting \patterns
+ c = hpf_getc(fp); // or \hyphenation
+ }
+ if (i > 0) {
+ if (have_patterns || final_pattern || traditional) {
+ for (int j = 0; j < i; j++)
+ buf[j] = hpf_code_table[buf[j]];
+ insert_pattern(buf, i, num);
+ final_pattern = 0;
+ }
+ else if (have_hyphenation || final_hyphenation) {
+ insert_hyphenation(ex, buf, i);
+ final_hyphenation = 0;
+ }
+ }
}
fclose(fp);
a_delete path;
@@ -3419,18 +3785,30 @@ void hyphenate(hyphen_list *h, unsigned flags)
}
}
-static void hyphenation_patterns_file()
+static void do_hyphenation_patterns_file(int append)
{
symbol name = get_long_name(1);
if (!name.is_null()) {
if (!current_language)
error("no current hyphenation language");
else
- current_language->patterns.read_patterns_file(name.contents());
+ current_language->patterns.read_patterns_file(
+ name.contents(), append,
+ current_language->exceptions);
}
skip_line();
}
+static void hyphenation_patterns_file()
+{
+ do_hyphenation_patterns_file(0);
+}
+
+static void hyphenation_patterns_file_append()
+{
+ do_hyphenation_patterns_file(1);
+}
+
class hyphenation_language_reg : public reg {
public:
const char *get_string();
@@ -3446,5 +3824,6 @@ void init_hyphen_requests()
init_request("hw", hyphen_word);
init_request("hla", set_hyphenation_language);
init_request("hpf", hyphenation_patterns_file);
+ init_request("hpfa", hyphenation_patterns_file_append);
number_reg_dictionary.define(".hla", new hyphenation_language_reg);
}
diff --git a/contrib/groff/src/roff/troff/env.h b/contrib/groff/src/roff/troff/env.h
index 851a9a0..43a4c97 100644
--- a/contrib/groff/src/roff/troff/env.h
+++ b/contrib/groff/src/roff/troff/env.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
@@ -85,6 +85,7 @@ public:
~tab_stops();
void operator=(const tab_stops &);
tab_type distance_to_next_tab(hunits pos, hunits *distance);
+ tab_type distance_to_next_tab(hunits curpos, hunits *distance, hunits *leftpos);
void clear();
void add_tab(hunits pos, tab_type type, int repeated);
const char *to_string();
@@ -140,6 +141,7 @@ class environment {
int underline_spaces;
symbol input_trap;
int input_trap_count;
+ int continued_input_trap;
node *line; // in reverse order
hunits prev_text_length;
hunits width_total;
@@ -181,11 +183,15 @@ class environment {
#ifdef WIDOW_CONTROL
int widow_control;
#endif /* WIDOW_CONTROL */
- int need_eol;
int ignore_next_eol;
int emitted_node; // have we emitted a node since the last html eol tag?
+ color *glyph_color;
+ color *prev_glyph_color;
+ color *fill_color;
+ color *prev_fill_color;
tab_type distance_to_next_tab(hunits *);
+ tab_type distance_to_next_tab(hunits *distance, hunits *leftpos);
void start_line();
void output_line(node *, hunits);
void output(node *nd, int retain_size, vunits vs, vunits post_vs,
@@ -261,6 +267,12 @@ public:
int get_center_lines();
int get_right_justify_lines();
int get_prev_line_interrupted() { return prev_line_interrupted; }
+ color *get_fill_color();
+ color *get_glyph_color();
+ color *get_prev_glyph_color();
+ color *get_prev_fill_color();
+ void set_glyph_color(color *c);
+ void set_fill_color(color *c);
node *make_char_node(charinfo *);
node *extract_output_line();
void width_registers();
@@ -277,10 +289,11 @@ public:
void possibly_break_line(int start_here = 0, int forced = 0);
void do_break(int spread = 0); // .br
void final_break();
- void add_html_tag_eol();
- void add_html_tag(const char *);
- void add_html_tag(const char *, int);
- void add_html_tag_tabs();
+ void add_html_tag(int, const char *);
+ void add_html_tag(int, const char *, int);
+ void add_html_tag_tabs(int);
+ node *make_html_tag(const char *name, int i);
+ node *make_html_tag(const char *);
void newline();
void handle_tab(int is_leader = 0); // do a tab or leader
void add_node(node *);
@@ -291,6 +304,7 @@ public:
void space(hunits, hunits);
void space_newline();
const char *get_font_family_string();
+ const char *get_font_name_string();
const char *get_name_string();
const char *get_point_size_string();
const char *get_requested_point_size_string();
@@ -311,7 +325,7 @@ public:
friend void indent();
friend void temporary_indent();
friend void do_underline(int);
- friend void input_trap();
+ friend void do_input_trap(int);
friend void set_tabs();
friend void margin_character();
friend void no_number();
@@ -343,7 +357,12 @@ extern void push_env(int);
void init_environments();
void read_hyphen_file(const char *name);
+void title();
+
+extern double spread_limit;
extern int break_flag;
extern symbol default_family;
extern int translate_space_to_dummy;
+
+extern unsigned char hpf_code_table[];
diff --git a/contrib/groff/src/roff/troff/input.cc b/contrib/groff/src/roff/troff/input.cc
index 54aaa3f..7a90e4b 100644
--- a/contrib/groff/src/roff/troff/input.cc
+++ b/contrib/groff/src/roff/troff/input.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
@@ -36,7 +36,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "input.h"
-// Needed for getpid().
+// Needed for getpid() and isatty()
#include "posix.h"
#include "nonposix.h"
@@ -47,17 +47,6 @@ extern "C" {
}
#endif /* NEED_DECLARATION_PUTENV */
-#ifdef ISATTY_MISSING
-#undef isatty
-#define isatty(n) (1)
-#else /* not ISATTY_MISSING */
-#ifndef isatty
-extern "C" {
- int isatty(int);
-}
-#endif /* not isatty */
-#endif /* not ISATTY_MISSING */
-
#define MACRO_PREFIX "tmac."
#define MACRO_POSTFIX ".tmac"
#define INITIAL_STARTUP_FILE "troffrc"
@@ -86,17 +75,19 @@ void copy_file();
#ifdef COLUMN
void vjustify();
#endif /* COLUMN */
-void transparent();
void transparent_file();
+void process_input_stack();
const char *program_name = 0;
token tok;
int break_flag = 0;
+int color_flag = 1; // colors are on by default
static int backtrace_flag = 0;
#ifndef POPEN_MISSING
char *pipe_command = 0;
#endif
charinfo *charset_table[256];
+unsigned char hpf_code_table[256];
static int warning_mask = DEFAULT_WARNING_MASK;
static int inhibit_errors = 0;
@@ -114,9 +105,18 @@ int suppress_output_flag = 0;
int is_html = 0;
int begin_level = 0; // number of nested .begin requests
+int have_input = 0; // whether \f, \H, \R, \s, or \S has
+ // been processed in token::next()
int tcommand_flag = 0;
int safer_flag = 1; // safer by default
+int have_string_arg = 0; // whether we have \*[foo bar...]
+
+double spread_limit = -3.0 - 1.0; // negative means deactivated
+
+double warn_scale;
+char warn_scaling_indicator;
+
search_path *mac_path = &safer_macro_path;
static int get_copy(node**, int = 0);
@@ -125,8 +125,11 @@ static void copy_mode_error(const char *,
const errarg & = empty_errarg,
const errarg & = empty_errarg);
-static symbol read_escape_name();
+enum read_mode { ALLOW_EMPTY, WITH_ARGS, NO_ARGS };
+static symbol read_escape_name(read_mode mode = NO_ARGS);
+static symbol read_long_escape_name(read_mode mode = NO_ARGS);
static void interpolate_string(symbol);
+static void interpolate_string_with_args(symbol);
static void interpolate_macro(symbol);
static void interpolate_number_format(symbol);
static void interpolate_environment_variable(symbol);
@@ -135,7 +138,6 @@ static void interpolate_arg(symbol);
static request_or_macro *lookup_request(symbol);
static int get_delim_number(units *, int);
static int get_delim_number(units *, int, units);
-static symbol get_delim_file_name();
static int get_line_arg(units *res, int si, charinfo **cp);
static int read_size(int *);
static symbol get_delim_name();
@@ -185,7 +187,7 @@ void restore_escape_char()
class input_iterator {
public:
input_iterator();
- virtual ~input_iterator();
+ virtual ~input_iterator() {}
int get(node **);
friend class input_stack;
protected:
@@ -197,15 +199,13 @@ private:
virtual int peek();
virtual int has_args() { return 0; }
virtual int nargs() { return 0; }
- virtual input_iterator *get_arg(int) { return NULL; }
- virtual int get_location(int, const char **, int *)
- { return 0; }
+ virtual input_iterator *get_arg(int) { return 0; }
+ virtual int get_location(int, const char **, int *) { return 0; }
virtual void backtrace() {}
- virtual int set_location(const char *, int)
- { return 0; }
+ virtual int set_location(const char *, int) { return 0; }
virtual int next_file(FILE *, const char *) { return 0; }
virtual void shift(int) {}
- virtual int is_boundary() { return 0; }
+ virtual int is_boundary() {return 0; }
virtual int internal_level() { return 0; }
virtual int is_file() { return 0; }
virtual int is_macro() { return 0; }
@@ -218,10 +218,6 @@ input_iterator::input_iterator()
{
}
-input_iterator::~input_iterator()
-{
-}
-
int input_iterator::fill(node **)
{
return EOF;
@@ -253,6 +249,7 @@ class file_iterator : public input_iterator {
const char *filename;
int popened;
int newline_flag;
+ int seen_escape;
enum { BUF_SIZE = 512 };
unsigned char buf[BUF_SIZE];
void close();
@@ -269,7 +266,8 @@ public:
};
file_iterator::file_iterator(FILE *f, const char *fn, int po)
-: fp(f), lineno(1), filename(fn), popened(po), newline_flag(0)
+: fp(f), lineno(1), filename(fn), popened(po),
+ newline_flag(0), seen_escape(0)
{
if ((font::use_charnames_in_special) && (fn != 0)) {
if (!the_output)
@@ -307,6 +305,7 @@ int file_iterator::next_file(FILE *f, const char *s)
fp = f;
lineno = 1;
newline_flag = 0;
+ seen_escape = 0;
popened = 0;
ptr = 0;
eptr = 0;
@@ -315,10 +314,8 @@ int file_iterator::next_file(FILE *f, const char *s)
int file_iterator::fill(node **)
{
- if (newline_flag) {
- curenv->add_html_tag_eol();
+ if (newline_flag)
lineno++;
- }
newline_flag = 0;
unsigned char *p = buf;
ptr = p;
@@ -327,14 +324,16 @@ int file_iterator::fill(node **)
int c = getc(fp);
if (c == EOF)
break;
- if (illegal_input_char(c))
- warning(WARN_INPUT, "illegal input character code %1", int(c));
+ if (invalid_input_char(c))
+ warning(WARN_INPUT, "invalid input character code %1", int(c));
else {
*p++ = c;
if (c == '\n') {
+ seen_escape = 0;
newline_flag = 1;
break;
}
+ seen_escape = (c == '\\');
}
}
if (p > buf) {
@@ -350,8 +349,8 @@ int file_iterator::fill(node **)
int file_iterator::peek()
{
int c = getc(fp);
- while (illegal_input_char(c)) {
- warning(WARN_INPUT, "illegal input character code %1", int(c));
+ while (invalid_input_char(c)) {
+ warning(WARN_INPUT, "invalid input character code %1", int(c));
c = getc(fp);
}
if (c != EOF)
@@ -517,7 +516,7 @@ void input_stack::push(input_iterator *in)
input_iterator *input_stack::get_arg(int i)
{
input_iterator *p;
- for (p = top; p != NULL; p = p->next)
+ for (p = top; p != 0; p = p->next)
if (p->has_args())
return p->get_arg(i);
return 0;
@@ -677,21 +676,25 @@ void shift()
skip_line();
}
-static int get_char_for_escape_name()
+static int get_char_for_escape_name(int allow_space = 0)
{
- int c = get_copy(NULL);
+ int c = get_copy(0);
switch (c) {
case EOF:
copy_mode_error("end of input in escape name");
return '\0';
default:
- if (!illegal_input_char(c))
+ if (!invalid_input_char(c))
break;
// fall through
case '\n':
if (c == '\n')
input_stack::push(make_temp_iterator("\n"));
+ // fall through
case ' ':
+ if (c == ' ' && allow_space)
+ break;
+ // fall through
case '\t':
case '\001':
case '\b':
@@ -716,20 +719,25 @@ static symbol read_two_char_escape_name()
return symbol(buf);
}
-static symbol read_long_escape_name()
+static symbol read_long_escape_name(read_mode mode)
{
int start_level = input_stack::get_level();
char abuf[ABUF_SIZE];
char *buf = abuf;
int buf_size = ABUF_SIZE;
int i = 0;
+ int c;
+ int have_char = 0;
for (;;) {
- int c = get_char_for_escape_name();
+ c = get_char_for_escape_name(have_char && mode == WITH_ARGS);
if (c == 0) {
if (buf != abuf)
a_delete buf;
return NULL_SYMBOL;
}
+ have_char = 1;
+ if (mode == WITH_ARGS && c == ' ')
+ break;
if (i + 2 > buf_size) {
if (buf == abuf) {
buf = new char[ABUF_SIZE*2];
@@ -749,10 +757,13 @@ static symbol read_long_escape_name()
buf[i++] = c;
}
buf[i] = 0;
+ if (c == ' ')
+ have_string_arg = 1;
if (buf == abuf) {
if (i == 0) {
- copy_mode_error("empty escape name");
- return NULL_SYMBOL;
+ if (mode != ALLOW_EMPTY)
+ copy_mode_error("empty escape name");
+ return EMPTY_SYMBOL;
}
return symbol(abuf);
}
@@ -763,7 +774,7 @@ static symbol read_long_escape_name()
}
}
-static symbol read_escape_name()
+static symbol read_escape_name(read_mode mode)
{
int c = get_char_for_escape_name();
if (c == 0)
@@ -771,7 +782,7 @@ static symbol read_escape_name()
if (c == '(')
return read_two_char_escape_name();
if (c == '[' && !compatible_flag)
- return read_long_escape_name();
+ return read_long_escape_name(mode);
char buf[2];
buf[0] = c;
buf[1] = '\0';
@@ -826,131 +837,137 @@ static int get_copy(node **nd, int defining)
case 0:
return escape_char;
case '"':
- (void)input_stack::get(NULL);
- while ((c = input_stack::get(NULL)) != '\n' && c != EOF)
+ (void)input_stack::get(0);
+ while ((c = input_stack::get(0)) != '\n' && c != EOF)
;
return c;
case '#': // Like \" but newline is ignored.
- (void)input_stack::get(NULL);
- while ((c = input_stack::get(NULL)) != '\n')
+ (void)input_stack::get(0);
+ while ((c = input_stack::get(0)) != '\n')
if (c == EOF)
return EOF;
break;
case '$':
{
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
symbol s = read_escape_name();
- if (!s.is_null())
+ if (!(s.is_null() || s.is_empty()))
interpolate_arg(s);
break;
}
case '*':
{
- (void)input_stack::get(NULL);
- symbol s = read_escape_name();
- if (!s.is_null())
- interpolate_string(s);
+ (void)input_stack::get(0);
+ symbol s = read_escape_name(WITH_ARGS);
+ if (!(s.is_null() || s.is_empty())) {
+ if (have_string_arg) {
+ have_string_arg = 0;
+ interpolate_string_with_args(s);
+ }
+ else
+ interpolate_string(s);
+ }
break;
}
case 'a':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return '\001';
case 'e':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_e;
case 'E':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_E;
case 'n':
{
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
int inc;
symbol s = read_increment_and_escape_name(&inc);
- if (!s.is_null())
+ if (!(s.is_null() || s.is_empty()))
interpolate_number_reg(s, inc);
break;
}
case 'g':
{
- (void)input_stack::get(NULL);
- symbol s = read_escape_name();
- if (!s.is_null())
+ (void)input_stack::get(0);
+ symbol s = read_escape_name();
+ if (!(s.is_null() || s.is_empty()))
interpolate_number_format(s);
- break;
+ break;
}
case 't':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return '\t';
case 'V':
{
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
symbol s = read_escape_name();
- if (!s.is_null())
+ if (!(s.is_null() || s.is_empty()))
interpolate_environment_variable(s);
break;
}
case '\n':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
if (defining)
return ESCAPE_NEWLINE;
break;
case ' ':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_SPACE;
case '~':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_TILDE;
case ':':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_COLON;
case '|':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_BAR;
case '^':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_CIRCUMFLEX;
case '{':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_LEFT_BRACE;
case '}':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_RIGHT_BRACE;
case '`':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_LEFT_QUOTE;
case '\'':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_RIGHT_QUOTE;
case '-':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_HYPHEN;
case '_':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_UNDERSCORE;
case 'c':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_c;
case '!':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_BANG;
case '?':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_QUESTION;
case '&':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_AMPERSAND;
case ')':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_RIGHT_PARENTHESIS;
case '.':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return c;
case '%':
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return ESCAPE_PERCENT;
default:
if (c == escape_char) {
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
return c;
}
else
@@ -1004,27 +1021,255 @@ int non_interpreted_char_node::interpret(macro *mac)
static void do_width();
static node *do_non_interpreted();
static node *do_special();
-static node *do_suppress();
+static node *do_suppress(symbol nm);
static void do_register();
+dictionary color_dictionary(501);
+static symbol default_symbol("default");
+
+static color *lookup_color(symbol nm)
+{
+ assert(!nm.is_null());
+ if (nm == default_symbol)
+ return &default_color;
+ color *c = (color *)color_dictionary.lookup(nm);
+ if (c == 0)
+ warning(WARN_COLOR, "`%1' not defined", nm.contents());
+ return c;
+}
+
+void do_glyph_color(symbol nm)
+{
+ if (nm.is_null())
+ return;
+ if (nm.is_empty())
+ curenv->set_glyph_color(curenv->get_prev_glyph_color());
+ else {
+ color *tem = lookup_color(nm);
+ if (tem)
+ curenv->set_glyph_color(tem);
+ else
+ (void)color_dictionary.lookup(nm, new color);
+ }
+}
+
+void do_fill_color(symbol nm)
+{
+ if (nm.is_null())
+ return;
+ if (nm.is_empty())
+ curenv->set_fill_color(curenv->get_prev_fill_color());
+ else {
+ color *tem = lookup_color(nm);
+ if (tem)
+ curenv->set_fill_color(tem);
+ else
+ (void)color_dictionary.lookup(nm, new color);
+ }
+}
+
+static unsigned int get_color_element(const char *scheme, const char *col)
+{
+ units val;
+ if (!get_number(&val, 'f')) {
+ warning(WARN_COLOR, "%1 in %2 definition set to 0", col, scheme);
+ tok.next();
+ return 0;
+ }
+ if (val < 0) {
+ warning(WARN_RANGE, "%1 cannot be negative: set to 0", col);
+ return 0;
+ }
+ if (val > color::MAX_COLOR_VAL+1) {
+ warning(WARN_RANGE, "%1 cannot be greater than 1", col);
+ // we change 0x10000 to 0xffff
+ return color::MAX_COLOR_VAL;
+ }
+ return (unsigned int)val;
+}
+
+static color *read_rgb()
+{
+ symbol component = get_long_name(0);
+ if (component.is_null()) {
+ warning(WARN_COLOR, "missing rgb color values");
+ return 0;
+ }
+ const char *s = component.contents();
+ color *col = new color;
+ if (*s == '#') {
+ if (!col->read_rgb(s)) {
+ warning(WARN_COLOR, "expecting rgb color definition not `%1'", s);
+ delete col;
+ return 0;
+ }
+ }
+ else {
+ input_stack::push(make_temp_iterator(" "));
+ input_stack::push(make_temp_iterator(s));
+ tok.next();
+ unsigned int r = get_color_element("rgb color", "red component");
+ unsigned int g = get_color_element("rgb color", "green component");
+ unsigned int b = get_color_element("rgb color", "blue component");
+ col->set_rgb(r, g, b);
+ }
+ return col;
+}
+
+static color *read_cmy()
+{
+ symbol component = get_long_name(0);
+ if (component.is_null()) {
+ warning(WARN_COLOR, "missing cmy color values");
+ return 0;
+ }
+ const char *s = component.contents();
+ color *col = new color;
+ if (*s == '#') {
+ if (!col->read_cmy(s)) {
+ warning(WARN_COLOR, "expecting cmy color definition not `%1'", s);
+ delete col;
+ return 0;
+ }
+ }
+ else {
+ input_stack::push(make_temp_iterator(" "));
+ input_stack::push(make_temp_iterator(s));
+ tok.next();
+ unsigned int c = get_color_element("cmy color", "cyan component");
+ unsigned int m = get_color_element("cmy color", "magenta component");
+ unsigned int y = get_color_element("cmy color", "yellow component");
+ col->set_cmy(c, m, y);
+ }
+ return col;
+}
+
+static color *read_cmyk()
+{
+ symbol component = get_long_name(0);
+ if (component.is_null()) {
+ warning(WARN_COLOR, "missing cmyk color values");
+ return 0;
+ }
+ const char *s = component.contents();
+ color *col = new color;
+ if (*s == '#') {
+ if (!col->read_cmyk(s)) {
+ warning(WARN_COLOR, "`expecting a cmyk color definition not `%1'", s);
+ delete col;
+ return 0;
+ }
+ }
+ else {
+ input_stack::push(make_temp_iterator(" "));
+ input_stack::push(make_temp_iterator(s));
+ tok.next();
+ unsigned int c = get_color_element("cmyk color", "cyan component");
+ unsigned int m = get_color_element("cmyk color", "magenta component");
+ unsigned int y = get_color_element("cmyk color", "yellow component");
+ unsigned int k = get_color_element("cmyk color", "black component");
+ col->set_cmyk(c, m, y, k);
+ }
+ return col;
+}
+
+static color *read_gray()
+{
+ symbol component = get_long_name(0);
+ if (component.is_null()) {
+ warning(WARN_COLOR, "missing gray values");
+ return 0;
+ }
+ const char *s = component.contents();
+ color *col = new color;
+ if (*s == '#') {
+ if (!col->read_gray(s)) {
+ warning(WARN_COLOR, "`expecting a gray definition not `%1'", s);
+ delete col;
+ return 0;
+ }
+ }
+ else {
+ input_stack::push(make_temp_iterator("\n"));
+ input_stack::push(make_temp_iterator(s));
+ tok.next();
+ unsigned int g = get_color_element("gray", "gray value");
+ col->set_gray(g);
+ }
+ return col;
+}
+
+static void activate_color()
+{
+ int n;
+ if (has_arg() && get_integer(&n))
+ color_flag = n != 0;
+ else
+ color_flag = 1;
+ skip_line();
+}
+
+static void define_color()
+{
+ symbol color_name = get_long_name(1);
+ if (color_name.is_null()) {
+ skip_line();
+ return;
+ }
+ if (color_name == default_symbol) {
+ warning(WARN_COLOR, "default color can't be redefined");
+ skip_line();
+ return;
+ }
+ symbol style = get_long_name(1);
+ if (style.is_null()) {
+ skip_line();
+ return;
+ }
+ color *col;
+ if (strcmp(style.contents(), "rgb") == 0)
+ col = read_rgb();
+ else if (strcmp(style.contents(), "cmyk") == 0)
+ col = read_cmyk();
+ else if (strcmp(style.contents(), "gray") == 0)
+ col = read_gray();
+ else if (strcmp(style.contents(), "grey") == 0)
+ col = read_gray();
+ else if (strcmp(style.contents(), "cmy") == 0)
+ col = read_cmy();
+ else {
+ warning(WARN_COLOR,
+ "unknown color space `%1'; use rgb, cmyk, gray or cmy",
+ style.contents());
+ skip_line();
+ return;
+ }
+ if (col)
+ (void)color_dictionary.lookup(color_name, col);
+ skip_line();
+}
+
static node *do_overstrike()
{
token start;
overstrike_node *on = new overstrike_node;
+ int start_level = input_stack::get_level();
start.next();
- tok.next();
- while (tok != start) {
+ for (;;) {
+ tok.next();
if (tok.newline() || tok.eof()) {
warning(WARN_DELIM, "missing closing delimiter");
break;
}
+ if (tok == start
+ && (compatible_flag || input_stack::get_level() == start_level))
+ break;
charinfo *ci = tok.get_char(1);
if (ci) {
node *n = curenv->make_char_node(ci);
if (n)
on->overstrike(n);
}
- tok.next();
}
return on;
}
@@ -1034,8 +1279,9 @@ static node *do_bracket()
token start;
bracket_node *bn = new bracket_node;
start.next();
- tok.next();
- while (tok != start) {
+ int start_level = input_stack::get_level();
+ for (;;) {
+ tok.next();
if (tok.eof()) {
warning(WARN_DELIM, "missing closing delimiter");
break;
@@ -1045,13 +1291,15 @@ static node *do_bracket()
input_stack::push(make_temp_iterator("\n"));
break;
}
+ if (tok == start
+ && (compatible_flag || input_stack::get_level() == start_level))
+ break;
charinfo *ci = tok.get_char(1);
if (ci) {
node *n = curenv->make_char_node(ci);
if (n)
bn->bracket(n);
}
- tok.next();
}
return bn;
}
@@ -1164,7 +1412,7 @@ static node *do_zero_width()
&& (compatible_flag || input_stack::get_level() == start_level))
break;
if (!tok.add_to_node_list(&rev))
- error("illegal token in argument to \\Z");
+ error("invalid token in argument to \\Z");
}
node *n = 0;
while (rev) {
@@ -1326,8 +1574,7 @@ void token::next()
return;
case ESCAPE_SPACE:
ESCAPE_SPACE:
- type = TOKEN_NODE;
- nd = new space_char_hmotion_node(curenv->get_space_width());
+ type = TOKEN_UNSTRETCHABLE_SPACE;
return;
case ESCAPE_TILDE:
ESCAPE_TILDE:
@@ -1335,10 +1582,7 @@ void token::next()
return;
case ESCAPE_COLON:
ESCAPE_COLON:
- type = TOKEN_NODE;
- nd = new space_node(H0);
- nd->freeze_space();
- nd->is_escape_colon();
+ type = TOKEN_ZERO_WIDTH_BREAK;
return;
case ESCAPE_e:
ESCAPE_e:
@@ -1349,12 +1593,14 @@ void token::next()
case ESCAPE_BAR:
ESCAPE_BAR:
type = TOKEN_NODE;
- nd = new hmotion_node(curenv->get_narrow_space_width());
+ nd = new hmotion_node(curenv->get_narrow_space_width(),
+ curenv->get_fill_color());
return;
case ESCAPE_CIRCUMFLEX:
ESCAPE_CIRCUMFLEX:
type = TOKEN_NODE;
- nd = new hmotion_node(curenv->get_half_narrow_space_width());
+ nd = new hmotion_node(curenv->get_half_narrow_space_width(),
+ curenv->get_fill_color());
return;
case ESCAPE_NEWLINE:
break;
@@ -1447,7 +1693,7 @@ void token::next()
}
else {
handle_escape_char:
- cc = input_stack::get(NULL);
+ cc = input_stack::get(0);
switch(cc) {
case '(':
nm = read_two_char_escape_name();
@@ -1470,7 +1716,8 @@ void token::next()
case ' ':
goto ESCAPE_SPACE;
case '0':
- nd = new hmotion_node(curenv->get_digit_width());
+ nd = new hmotion_node(curenv->get_digit_width(),
+ curenv->get_fill_color());
type = TOKEN_NODE;
return;
case '|':
@@ -1497,7 +1744,7 @@ void token::next()
case ':':
goto ESCAPE_COLON;
case '"':
- while ((cc = input_stack::get(NULL)) != '\n' && cc != EOF)
+ while ((cc = input_stack::get(0)) != '\n' && cc != EOF)
;
if (cc == '\n')
type = TOKEN_NEWLINE;
@@ -1505,7 +1752,7 @@ void token::next()
type = TOKEN_EOF;
return;
case '#': // Like \" but newline is ignored.
- while ((cc = input_stack::get(NULL)) != '\n')
+ while ((cc = input_stack::get(0)) != '\n')
if (cc == EOF) {
type = TOKEN_EOF;
return;
@@ -1514,15 +1761,21 @@ void token::next()
case '$':
{
symbol nm = read_escape_name();
- if (!nm.is_null())
+ if (!(nm.is_null() || nm.is_empty()))
interpolate_arg(nm);
break;
}
case '*':
{
- symbol nm = read_escape_name();
- if (!nm.is_null())
- interpolate_string(nm);
+ symbol nm = read_escape_name(WITH_ARGS);
+ if (!(nm.is_null() || nm.is_empty())) {
+ if (have_string_arg) {
+ have_string_arg = 0;
+ interpolate_string_with_args(nm);
+ }
+ else
+ interpolate_string(nm);
+ }
break;
}
case 'a':
@@ -1551,7 +1804,8 @@ void token::next()
return;
case 'd':
type = TOKEN_NODE;
- nd = new vmotion_node(curenv->get_size()/2);
+ nd = new vmotion_node(curenv->get_size() / 2,
+ curenv->get_fill_color());
return;
case 'D':
nd = read_draw_node();
@@ -1565,23 +1819,33 @@ void token::next()
goto handle_escape_char;
case 'f':
{
- symbol s = read_escape_name();
+ symbol s = read_escape_name(ALLOW_EMPTY);
if (s.is_null())
break;
const char *p;
for (p = s.contents(); *p != '\0'; p++)
if (!csdigit(*p))
break;
- if (*p)
+ if (*p || s.is_empty())
curenv->set_font(s);
else
curenv->set_font(atoi(s.contents()));
+ if (!compatible_flag)
+ have_input = 1;
+ break;
+ }
+ case 'F':
+ {
+ symbol s = read_escape_name(ALLOW_EMPTY);
+ if (s.is_null())
+ break;
+ curenv->set_family(s);
break;
}
case 'g':
{
symbol s = read_escape_name();
- if (!s.is_null())
+ if (!(s.is_null() || s.is_empty()))
interpolate_number_format(s);
break;
}
@@ -1589,15 +1853,27 @@ void token::next()
if (!get_delim_number(&x, 'm'))
break;
type = TOKEN_NODE;
- nd = new hmotion_node(x);
+ nd = new hmotion_node(x, curenv->get_fill_color());
return;
case 'H':
- if (get_delim_number(&x, 'z', curenv->get_requested_point_size()))
- curenv->set_char_height(x);
+ // don't take height increments relative to previous height if
+ // in compatibility mode
+ if (!compatible_flag && curenv->get_char_height())
+ {
+ if (get_delim_number(&x, 'z', curenv->get_char_height()))
+ curenv->set_char_height(x);
+ }
+ else
+ {
+ if (get_delim_number(&x, 'z', curenv->get_requested_point_size()))
+ curenv->set_char_height(x);
+ }
+ if (!compatible_flag)
+ have_input = 1;
break;
case 'k':
nm = read_escape_name();
- if (nm.is_null())
+ if (nm.is_null() || nm.is_empty())
break;
type = TOKEN_MARK_INPUT;
return;
@@ -1617,11 +1893,21 @@ void token::next()
nd = new vline_node(x, n);
return;
}
+ case 'm':
+ do_glyph_color(read_escape_name(ALLOW_EMPTY));
+ if (!compatible_flag)
+ have_input = 1;
+ break;
+ case 'M':
+ do_fill_color(read_escape_name(ALLOW_EMPTY));
+ if (!compatible_flag)
+ have_input = 1;
+ break;
case 'n':
{
int inc;
symbol nm = read_increment_and_escape_name(&inc);
- if (!nm.is_null())
+ if (!(nm.is_null() || nm.is_empty()))
interpolate_number_reg(nm, inc);
break;
}
@@ -1635,7 +1921,7 @@ void token::next()
type = TOKEN_NODE;
return;
case 'O':
- nd = do_suppress();
+ nd = do_suppress(read_escape_name());
if (!nd)
break;
type = TOKEN_NODE;
@@ -1645,18 +1931,24 @@ void token::next()
return;
case 'r':
type = TOKEN_NODE;
- nd = new vmotion_node(-curenv->get_size());
+ nd = new vmotion_node(-curenv->get_size(), curenv->get_fill_color());
return;
case 'R':
do_register();
+ if (!compatible_flag)
+ have_input = 1;
break;
case 's':
if (read_size(&x))
curenv->set_size(x);
+ if (!compatible_flag)
+ have_input = 1;
break;
case 'S':
if (get_delim_number(&x, 0))
curenv->set_char_slant(x);
+ if (!compatible_flag)
+ have_input = 1;
break;
case 't':
type = TOKEN_NODE;
@@ -1664,18 +1956,19 @@ void token::next()
return;
case 'u':
type = TOKEN_NODE;
- nd = new vmotion_node(-curenv->get_size()/2);
+ nd = new vmotion_node(-curenv->get_size() / 2,
+ curenv->get_fill_color());
return;
case 'v':
if (!get_delim_number(&x, 'v'))
break;
type = TOKEN_NODE;
- nd = new vmotion_node(x);
+ nd = new vmotion_node(x, curenv->get_fill_color());
return;
case 'V':
- {
+ {
symbol nm = read_escape_name();
- if (!nm.is_null())
+ if (!(nm.is_null() || nm.is_empty()))
interpolate_environment_variable(nm);
break;
}
@@ -1697,7 +1990,7 @@ void token::next()
case 'Y':
{
symbol s = read_escape_name();
- if (s.is_null())
+ if (s.is_null() || s.is_empty())
break;
request_or_macro *p = lookup_request(s);
macro *m = p->to_macro();
@@ -1712,9 +2005,9 @@ void token::next()
case 'z':
{
next();
- if (type == TOKEN_NODE)
- nd = new zero_width_node(nd);
- else {
+ if (type == TOKEN_NODE)
+ nd = new zero_width_node(nd);
+ else {
charinfo *ci = get_char(1);
if (ci == 0)
break;
@@ -1723,7 +2016,7 @@ void token::next()
break;
nd = new zero_width_node(gn);
type = TOKEN_NODE;
- }
+ }
return;
}
case 'Z':
@@ -1741,7 +2034,7 @@ void token::next()
case '[':
if (!compatible_flag) {
nm = read_long_escape_name();
- if (nm.is_null())
+ if (nm.is_null() || nm.is_empty())
break;
type = TOKEN_SPECIAL;
return;
@@ -1817,6 +2110,7 @@ int token::delimiter(int err)
case TOKEN_NODE:
case TOKEN_SPACE:
case TOKEN_STRETCHABLE_SPACE:
+ case TOKEN_UNSTRETCHABLE_SPACE:
case TOKEN_TAB:
case TOKEN_NEWLINE:
if (err)
@@ -1871,12 +2165,16 @@ const char *token::description()
return "`\\p'";
case TOKEN_STRETCHABLE_SPACE:
return "`\\~'";
+ case TOKEN_UNSTRETCHABLE_SPACE:
+ return "`\\ '";
case TOKEN_TAB:
return "a tab character";
case TOKEN_TRANSPARENT:
return "`\\!'";
case TOKEN_TRANSPARENT_DUMMY:
return "`\\)'";
+ case TOKEN_ZERO_WIDTH_BREAK:
+ return "`\\:'";
case TOKEN_EOF:
return "end of input";
default:
@@ -2015,19 +2313,21 @@ void exit_troff()
tok.next();
process_input_stack();
end_diversions();
- done_end_macro = 1;
- topdiv->set_ejecting();
- static unsigned char buf[2] = { LAST_PAGE_EJECTOR, '\0' };
- input_stack::push(make_temp_iterator((char *)buf));
- topdiv->space(topdiv->get_page_length(), 1);
- tok.next();
- process_input_stack();
- seen_last_page_ejector = 1; // should be set already
- topdiv->set_ejecting();
- push_page_ejector();
- topdiv->space(topdiv->get_page_length(), 1);
- tok.next();
- process_input_stack();
+ if (topdiv->get_page_length() > 0) {
+ done_end_macro = 1;
+ topdiv->set_ejecting();
+ static unsigned char buf[2] = { LAST_PAGE_EJECTOR, '\0' };
+ input_stack::push(make_temp_iterator((char *)buf));
+ topdiv->space(topdiv->get_page_length(), 1);
+ tok.next();
+ process_input_stack();
+ seen_last_page_ejector = 1; // should be set already
+ topdiv->set_ejecting();
+ push_page_ejector();
+ topdiv->space(topdiv->get_page_length(), 1);
+ tok.next();
+ process_input_stack();
+ }
// This will only happen if a trap-invoked macro starts a diversion,
// or if vertical position traps have been disabled.
cleanup_and_exit(0);
@@ -2095,7 +2395,7 @@ inline int possibly_handle_first_page_transition()
static int transparent_translate(int cc)
{
- if (!illegal_input_char(cc)) {
+ if (!invalid_input_char(cc)) {
charinfo *ci = charset_table[cc];
switch (ci->get_special_translation(1)) {
case charinfo::TRANSLATE_SPACE:
@@ -2230,9 +2530,9 @@ void process_input_stack()
case token::TOKEN_CHAR:
{
unsigned char ch = tok.c;
- if (bol &&
- (ch == curenv->control_char
- || ch == curenv->no_break_control_char)) {
+ if (bol && !have_input
+ && (ch == curenv->control_char
+ || ch == curenv->no_break_control_char)) {
break_flag = ch == curenv->control_char;
// skip tabs as well as spaces here
do {
@@ -2244,6 +2544,7 @@ void process_input_stack()
else
interpolate_macro(nm);
suppress_next = 1;
+ have_input = 0;
}
else {
if (possibly_handle_first_page_transition())
@@ -2286,11 +2587,13 @@ void process_input_stack()
}
case token::TOKEN_NEWLINE:
{
- if (bol && !curenv->get_prev_line_interrupted())
+ if (bol && !have_input
+ && !curenv->get_prev_line_interrupted())
trapping_blank_line();
else {
curenv->newline();
bol = 1;
+ have_input = 0;
}
break;
}
@@ -2318,6 +2621,7 @@ void process_input_stack()
break;
}
suppress_next = 1;
+ have_input = 0;
break;
}
case token::TOKEN_SPACE:
@@ -2326,6 +2630,9 @@ void process_input_stack()
;
else if (bol && !curenv->get_prev_line_interrupted()) {
int nspaces = 0;
+ // save space_width now so that it isn't changed by \f or \s
+ // which we wouldn't notice here
+ hunits space_width = curenv->get_space_width();
do {
nspaces += tok.nspaces();
tok.next();
@@ -2335,8 +2642,8 @@ void process_input_stack()
else {
push_token(tok);
curenv->do_break();
- curenv->add_node(new hmotion_node(curenv->get_space_width()
- * nspaces));
+ curenv->add_node(new hmotion_node(space_width * nspaces,
+ curenv->get_fill_color()));
bol = 0;
}
}
@@ -2375,6 +2682,7 @@ void process_input_stack()
{
trap_bol_stack.push(bol);
bol = 1;
+ have_input = 0;
break;
}
case token::TOKEN_END_TRAP:
@@ -2388,9 +2696,9 @@ void process_input_stack()
way to do it. Doing an output_pending_lines() whenever a
TOKEN_END_TRAP is detected doesn't work: for example,
- .wh -1i x
- .de x
- 'bp
+ .wh -1i x
+ .de x
+ 'bp
..
.wh -.5i y
.de y
@@ -2401,8 +2709,8 @@ void process_input_stack()
.sp |\n(.pu-1i-.5v
a\%very\%very\%long\%word
- will print all but the first lines from the word immediately
- after the footer, rather than on the next page. */
+ will print all but the first lines from the word immediately
+ after the footer, rather than on the next page. */
if (trap_bol_stack.is_empty())
curenv->output_pending_lines();
@@ -2468,6 +2776,8 @@ public:
char_list();
~char_list();
void append(unsigned char);
+ void set(unsigned char, int);
+ unsigned char get(int);
int length();
private:
unsigned char *ptr;
@@ -2514,6 +2824,44 @@ void char_list::append(unsigned char c)
len++;
}
+void char_list::set(unsigned char c, int offset)
+{
+ assert(len > offset);
+ // optimization for access at the end
+ int boundary = len - len % char_block::SIZE;
+ if (offset >= boundary) {
+ *(tail->s + offset - boundary) = c;
+ return;
+ }
+ char_block *tem = head;
+ int l = 0;
+ for (;;) {
+ l += char_block::SIZE;
+ if (l > offset) {
+ *(tem->s + offset % char_block::SIZE) = c;
+ return;
+ }
+ tem = tem->next;
+ }
+}
+
+unsigned char char_list::get(int offset)
+{
+ assert(len > offset);
+ // optimization for access at the end
+ int boundary = len - len % char_block::SIZE;
+ if (offset >= boundary)
+ return *(tail->s + offset - boundary);
+ char_block *tem = head;
+ int l = 0;
+ for (;;) {
+ l += char_block::SIZE;
+ if (l > offset)
+ return *(tem->s + offset % char_block::SIZE);
+ tem = tem->next;
+ }
+}
+
class node_list {
node *head;
node *tail;
@@ -2586,12 +2934,14 @@ macro::macro()
filename = 0;
lineno = 0;
}
- length = 0;
+ len = 0;
+ empty_macro = 1;
p = 0;
}
macro::macro(const macro &m)
-: p(m.p), filename(m.filename), lineno(m.lineno), length(m.length)
+: p(m.p), filename(m.filename), lineno(m.lineno), len(m.len),
+ empty_macro(m.empty_macro)
{
if (p != 0)
p->count++;
@@ -2607,7 +2957,8 @@ macro &macro::operator=(const macro &m)
p = m.p;
filename = m.filename;
lineno = m.lineno;
- length = m.length;
+ len = m.len;
+ empty_macro = m.empty_macro;
return *this;
}
@@ -2616,14 +2967,34 @@ void macro::append(unsigned char c)
assert(c != 0);
if (p == 0)
p = new macro_header;
- if (p->cl.length() != length) {
- macro_header *tem = p->copy(length);
+ if (p->cl.length() != len) {
+ macro_header *tem = p->copy(len);
if (--(p->count) <= 0)
delete p;
p = tem;
}
p->cl.append(c);
- ++length;
+ ++len;
+ if (c != COMPATIBLE_SAVE && c != COMPATIBLE_RESTORE)
+ empty_macro = 0;
+}
+
+void macro::set(unsigned char c, int offset)
+{
+ assert(p != 0);
+ assert(c != 0);
+ p->cl.set(c, offset);
+}
+
+unsigned char macro::get(int offset)
+{
+ assert(p != 0);
+ return p->cl.get(offset);
+}
+
+int macro::length()
+{
+ return len;
}
void macro::append_str(const char *s)
@@ -2643,15 +3014,16 @@ void macro::append(node *n)
assert(n != 0);
if (p == 0)
p = new macro_header;
- if (p->cl.length() != length) {
- macro_header *tem = p->copy(length);
+ if (p->cl.length() != len) {
+ macro_header *tem = p->copy(len);
if (--(p->count) <= 0)
delete p;
p = tem;
}
p->cl.append(0);
p->nl.append(n);
- ++length;
+ ++len;
+ empty_macro = 0;
}
void macro::append_unsigned(unsigned int i)
@@ -2673,7 +3045,7 @@ void macro::append_int(int i)
void macro::print_size()
{
- errprint("%1", length);
+ errprint("%1", len);
}
// make a copy of the first n bytes
@@ -2740,9 +3112,10 @@ public:
};
string_iterator::string_iterator(const macro &m, const char *p, symbol s)
-: mac(m), how_invoked(p), newline_flag(0), lineno(1), nm(s)
+: mac(m), how_invoked(p),
+ newline_flag(0), lineno(1), nm(s)
{
- count = mac.length;
+ count = mac.len;
if (count != 0) {
bp = mac.p->cl.head;
nd = mac.p->nl.head;
@@ -2811,8 +3184,6 @@ int string_iterator::peek()
if (count <= 0)
return EOF;
const unsigned char *p = eptr;
- if (count <= 0)
- return EOF;
if (p >= bp->s + char_block::SIZE) {
p = bp->next->s;
}
@@ -2940,7 +3311,7 @@ input_iterator *make_temp_iterator(const char *s)
}
}
-// this is used when macros are interpolated using the .macro_name notation
+// this is used when macros with arguments are interpolated
struct arg_list {
macro mac;
@@ -3012,11 +3383,11 @@ void macro_iterator::shift(int n)
int operator==(const macro &m1, const macro &m2)
{
- if (m1.length != m2.length)
+ if (m1.len != m2.len)
return 0;
string_iterator iter1(m1);
string_iterator iter2(m2);
- int n = m1.length;
+ int n = m1.len;
while (--n >= 0) {
node *nd1 = 0;
int c1 = iter1.get(&nd1);
@@ -3084,7 +3455,7 @@ static void decode_args(macro_iterator *mi)
if (!tok.newline() && !tok.eof()) {
node *n;
int c = get_copy(&n);
- for (;;) {
+ for (;;) {
while (c == ' ')
c = get_copy(&n);
if (c == '\n' || c == EOF)
@@ -3126,6 +3497,56 @@ static void decode_args(macro_iterator *mi)
}
}
+static void decode_string_args(macro_iterator *mi)
+{
+ node *n;
+ int c = get_copy(&n);
+ for (;;) {
+ while (c == ' ')
+ c = get_copy(&n);
+ if (c == '\n' || c == EOF) {
+ error("missing `]'");
+ break;
+ }
+ if (c == ']')
+ break;
+ macro arg;
+ int quote_input_level = 0;
+ int done_tab_warning = 0;
+ if (c == '\"') {
+ quote_input_level = input_stack::get_level();
+ c = get_copy(&n);
+ }
+ while (c != EOF && c != '\n'
+ && !(c == ']' && quote_input_level == 0)
+ && !(c == ' ' && quote_input_level == 0)) {
+ if (quote_input_level > 0 && c == '\"'
+ && input_stack::get_level() == quote_input_level) {
+ c = get_copy(&n);
+ if (c == '"') {
+ arg.append(c);
+ c = get_copy(&n);
+ }
+ else
+ break;
+ }
+ else {
+ if (c == 0)
+ arg.append(n);
+ else {
+ if (c == '\t' && quote_input_level == 0 && !done_tab_warning) {
+ warning(WARN_TAB, "tab character in unquoted string argument");
+ done_tab_warning = 1;
+ }
+ arg.append(c);
+ }
+ c = get_copy(&n);
+ }
+ }
+ mi->add_arg(arg);
+ }
+}
+
void macro::invoke(symbol nm)
{
macro_iterator *mi = new macro_iterator(nm, *this);
@@ -3141,7 +3562,7 @@ macro *macro::to_macro()
int macro::empty()
{
- return length == 0;
+ return empty_macro == 1;
}
macro_iterator::macro_iterator(symbol s, macro &m, const char *how_invoked)
@@ -3209,16 +3630,16 @@ void read_request()
int reading_from_terminal = isatty(fileno(stdin));
int had_prompt = 0;
if (!tok.newline() && !tok.eof()) {
- int c = get_copy(NULL);
+ int c = get_copy(0);
while (c == ' ')
- c = get_copy(NULL);
+ c = get_copy(0);
while (c != EOF && c != '\n' && c != ' ') {
- if (!illegal_input_char(c)) {
+ if (!invalid_input_char(c)) {
if (reading_from_terminal)
fputc(c, stderr);
had_prompt = 1;
}
- c = get_copy(NULL);
+ c = get_copy(0);
}
if (c == ' ') {
tok.make_space();
@@ -3234,8 +3655,8 @@ void read_request()
int nl = 0;
int c;
while ((c = getchar()) != EOF) {
- if (illegal_input_char(c))
- warning(WARN_INPUT, "illegal input character code %1", int(c));
+ if (invalid_input_char(c))
+ warning(WARN_INPUT, "invalid input character code %1", int(c));
else {
if (c == '\n') {
if (nl)
@@ -3254,7 +3675,10 @@ void read_request()
tok.next();
}
-void do_define_string(int append)
+enum define_mode { DEFINE_NORMAL, DEFINE_APPEND, DEFINE_IGNORE };
+enum calling_mode { CALLING_NORMAL, CALLING_INDIRECT, CALLING_DISABLE_COMP };
+
+void do_define_string(define_mode mode, calling_mode calling)
{
symbol nm;
node *n;
@@ -3282,8 +3706,10 @@ void do_define_string(int append)
macro mac;
request_or_macro *rm = (request_or_macro *)request_dictionary.lookup(nm);
macro *mm = rm ? rm->to_macro() : 0;
- if (append && mm)
+ if (mode == DEFINE_APPEND && mm)
mac = *mm;
+ if (calling == CALLING_DISABLE_COMP)
+ mac.append(COMPATIBLE_SAVE);
while (c != '\n' && c != EOF) {
if (c == 0)
mac.append(n);
@@ -3295,21 +3721,33 @@ void do_define_string(int append)
mm = new macro;
request_dictionary.define(nm, mm);
}
+ if (calling == CALLING_DISABLE_COMP)
+ mac.append(COMPATIBLE_RESTORE);
*mm = mac;
tok.next();
}
void define_string()
{
- do_define_string(0);
+ do_define_string(DEFINE_NORMAL, CALLING_NORMAL);
+}
+
+void define_nocomp_string()
+{
+ do_define_string(DEFINE_NORMAL, CALLING_DISABLE_COMP);
}
void append_string()
{
- do_define_string(1);
+ do_define_string(DEFINE_APPEND, CALLING_NORMAL);
}
-void define_character()
+void append_nocomp_string()
+{
+ do_define_string(DEFINE_APPEND, CALLING_DISABLE_COMP);
+}
+
+void do_define_character(int fallback)
{
node *n;
int c;
@@ -3343,12 +3781,22 @@ void define_character()
m->append((unsigned char)c);
c = get_copy(&n);
}
- m = ci->set_macro(m);
+ m = ci->set_macro(m, fallback);
if (m)
delete m;
tok.next();
}
+void define_character()
+{
+ do_define_character(0);
+}
+
+void define_fallback_character()
+{
+ do_define_character(1);
+}
+
static void remove_character()
{
tok.skip();
@@ -3371,13 +3819,26 @@ static void interpolate_string(symbol nm)
request_or_macro *p = lookup_request(nm);
macro *m = p->to_macro();
if (!m)
- error("you can only invoke a string using \\*");
+ error("you can only invoke a string or macro using \\*");
else {
string_iterator *si = new string_iterator(*m, "string", nm);
input_stack::push(si);
}
}
+static void interpolate_string_with_args(symbol s)
+{
+ request_or_macro *p = lookup_request(s);
+ macro *m = p->to_macro();
+ if (!m)
+ error("you can only invoke a string or macro using \\*");
+ else {
+ macro_iterator *mi = new macro_iterator(s, *m);
+ decode_string_args(mi);
+ input_stack::push(mi);
+ }
+}
+
/* This class is used for the implementation of \$@. It is used for
each of the closing double quotes. It artificially increases the
input level by 2, so that the closing double quote will appear to have
@@ -3473,9 +3934,6 @@ void handle_initial_title()
// this should be local to define_macro, but cfront 1.2 doesn't support that
static symbol dot_symbol(".");
-enum define_mode { DEFINE_NORMAL, DEFINE_APPEND, DEFINE_IGNORE };
-enum calling_mode { CALLING_NORMAL, CALLING_INDIRECT, CALLING_DISABLE_COMP };
-
void do_define_macro(define_mode mode, calling_mode calling)
{
symbol nm, term;
@@ -3537,11 +3995,17 @@ void do_define_macro(define_mode mode, calling_mode calling)
const char *s = term.contents();
int d = 0;
// see if it matches term
- int i;
- for (i = 0; s[i] != 0; i++) {
- d = get_copy(&n);
- if ((unsigned char)s[i] != d)
- break;
+ int i = 0;
+ if (s[0] != 0) {
+ while ((d = get_copy(&n)) == ' ' || d == '\t')
+ ;
+ if ((unsigned char)s[0] == d) {
+ for (i = 1; s[i] != 0; i++) {
+ d = get_copy(&n);
+ if ((unsigned char)s[i] != d)
+ break;
+ }
+ }
}
if (s[i] == 0
&& ((i == 2 && compatible_flag)
@@ -3625,6 +4089,11 @@ void append_macro()
do_define_macro(DEFINE_APPEND, CALLING_NORMAL);
}
+void append_indirect_macro()
+{
+ do_define_macro(DEFINE_APPEND, CALLING_INDIRECT);
+}
+
void append_nocomp_macro()
{
do_define_macro(DEFINE_APPEND, CALLING_DISABLE_COMP);
@@ -3680,75 +4149,121 @@ void chop_macro()
macro *m = p->to_macro();
if (!m)
error("cannot chop request");
- else if (m->length == 0)
+ else if (m->empty())
error("cannot chop empty macro");
- else
- m->length -= 1;
+ else {
+ int have_restore = 0;
+ // we have to check for additional save/restore pairs which could be
+ // there due to empty am1 requests.
+ for (;;) {
+ if (m->get(m->len - 1) != COMPATIBLE_RESTORE)
+ break;
+ have_restore = 1;
+ m->len -= 1;
+ if (m->get(m->len - 1) != COMPATIBLE_SAVE)
+ break;
+ have_restore = 0;
+ m->len -= 1;
+ if (m->len == 0)
+ break;
+ }
+ if (m->len == 0)
+ error("cannot chop empty macro");
+ else {
+ if (have_restore)
+ m->set(COMPATIBLE_RESTORE, m->len - 1);
+ else
+ m->len -= 1;
+ }
+ }
}
skip_line();
}
-void substring_macro()
+void substring_request()
{
- int start;
+ int start; // 0, 1, ..., n-1 or -1, -2, ...
symbol s = get_name(1);
if (!s.is_null() && get_integer(&start)) {
request_or_macro *p = lookup_request(s);
macro *m = p->to_macro();
if (!m)
- error("cannot substring request");
+ error("cannot apply `substring' on a request");
else {
- if (start <= 0)
- start += m->length;
- else
- start--;
- int end = 0;
+ int end = -1;
if (!has_arg() || get_integer(&end)) {
- if (end <= 0)
- end += m->length;
- else
- end--;
+ int real_length = 0; // 1, 2, ..., n
+ string_iterator iter1(*m);
+ for (int l = 0; l < m->len; l++) {
+ int c = iter1.get(0);
+ if (c == COMPATIBLE_SAVE || c == COMPATIBLE_RESTORE)
+ continue;
+ if (c == EOF)
+ break;
+ real_length++;
+ }
+ if (start < 0)
+ start += real_length;
+ if (end < 0)
+ end += real_length;
if (start > end) {
int tem = start;
start = end;
end = tem;
}
- if (start >= m->length || start == end) {
- m->length = 0;
+ if (start >= real_length || end < 0) {
+ warning(WARN_RANGE,
+ "start and end index of substring out of range");
+ m->len = 0;
if (m->p) {
if (--(m->p->count) <= 0)
delete m->p;
m->p = 0;
}
+ skip_line();
+ return;
}
- else if (start == 0)
- m->length = end;
- else {
- string_iterator iter(*m);
- int i;
- for (i = 0; i < start; i++)
- if (iter.get(0) == EOF)
- break;
- macro mac;
- for (; i < end; i++) {
- node *nd;
- int c = iter.get(&nd);
- if (c == EOF)
- break;
- if (c == 0)
- mac.append(nd);
- else
- mac.append((unsigned char)c);
- }
- *m = mac;
+ if (start < 0) {
+ warning(WARN_RANGE,
+ "start index of substring out of range, set to 0");
+ start = 0;
+ }
+ if (end >= real_length) {
+ warning(WARN_RANGE,
+ "end index of substring out of range, set to string length");
+ end = real_length - 1;
}
+ // now extract the substring
+ string_iterator iter(*m);
+ int i;
+ for (i = 0; i < start; i++) {
+ int c = iter.get(0);
+ while (c == COMPATIBLE_SAVE || c == COMPATIBLE_RESTORE)
+ c = iter.get(0);
+ if (c == EOF)
+ break;
+ }
+ macro mac;
+ for (; i <= end; i++) {
+ node *nd;
+ int c = iter.get(&nd);
+ while (c == COMPATIBLE_SAVE || c == COMPATIBLE_RESTORE)
+ c = iter.get(0);
+ if (c == EOF)
+ break;
+ if (c == 0)
+ mac.append(nd);
+ else
+ mac.append((unsigned char)c);
+ }
+ *m = mac;
}
}
}
skip_line();
}
-void length_macro()
+void length_request()
{
symbol ret;
ret = get_name(1);
@@ -3778,12 +4293,12 @@ void length_macro()
++len;
c = get_copy(&n);
}
- tok.next();
reg *r = (reg*)number_reg_dictionary.lookup(ret);
if (r)
r->set_value(len);
else
set_number_reg(ret, len);
+ tok.next();
}
void asciify_macro()
@@ -3900,19 +4415,20 @@ static int get_line_arg(units *n, int si, charinfo **cp)
{
token start;
start.next();
- if (start.delimiter(1)) {
- tok.next();
- if (get_number(n, si)) {
- if (tok.dummy() || tok.transparent_dummy())
- tok.next();
- if (start != tok) {
- *cp = tok.get_char(1);
- tok.next();
- }
- if (start != tok)
- warning(WARN_DELIM, "closing delimiter does not match");
- return 1;
+ int start_level = input_stack::get_level();
+ if (!start.delimiter(1))
+ return 0;
+ tok.next();
+ if (get_number(n, si)) {
+ if (tok.dummy() || tok.transparent_dummy())
+ tok.next();
+ if (!(start == tok && input_stack::get_level() == start_level)) {
+ *cp = tok.get_char(1);
+ tok.next();
}
+ if (!(start == tok && input_stack::get_level() == start_level))
+ warning(WARN_DELIM, "closing delimiter does not match");
+ return 1;
}
return 0;
}
@@ -4085,65 +4601,6 @@ static symbol get_delim_name()
}
}
-static symbol get_delim_file_name()
-{
- token start;
- start.next();
- if (start.eof()) {
- error("end of input at start of delimited file name");
- return NULL_SYMBOL;
- }
- if (start.newline()) {
- error("can't delimit file name with a newline");
- return NULL_SYMBOL;
- }
- int start_level = input_stack::get_level();
- char abuf[ABUF_SIZE];
- char *buf = abuf;
- int buf_size = ABUF_SIZE;
- int i = 0;
- for (;;) {
- if (i + 1 > buf_size) {
- if (buf == abuf) {
- buf = new char[ABUF_SIZE*2];
- memcpy(buf, abuf, buf_size);
- buf_size = ABUF_SIZE*2;
- }
- else {
- char *old_buf = buf;
- buf = new char[buf_size*2];
- memcpy(buf, old_buf, buf_size);
- buf_size *= 2;
- a_delete old_buf;
- }
- }
- tok.next();
- if (tok.ch() == ']' && input_stack::get_level() == start_level)
- break;
- if ((buf[i] = tok.ch()) == 0) {
- error("missing delimiter (got %1)", tok.description());
- if (buf != abuf)
- a_delete buf;
- return NULL_SYMBOL;
- }
- i++;
- }
- buf[i] = '\0';
- if (buf == abuf) {
- if (i == 0) {
- error("empty delimited file name");
- return NULL_SYMBOL;
- }
- else
- return symbol(buf);
- }
- else {
- symbol s(buf);
- a_delete buf;
- return s;
- }
-}
-
// Implement \R
static void do_register()
@@ -4331,9 +4788,14 @@ static void encode_char(macro *mac, char c)
mac->append(')');
}
}
- else {
- error("%1 is illegal within \\X", tok.description());
- }
+ else if (tok.stretchable_space()
+ || tok.unstretchable_space())
+ mac->append(' ');
+ else if (!(tok.hyphen_indicator()
+ || tok.dummy()
+ || tok.transparent_dummy()
+ || tok.zero_width_break()))
+ error("%1 is invalid within \\X", tok.description());
}
else {
if ((font::use_charnames_in_special) && (c == '\\')) {
@@ -4380,29 +4842,48 @@ node *do_special()
return new special_node(mac);
}
-node *do_suppress()
+void output_request()
{
+ if (!tok.newline() && !tok.eof()) {
+ int c;
+ for (;;) {
+ c = get_copy(0);
+ if (c == '"') {
+ c = get_copy(0);
+ break;
+ }
+ if (c != ' ' && c != '\t')
+ break;
+ }
+ for (; c != '\n' && c != EOF; c = get_copy(0))
+ topdiv->transparent_output(c);
+ topdiv->transparent_output('\n');
+ }
tok.next();
- int c = tok.ch();
- if (c != '[') {
- error("argument(s) of \\O must be enclosed in brackets (got %1)",
- char(c));
+}
+
+extern int image_no; // from node.cc
+
+static node *do_suppress(symbol nm)
+{
+ if (nm.is_null() || nm.is_empty()) {
+ error("expecting an argument to escape \\O");
return 0;
}
- tok.next();
- c = tok.ch();
- tok.next();
- switch (c) {
+ const char *s = nm.contents();
+ switch (*s) {
case '0':
- if (begin_level == 1)
+ if (begin_level == 0)
+ // suppress generation of glyphs
return new suppress_node(0, 0);
break;
case '1':
- if (begin_level == 1)
+ if (begin_level == 0)
+ // enable generation of glyphs
return new suppress_node(1, 0);
break;
case '2':
- if (begin_level == 1)
+ if (begin_level == 0)
return new suppress_node(1, 1);
break;
case '3':
@@ -4411,20 +4892,33 @@ node *do_suppress()
case '4':
begin_level--;
break;
- case '5': {
- symbol filename = get_delim_file_name();
- tok.next();
- if (filename.is_null()) {
- error("missing filename as second argument to \\O");
- return 0;
+ case '5':
+ {
+ s++; // move over '5'
+ char position = *s;
+ if (*s == (char)0) {
+ error("missing position and filename in \\O");
+ return 0;
+ }
+ if (!(position == 'l'
+ || position == 'r'
+ || position == 'c'
+ || position == 'i')) {
+ error("l, r, c, or i position expected (got %1 in \\O)", position);
+ return 0;
+ }
+ s++; // onto image name
+ if (s == (char *)0) {
+ error("missing image name for \\O");
+ return 0;
+ }
+ image_no++;
+ if (begin_level == 0)
+ return new suppress_node(symbol(s), position, image_no);
}
- if (begin_level == 1)
- return new suppress_node(filename, 'i');
- return 0;
break;
- }
default:
- error("`%1' is an invalid argument to \\O", char(c));
+ error("`%1' is an invalid argument to \\O", *s);
}
return 0;
}
@@ -4434,7 +4928,7 @@ void special_node::tprint(troff_output_file *out)
tprint_start(out);
string_iterator iter(mac);
for (;;) {
- int c = iter.get(NULL);
+ int c = iter.get(0);
if (c == EOF)
break;
for (const char *s = ::asciify(c); *s; s++)
@@ -4484,7 +4978,7 @@ static void skip_alternative()
level++;
int c;
for (;;) {
- c = input_stack::get(NULL);
+ c = input_stack::get(0);
if (c == EOF)
break;
if (c == ESCAPE_LEFT_BRACE)
@@ -4492,7 +4986,7 @@ static void skip_alternative()
else if (c == ESCAPE_RIGHT_BRACE)
--level;
else if (c == escape_char && escape_char > 0)
- switch(input_stack::get(NULL)) {
+ switch(input_stack::get(0)) {
case '{':
++level;
break;
@@ -4500,7 +4994,7 @@ static void skip_alternative()
--level;
break;
case '"':
- while ((c = input_stack::get(NULL)) != '\n' && c != EOF)
+ while ((c = input_stack::get(0)) != '\n' && c != EOF)
;
}
/*
@@ -4574,6 +5068,16 @@ int do_if_request()
? request_dictionary.lookup(nm) != 0
: number_reg_dictionary.lookup(nm) != 0);
}
+ else if (c == 'm') {
+ tok.next();
+ symbol nm = get_long_name(1);
+ if (nm.is_null()) {
+ skip_alternative();
+ return 0;
+ }
+ result = (nm == default_symbol
+ || color_dictionary.lookup(nm) != 0);
+ }
else if (c == 'c') {
tok.next();
tok.skip();
@@ -4660,65 +5164,6 @@ void else_request()
}
}
-/*
- * begin - if this is the outermost html_begin request then execute the
- * rest of the line, else skip line
- */
-
-void begin()
-{
- begin_level++;
- if (begin_level == 1)
- begin_alternative();
- else
- skip_alternative();
-}
-
-/*
- * end - if this is the outermost html_end request then execute the
- * rest of the line, else skip line
- */
-
-void end()
-{
- begin_level--;
- if (begin_level == 0)
- begin_alternative();
- else
- skip_alternative();
- if (begin_level < 0)
- begin_level = 0;
-}
-
-/*
- * image - implements the directive `.image {l|r|c|i} filename'
- * which places the filename into a node which is later
- * written out
- *
- * . either as a special in the form of an image tag for -Thtml
- * . or as an image region definition for all other devices
- *
- */
-
-void image()
-{
- if (has_arg()) {
- char position = tok.ch();
- if (!(position == 'l'
- || position == 'r'
- || position == 'c'
- || position == 'i')) {
- error("l, r, c, or i expected (got %1)", tok.description());
- position = 'c';
- }
- tok.next();
- symbol filename = get_long_name(1);
- if (!filename.is_null())
- curenv->add_node(new suppress_node(filename, position));
- }
- skip_line();
-}
-
static int while_depth = 0;
static int while_break_flag = 0;
@@ -4766,7 +5211,7 @@ void while_request()
input_stack::push(new string_iterator(mac, "while loop"));
tok.next();
if (!do_if_request()) {
- while (input_stack::get(NULL) != EOF)
+ while (input_stack::get(0) != EOF)
;
break;
}
@@ -4790,7 +5235,7 @@ void while_break_request()
}
else {
while_break_flag = 1;
- while (input_stack::get(NULL) != EOF)
+ while (input_stack::get(0) != EOF)
;
tok.next();
}
@@ -4803,7 +5248,7 @@ void while_continue_request()
skip_line();
}
else {
- while (input_stack::get(NULL) != EOF)
+ while (input_stack::get(0) != EOF)
;
tok.next();
}
@@ -4846,12 +5291,12 @@ void pipe_source()
error("missing command");
else {
int c;
- while ((c = get_copy(NULL)) == ' ' || c == '\t')
+ while ((c = get_copy(0)) == ' ' || c == '\t')
;
int buf_size = 24;
char *buf = new char[buf_size];
int buf_used = 0;
- for (; c != '\n' && c != EOF; c = get_copy(NULL)) {
+ for (; c != '\n' && c != EOF; c = get_copy(0)) {
const char *s = asciify(c);
int slen = strlen(s);
if (buf_used + slen + 1> buf_size) {
@@ -4938,7 +5383,7 @@ int ps_get_line(char *buf, FILE *fp, const char* filename)
int err = 0;
while (c != '\r' && c != '\n' && c != EOF) {
if ((c < 0x1b && !white_space(c)) || c == 0x7f)
- error("illegal input character code %1 in `%2'", int(c), filename);
+ error("invalid input character code %1 in `%2'", int(c), filename);
else if (i < PS_LINE_MAX)
buf[i++] = c;
else if (!err) {
@@ -4991,14 +5436,15 @@ void do_ps_file(FILE *fp, const char* filename)
if (res == 1) {
assign_registers(bb.llx, bb.lly, bb.urx, bb.ury);
return;
- } else if (res == 2) {
+ }
+ else if (res == 2) {
bb_at_end = 1;
break;
}
else {
error("the arguments to the %%%%BoundingBox comment in `%1' are bad",
filename);
- return;
+ return;
}
}
}
@@ -5132,8 +5578,12 @@ const char *asciify(int c)
case ESCAPE_COLON:
buf[1] = ':';
break;
+ case COMPATIBLE_SAVE:
+ case COMPATIBLE_RESTORE:
+ buf[0] = '\0';
+ break;
default:
- if (illegal_input_char(c))
+ if (invalid_input_char(c))
buf[0] = '\0';
else
buf[0] = c;
@@ -5159,7 +5609,7 @@ const char *input_char_description(int c)
return "a node";
}
static char buf[sizeof("magic character code ") + 1 + INT_DIGITS];
- if (illegal_input_char(c)) {
+ if (invalid_input_char(c)) {
const char *s = asciify(c);
if (*s) {
buf[0] = '`';
@@ -5187,15 +5637,15 @@ void do_terminal(int newline, int string_like)
if (!tok.newline() && !tok.eof()) {
int c;
for (;;) {
- c = get_copy(NULL);
+ c = get_copy(0);
if (string_like && c == '"') {
- c = get_copy(NULL);
+ c = get_copy(0);
break;
}
if (c != ' ' && c != '\t')
break;
}
- for (; c != '\n' && c != EOF; c = get_copy(NULL))
+ for (; c != '\n' && c != EOF; c = get_copy(0))
fputs(asciify(c), stderr);
}
if (newline)
@@ -5278,7 +5728,9 @@ void close_request()
skip_line();
}
-void write_request()
+// .write and .writec
+
+void do_write_request(int newline)
{
symbol stream = get_name(1);
if (stream.is_null()) {
@@ -5292,17 +5744,28 @@ void write_request()
return;
}
int c;
- while ((c = get_copy(NULL)) == ' ')
+ while ((c = get_copy(0)) == ' ')
;
if (c == '"')
- c = get_copy(NULL);
- for (; c != '\n' && c != EOF; c = get_copy(NULL))
+ c = get_copy(0);
+ for (; c != '\n' && c != EOF; c = get_copy(0))
fputs(asciify(c), fp);
- fputc('\n', fp);
+ if (newline)
+ fputc('\n', fp);
fflush(fp);
tok.next();
}
+void write_request()
+{
+ do_write_request(1);
+}
+
+void write_request_continue()
+{
+ do_write_request(0);
+}
+
void write_macro_request()
{
symbol stream = get_name(1);
@@ -5338,6 +5801,47 @@ void write_macro_request()
skip_line();
}
+void warnscale_request()
+{
+ if (has_arg()) {
+ char c = tok.ch();
+ if (c == 'u')
+ warn_scale = 1.0;
+ else if (c == 'i')
+ warn_scale = (double)units_per_inch;
+ else if (c == 'c')
+ warn_scale = (double)units_per_inch / 2.54;
+ else if (c == 'p')
+ warn_scale = (double)units_per_inch / 72.0;
+ else if (c == 'P')
+ warn_scale = (double)units_per_inch / 6.0;
+ else {
+ warning(WARN_SCALE,
+ "invalid scaling indicator `%1', using `i' instead", c);
+ c = 'i';
+ }
+ warn_scaling_indicator = c;
+ }
+ skip_line();
+}
+
+void spreadwarn_request()
+{
+ hunits n;
+ if (has_arg() && get_hunits(&n, 'm')) {
+ if (n < 0)
+ n = 0;
+ hunits em = curenv->get_size();
+ spread_limit = (double)n.to_units()
+ / (em.is_zero() ? hresolution : em.to_units());
+ }
+ else
+ spread_limit = -spread_limit - 1; // no arg toggles on/off without
+ // changing value; we mirror at
+ // -0.5 to make zero a valid value
+ skip_line();
+}
+
static void init_charset_table()
{
char buf[16];
@@ -5369,7 +5873,13 @@ static void init_charset_table()
page_character = charset_table['%'];
}
-static void do_translate(int translate_transparent)
+static void init_hpf_code_table()
+{
+ for (int i = 0; i < 256; i++)
+ hpf_code_table[i] = i;
+}
+
+static void do_translate(int translate_transparent, int translate_input)
{
tok.skip();
while (!tok.newline() && !tok.eof()) {
@@ -5408,9 +5918,9 @@ static void do_translate(int translate_transparent)
if (ci2 == 0)
break;
if (ci1 == ci2)
- ci1->set_translation(0, translate_transparent);
+ ci1->set_translation(0, translate_transparent, translate_input);
else
- ci1->set_translation(ci2, translate_transparent);
+ ci1->set_translation(ci2, translate_transparent, translate_input);
}
tok.next();
}
@@ -5419,12 +5929,17 @@ static void do_translate(int translate_transparent)
void translate()
{
- do_translate(1);
+ do_translate(1, 0);
}
void translate_no_transparent()
{
- do_translate(0);
+ do_translate(0, 0);
+}
+
+void translate_input()
+{
+ do_translate(1, 1);
}
void char_flags()
@@ -5463,12 +5978,42 @@ void hyphenation_code()
break;
}
ci->set_hyphenation_code(c);
+ if (ci->get_translation()
+ && ci->get_translation()->get_translation_input())
+ ci->get_translation()->set_hyphenation_code(c);
tok.next();
tok.skip();
}
skip_line();
}
+void hyphenation_patterns_file_code()
+{
+ tok.skip();
+ while (!tok.newline() && !tok.eof()) {
+ int n1, n2;
+ if (get_integer(&n1) && (0 <= n1 && n1 <= 255)) {
+ if (!has_arg()) {
+ error("missing output hyphenation code");
+ break;
+ }
+ if (get_integer(&n2) && (0 <= n2 && n2 <= 255)) {
+ hpf_code_table[n1] = n2;
+ tok.skip();
+ }
+ else {
+ error("output hyphenation code must be integer in the range 0..255");
+ break;
+ }
+ }
+ else {
+ error("input hyphenation code must be integer in the range 0..255");
+ break;
+ }
+ }
+ skip_line();
+}
+
charinfo *token::get_char(int required)
{
if (type == TOKEN_CHAR)
@@ -5553,17 +6098,28 @@ int token::add_to_node_list(node **pp)
case TOKEN_RIGHT_BRACE:
break;
case TOKEN_SPACE:
- n = new hmotion_node(curenv->get_space_width());
+ n = new hmotion_node(curenv->get_space_width(),
+ curenv->get_fill_color());
break;
case TOKEN_SPECIAL:
*pp = (*pp)->add_char(get_charinfo(nm), curenv, &w, &s);
break;
case TOKEN_STRETCHABLE_SPACE:
- n = new unbreakable_space_node(curenv->get_space_width());
+ n = new unbreakable_space_node(curenv->get_space_width(),
+ curenv->get_fill_color());
+ break;
+ case TOKEN_UNSTRETCHABLE_SPACE:
+ n = new space_char_hmotion_node(curenv->get_space_width(),
+ curenv->get_fill_color());
break;
case TOKEN_TRANSPARENT_DUMMY:
n = new transparent_dummy_node;
break;
+ case TOKEN_ZERO_WIDTH_BREAK:
+ n = new space_node(H0, curenv->get_fill_color());
+ n->freeze_space();
+ n->is_escape_colon();
+ break;
default:
return 0;
}
@@ -5580,7 +6136,8 @@ void token::process()
return;
switch (type) {
case TOKEN_BACKSPACE:
- curenv->add_node(new hmotion_node(-curenv->get_space_width()));
+ curenv->add_node(new hmotion_node(-curenv->get_space_width(),
+ curenv->get_fill_color()));
break;
case TOKEN_CHAR:
curenv->add_char(charset_table[c]);
@@ -5631,7 +6188,7 @@ void token::process()
curenv->add_char(get_charinfo_by_number(val));
break;
case TOKEN_REQUEST:
- // handled in process_input_stack
+ // handled in process_input_stack()
break;
case TOKEN_RIGHT_BRACE:
break;
@@ -5645,7 +6202,12 @@ void token::process()
curenv->spread();
break;
case TOKEN_STRETCHABLE_SPACE:
- curenv->add_node(new unbreakable_space_node(curenv->get_space_width()));
+ curenv->add_node(new unbreakable_space_node(curenv->get_space_width(),
+ curenv->get_fill_color()));
+ break;
+ case TOKEN_UNSTRETCHABLE_SPACE:
+ curenv->add_node(new space_char_hmotion_node(curenv->get_space_width(),
+ curenv->get_fill_color()));
break;
case TOKEN_TAB:
curenv->handle_tab(0);
@@ -5655,6 +6217,14 @@ void token::process()
case TOKEN_TRANSPARENT_DUMMY:
curenv->add_node(new transparent_dummy_node);
break;
+ case TOKEN_ZERO_WIDTH_BREAK:
+ {
+ node *tmp = new space_node(H0, curenv->get_fill_color());
+ tmp->freeze_space();
+ tmp->is_escape_colon();
+ curenv->add_node(tmp);
+ break;
+ }
default:
assert(0);
}
@@ -5764,7 +6334,7 @@ void abort_request()
if (c == EOF || c == '\n')
fputs("User Abort.", stderr);
else {
- for (; c != '\n' && c != EOF; c = get_copy(NULL))
+ for (; c != '\n' && c != EOF; c = get_copy(0))
fputs(asciify(c), stderr);
}
fputc('\n', stderr);
@@ -5780,7 +6350,7 @@ char *read_string()
;
int i = 0;
while (c != '\n' && c != EOF) {
- if (!illegal_input_char(c)) {
+ if (!invalid_input_char(c)) {
if (i + 2 > len) {
char *tem = s;
s = new char[len*2];
@@ -5817,8 +6387,20 @@ void pipe_output()
skip_line();
}
else {
- if ((pipe_command = read_string()) == 0)
+ char *pc;
+ if ((pc = read_string()) == 0)
error("can't pipe to empty command");
+ if (pipe_command) {
+ char *s = new char[strlen(pipe_command) + strlen(pc) + 1 + 1];
+ strcpy(s, pipe_command);
+ strcat(s, "|");
+ strcat(s, pc);
+ a_delete pipe_command;
+ a_delete pc;
+ pipe_command = s;
+ }
+ else
+ pipe_command = pc;
}
#endif /* not POPEN_MISSING */
}
@@ -5897,8 +6479,8 @@ void transparent_file()
int c = getc(fp);
if (c == EOF)
break;
- if (illegal_input_char(c))
- warning(WARN_INPUT, "illegal input character code %1", int(c));
+ if (invalid_input_char(c))
+ warning(WARN_INPUT, "invalid input character code %1", int(c));
else {
curdiv->transparent_output(c);
bol = c == '\n';
@@ -6098,7 +6680,7 @@ static int evaluate_expression(const char *expr, units *res)
input_stack::push(make_temp_iterator(expr));
tok.next();
int success = get_number(res, 'u');
- while (input_stack::get(NULL) != EOF)
+ while (input_stack::get(0) != EOF)
;
return success;
}
@@ -6129,7 +6711,7 @@ static void set_string(const char *name, const char *value)
{
macro *m = new macro;
for (const char *p = value; *p; p++)
- if (!illegal_input_char((unsigned char)*p))
+ if (!invalid_input_char((unsigned char)*p))
m->append(*p);
request_dictionary.define(name, m);
}
@@ -6177,7 +6759,7 @@ static void add_string(const char *s, string_list **p)
void usage(FILE *stream, const char *prog)
{
fprintf(stream,
-"usage: %s -abivzCERU -wname -Wname -dcs -ffam -mname -nnum -olist\n"
+"usage: %s -abcivzCERU -wname -Wname -dcs -ffam -mname -nnum -olist\n"
" -rcn -Tname -Fdir -Mdir [files...]\n",
prog);
}
@@ -6213,10 +6795,10 @@ int main(int argc, char **argv)
static const struct option long_options[] = {
{ "help", no_argument, 0, CHAR_MAX + 1 },
{ "version", no_argument, 0, 'v' },
- { NULL, 0, 0, 0 }
+ { 0, 0, 0, 0 }
};
- while ((c = getopt_long(argc, argv, "abivw:W:zCEf:m:n:o:r:d:F:M:T:tqs:RU",
- long_options, NULL))
+ while ((c = getopt_long(argc, argv, "abcivw:W:zCEf:m:n:o:r:d:F:M:T:tqs:RU",
+ long_options, 0))
!= EOF)
switch(c) {
case 'v':
@@ -6232,6 +6814,9 @@ int main(int argc, char **argv)
break;
case 'C':
compatible_flag = 1;
+ // fall through
+ case 'c':
+ color_flag = 0;
break;
case 'M':
macro_path.command_line_dir(optarg);
@@ -6316,6 +6901,7 @@ int main(int argc, char **argv)
mac_path = &macro_path;
set_string(".T", device);
init_charset_table();
+ init_hpf_code_table();
if (!font::load_desc())
fatal("sorry, I can't continue");
units_per_inch = font::res;
@@ -6323,6 +6909,8 @@ int main(int argc, char **argv)
vresolution = font::vert;
sizescale = font::sizescale;
tcommand_flag = font::tcommand;
+ warn_scale = (double)units_per_inch;
+ warn_scaling_indicator = 'i';
if (!fflag && font::family != 0 && *font::family != '\0')
default_family = symbol(font::family);
font_size::init_size_table(font::sizes);
@@ -6347,7 +6935,6 @@ int main(int argc, char **argv)
init_column_requests();
#endif /* COLUMN */
init_node_requests();
- init_markup_requests();
number_reg_dictionary.define(".T", new constant_reg(tflag ? "1" : "0"));
init_registers();
init_reg_requests();
@@ -6408,6 +6995,9 @@ static void init_registers()
t = time(0);
// Use struct here to work around misfeature in old versions of g++.
struct tm *tt = localtime(&t);
+ set_number_reg("seconds", int(tt->tm_sec));
+ set_number_reg("minutes", int(tt->tm_min));
+ set_number_reg("hours", int(tt->tm_hour));
set_number_reg("dw", int(tt->tm_wday + 1));
set_number_reg("dy", int(tt->tm_mday));
set_number_reg("mo", int(tt->tm_mon + 1));
@@ -6458,120 +7048,126 @@ void get_output_registers(int *minx, int *miny, int *maxx, int *maxy)
*maxy = output_reg_maxy_contents;
}
-void init_markup_requests()
-{
- init_request("begin", begin);
- init_request("end", end);
- init_request("image", image);
-}
-
void init_input_requests()
{
- init_request("ds", define_string);
+ init_request("ab", abort_request);
+ init_request("als", alias_macro);
+ init_request("am", append_macro);
+ init_request("am1", append_nocomp_macro);
+ init_request("ami", append_indirect_macro);
init_request("as", append_string);
+ init_request("as1", append_nocomp_string);
+ init_request("asciify", asciify_macro);
+ init_request("backtrace", backtrace_request);
+ init_request("blm", blank_line_macro);
+ init_request("break", while_break_request);
+ init_request("cf", copy_file);
+ init_request("cflags", char_flags);
+ init_request("char", define_character);
+ init_request("chop", chop_macro);
+ init_request("close", close_request);
+ init_request("color", activate_color);
+ init_request("continue", while_continue_request);
+ init_request("cp", compatible);
init_request("de", define_macro);
- init_request("dei", define_indirect_macro);
init_request("de1", define_nocomp_macro);
- init_request("am", append_macro);
- init_request("am1", append_nocomp_macro);
+ init_request("defcolor", define_color);
+ init_request("dei", define_indirect_macro);
+ init_request("do", do_request);
+ init_request("ds", define_string);
+ init_request("ds1", define_nocomp_string);
+ init_request("ec", set_escape_char);
+ init_request("ecr", restore_escape_char);
+ init_request("ecs", save_escape_char);
+ init_request("el", else_request);
+ init_request("em", end_macro);
+ init_request("eo", escape_off);
+ init_request("ex", exit_request);
+ init_request("fchar", define_fallback_character);
+#ifdef WIDOW_CONTROL
+ init_request("fpl", flush_pending_lines);
+#endif /* WIDOW_CONTROL */
+ init_request("hcode", hyphenation_code);
+ init_request("hpfcode", hyphenation_patterns_file_code);
+ init_request("ie", if_else_request);
+ init_request("if", if_request);
init_request("ig", ignore);
- init_request("rm", remove_macro);
- init_request("rn", rename_macro);
+ init_request("length", length_request);
+ init_request("lf", line_file);
+ init_request("mso", macro_source);
init_request("nop", nop_request);
- init_request("if", if_request);
- init_request("ie", if_else_request);
- init_request("el", else_request);
- init_request("so", source);
init_request("nx", next_file);
- init_request("pm", print_macros);
- init_request("eo", escape_off);
- init_request("ec", set_escape_char);
- init_request("ecs", save_escape_char);
- init_request("ecr", restore_escape_char);
+ init_request("open", open_request);
+ init_request("opena", opena_request);
+ init_request("output", output_request);
init_request("pc", set_page_character);
+ init_request("pi", pipe_output);
+ init_request("pm", print_macros);
+ init_request("psbb", ps_bbox_request);
+#ifndef POPEN_MISSING
+ init_request("pso", pipe_source);
+#endif /* not POPEN_MISSING */
+ init_request("rchar", remove_character);
+ init_request("rd", read_request);
+ init_request("return", return_macro_request);
+ init_request("rm", remove_macro);
+ init_request("rn", rename_macro);
+ init_request("shift", shift);
+ init_request("so", source);
+ init_request("spreadwarn", spreadwarn_request);
+ init_request("substring", substring_request);
+ init_request("sy", system_request);
init_request("tm", terminal);
init_request("tm1", terminal1);
init_request("tmc", terminal_continue);
- init_request("ex", exit_request);
- init_request("return", return_macro_request);
- init_request("em", end_macro);
- init_request("blm", blank_line_macro);
init_request("tr", translate);
+ init_request("trf", transparent_file);
+ init_request("trin", translate_input);
init_request("trnt", translate_no_transparent);
- init_request("ab", abort_request);
- init_request("pi", pipe_output);
- init_request("cf", copy_file);
- init_request("sy", system_request);
- init_request("lf", line_file);
- init_request("cflags", char_flags);
- init_request("shift", shift);
- init_request("rd", read_request);
- init_request("cp", compatible);
- init_request("char", define_character);
- init_request("rchar", remove_character);
- init_request("hcode", hyphenation_code);
- init_request("while", while_request);
- init_request("break", while_break_request);
- init_request("continue", while_continue_request);
- init_request("als", alias_macro);
- init_request("backtrace", backtrace_request);
- init_request("chop", chop_macro);
- init_request("substring", substring_macro);
- init_request("length", length_macro);
- init_request("asciify", asciify_macro);
init_request("unformat", unformat_macro);
init_request("warn", warn_request);
- init_request("open", open_request);
- init_request("opena", opena_request);
- init_request("close", close_request);
+ init_request("while", while_request);
init_request("write", write_request);
+ init_request("writec", write_request_continue);
init_request("writem", write_macro_request);
- init_request("trf", transparent_file);
-#ifdef WIDOW_CONTROL
- init_request("fpl", flush_pending_lines);
-#endif /* WIDOW_CONTROL */
init_request("nroff", nroff_request);
init_request("troff", troff_request);
#ifdef COLUMN
init_request("vj", vjustify);
#endif /* COLUMN */
- init_request("mso", macro_source);
- init_request("do", do_request);
-#ifndef POPEN_MISSING
- init_request("pso", pipe_source);
-#endif /* not POPEN_MISSING */
- init_request("psbb", ps_bbox_request);
- number_reg_dictionary.define("systat", new variable_reg(&system_status));
- number_reg_dictionary.define("slimit",
- new variable_reg(&input_stack::limit));
+ init_request("warnscale", warnscale_request);
number_reg_dictionary.define(".$", new nargs_reg);
- number_reg_dictionary.define(".c", new lineno_reg);
- number_reg_dictionary.define("c.", new writable_lineno_reg);
- number_reg_dictionary.define(".F", new filename_reg);
number_reg_dictionary.define(".C", new constant_int_reg(&compatible_flag));
+ number_reg_dictionary.define(".F", new filename_reg);
number_reg_dictionary.define(".H", new constant_int_reg(&hresolution));
- number_reg_dictionary.define(".V", new constant_int_reg(&vresolution));
number_reg_dictionary.define(".R", new constant_reg("10000"));
- extern const char *major_version;
- number_reg_dictionary.define(".x", new constant_reg(major_version));
- extern const char *minor_version;
- number_reg_dictionary.define(".y", new constant_reg(minor_version));
+ number_reg_dictionary.define(".V", new constant_int_reg(&vresolution));
extern const char *revision;
number_reg_dictionary.define(".Y", new constant_reg(revision));
+ number_reg_dictionary.define(".c", new lineno_reg);
number_reg_dictionary.define(".g", new constant_reg("1"));
+ number_reg_dictionary.define(".color", new constant_int_reg(&color_flag));
number_reg_dictionary.define(".warn", new constant_int_reg(&warning_mask));
+ extern const char *major_version;
+ number_reg_dictionary.define(".x", new constant_reg(major_version));
+ extern const char *minor_version;
+ number_reg_dictionary.define(".y", new constant_reg(minor_version));
+ number_reg_dictionary.define("c.", new writable_lineno_reg);
number_reg_dictionary.define("llx", new variable_reg(&llx_reg_contents));
number_reg_dictionary.define("lly", new variable_reg(&lly_reg_contents));
- number_reg_dictionary.define("urx", new variable_reg(&urx_reg_contents));
- number_reg_dictionary.define("ury", new variable_reg(&ury_reg_contents));
- number_reg_dictionary.define("opminx",
- new variable_reg(&output_reg_minx_contents));
- number_reg_dictionary.define("opminy",
- new variable_reg(&output_reg_miny_contents));
number_reg_dictionary.define("opmaxx",
new variable_reg(&output_reg_maxx_contents));
number_reg_dictionary.define("opmaxy",
new variable_reg(&output_reg_maxy_contents));
+ number_reg_dictionary.define("opminx",
+ new variable_reg(&output_reg_minx_contents));
+ number_reg_dictionary.define("opminy",
+ new variable_reg(&output_reg_miny_contents));
+ number_reg_dictionary.define("slimit",
+ new variable_reg(&input_stack::limit));
+ number_reg_dictionary.define("systat", new variable_reg(&system_status));
+ number_reg_dictionary.define("urx", new variable_reg(&urx_reg_contents));
+ number_reg_dictionary.define("ury", new variable_reg(&ury_reg_contents));
}
object_dictionary request_dictionary(501);
@@ -6718,12 +7314,20 @@ static node *read_draw_node()
if (no_last_v)
error("even number of arguments needed for spline");
break;
+ case 'f':
+ if (npoints != 1 || !no_last_v) {
+ error("one argument needed for gray shade");
+ npoints = 1;
+ point[0].v = V0;
+ }
default:
// silently pass it through
break;
}
draw_node *dn = new draw_node(type, point, npoints,
- curenv->get_font_size());
+ curenv->get_font_size(),
+ curenv->get_glyph_color(),
+ curenv->get_fill_color());
a_delete point;
return dn;
}
@@ -6758,6 +7362,7 @@ static struct {
{ "mac", WARN_MAC },
{ "reg", WARN_REG },
{ "ig", WARN_IG },
+ { "color", WARN_COLOR },
{ "all", WARN_TOTAL & ~(WARN_DI | WARN_MAC | WARN_REG) },
{ "w", WARN_TOTAL },
{ "default", DEFAULT_WARNING_MASK },
@@ -6808,7 +7413,7 @@ static void copy_mode_error(const char *format,
error(format, arg1, arg2, arg3);
}
-enum error_type { WARNING, ERROR, FATAL };
+enum error_type { WARNING, OUTPUT_WARNING, ERROR, FATAL };
static void do_error(error_type type,
const char *format,
@@ -6837,6 +7442,18 @@ static void do_error(error_type type,
case WARNING:
fputs("warning: ", stderr);
break;
+ case OUTPUT_WARNING:
+ double fromtop = topdiv->get_vertical_position().to_units() / warn_scale;
+ fprintf(stderr, "warning [p %d, %.1f%c",
+ topdiv->get_page_number(), fromtop, warn_scaling_indicator);
+ if (topdiv != curdiv) {
+ double fromtop1 = curdiv->get_vertical_position().to_units()
+ / warn_scale;
+ fprintf(stderr, ", div `%s', %.1f%c",
+ curdiv->get_diversion_name(), fromtop1, warn_scaling_indicator);
+ }
+ fprintf(stderr, "]: ");
+ break;
}
errprint(format, arg1, arg2, arg3);
fputc('\n', stderr);
@@ -6859,6 +7476,20 @@ int warning(warning_type t,
return 0;
}
+int output_warning(warning_type t,
+ const char *format,
+ const errarg &arg1,
+ const errarg &arg2,
+ const errarg &arg3)
+{
+ if ((t & warning_mask) != 0) {
+ do_error(OUTPUT_WARNING, format, arg1, arg2, arg3);
+ return 1;
+ }
+ else
+ return 0;
+}
+
void error(const char *format,
const errarg &arg1,
const errarg &arg2,
@@ -6916,8 +7547,9 @@ int charinfo::next_index = 0;
charinfo::charinfo(symbol s)
: translation(0), mac(0), special_translation(TRANSLATE_NONE),
- hyphenation_code(0), flags(0), ascii_code(0), not_found(0),
- transparent_translate(1), nm(s)
+ hyphenation_code(0), flags(0), ascii_code(0), asciify_code(0),
+ not_found(0), transparent_translate(1), translate_input(0),
+ fallback(0), nm(s)
{
index = next_index++;
}
@@ -6927,9 +7559,18 @@ void charinfo::set_hyphenation_code(unsigned char c)
hyphenation_code = c;
}
-void charinfo::set_translation(charinfo *ci, int tt)
+void charinfo::set_translation(charinfo *ci, int tt, int ti)
{
translation = ci;
+ if (ci && ti) {
+ if (hyphenation_code != 0)
+ ci->set_hyphenation_code(hyphenation_code);
+ if (asciify_code != 0)
+ ci->set_asciify_code(asciify_code);
+ else if (ascii_code != 0)
+ ci->set_asciify_code(ascii_code);
+ ci->set_translation_input();
+ }
special_translation = TRANSLATE_NONE;
transparent_translate = tt;
}
@@ -6946,10 +7587,16 @@ void charinfo::set_ascii_code(unsigned char c)
ascii_code = c;
}
-macro *charinfo::set_macro(macro *m)
+void charinfo::set_asciify_code(unsigned char c)
+{
+ asciify_code = c;
+}
+
+macro *charinfo::set_macro(macro *m, int f)
{
macro *tem = mac;
mac = m;
+ fallback = f;
return tem;
}
diff --git a/contrib/groff/src/roff/troff/node.cc b/contrib/groff/src/roff/troff/node.cc
index 2d2d799..650bf0e 100644
--- a/contrib/groff/src/roff/troff/node.cc
+++ b/contrib/groff/src/roff/troff/node.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
@@ -19,11 +19,12 @@ You should have received a copy of the GNU General Public License along
with groff; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+#include "troff.h"
+
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#include "troff.h"
#include "symbol.h"
#include "dictionary.h"
#include "hvunits.h"
@@ -35,6 +36,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "font.h"
#include "reg.h"
#include "input.h"
+#include "div.h"
+#include "geometry.h"
#include "nonposix.h"
@@ -60,8 +63,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
* debugging grohtml
*/
-static int image_no=0;
-static int suppress_start_page=0;
+int image_no = 0;
+static int suppress_start_page = 0;
#define STORE_WIDTH 1
@@ -147,6 +150,7 @@ public:
int get_bold(hunits *);
int is_special();
int is_style();
+ friend symbol get_font_name(int, environment *);
};
class tfont_spec {
@@ -234,6 +238,14 @@ inline int font_info::is_style()
return fm == 0;
}
+tfont *make_tfont(tfont_spec &spec)
+{
+ for (tfont *p = tfont::tfont_list; p; p = p->next)
+ if (*p == spec)
+ return p;
+ return new tfont(spec);
+}
+
// this is the current_font, fontno is where we found the character,
// presumably a special font
@@ -378,6 +390,15 @@ symbol font_info::get_name()
return internal_name;
}
+symbol get_font_name(int fontno, environment *env)
+{
+ symbol f = font_table[fontno]->get_name();
+ if (font_table[fontno]->is_style()) {
+ return concat(env->get_family()->nm, f);
+ }
+ return f;
+}
+
hunits font_info::get_space_width(font_size fs, int space_size)
{
if (is_constant_spaced == CONSTANT_SPACE_NONE)
@@ -626,14 +647,6 @@ inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res)
}
}
-tfont *make_tfont(tfont_spec &spec)
-{
- for (tfont *p = tfont::tfont_list; p; p = p->next)
- if (*p == spec)
- return p;
- return new tfont(spec);
-}
-
tfont *tfont::tfont_list = 0;
tfont::tfont(tfont_spec &spec) : tfont_spec(spec)
@@ -658,7 +671,7 @@ class real_output_file : public output_file {
int piped;
#endif
int printing; // decision via optional page list
- int output_on; // .output 1 or .output 0 requests
+ int output_on; // \O[0] or \O[1] escape calls
virtual void really_transparent_char(unsigned char) = 0;
virtual void really_print_line(hunits x, vunits y, node *n,
vunits before, vunits after, hunits width) = 0;
@@ -727,6 +740,8 @@ class troff_output_file : public real_output_file {
int current_slant;
int current_height;
tfont *current_tfont;
+ color *current_fill_color;
+ color *current_glyph_color;
int current_font_number;
symbol *font_position;
int nfont_positions;
@@ -739,6 +754,7 @@ class troff_output_file : public real_output_file {
void put(char c);
void put(unsigned char c);
void put(int i);
+ void put(unsigned int i);
void put(const char *s);
void set_font(tfont *tf);
void flush_tbuf();
@@ -746,13 +762,13 @@ public:
troff_output_file();
~troff_output_file();
void trailer(vunits page_length);
- void put_char(charinfo *ci, tfont *tf);
- void put_char_width(charinfo *ci, tfont *tf, hunits w, hunits k);
+ void put_char(charinfo *, tfont *, color *, color *);
+ void put_char_width(charinfo *, tfont *, color *, color *, hunits, hunits);
void right(hunits);
void down(vunits);
void moveto(hunits, vunits);
- void start_special(tfont *tf, int no_init_string = 0);
- void start_special(int no_init_string = 0);
+ void start_special(tfont *, color *, color *, int = 0);
+ void start_special();
void special_char(unsigned char c);
void end_special();
void word_marker();
@@ -763,9 +779,11 @@ public:
void really_put_filename(const char *filename);
void really_on();
void really_off();
- void draw(char, hvpair *, int, font_size);
+ void draw(char, hvpair *, int, font_size, color *, color *);
void determine_line_limits (char code, hvpair *point, int npoints);
void check_charinfo(tfont *tf, charinfo *ci);
+ void glyph_color(color *c);
+ void fill_color(color *c);
int get_hpos() { return hpos; }
int get_vpos() { return vpos; }
};
@@ -796,29 +814,29 @@ inline void troff_output_file::put(int i)
put_string(i_to_a(i), fp);
}
-void troff_output_file::start_special(tfont *tf, int no_init_string)
+inline void troff_output_file::put(unsigned int i)
{
- flush_tbuf();
+ put_string(ui_to_a(i), fp);
+}
- /*
- * although this is extremely unlikely to have an effect on other devices
- * this way is safer. Currently this is only needed for html.
- */
- if (is_html && tf) {
- if (tf != current_tfont)
- set_font(tf);
- }
+void troff_output_file::start_special(tfont *tf, color *gcol, color *fcol,
+ int no_init_string)
+{
+ flush_tbuf();
do_motion();
+ if (tf != current_tfont)
+ set_font(tf);
+ glyph_color(gcol);
+ fill_color(fcol);
if (!no_init_string)
put("x X ");
}
-void troff_output_file::start_special(int no_init_string)
+void troff_output_file::start_special()
{
flush_tbuf();
do_motion();
- if (!no_init_string)
- put("x X ");
+ put("x X ");
}
void troff_output_file::special_char(unsigned char c)
@@ -844,8 +862,7 @@ void troff_output_file::really_print_line(hunits x, vunits y, node *n,
{
moveto(x, y);
while (n != 0) {
- if (is_on() || (n->force_tprint()))
- n->tprint(this);
+ n->tprint(this);
n = n->next;
}
flush_tbuf();
@@ -864,7 +881,8 @@ void troff_output_file::really_print_line(hunits x, vunits y, node *n,
inline void troff_output_file::word_marker()
{
flush_tbuf();
- put('w');
+ if (is_on())
+ put('w');
}
inline void troff_output_file::right(hunits n)
@@ -920,6 +938,11 @@ void troff_output_file::do_motion()
void troff_output_file::flush_tbuf()
{
+ if (!is_on()) {
+ tbuf_len = 0;
+ return;
+ }
+
if (tbuf_len == 0)
return;
if (tbuf_kern == 0)
@@ -930,7 +953,7 @@ void troff_output_file::flush_tbuf()
put(' ');
}
check_output_limits(hpos, vpos);
- check_output_limits(hpos, vpos + current_size + current_height);
+ check_output_limits(hpos, vpos - current_size);
for (int i = 0; i < tbuf_len; i++)
put(tbuf[i]);
@@ -940,29 +963,37 @@ void troff_output_file::flush_tbuf()
void troff_output_file::check_charinfo(tfont *tf, charinfo *ci)
{
- int size = tf->get_size().to_scaled_points();
+ if (!is_on())
+ return;
+
int height = tf->get_char_height(ci).to_units();
int width = tf->get_width(ci).to_units()
+ tf->get_italic_correction(ci).to_units();
int depth = tf->get_char_depth(ci).to_units();
- check_output_limits(output_hpos,
- output_vpos - height);
- check_output_limits(output_hpos + width,
- output_vpos + size + depth);
+ check_output_limits(output_hpos, output_vpos - height);
+ check_output_limits(output_hpos + width, output_vpos + depth);
}
-void troff_output_file::put_char_width(charinfo *ci, tfont *tf, hunits w,
- hunits k)
+void troff_output_file::put_char_width(charinfo *ci, tfont *tf,
+ color *gcol, color *fcol,
+ hunits w, hunits k)
{
+ int kk = k.to_units();
+ if (!is_on()) {
+ flush_tbuf();
+ hpos += w.to_units() + kk;
+ return;
+ }
if (tf != current_tfont) {
flush_tbuf();
set_font(tf);
}
char c = ci->get_ascii_code();
- int kk = k.to_units();
if (c == '\0') {
flush_tbuf();
do_motion();
+ glyph_color(gcol);
+ fill_color(fcol);
check_charinfo(tf, ci);
if (ci->numbered()) {
put('N');
@@ -983,6 +1014,7 @@ void troff_output_file::put_char_width(charinfo *ci, tfont *tf, hunits w,
}
else if (tcommand_flag) {
if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos
+ && gcol == current_glyph_color && fcol == current_fill_color
&& kk == tbuf_kern
&& tbuf_len < TBUF_SIZE) {
check_charinfo(tf, ci);
@@ -993,6 +1025,8 @@ void troff_output_file::put_char_width(charinfo *ci, tfont *tf, hunits w,
}
flush_tbuf();
do_motion();
+ glyph_color(gcol);
+ fill_color(fcol);
check_charinfo(tf, ci);
tbuf[tbuf_len++] = c;
output_hpos += w.to_units() + kk;
@@ -1004,7 +1038,9 @@ void troff_output_file::put_char_width(charinfo *ci, tfont *tf, hunits w,
int n = hpos - output_hpos;
check_charinfo(tf, ci);
// check_output_limits(output_hpos, output_vpos);
- if (vpos == output_vpos && n > 0 && n < 100 && !force_motion) {
+ if (vpos == output_vpos
+ && gcol == current_glyph_color && fcol == current_fill_color
+ && n > 0 && n < 100 && !force_motion) {
put(char(n/10 + '0'));
put(char(n%10 + '0'));
put(c);
@@ -1019,14 +1055,19 @@ void troff_output_file::put_char_width(charinfo *ci, tfont *tf, hunits w,
}
}
-void troff_output_file::put_char(charinfo *ci, tfont *tf)
+void troff_output_file::put_char(charinfo *ci, tfont *tf,
+ color *gcol, color *fcol)
{
flush_tbuf();
+ if (!is_on())
+ return;
if (tf != current_tfont)
set_font(tf);
char c = ci->get_ascii_code();
if (c == '\0') {
do_motion();
+ glyph_color(gcol);
+ fill_color(fcol);
if (ci->numbered()) {
put('N');
put(ci->get_number());
@@ -1045,7 +1086,9 @@ void troff_output_file::put_char(charinfo *ci, tfont *tf)
}
else {
int n = hpos - output_hpos;
- if (vpos == output_vpos && n > 0 && n < 100) {
+ if (vpos == output_vpos
+ && gcol == current_glyph_color && fcol == current_fill_color
+ && n > 0 && n < 100) {
put(char(n/10 + '0'));
put(char(n%10 + '0'));
put(c);
@@ -1053,6 +1096,8 @@ void troff_output_file::put_char(charinfo *ci, tfont *tf)
}
else {
do_motion();
+ glyph_color(gcol);
+ fill_color(fcol);
put('c');
put(c);
}
@@ -1115,12 +1160,112 @@ void troff_output_file::set_font(tfont *tf)
current_tfont = tf;
}
+void troff_output_file::fill_color(color *col)
+{
+ if ((current_fill_color == col) || !color_flag)
+ return;
+ flush_tbuf();
+ put("DF");
+ unsigned int components[4];
+ color_scheme cs;
+ cs = col->get_components(components);
+ switch (cs) {
+ case DEFAULT:
+ put('d');
+ break;
+ case RGB:
+ put("r ");
+ put(Red);
+ put(' ');
+ put(Green);
+ put(' ');
+ put(Blue);
+ break;
+ case CMY:
+ put("c ");
+ put(Cyan);
+ put(' ');
+ put(Magenta);
+ put(' ');
+ put(Yellow);
+ break;
+ case CMYK:
+ put("k ");
+ put(Cyan);
+ put(' ');
+ put(Magenta);
+ put(' ');
+ put(Yellow);
+ put(' ');
+ put(Black);
+ break;
+ case GRAY:
+ put("g ");
+ put(Gray);
+ break;
+ }
+ put('\n');
+ current_fill_color = col;
+}
+
+void troff_output_file::glyph_color(color *col)
+{
+ if ((current_glyph_color == col) || !color_flag)
+ return;
+ flush_tbuf();
+ put("m");
+ unsigned int components[4];
+ color_scheme cs;
+ cs = col->get_components(components);
+ switch (cs) {
+ case DEFAULT:
+ put('d');
+ break;
+ case RGB:
+ put("r ");
+ put(Red);
+ put(' ');
+ put(Green);
+ put(' ');
+ put(Blue);
+ break;
+ case CMY:
+ put("c ");
+ put(Cyan);
+ put(' ');
+ put(Magenta);
+ put(' ');
+ put(Yellow);
+ break;
+ case CMYK:
+ put("k ");
+ put(Cyan);
+ put(' ');
+ put(Magenta);
+ put(' ');
+ put(Yellow);
+ put(' ');
+ put(Black);
+ break;
+ case GRAY:
+ put("g ");
+ put(Gray);
+ break;
+ }
+ put('\n');
+ current_glyph_color = col;
+}
+
// determine_line_limits - works out the smallest box which will contain
// the entity, code, built from the point array.
void troff_output_file::determine_line_limits(char code, hvpair *point,
int npoints)
{
int i, x, y;
+
+ if (!is_on())
+ return;
+
switch (code) {
case 'c':
case 'C':
@@ -1157,8 +1302,37 @@ void troff_output_file::determine_line_limits(char code, hvpair *point,
check_output_limits(x, y);
}
break;
+ case 'a':
+ double c[2];
+ int p[4];
+ int minx, miny, maxx, maxy;
+ x = output_hpos;
+ y = output_vpos;
+ p[0] = point[0].h.to_units();
+ p[1] = point[0].v.to_units();
+ p[2] = point[1].h.to_units();
+ p[3] = point[1].v.to_units();
+ if (adjust_arc_center(p, c)) {
+ check_output_arc_limits(x, y,
+ p[0], p[1], p[2], p[3],
+ c[0], c[1],
+ &minx, &maxx, &miny, &maxy);
+ check_output_limits(minx, miny);
+ check_output_limits(maxx, maxy);
+ break;
+ }
+ // fall through
+ case 'l':
+ x = output_hpos;
+ y = output_vpos;
+ check_output_limits(x, y);
+ for (i = 0; i < npoints; i++) {
+ x += point[i].h.to_units();
+ y += point[i].v.to_units();
+ check_output_limits(x, y);
+ }
+ break;
default:
- // remember this doesn't work for arc.. yet
x = output_hpos;
y = output_vpos;
for (i = 0; i < npoints; i++) {
@@ -1170,34 +1344,37 @@ void troff_output_file::determine_line_limits(char code, hvpair *point,
}
void troff_output_file::draw(char code, hvpair *point, int npoints,
- font_size fsize)
+ font_size fsize, color *gcol, color *fcol)
{
+ int i;
flush_tbuf();
do_motion();
- int size = fsize.to_scaled_points();
- if (current_size != size) {
- put('s');
- put(size);
- put('\n');
- current_size = size;
- current_tfont = 0;
- }
- put('D');
- put(code);
- int i;
- if (code == 'c') {
- put(' ');
- put(point[0].h.to_units());
- }
- else
- for (i = 0; i < npoints; i++) {
- put(' ');
- put(point[i].h.to_units());
+ glyph_color(gcol);
+ fill_color(fcol);
+ if (is_on()) {
+ int size = fsize.to_scaled_points();
+ if (current_size != size) {
+ put('s');
+ put(size);
+ put('\n');
+ current_size = size;
+ current_tfont = 0;
+ }
+ put('D');
+ put(code);
+ if (code == 'c') {
put(' ');
- put(point[i].v.to_units());
+ put(point[0].h.to_units());
}
-
- determine_line_limits(code, point, npoints);
+ else
+ for (i = 0; i < npoints; i++) {
+ put(' ');
+ put(point[i].h.to_units());
+ put(' ');
+ put(point[i].v.to_units());
+ }
+ determine_line_limits(code, point, npoints);
+ }
for (i = 0; i < npoints; i++)
output_hpos += point[i].h.to_units();
@@ -1207,15 +1384,18 @@ void troff_output_file::draw(char code, hvpair *point, int npoints,
output_vpos += point[i].v.to_units();
vpos = output_vpos;
}
- put('\n');
+ if (is_on())
+ put('\n');
}
-void troff_output_file::really_on ()
+void troff_output_file::really_on()
{
flush_tbuf();
+ force_motion = 1;
+ do_motion();
}
-void troff_output_file::really_off ()
+void troff_output_file::really_off()
{
flush_tbuf();
}
@@ -1412,7 +1592,7 @@ int real_output_file::is_printing()
void real_output_file::begin_page(int pageno, vunits page_length)
{
printing = in_output_page_list(pageno);
- if (printing && output_on)
+ if (printing)
really_begin_page(pageno, page_length);
}
@@ -1454,9 +1634,8 @@ void real_output_file::really_put_filename(const char *filename)
void real_output_file::on()
{
really_on();
- if (output_on == 0) {
+ if (output_on == 0)
output_on = 1;
- }
}
void real_output_file::off()
@@ -1467,7 +1646,7 @@ void real_output_file::off()
int real_output_file::is_on()
{
- return( output_on );
+ return output_on;
}
void real_output_file::really_on()
@@ -1562,14 +1741,16 @@ class glyph_node : public charinfo_node {
static glyph_node *free_list;
protected:
tfont *tf;
+ color *gcol;
+ color *fcol; /* this is needed for grotty */
#ifdef STORE_WIDTH
hunits wid;
- glyph_node(charinfo *, tfont *, hunits, node * = 0);
+ glyph_node(charinfo *, tfont *, color *, color *, hunits, node * = 0);
#endif
public:
void *operator new(size_t);
void operator delete(void *);
- glyph_node(charinfo *, tfont *, node * = 0);
+ glyph_node(charinfo *, tfont *, color *, color *, node * = 0);
~glyph_node() {}
node *copy();
node *merge_glyph_node(glyph_node *);
@@ -1584,6 +1765,8 @@ public:
hunits skew();
hyphenation_type get_hyphenation_type();
tfont *get_tfont();
+ color *get_glyph_color();
+ color *get_fill_color();
void tprint(troff_output_file *);
void zero_width_tprint(troff_output_file *);
hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
@@ -1602,12 +1785,14 @@ class ligature_node : public glyph_node {
node *n1;
node *n2;
#ifdef STORE_WIDTH
- ligature_node(charinfo *, tfont *, hunits, node *gn1, node *gn2, node *x = 0);
+ ligature_node(charinfo *, tfont *, color *, color *, hunits,
+ node *, node *, node * = 0);
#endif
public:
void *operator new(size_t);
void operator delete(void *);
- ligature_node(charinfo *, tfont *, node *gn1, node *gn2, node *x = 0);
+ ligature_node(charinfo *, tfont *, color *, color *,
+ node *, node *, node * = 0);
~ligature_node();
node *copy();
node *add_self(node *, hyphen_list **);
@@ -1708,8 +1893,8 @@ void ligature_node::operator delete(void *p)
delete[] (char *)p;
}
-glyph_node::glyph_node(charinfo *c, tfont *t, node *x)
-: charinfo_node(c, x), tf(t)
+glyph_node::glyph_node(charinfo *c, tfont *t, color *gc, color *fc, node *x)
+: charinfo_node(c, x), tf(t), gcol(gc), fcol(fc)
{
#ifdef STORE_WIDTH
wid = tf->get_width(ci);
@@ -1717,8 +1902,9 @@ glyph_node::glyph_node(charinfo *c, tfont *t, node *x)
}
#ifdef STORE_WIDTH
-glyph_node::glyph_node(charinfo *c, tfont *t, hunits w, node *x)
-: charinfo_node(c, x), tf(t), wid(w)
+glyph_node::glyph_node(charinfo *c, tfont *t,
+ color *gc, color *fc, hunits w, node *x)
+: charinfo_node(c, x), tf(t), gcol(gc), fcol(fc), wid(w)
{
}
#endif
@@ -1726,9 +1912,9 @@ glyph_node::glyph_node(charinfo *c, tfont *t, hunits w, node *x)
node *glyph_node::copy()
{
#ifdef STORE_WIDTH
- return new glyph_node(ci, tf, wid);
+ return new glyph_node(ci, tf, gcol, fcol, wid);
#else
- return new glyph_node(ci, tf);
+ return new glyph_node(ci, tf, gcol, fcol);
#endif
}
@@ -1779,6 +1965,26 @@ tfont *glyph_node::get_tfont()
return tf;
}
+color *node::get_glyph_color()
+{
+ return 0;
+}
+
+color *glyph_node::get_glyph_color()
+{
+ return gcol;
+}
+
+color *node::get_fill_color()
+{
+ return 0;
+}
+
+color *glyph_node::get_fill_color()
+{
+ return fcol;
+}
+
node *node::merge_glyph_node(glyph_node * /*gn*/)
{
return 0;
@@ -1786,12 +1992,12 @@ node *node::merge_glyph_node(glyph_node * /*gn*/)
node *glyph_node::merge_glyph_node(glyph_node *gn)
{
- if (tf == gn->tf) {
+ if (tf == gn->tf && gcol == gn->gcol && fcol == gn->fcol) {
charinfo *lig;
if ((lig = tf->get_lig(ci, gn->ci)) != 0) {
node *next1 = next;
next = 0;
- return new ligature_node(lig, tf, this, gn, next1);
+ return new ligature_node(lig, tf, gcol, fcol, this, gn, next1);
}
hunits kern;
if (tf->get_kern(ci, gn->ci, &kern)) {
@@ -1860,16 +2066,16 @@ void glyph_node::ascii_print(ascii_output_file *ascii)
ascii->outs(ci->nm.contents());
}
-ligature_node::ligature_node(charinfo *c, tfont *t,
+ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
node *gn1, node *gn2, node *x)
-: glyph_node(c, t, x), n1(gn1), n2(gn2)
+: glyph_node(c, t, gc, fc, x), n1(gn1), n2(gn2)
{
}
#ifdef STORE_WIDTH
-ligature_node::ligature_node(charinfo *c, tfont *t, hunits w,
- node *gn1, node *gn2, node *x)
-: glyph_node(c, t, w, x), n1(gn1), n2(gn2)
+ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc,
+ hunits w, node *gn1, node *gn2, node *x)
+: glyph_node(c, t, gc, fc, w, x), n1(gn1), n2(gn2)
{
}
#endif
@@ -1883,9 +2089,9 @@ ligature_node::~ligature_node()
node *ligature_node::copy()
{
#ifdef STORE_WIDTH
- return new ligature_node(ci, tf, wid, n1->copy(), n2->copy());
+ return new ligature_node(ci, tf, gcol, fcol, wid, n1->copy(), n2->copy());
#else
- return new ligature_node(ci, tf, n1->copy(), n2->copy());
+ return new ligature_node(ci, tf, gcol, fcol, n1->copy(), n2->copy());
#endif
}
@@ -1986,10 +2192,12 @@ node *kern_pair_node::add_discretionary_hyphen()
tfont *tf = n2->get_tfont();
if (tf) {
if (tf->contains(soft_hyphen_char)) {
+ color *gcol = n2->get_glyph_color();
+ color *fcol = n2->get_fill_color();
node *next1 = next;
next = 0;
node *n = copy();
- glyph_node *gn = new glyph_node(soft_hyphen_char, tf);
+ glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol);
node *nn = n->merge_glyph_node(gn);
if (nn == 0) {
gn->next = n;
@@ -2121,10 +2329,12 @@ node *node::add_discretionary_hyphen()
if (!tf)
return new hyphen_inhibitor_node(this);
if (tf->contains(soft_hyphen_char)) {
+ color *gcol = get_glyph_color();
+ color *fcol = get_fill_color();
node *next1 = next;
next = 0;
node *n = copy();
- glyph_node *gn = new glyph_node(soft_hyphen_char, tf);
+ glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol);
node *n1 = n->merge_glyph_node(gn);
if (n1 == 0) {
gn->next = n;
@@ -2362,8 +2572,9 @@ int italic_corrected_node::character_type()
class break_char_node : public node {
node *ch;
char break_code;
+ color *col;
public:
- break_char_node(node *, int, node * = 0);
+ break_char_node(node *, int, color *, node * = 0);
~break_char_node();
node *copy();
hunits width();
@@ -2387,8 +2598,8 @@ public:
int force_tprint();
};
-break_char_node::break_char_node(node *n, int c, node *x)
-: node(x), ch(n), break_code(c)
+break_char_node::break_char_node(node *n, int bc, color *c, node *x)
+: node(x), ch(n), break_code(bc), col(c)
{
}
@@ -2399,7 +2610,7 @@ break_char_node::~break_char_node()
node *break_char_node::copy()
{
- return new break_char_node(ch->copy(), break_code);
+ return new break_char_node(ch->copy(), break_code, col);
}
hunits break_char_node::width()
@@ -2431,13 +2642,13 @@ node *break_char_node::add_self(node *n, hyphen_list **p)
{
assert((*p)->hyphenation_code == 0);
if ((*p)->breakable && (break_code & 1)) {
- n = new space_node(H0, n);
+ n = new space_node(H0, col, n);
n->freeze_space();
}
next = n;
n = this;
if ((*p)->breakable && (break_code & 2)) {
- n = new space_node(H0, n);
+ n = new space_node(H0, col, n);
n->freeze_space();
}
hyphen_list *pp = *p;
@@ -2493,17 +2704,17 @@ node *vertical_size_node::copy()
node *hmotion_node::copy()
{
- return new hmotion_node(n, was_tab, unformat);
+ return new hmotion_node(n, was_tab, unformat, col);
}
node *space_char_hmotion_node::copy()
{
- return new space_char_hmotion_node(n);
+ return new space_char_hmotion_node(n, col);
}
node *vmotion_node::copy()
{
- return new vmotion_node(n);
+ return new vmotion_node(n, col);
}
node *dummy_node::copy()
@@ -2648,6 +2859,8 @@ node *bracket_node::copy()
bracket_node *on = new bracket_node;
node *last = 0;
node *tem;
+ if (list)
+ list->last = 0;
for (tem = list; tem; tem = tem->next) {
if (tem->next)
tem->next->last = tem;
@@ -2711,13 +2924,13 @@ inline void space_node::operator delete(void *p)
}
#endif
-space_node::space_node(hunits nn, node *p)
-: node(p), n(nn), set(0), was_escape_colon(0)
+space_node::space_node(hunits nn, color *c, node *p)
+: node(p), n(nn), set(0), was_escape_colon(0), col(c)
{
}
-space_node::space_node(hunits nn, int s, int flag, node *p)
-: node(p), n(nn), set(s), was_escape_colon(flag)
+space_node::space_node(hunits nn, int s, int flag, color *c, node *p)
+: node(p), n(nn), set(s), was_escape_colon(flag), col(c)
{
}
@@ -2729,7 +2942,7 @@ space_node::~space_node()
node *space_node::copy()
{
- return new space_node(n, set, was_escape_colon);
+ return new space_node(n, set, was_escape_colon, col);
}
int space_node::force_tprint()
@@ -3025,7 +3238,9 @@ void node::asciify(macro *m)
void glyph_node::asciify(macro *m)
{
- unsigned char c = ci->get_ascii_code();
+ unsigned char c = ci->get_asciify_code();
+ if (c == 0)
+ c = ci->get_ascii_code();
if (c != 0) {
m->append(c);
delete this;
@@ -3098,8 +3313,9 @@ void hmotion_node::asciify(macro *m)
m->append(this);
}
-space_char_hmotion_node::space_char_hmotion_node(hunits i, node *next)
-: hmotion_node(i, next)
+space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c,
+ node *next)
+: hmotion_node(i, c, next)
{
}
@@ -3153,8 +3369,8 @@ int node::nbreaks()
return 0;
}
-breakpoint *space_node::get_breakpoints(hunits width, int ns, breakpoint *rest,
- int is_inner)
+breakpoint *space_node::get_breakpoints(hunits width, int ns,
+ breakpoint *rest, int is_inner)
{
if (next->discardable())
return rest;
@@ -3351,23 +3567,27 @@ special_node::special_node(const macro &m, int n)
font_size fs = curenv->get_font_size();
int char_height = curenv->get_char_height();
int char_slant = curenv->get_char_slant();
- int fontno = curenv->get_font();
- tf = font_table[fontno]->get_tfont(fs, char_height, char_slant,
- fontno);
+ int fontno = env_definite_font(curenv);
+ tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fontno);
if (curenv->is_composite())
tf = tf->get_plain();
+ gcol = curenv->get_glyph_color();
+ fcol = curenv->get_fill_color();
}
-special_node::special_node(const macro &m, tfont *t, int n)
-: mac(m), tf(t), no_init_string(n)
+special_node::special_node(const macro &m, tfont *t,
+ color *gc, color *fc, int n)
+: mac(m), tf(t), gcol(gc), fcol(fc), no_init_string(n)
{
}
int special_node::same(node *n)
{
- return ((mac == ((special_node *)n)->mac)
- && (tf == ((special_node *)n)->tf)
- && (no_init_string == ((special_node *)n)->no_init_string));
+ return mac == ((special_node *)n)->mac
+ && tf == ((special_node *)n)->tf
+ && gcol == ((special_node *)n)->gcol
+ && fcol == ((special_node *)n)->fcol
+ && no_init_string == ((special_node *)n)->no_init_string;
}
const char *special_node::type()
@@ -3387,12 +3607,12 @@ int special_node::force_tprint()
node *special_node::copy()
{
- return new special_node(mac, tf, no_init_string);
+ return new special_node(mac, tf, gcol, fcol, no_init_string);
}
void special_node::tprint_start(troff_output_file *out)
{
- out->start_special(get_tfont(), no_init_string);
+ out->start_special(tf, gcol, fcol, no_init_string);
}
void special_node::tprint_char(troff_output_file *out, unsigned char c)
@@ -3413,18 +3633,20 @@ tfont *special_node::get_tfont()
/* suppress_node */
suppress_node::suppress_node(int on_or_off, int issue_limits)
-: is_on(on_or_off), emit_limits(issue_limits), filename(0), position(0)
+: is_on(on_or_off), emit_limits(issue_limits),
+ filename(0), position(0), image_id(0)
{
}
-suppress_node::suppress_node(symbol f, char p)
-: is_on(2), emit_limits(0), filename(f), position(p)
+suppress_node::suppress_node(symbol f, char p, int id)
+: is_on(2), emit_limits(0), filename(f), position(p), image_id(id)
{
}
suppress_node::suppress_node(int issue_limits, int on_or_off,
- symbol f, char p)
-: is_on(on_or_off), emit_limits(issue_limits), filename(f), position(p)
+ symbol f, char p, int id)
+: is_on(on_or_off), emit_limits(issue_limits),
+ filename(f), position(p), image_id(id)
{
}
@@ -3433,8 +3655,8 @@ int suppress_node::same(node *n)
return ((is_on == ((suppress_node *)n)->is_on)
&& (emit_limits == ((suppress_node *)n)->emit_limits)
&& (filename == ((suppress_node *)n)->filename)
- && (position == ((suppress_node *)n)->position));
-;
+ && (position == ((suppress_node *)n)->position)
+ && (image_id == ((suppress_node *)n)->image_id));
}
const char *suppress_node::type()
@@ -3444,7 +3666,7 @@ const char *suppress_node::type()
node *suppress_node::copy()
{
- return new suppress_node(emit_limits, is_on, filename, position);
+ return new suppress_node(emit_limits, is_on, filename, position, image_id);
}
int get_reg_int(const char *p)
@@ -3483,6 +3705,7 @@ void suppress_node::put(troff_output_file *out, const char *s)
static char last_position = 0;
static const char *last_image_filename = 0;
+static int last_image_id = 0;
inline int min(int a, int b)
{
@@ -3508,22 +3731,23 @@ inline int min(int a, int b)
void suppress_node::tprint(troff_output_file *out)
{
- int current_page = get_reg_int("%");
+ int current_page = topdiv->get_page_number();
// firstly check to see whether this suppress node contains
// an image filename & position.
if (is_on == 2) {
// remember position and filename
last_position = position;
- last_image_filename = filename.contents();
+ last_image_filename = strdup(filename.contents());
+ last_image_id = image_id;
+ // printf("start of image and page = %d\n", current_page);
}
else {
// now check whether the suppress node requires us to issue limits.
if (emit_limits) {
char name[8192];
- image_no++;
// remember that the filename will contain a %d in which the
- // image_no is placed
- sprintf(name, last_image_filename, image_no);
+ // last_image_id is placed
+ sprintf(name, last_image_filename, last_image_id);
if (is_html) {
switch (last_position) {
case 'c':
@@ -3551,14 +3775,18 @@ void suppress_node::tprint(troff_output_file *out)
}
else {
// postscript (or other device)
- if (current_page != suppress_start_page)
+ if (suppress_start_page > 0 && current_page != suppress_start_page)
error("suppression limit registers span more than one page;\n"
"image description %1 will be wrong", image_no);
+ // if (topdiv->get_page_number() != suppress_start_page)
+ // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n",
+ // topdiv->get_page_number(), suppress_start_page);
+
// remember that the filename will contain a %d in which the
// image_no is placed
fprintf(stderr,
"grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n",
- current_page,
+ topdiv->get_page_number(),
get_reg_int("opminx"), get_reg_int("opminy"),
get_reg_int("opmaxx"), get_reg_int("opmaxy"),
// page offset + line length
@@ -3568,12 +3796,13 @@ void suppress_node::tprint(troff_output_file *out)
}
}
else {
- if (is_on)
+ if (is_on) {
out->on();
+ // lastly we reset the output registers
+ reset_output_registers(out->get_vpos());
+ }
else
out->off();
- // lastly we reset the output registers
- reset_output_registers(out->get_vpos());
suppress_start_page = current_page;
}
}
@@ -3670,7 +3899,9 @@ hyphenation_type composite_node::get_hyphenation_type()
void composite_node::asciify(macro *m)
{
- unsigned char c = ci->get_ascii_code();
+ unsigned char c = ci->get_asciify_code();
+ if (c == 0)
+ c = ci->get_ascii_code();
if (c != 0) {
m->append(c);
delete this;
@@ -3741,14 +3972,14 @@ width_list::width_list(width_list *w)
{
}
-word_space_node::word_space_node(hunits d, width_list *w, node *x)
-: space_node(d, x), orig_width(w), unformat(0)
+word_space_node::word_space_node(hunits d, color *c, width_list *w, node *x)
+: space_node(d, c, x), orig_width(w), unformat(0)
{
}
-word_space_node::word_space_node(hunits d, int s, width_list *w,
+word_space_node::word_space_node(hunits d, int s, color *c, width_list *w,
int flag, node *x)
-: space_node(d, s, 0, x), orig_width(w), unformat(flag)
+: space_node(d, s, 0, c, x), orig_width(w), unformat(flag)
{
}
@@ -3774,7 +4005,7 @@ node *word_space_node::copy()
w_new_curr = w_new_curr->next;
w_old_curr = w_old_curr->next;
}
- return new word_space_node(n, set, w_new, unformat);
+ return new word_space_node(n, set, col, w_new, unformat);
}
int word_space_node::set_unformat_flag()
@@ -3785,8 +4016,9 @@ int word_space_node::set_unformat_flag()
void word_space_node::tprint(troff_output_file *out)
{
+ out->fill_color(col);
out->word_marker();
- space_node::tprint(out);
+ out->right(n);
}
int word_space_node::merge_space(hunits h, hunits sw, hunits ssw)
@@ -3800,19 +4032,20 @@ int word_space_node::merge_space(hunits h, hunits sw, hunits ssw)
return 1;
}
-unbreakable_space_node::unbreakable_space_node(hunits d, node *x)
-: word_space_node(d, 0, x)
+unbreakable_space_node::unbreakable_space_node(hunits d, color *c, node *x)
+: word_space_node(d, c, 0, x)
{
}
-unbreakable_space_node::unbreakable_space_node(hunits d, int s, node *x)
-: word_space_node(d, s, 0, 0, x)
+unbreakable_space_node::unbreakable_space_node(hunits d, int s,
+ color *c, node *x)
+: word_space_node(d, s, c, 0, 0, x)
{
}
node *unbreakable_space_node::copy()
{
- return new unbreakable_space_node(n, set);
+ return new unbreakable_space_node(n, set, col);
}
int unbreakable_space_node::force_tprint()
@@ -3845,8 +4078,9 @@ hvpair::hvpair()
{
}
-draw_node::draw_node(char c, hvpair *p, int np, font_size s)
-: npoints(np), sz(s), code(c)
+draw_node::draw_node(char c, hvpair *p, int np, font_size s,
+ color *gc, color *fc)
+: npoints(np), sz(s), gcol(gc), fcol(fc), code(c)
{
point = new hvpair[npoints];
for (int i = 0; i < npoints; i++)
@@ -3856,7 +4090,8 @@ draw_node::draw_node(char c, hvpair *p, int np, font_size s)
int draw_node::same(node *n)
{
draw_node *nd = (draw_node *)n;
- if (code != nd->code || npoints != nd->npoints || sz != nd->sz)
+ if (code != nd->code || npoints != nd->npoints || sz != nd->sz
+ || gcol != nd->gcol || fcol != nd->fcol)
return 0;
for (int i = 0; i < npoints; i++)
if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v)
@@ -3900,12 +4135,12 @@ vunits draw_node::vertical_width()
node *draw_node::copy()
{
- return new draw_node(code, point, npoints, sz);
+ return new draw_node(code, point, npoints, sz, gcol, fcol);
}
void draw_node::tprint(troff_output_file *out)
{
- out->draw(code, point, npoints, sz);
+ out->draw(code, point, npoints, sz, gcol, fcol);
}
/* tprint methods */
@@ -3914,7 +4149,7 @@ void glyph_node::tprint(troff_output_file *out)
{
tfont *ptf = tf->get_plain();
if (ptf == tf)
- out->put_char_width(ci, ptf, width(), H0);
+ out->put_char_width(ci, ptf, gcol, fcol, width(), H0);
else {
hunits offset;
int bold = tf->get_bold(&offset);
@@ -3933,10 +4168,10 @@ void glyph_node::tprint(troff_output_file *out)
else
k = tf->get_track_kern();
if (bold) {
- out->put_char(ci, ptf);
+ out->put_char(ci, ptf, gcol, fcol);
out->right(offset);
}
- out->put_char_width(ci, ptf, w, k);
+ out->put_char_width(ci, ptf, gcol, fcol, w, k);
}
}
@@ -3954,10 +4189,10 @@ void glyph_node::zero_width_tprint(troff_output_file *out)
x = x/2;
out->right(x);
}
- out->put_char(ci, ptf);
+ out->put_char(ci, ptf, gcol, fcol);
if (bold) {
out->right(offset);
- out->put_char(ci, ptf);
+ out->put_char(ci, ptf, gcol, fcol);
out->right(-offset);
}
if (cs)
@@ -3995,20 +4230,23 @@ void hline_node::tprint(troff_output_file *out)
hunits xx = x - w;
hunits xx2 = xx/2;
out->right(xx2);
- n->tprint(out);
+ if (out->is_on())
+ n->tprint(out);
out->right(xx - xx2);
}
else {
hunits rem = x - w*i;
if (rem > H0)
if (n->overlaps_horizontally()) {
- n->tprint(out);
+ if (out->is_on())
+ n->tprint(out);
out->right(rem - w);
}
else
out->right(rem);
while (--i >= 0)
- n->tprint(out);
+ if (out->is_on())
+ n->tprint(out);
}
}
@@ -4037,11 +4275,13 @@ void vline_node::tprint(troff_output_file *out)
if (overlaps) {
n->zero_width_tprint(out);
out->down(-rem);
- n->tprint(out);
+ if (out->is_on())
+ n->tprint(out);
out->down(-h);
}
else {
- n->tprint(out);
+ if (out->is_on())
+ n->tprint(out);
out->down(-h - rem);
}
}
@@ -4062,7 +4302,8 @@ void vline_node::tprint(troff_output_file *out)
n->zero_width_tprint(out);
out->down(h);
}
- n->tprint(out);
+ if (out->is_on())
+ n->tprint(out);
}
}
}
@@ -4131,16 +4372,19 @@ void node::zero_width_tprint(troff_output_file *out)
void space_node::tprint(troff_output_file *out)
{
+ out->fill_color(col);
out->right(n);
}
void hmotion_node::tprint(troff_output_file *out)
{
+ out->fill_color(col);
out->right(n);
}
void vmotion_node::tprint(troff_output_file *out)
{
+ out->fill_color(col);
out->down(n);
}
@@ -4226,6 +4470,8 @@ node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0)
int fn = fontno;
int found = font_table[fontno]->contains(s);
if (!found) {
+ if (s->is_fallback())
+ return make_composite_node(s, env);
if (s->numbered()) {
if (!no_error_message)
warning(WARN_CHAR, "can't find numbered character %1",
@@ -4284,16 +4530,20 @@ node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0)
tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn);
if (env->is_composite())
tf = tf->get_plain();
- return new glyph_node(s, tf);
+ color *gcol = env->get_glyph_color();
+ color *fcol = env->get_fill_color();
+ return new glyph_node(s, tf, gcol, fcol);
}
node *make_node(charinfo *ci, environment *env)
{
switch (ci->get_special_translation()) {
case charinfo::TRANSLATE_SPACE:
- return new space_char_hmotion_node(env->get_space_width());
+ return new space_char_hmotion_node(env->get_space_width(),
+ env->get_fill_color());
case charinfo::TRANSLATE_STRETCHABLE_SPACE:
- return new unbreakable_space_node(env->get_space_width());
+ return new unbreakable_space_node(env->get_space_width(),
+ env->get_fill_color());
case charinfo::TRANSLATE_DUMMY:
return new dummy_node;
case charinfo::TRANSLATE_HYPHEN_INDICATOR:
@@ -4304,7 +4554,7 @@ node *make_node(charinfo *ci, environment *env)
if (tem)
ci = tem;
macro *mac = ci->get_macro();
- if (mac)
+ if (mac && !ci->is_fallback())
return make_composite_node(ci, env);
else
return make_glyph_node(ci, env);
@@ -4333,11 +4583,14 @@ node *node::add_char(charinfo *ci, environment *env,
node *res;
switch (ci->get_special_translation()) {
case charinfo::TRANSLATE_SPACE:
- res = new space_char_hmotion_node(env->get_space_width(), this);
+ res = new space_char_hmotion_node(env->get_space_width(),
+ env->get_fill_color(), this);
*widthp += res->width();
return res;
case charinfo::TRANSLATE_STRETCHABLE_SPACE:
- res = new unbreakable_space_node(env->get_space_width(), this);
+ res = new unbreakable_space_node(env->get_space_width(),
+ env->get_fill_color(), this);
+ res->freeze_space();
*widthp += res->width();
*spacep += res->nspaces();
return res;
@@ -4350,7 +4603,7 @@ node *node::add_char(charinfo *ci, environment *env,
if (tem)
ci = tem;
macro *mac = ci->get_macro();
- if (mac) {
+ if (mac && !ci->is_fallback()) {
res = make_composite_node(ci, env);
if (res) {
res->next = this;
@@ -4385,7 +4638,7 @@ node *node::add_char(charinfo *ci, environment *env,
if (break_code) {
node *next1 = res->next;
res->next = 0;
- res = new break_char_node(res, break_code, next1);
+ res = new break_char_node(res, break_code, env->get_fill_color(), next1);
}
return res;
}
@@ -4453,7 +4706,8 @@ int vertical_size_node::force_tprint()
int hmotion_node::same(node *nd)
{
- return n == ((hmotion_node *)nd)->n;
+ return n == ((hmotion_node *)nd)->n
+ && col == ((hmotion_node *)nd)->col;
}
const char *hmotion_node::type()
@@ -4488,7 +4742,8 @@ hyphen_list *hmotion_node::get_hyphen_list(hyphen_list *tail)
int space_char_hmotion_node::same(node *nd)
{
- return n == ((space_char_hmotion_node *)nd)->n;
+ return n == ((space_char_hmotion_node *)nd)->n
+ && col == ((space_char_hmotion_node *)nd)->col;
}
const char *space_char_hmotion_node::type()
@@ -4517,7 +4772,8 @@ hyphen_list *space_char_hmotion_node::get_hyphen_list(hyphen_list *tail)
int vmotion_node::same(node *nd)
{
- return n == ((vmotion_node *)nd)->n;
+ return n == ((vmotion_node *)nd)->n
+ && col == ((vmotion_node *)nd)->col;
}
const char *vmotion_node::type()
@@ -4841,7 +5097,10 @@ int composite_node::force_tprint()
int glyph_node::same(node *nd)
{
- return ci == ((glyph_node *)nd)->ci && tf == ((glyph_node *)nd)->tf;
+ return ci == ((glyph_node *)nd)->ci
+ && tf == ((glyph_node *)nd)->tf
+ && gcol == ((glyph_node *)nd)->gcol
+ && fcol == ((glyph_node *)nd)->fcol;
}
const char *glyph_node::type()
@@ -4907,8 +5166,9 @@ int dbreak_node::force_tprint()
int break_char_node::same(node *nd)
{
- return (break_code == ((break_char_node *)nd)->break_code
- && same_node(ch, ((break_char_node *)nd)->ch));
+ return break_code == ((break_char_node *)nd)->break_code
+ && col == ((break_char_node *)nd)->col
+ && same_node(ch, ((break_char_node *)nd)->ch);
}
const char *break_char_node::type()
@@ -4938,7 +5198,9 @@ int line_start_node::force_tprint()
int space_node::same(node *nd)
{
- return n == ((space_node *)nd)->n && set == ((space_node *)nd)->set;
+ return n == ((space_node *)nd)->n
+ && set == ((space_node *)nd)->set
+ && col == ((space_node *)nd)->col;
}
const char *space_node::type()
@@ -4948,8 +5210,9 @@ const char *space_node::type()
int word_space_node::same(node *nd)
{
- return (n == ((word_space_node *)nd)->n
- && set == ((word_space_node *)nd)->set);
+ return n == ((word_space_node *)nd)->n
+ && set == ((word_space_node *)nd)->set
+ && col == ((word_space_node *)nd)->col;
}
const char *word_space_node::type()
@@ -4964,8 +5227,9 @@ int word_space_node::force_tprint()
int unbreakable_space_node::same(node *nd)
{
- return (n == ((unbreakable_space_node *)nd)->n
- && set == ((unbreakable_space_node *)nd)->set);
+ return n == ((unbreakable_space_node *)nd)->n
+ && set == ((unbreakable_space_node *)nd)->set
+ && col == ((unbreakable_space_node *)nd)->col;
}
const char *unbreakable_space_node::type()
@@ -5345,7 +5609,7 @@ int symbol_fontno(symbol s)
int is_good_fontno(int n)
{
- return n >= 0 && n < font_table_size && font_table[n] != NULL;
+ return n >= 0 && n < font_table_size && font_table[n] != 0;
}
int get_bold_fontno(int n)
diff --git a/contrib/groff/src/roff/troff/node.h b/contrib/groff/src/roff/troff/node.h
index a58afed..13295f4 100644
--- a/contrib/groff/src/roff/troff/node.h
+++ b/contrib/groff/src/roff/troff/node.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
@@ -97,6 +97,8 @@ struct node {
virtual node *merge_glyph_node(glyph_node *);
virtual tfont *get_tfont();
+ virtual color *get_glyph_color();
+ virtual color *get_fill_color();
virtual void tprint(troff_output_file *);
virtual void zero_width_tprint(troff_output_file *);
@@ -106,11 +108,13 @@ struct node {
virtual const char *type() = 0;
};
-inline node::node() : next(0), last(0)
+inline node::node()
+: next(0), last(0)
{
}
-inline node::node(node *n) : next(n), last(0)
+inline node::node(node *n)
+: next(n), last(0)
{
}
@@ -152,9 +156,10 @@ protected:
hunits n;
char set;
char was_escape_colon;
- space_node(hunits, int, int, node * = 0);
+ color *col; /* for grotty */
+ space_node(hunits, int, int, color *, node * = 0);
public:
- space_node(hunits d, node *p = 0);
+ space_node(hunits, color *, node * = 0);
#if 0
~space_node();
void *operator new(size_t);
@@ -192,9 +197,9 @@ class word_space_node : public space_node {
protected:
width_list *orig_width;
unsigned char unformat;
- word_space_node(hunits, int, width_list *, int, node * = 0);
+ word_space_node(hunits, int, color *, width_list *, int, node * = 0);
public:
- word_space_node(hunits, width_list *, node * = 0);
+ word_space_node(hunits, color *, width_list *, node * = 0);
~word_space_node();
node *copy();
int reread(int *);
@@ -208,9 +213,9 @@ public:
};
class unbreakable_space_node : public word_space_node {
- unbreakable_space_node(hunits, int, node * = 0);
+ unbreakable_space_node(hunits, int, color *, node * = 0);
public:
- unbreakable_space_node(hunits, node * = 0);
+ unbreakable_space_node(hunits, color *, node * = 0);
node *copy();
int reread(int *);
int same(node *);
@@ -279,11 +284,12 @@ protected:
hunits n;
unsigned char was_tab;
unsigned char unformat;
+ color *col; /* for grotty */
public:
- hmotion_node(hunits i, node *next = 0)
- : node(next), n(i), was_tab(0), unformat(0) {}
- hmotion_node(hunits i, int flag1, int flag2, node *next = 0)
- : node(next), n(i), was_tab(flag1), unformat(flag2) {}
+ hmotion_node(hunits i, color *c, node *next = 0)
+ : node(next), n(i), was_tab(0), unformat(0), col(c) {}
+ hmotion_node(hunits i, int flag1, int flag2, color *c, node *next = 0)
+ : node(next), n(i), was_tab(flag1), unformat(flag2), col(c) {}
node *copy();
int reread(int *);
int set_unformat_flag();
@@ -301,7 +307,7 @@ public:
class space_char_hmotion_node : public hmotion_node {
public:
- space_char_hmotion_node(hunits i, node *next = 0);
+ space_char_hmotion_node(hunits, color *, node * = 0);
node *copy();
void ascii_print(ascii_output_file *);
void asciify(macro *);
@@ -315,8 +321,9 @@ public:
class vmotion_node : public node {
vunits n;
+ color *col; /* for grotty */
public:
- vmotion_node(vunits i) : n(i) {}
+ vmotion_node(vunits i, color *c) : n(i), col(c) {}
void tprint(troff_output_file *);
node *copy();
vunits vertical_width();
@@ -458,13 +465,15 @@ public:
class special_node : public node {
macro mac;
tfont *tf;
+ color *gcol;
+ color *fcol;
int no_init_string;
void tprint_start(troff_output_file *);
void tprint_char(troff_output_file *, unsigned char);
void tprint_end(troff_output_file *);
public:
special_node(const macro &, int = 0);
- special_node(const macro &, tfont *, int = 0);
+ special_node(const macro &, tfont *, color *, color *, int = 0);
node *copy();
void tprint(troff_output_file *);
int same(node *);
@@ -479,10 +488,11 @@ class suppress_node : public node {
int emit_limits; // must we issue the extent of the area written out?
symbol filename;
char position;
+ int image_id;
public:
suppress_node(int, int);
- suppress_node(symbol f, char p);
- suppress_node(int, int, symbol f, char p);
+ suppress_node(symbol f, char p, int id);
+ suppress_node(int, int, symbol f, char p, int id);
node *copy();
void tprint(troff_output_file *);
hunits width();
@@ -502,10 +512,12 @@ struct hvpair {
class draw_node : public node {
int npoints;
font_size sz;
+ color *gcol;
+ color *fcol;
char code;
hvpair *point;
public:
- draw_node(char, hvpair *, int, font_size);
+ draw_node(char, hvpair *, int, font_size, color *, color *);
~draw_node();
hunits width();
vunits vertical_width();
@@ -582,3 +594,4 @@ public:
};
font_family *lookup_family(symbol);
+symbol get_font_name(int, environment *);
diff --git a/contrib/groff/src/roff/troff/number.cc b/contrib/groff/src/roff/troff/number.cc
index 5393842..8fed342 100644
--- a/contrib/groff/src/roff/troff/number.cc
+++ b/contrib/groff/src/roff/troff/number.cc
@@ -1,5 +1,6 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
+ Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -234,7 +235,7 @@ static int start_number()
enum { OP_LEQ = 'L', OP_GEQ = 'G', OP_MAX = 'X', OP_MIN = 'N' };
-#define SCALE_INDICATOR_CHARS "icPmnpuvMsz"
+#define SCALE_INDICATOR_CHARS "icfPmnpuvMsz"
static int parse_term(units *v, int scale_indicator,
int parenthesised, int rigid);
@@ -320,6 +321,7 @@ static int parse_expr(units *v, int scale_indicator,
break;
case ':':
*v = *v > 0 || v2 > 0;
+ break;
case '+':
if (v2 < 0) {
if (*v < INT_MIN - v2)
@@ -590,6 +592,9 @@ static int parse_term(units *v, int scale_indicator,
if (divisor != 1)
*v /= divisor;
break;
+ case 'f':
+ *v = scale(*v, 65536, divisor);
+ break;
case 'p':
*v = scale(*v, units_per_inch, divisor*72);
break;
diff --git a/contrib/groff/src/roff/troff/request.h b/contrib/groff/src/roff/troff/request.h
index 5654b83..0433ac1 100644
--- a/contrib/groff/src/roff/troff/request.h
+++ b/contrib/groff/src/roff/troff/request.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
@@ -48,7 +48,8 @@ class macro : public request_or_macro {
macro_header *p;
const char *filename; // where was it defined?
int lineno;
- int length;
+ int len;
+ int empty_macro;
public:
macro();
~macro();
@@ -59,13 +60,16 @@ public:
void append_unsigned(unsigned int i);
void append_int(int i);
void append_str(const char *);
+ void set(unsigned char, int);
+ unsigned char get(int);
+ int length();
void invoke(symbol);
macro *to_macro();
void print_size();
int empty();
friend class string_iterator;
friend void chop_macro();
- friend void substring_macro();
+ friend void substring_request();
friend int operator==(const macro &, const macro &);
};
diff --git a/contrib/groff/src/roff/troff/symbol.cc b/contrib/groff/src/roff/troff/symbol.cc
index ce09e39..09f4c98 100644
--- a/contrib/groff/src/roff/troff/symbol.cc
+++ b/contrib/groff/src/roff/troff/symbol.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2002 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -29,6 +29,7 @@ char *symbol::block = 0;
int symbol::block_size = 0;
const symbol NULL_SYMBOL;
+const symbol EMPTY_SYMBOL("");
#ifdef BLOCK_SIZE
#undef BLOCK_SIZE
@@ -38,9 +39,9 @@ const int BLOCK_SIZE = 1024;
// the table will increase in size as necessary
// the size will be chosen from the following array
// add some more if you want
-// I think it unlikely that we'll need more than a million symbols
static const unsigned int table_sizes[] = {
-101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, 80021, 160001, 500009, 1000003, 0
+ 101, 503, 1009, 2003, 3001, 4001, 5003, 10007, 20011, 40009, 80021,
+ 160001, 500009, 1000003, 1500007, 2000003, 0
};
const double FULL_MAX = 0.3; // don't let the table get more than this full
@@ -73,10 +74,14 @@ inline void unused(void *) { }
symbol::symbol(const char *p, int how)
{
- if (p == 0 || *p == 0) {
+ if (p == 0) {
s = 0;
return;
}
+ if (*p == 0) {
+ s = "";
+ return;
+ }
if (table == 0) {
table_size = table_sizes[0];
table = (const char **)new char*[table_size];
@@ -147,4 +152,3 @@ symbol concat(symbol s1, symbol s2)
a_delete buf;
return res;
}
-
diff --git a/contrib/groff/src/roff/troff/symbol.h b/contrib/groff/src/roff/troff/symbol.h
index 88e0fff..5b7c9b1 100644
--- a/contrib/groff/src/roff/troff/symbol.h
+++ b/contrib/groff/src/roff/troff/symbol.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2002 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -36,10 +36,12 @@ public:
int operator !=(symbol) const;
const char *contents() const;
int is_null() const;
+ int is_empty() const;
};
extern const symbol NULL_SYMBOL;
+extern const symbol EMPTY_SYMBOL;
inline symbol::symbol() : s(0)
{
@@ -70,4 +72,9 @@ inline int symbol::is_null() const
return s == 0;
}
+inline int symbol::is_empty() const
+{
+ return s != 0 && *s == 0;
+}
+
symbol concat(symbol, symbol);
diff --git a/contrib/groff/src/roff/troff/token.h b/contrib/groff/src/roff/troff/token.h
index b87a0b1..59f2aa2 100644
--- a/contrib/groff/src/roff/troff/token.h
+++ b/contrib/groff/src/roff/troff/token.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
@@ -51,14 +51,16 @@ class token {
TOKEN_REQUEST,
TOKEN_RIGHT_BRACE,
TOKEN_SPACE, // ` ' -- ordinary space
- TOKEN_SPECIAL, // a special character -- \' \` \- \(xx
+ TOKEN_SPECIAL, // a special character -- \' \` \- \(xx \[xxx]
TOKEN_SPREAD, // \p -- break and spread output line
TOKEN_STRETCHABLE_SPACE, // \~
+ TOKEN_UNSTRETCHABLE_SPACE, // `\ '
TOKEN_TAB, // tab
TOKEN_TRANSPARENT, // \!
TOKEN_TRANSPARENT_DUMMY, // \)
+ TOKEN_ZERO_WIDTH_BREAK, // \:
TOKEN_EOF // end of file
- } type;
+ } type;
public:
token();
~token();
@@ -71,6 +73,7 @@ public:
int nspaces(); // 1 if space, 2 if double space, 0 otherwise
int space(); // is the current token a space?
int stretchable_space(); // is the current token a stretchable space?
+ int unstretchable_space(); // is the current token an unstretchable space?
int white_space(); // is the current token space or tab?
int special(); // is the current token a special character?
int newline(); // is the current token a newline?
@@ -85,6 +88,7 @@ public:
int right_brace();
int page_ejector();
int hyphen_indicator();
+ int zero_width_break();
int operator==(const token &); // need this for delimiters, and for conditions
int operator!=(const token &); // ditto
unsigned char ch();
@@ -103,6 +107,7 @@ extern token tok; // the current token
extern symbol get_name(int required = 0);
extern symbol get_long_name(int required = 0);
extern charinfo *get_optional_char();
+extern char *read_string();
extern void check_missing_character();
extern void skip_line();
extern void handle_initial_title();
@@ -137,6 +142,11 @@ inline int token::stretchable_space()
return type == TOKEN_STRETCHABLE_SPACE;
}
+inline int token::unstretchable_space()
+{
+ return type == TOKEN_UNSTRETCHABLE_SPACE;
+}
+
inline int token::special()
{
return type == TOKEN_SPECIAL;
@@ -215,4 +225,9 @@ inline int token::hyphen_indicator()
return type == TOKEN_HYPHEN_INDICATOR;
}
+inline int token::zero_width_break()
+{
+ return type == TOKEN_ZERO_WIDTH_BREAK;
+}
+
int has_arg();
diff --git a/contrib/groff/src/roff/troff/troff.h b/contrib/groff/src/roff/troff/troff.h
index 254c626..80d9f0b 100644
--- a/contrib/groff/src/roff/troff/troff.h
+++ b/contrib/groff/src/roff/troff/troff.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002
Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
@@ -20,16 +20,16 @@ with groff; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-#include <stdio.h>
+#include "lib.h"
+
#include <ctype.h>
-#include <string.h>
#include <time.h>
#include <stddef.h>
#include <stdlib.h>
#include <errno.h>
-#include "lib.h"
#include "assert.h"
+#include "color.h"
#include "device.h"
#include "searchpath.h"
@@ -43,6 +43,7 @@ extern units units_per_inch;
extern int ascii_output_flag;
extern int suppress_output_flag;
+extern int color_flag;
extern int is_html;
extern int tcommand_flag;
@@ -76,13 +77,18 @@ enum warning_type {
WARN_ESCAPE = 0100000,
WARN_SPACE = 0200000,
WARN_FONT = 0400000,
- WARN_IG = 01000000
+ WARN_IG = 01000000,
+ WARN_COLOR = 02000000
// change WARN_TOTAL if you add more warning types
};
-const int WARN_TOTAL = 01777777;
+const int WARN_TOTAL = 02777777;
int warning(warning_type, const char *,
const errarg & = empty_errarg,
const errarg & = empty_errarg,
const errarg & = empty_errarg);
+int output_warning(warning_type, const char *,
+ const errarg & = empty_errarg,
+ const errarg & = empty_errarg,
+ const errarg & = empty_errarg);
diff --git a/contrib/groff/src/roff/troff/troff.man b/contrib/groff/src/roff/troff/troff.man
index ac746dc..19bb624 100644
--- a/contrib/groff/src/roff/troff/troff.man
+++ b/contrib/groff/src/roff/troff/troff.man
@@ -1,25 +1,44 @@
+'\" t
.ig
-Copyright (C) 1989-2000, 2001 Free Software Foundation, Inc.
+troff.man
-Permission is granted to make and distribute verbatim copies of
-this manual provided the copyright notice and this permission notice
-are preserved on all copies.
+Last update : 9 Jan 2002
-Permission is granted to copy and distribute modified versions of this
-manual under the conditions for verbatim copying, provided that the
-entire resulting derived work is distributed under the terms of a
-permission notice identical to this one.
+This file is part of groff, the GNU roff type-setting system.
-Permission is granted to copy and distribute translations of this
-manual into another language, under the above conditions for modified
-versions, except that this permission notice may be included in
-translations approved by the Free Software Foundation instead of in
-the original English.
+Copyright (C) 1989, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+written by James Clark
+
+modified by Werner Lemberg <wl@gnu.org>
+ Bernd Warken <bwarken@mayn.de>
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.1 or
+any later version published by the Free Software Foundation; with the
+Invariant Sections being this .ig-section and AUTHOR, with no
+Front-Cover Texts, and with no Back-Cover Texts.
+
+A copy of the Free Documentation License is included as a file called
+FDL in the main directory of the groff source package.
..
.
-.\" define a string tx for the TeX logo
-.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X
-.el .ds tx TeX
+.
+.\" --------------------------------------------------------------------
+.\" Setup
+.\" --------------------------------------------------------------------
+.
+.mso www.tmac
+.
+.if n \{\
+. mso tty-char.tmac
+. ftr CR R
+. ftr CI I
+. ftr CB B
+.\}
+.
+.if '\*[.T]'dvi' \
+. ftr CB CW
.
.de TQ
.br
@@ -34,22 +53,19 @@ the original English.
.el .TP "\\$1"
..
.
-.\" The BSD man macros can't handle " in arguments to font change macros,
-.\" so use \(ts instead of ".
-.tr \(ts"
.
+.\" --------------------------------------------------------------------
+.\" Title
+.\" --------------------------------------------------------------------
.
.TH @G@TROFF @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
-.
-.
.SH NAME
+@g@troff \- the troff processor of the groff text formatting system
.
.
-@g@troff \- format documents
-.
-.
+.\" --------------------------------------------------------------------
.SH SYNOPSIS
-.
+.\" --------------------------------------------------------------------
.
.nr a \n(.j
.ad l
@@ -61,90 +77,75 @@ the original English.
.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]"
.el .RB "[\ " "\\$1" "\ ]"
..
-.OP \-abivzCERU
-.OP \-w name
-.OP \-W name
+.OP \-abcivzCERU
.OP \-d cs
.OP \-f fam
+.OP \-F dir
.OP \-m name
+.OP \-M dir
.OP \-n num
.OP \-o list
.OP \-r cn
.OP \-T name
-.OP \-F dir
-.OP \-M dir
+.OP \-w name
+.OP \-W name
.RI "[\ " files\|.\|.\|. "\ ]"
.br
.ad \na
-.PP
-It is possible to have whitespace between a command line option and its
-parameter.
+.P
+It is possible to have whitespace between a command line option and
+its parameter.
.
.
+.\" --------------------------------------------------------------------
.SH DESCRIPTION
-.
+.\" --------------------------------------------------------------------
.
This manual page describes the GNU version of
-.BR troff ,
-which is part of the groff document formatting system.
-It is highly compatible with UNIX troff.
-Usually it should be invoked using the groff command, which will
-also run preprocessors and postprocessors in the appropriate
-order and with the appropriate options.
+.BR troff .
+It is part of the groff document formatting system.
.
+It is functionally compatible with UNIX troff, but has many extensions,
+see
+.BR \%groff_diff (@MAN7EXT@).
+Usually it should be invoked using the
+.BR groff (@MAN1EXT@)
+command which will also run preprocessors and postprocessors in the
+appropriate order and with the appropriate options.
.
-.SH OPTIONS
.
+.\" --------------------------------------------------------------------
+.SH OPTIONS
+.\" --------------------------------------------------------------------
.
.TP \w'\-dname=s'u+2n
.B \-a
Generate an
.SM ASCII
approximation of the typeset output.
+.
.TP
.B \-b
-Print a backtrace with each warning or error message. This backtrace
-should help track down the cause of the error. The line numbers given
-in the backtrace may not always be correct:
-.BR troff 's
-idea of line numbers
-gets confused by
+Print a backtrace with each warning or error message.
+.
+This backtrace should help track down the cause of the error.
+.
+The line numbers given in the backtrace may not always be correct, for
+.BR @g@troff 's
+idea of line numbers gets confused by
.B as
or
.B am
requests.
+.
.TP
-.B \-i
-Read the standard input after all the named input files have been
-processed.
-.TP
-.B \-v
-Print the version number.
-.TP
-.BI \-w name
-Enable warning
-.IR name .
-Available warnings are described in
-the Warnings subsection below.
-Multiple
-.B \-w
-options are allowed.
-.TP
-.BI \-W name
-Inhibit warning
-.IR name .
-Multiple
-.B \-W
-options are allowed.
-.TP
-.B \-E
-Inhibit all error messages.
-.TP
-.B \-z
-Suppress formatted output.
+.B \-c
+Disable color output (always disabled in compatibility mode).
+.
.TP
.B \-C
Enable compatibility mode.
+.
.TP
.BI \-d cs
.TQ
@@ -157,11 +158,42 @@ to be a string
.IR s ;
.I c
must be a one letter name.
+.
+.TP
+.B \-E
+Inhibit all error messages of
+.BR @g@troff .
+Note that this doesn't affect messages output to standard error by macro
+packages using the
+.B tm
+or
+.B tm1
+requests.
+.
.TP
.BI \-f fam
Use
.I fam
as the default font family.
+.
+.TP
+.BI \-F dir
+Search in directory (or directory path)
+.I dir
+for subdirectories
+.BI dev name
+.RI ( name
+is the name of the device) and there for the
+.B DESC
+file and font files.
+.I dir
+is scanned before all other font directories.
+.
+.TP
+.B \-i
+Read the standard input after all the named input files have been
+processed.
+.
.TP
.BI \-m name
Read in the file
@@ -169,36 +201,28 @@ Read in the file
If it isn't found, try
.BI tmac. name
instead.
+.
It will be first searched for in directories given with the
.B \-M
-command line option, then in directories given
-in the
+command line option, then in directories given in the
.B GROFF_TMAC_PATH
environment variable, then in the current directory (only if in unsafe
mode), the home directory, @SYSTEMMACRODIR@, @LOCALMACRODIR@, and
@MACRODIR@.
+.
.TP
-.B \-U
-Unsafe mode.
-This will enable the following requests:
-.BR .open ,
-.BR .opena ,
-.BR .pso ,
-.BR .sy ,
-and
-.BR .pi .
-For security reasons, these potentially dangerous requests are disabled
-otherwise. It will also add the current directory to the macro search path.
-.TP
-.B \-R
-Don't load
-.B troffrc
-and
-.BR troffrc-end .
+.BI \-M dir
+Search directory (or directory path)
+.I dir
+for macro files.
+.
+This is scanned before all other macro directories.
+.
.TP
.BI \-n num
Number the first page
.IR num .
+.
.TP
.BI \-o list
Output only pages in
@@ -218,8 +242,9 @@ means print every page up to
.IB n \-
means print every page from
.IR n .
-.B Troff
+.B @g@troff
will exit after printing the last page in the list.
+.
.TP
.BI \-r cn
.TQ
@@ -234,2227 +259,339 @@ to
must be a one character name;
.I n
can be any troff numeric expression.
+.
+.TP
+.B \-R
+Don't load
+.B troffrc
+and
+.BR troffrc-end .
+.
.TP
.BI \-T name
Prepare output for device
.IR name ,
rather than the default
.BR @DEVICE@ .
-.TP
-.BI \-F dir
-Search in directory (or directory path)
-.I dir
-for subdirectories
-.BI dev name
-.RI ( name
-is the name of the device) and there for the
-.B DESC
-file and font files.
-.I dir
-is scanned before all other font directories.
-.TP
-.BI \-M dir
-Search directory (or directory path)
-.I dir
-for macro files.
-This is scanned before all other macro directories.
-.
-.
-.SH USAGE
-.
-.
-Only the features not in UNIX troff are described here.
.
-.SS Long names
-.
-The names of number registers, fonts, strings/macros/diversions,
-special characters can be of any length. In escape sequences, where
-you can use
-.BI ( xx
-for a two character name, you can use
-.BI [ xxx ]
-for a name of arbitrary length:
-.TP
-.BI \e[ xxx ]
-Print the special character called
-.IR xxx .
-.TP
-.BI \ef[ xxx ]
-Set font
-.IR xxx .
.TP
-.BI \e*[ xxx ]
-Interpolate string
-.IR xxx .
-.TP
-.BI \en[ xxx ]
-Interpolate number register
-.IR xxx .
-.
-.SS Fractional pointsizes
-.
-A
-.I
-scaled point
-is equal to 1/sizescale
-points, where
-sizescale is specified in the
-.B DESC
-file (1 by default).
-There is a new scale indicator
-.B z
-which has the effect of multiplying by sizescale.
-Requests and escape sequences in troff
-interpret arguments that represent a pointsize as being in units
-of scaled points, but they evaluate each such argument
-using a default scale indicator of
-.BR z .
-Arguments treated in this way are
-the argument to the
-.B ps
-request,
-the third argument to the
-.B cs
-request,
-the second and fourth arguments to the
-.B tkf
-request,
-the argument to the
-.B \eH
-escape sequence,
-and those variants of the
-.B \es
-escape sequence that take a numeric expression as their argument.
-.LP
-For example, suppose sizescale is 1000;
-then a scaled point will be equivalent to a millipoint;
-the request
-.B .ps 10.25
-is equivalent to
-.B .ps 10.25z
-and so sets the pointsize to 10250 scaled points,
-which is equal to 10.25 points.
-.LP
-The number register
-.B \en[.s]
-returns the pointsize in points as decimal fraction.
-There is also a new number register
-.B \en[.ps]
-that returns the pointsize in scaled points.
-.LP
-It would make no sense to use the
-.B z
-scale indicator in a numeric expression
-whose default scale indicator was neither
-.B u
-nor
-.BR z ,
-and so
-.B troff
-disallows this.
-Similarly it would make no sense to use a scaling indicator
-other than
-.B z
-or
-.B u
-in a numeric expression whose default scale indicator was
-.BR z ,
-and so
-.B troff
-disallows this as well.
-.LP
-There is also new scale indicator
-.B s
-which multiplies by the number of units in a scaled point.
-So, for example,
-.B \en[.ps]s
-is equal to
-.BR 1m .
-Be sure not to confuse the
-.B s
-and
-.B z
-scale indicators.
-.
-.SS Numeric expressions
+.B \-U
+Unsafe mode.
.
-.LP
-Spaces are permitted in a number expression within parentheses.
-.LP
-.B M
-indicates a scale of 100ths of an em.
-.TP
-.IB e1 >? e2
-The maximum of
-.I e1
-and
-.IR e2 .
-.TP
-.IB e1 <? e2
-The minimum of
-.I e1
+This will enable the following requests:
+.BR open ,
+.BR opena ,
+.BR pso ,
+.BR sy ,
and
-.IR e2 .
-.TP
-.BI ( c ; e )
-Evaluate
-.I e
-using
-.I c
-as the default scaling indicator.
-If
-.I c
-is missing, ignore scaling indicators in the evaluation of
-.IR e .
+.BR pi .
+For security reasons, these potentially dangerous requests are disabled
+otherwise.
.
-.SS New escape sequences
+It will also add the current directory to the macro search path.
.
.TP
-.BI \eA' anything '
-This expands to
-.B 1
-or
-.B 0
-according as
-.I anything
-is or is not acceptable as the name of a string, macro, diversion,
-number register, environment or font.
-It will return
-.B 0
-if
-.I anything
-is empty.
-This is useful if you want to lookup user input in some sort of
-associative table.
-.TP
-.BI \eB' anything '
-This expands to
-.B 1
-or
-.B 0
-according as
-.I anything
-is or is not a valid numeric expression.
-It will return
-.B 0
-if
-.I anything
-is empty.
-.TP
-.BI \eC' xxx '
-Typeset character named
-.IR xxx .
-Normally it is more convenient to use
-.BI \e[ xxx ]\fR.
-But
-.B \eC
-has the advantage that it is compatible with recent versions of
-.SM UNIX
-and is available in compatibility mode.
-.TP
-.B \eE
-This is equivalent to an escape character,
-but it's not interpreted in copy-mode.
-For example, strings to start and end superscripting could be defined
-like this:
-.RS
-.IP
-\&.ds { \ev'\-.3m'\es'\eEn[.s]*6u/10u'
-.br
-\&.ds } \es0\ev'.3m'
-.LP
-The use of
-.B \eE
-ensures that these definitions will work even if
-.B \e*{
-gets interpreted in copy-mode
-(for example, by being used in a macro argument).
-.RE
-.TP
-.BI \eN' n '
-Typeset the character with code
-.I n
-in the current font.
-.I n
-can be any integer.
-Most devices only have characters with codes between 0 and 255.
-If the current font does not contain a character with that code,
-special fonts will
-.I not
-be searched.
-The
-.B \eN
-escape sequence can be conveniently used on conjunction with the
-.B char
-request:
-.RS
-.IP
-.B
-\&.char \e[phone] \ef(ZD\eN'37'
-.RE
-.IP
-The code of each character is given in the fourth column in the font
-description file after the
-.B charset
-command.
-It is possible to include unnamed characters in the font description
-file by using a name of
-.BR \-\-\- ;
-the
-.B \eN
-escape sequence is the only way to use these.
-.TP
-.BI \eR' name\ \(+-n '
-This has the same effect as
-.RS
-.IP
-.BI .nr\ name\ \(+-n
-.RE
-.TP
-.BI \es( nn
-.TQ
-.BI \es\(+-( nn
-Set the point size to
-.I nn
-points;
-.I nn
-must be exactly two digits.
-.TP
-.BI \es[\(+- n ]
-.TQ
-.BI \es\(+-[ n ]
-.TQ
-.BI \es'\(+- n '
-.TQ
-.BI \es\(+-' n '
-Set the point size to
-.I n
-scaled points;
-.I n
-is a numeric expression with a default scale indicator of
-.BR z .
-.TP
-.BI \eV x
-.TQ
-.BI \eV( xx
-.TQ
-.BI \eV[ xxx ]
-Interpolate the contents of the environment variable
-.IR xxx ,
-as returned by
-.BR getenv (3).
-.B \eV
-is interpreted in copy-mode.
-.TP
-.BI \eY x
-.TQ
-.BI \eY( xx
-.TQ
-.BI \eY[ xxx ]
-This is approximately equivalent to
-.BI \eX'\e*[ xxx ]'\fR.
-However the contents of the string or macro
-.I xxx
-are not interpreted;
-also it is permitted for
-.I xxx
-to have been defined as a macro and thus contain newlines
-(it is not permitted for the argument to
-.B \eX
-to contain newlines).
-The inclusion of newlines requires an extension to the UNIX troff output
-format, and will confuse drivers that do not know about this
-extension.
-.TP
-.BI \eZ' anything '
-Print anything and then restore the horizontal and vertical
-position;
-.I anything
-may not contain tabs or leaders.
-.TP
-.B \e$0
-The name by which the current macro was invoked.
-The
-.B als
-request can make a macro have more than one name.
-.TP
-.B \e$*
-In a macro, the concatenation of all the arguments separated by spaces.
-.TP
-.B \e$@
-In a macro, the concatenation of all the arguments with each surrounded by
-double quotes, and separated by spaces.
-.TP
-.BI \e$( nn
-.TQ
-.BI \e$[ nnn ]
-In a macro, this gives the
-.IR nn -th
-or
-.IR nnn -th
-argument.
-Macros can have an unlimited number of arguments.
-.TP
-.BI \e? anything \e?
-When used in a diversion, this will transparently embed
-.I anything
-in the diversion.
-.I anything
-is read in copy mode.
-When the diversion is reread,
-.I anything
-will be interpreted.
-.I anything
-may not contain newlines; use
-.B \e!\&
-if you want to embed newlines in a diversion.
-The escape sequence
-.B \e?\&
-is also recognised in copy mode and turned into a single internal
-code; it is this code that terminates
-.IR anything .
-Thus
-.RS
-.RS
-.ft B
-.nf
-.ne 15
-\&.nr x 1
-\&.nf
-\&.di d
-\e?\e\e?\e\e\e\e?\e\e\e\e\e\e\e\enx\e\e\e\e?\e\e?\e?
-\&.di
-\&.nr x 2
-\&.di e
-\&.d
-\&.di
-\&.nr x 3
-\&.di f
-\&.e
-\&.di
-\&.nr x 4
-\&.f
-.fi
-.ft
-.RE
-.RE
-.IP
-will print
-.BR 4 .
-.TP
-.B \e/
-This increases the width of the preceding character so that
-the spacing between that character and the following character
-will be correct if the following character is a roman character.
-For example, if an italic f is immediately followed by a roman
-right parenthesis, then in many fonts the top right portion of the f
-will overlap the top left of the right parenthesis producing \fIf\fR)\fR,
-which is ugly.
-Inserting
-.B \e/
-produces
-.ie \n(.g \fIf\/\fR)\fR
-.el \fIf\|\fR)\fR
-and avoids this problem.
-It is a good idea to use this escape sequence whenever an
-italic character is immediately followed by a roman character without any
-intervening space.
-.TP
-.B \e,
-This modifies the spacing of the following character so that the spacing
-between that character and the preceding character will correct if
-the preceding character is a roman character.
-For example, inserting
-.B \e,
-between the parenthesis and the f changes
-\fR(\fIf\fR to
-.ie \n(.g \fR(\,\fIf\fR.
-.el \fR(\^\fIf\fR.
-It is a good idea to use this escape sequence whenever a
-roman character is immediately followed by an italic character without any
-intervening space.
-.TP
-.B \e)
-Like
-.B \e&
-except that it behaves like a character declared with the
-.B cflags
-request to be transparent for the purposes of end of sentence recognition.
-.TP
-.B \e~
-This produces an unbreakable space that stretches like a normal inter-word
-space when a line is adjusted.
-.TP
-.B \e:
-This causes the insertion of a zero-width break point.
-It is equal to
-.B \e%
-but without insertion of a soft hyphen character.
-.TP
-.B \e#
-Everything up to and including the next newline is ignored.
-This is interpreted in copy mode.
-This is like
-.B \e"
-except that
-.B \e"
-does not ignore the terminating newline.
-.
-.SS New requests
+.B \-v
+Print the version number.
.
.TP
-.BI .aln\ xx\ yy
-Create an alias
-.I xx
-for number register object named
-.IR yy .
-The new name and the old name will be exactly equivalent.
-If
-.I yy
-is undefined, a warning of type
-.B reg
-will be generated, and the request will be ignored.
-.TP
-.BI .als\ xx\ yy
-Create an alias
-.I xx
-for request, string, macro, or diversion object named
-.IR yy .
-The new name and the old name will be exactly equivalent (it is similar to a
-hard rather than a soft link).
-If
-.I yy
-is undefined, a warning of type
-.B mac
-will be generated, and the request will be ignored.
-The
-.BR de ,
-.BR am ,
-.BR di ,
-.BR da ,
-.BR ds ,
-and
-.B as
-requests only create a new object if the name of the macro, diversion
-or string diversion is currently undefined or if it is defined to be a
-request; normally they modify the value of an existing object.
-.TP
-.BI .am1\ xx\ yy
-Similar to
-.BR .am ,
-but compatibility mode is switched off during execution.
-On entry, the current compatibility mode is saved and restored at exit.
-.TP
-.BI .asciify\ xx
-This request `unformats' the diversion
-.I xx
-in such a way that
-.SM ASCII
-and space characters (and some escape sequences) that were formatted and
-diverted into
-.I xx
-will be treated like ordinary input characters when
-.I xx
-is reread.
-Useful for diversions in conjunction with the
-.B .writem
-request.
-It can be also used for gross hacks; for example, this
-.RS
-.IP
-.ne 7v+\n(.Vu
-.ft B
-.nf
-\&.tr @.
-\&.di x
-\&@nr n 1
-\&.br
-\&.di
-\&.tr @@
-\&.asciify x
-\&.x
-.fi
-.RE
-.IP
-will set register
-.B n
-to 1.
-Note that glyph information (font, font size, etc.) is not preserved; use
-.B .unformat
-instead.
-.TP
-.B .backtrace
-Print a backtrace of the input stack on stderr.
-.TP
-.BI .blm\ xx
-Set the blank line macro to
-.IR xx .
-If there is a blank line macro,
-it will be invoked when a blank line is encountered instead of the usual
-troff behaviour.
-.TP
-.BI .box\ xx
-.TQ
-.BI .boxa\ xx
-These requests are similar to the
-.B di
-and
-.B da
-requests with the exception that a partially filled line will not become
-part of the diversion (i.e., the diversion always starts with a new line)
-but restored after ending the diversion, discarding the partially filled
-line which possibly comes from the diversion.
-.TP
-.B .break
-Break out of a while loop.
-See also the
-.B while
-and
-.B continue
-requests.
-Be sure not to confuse this with the
-.B br
-request.
-.TP
-.B .brp
-This is the same as
-.BR \ep .
-.TP
-.BI .cflags\ n\ c1\ c2\|.\|.\|.
-Characters
-.IR c1 ,
-.IR c2 ,\|.\|.\|.
-have properties determined by
-.IR n ,
-which is ORed from the following:
-.RS
-.TP
-1
-the character ends sentences
-(initially characters
-.B .?!\&
-have this property);
-.TP
-2
-lines can be broken before the character
-(initially no characters have this property);
-a line will not be broken at a character with this property
-unless the characters on each side both have non-zero
-hyphenation codes.
-.TP
-4
-lines can be broken after the character
-(initially characters
-.B \-\e(hy\e(em
-have this property);
-a line will not be broken at a character with this property
-unless the characters on each side both have non-zero
-hyphenation codes.
-.TP
-8
-the character overlaps horizontally
-(initially characters
-.B \e(ul\e(rn\e(ru
-have this property);
-.TP
-16
-the character overlaps vertically
-(initially character
-.B \e(br
-has this property);
-.TP
-32
-an end of sentence character followed by any number of characters
-with this property will be treated
-as the end of a sentence if followed by a newline or two spaces;
-in other words
-the character is transparent for the purposes of end of sentence
-recognition;
-this is the same as having a zero space factor in \*(tx
-(initially characters
-.B \(ts')]*\e(dg\e(rq
-have this property).
-.RE
-.TP
-.BI .char\ c\ string
-Define character
-.I c
-to be
-.IR string .
-Every time character
-.I c
-needs to be printed,
-.I string
-will be processed in a temporary environment and the result
-will be wrapped up into a single object.
-Compatibility mode will be turned off
-and the escape character will be set to
-.B \e
-while
-.I string
-is being processed.
-Any emboldening, constant spacing or track kerning will be applied
-to this object rather than to individual characters in
-.IR string .
-A character defined by this request can be used just like
-a normal character provided by the output device.
-In particular other characters can be translated to it
-with the
-.B tr
-request;
-it can be made the leader character by the
-.B lc
-request;
-repeated patterns can be drawn with the character using the
-.B \el
-and
-.B \eL
-escape sequences;
-words containing the character can be hyphenated
-correctly, if the
-.B hcode
-request is used to give the character a hyphenation code.
-There is a special anti-recursion feature:
-use of character within the character's definition
-will be handled like normal characters not defined with
-.BR char .
-A character definition can be removed with the
-.B rchar
-request.
-.TP
-.BI .chop\ xx
-Chop the last character off macro, string, or diversion
-.IR xx .
-This is useful for removing the newline from the end of diversions
-that are to be interpolated as strings.
-.TP
-.BI .close\ stream
-Close the stream named
-.IR stream ;
-.I stream
-will no longer be an acceptable argument to the
-.B write
-request.
-See the
-.B open
-request.
-.TP
-.B .continue
-Finish the current iteration of a while loop.
-See also the
-.B while
-and
-.B break
-requests.
-.TP
-.BI .cp\ n
-If
-.I n
-is non-zero or missing, enable compatibility mode, otherwise
-disable it.
-In compatibility mode, long names are not recognised, and the
-incompatibilities caused by long names do not arise.
-.TP
-.BI .dei\ xx\ yy
-Define macro indirectly.
-The following example
-.RS
-.IP
-.ne 2v+\n(.Vu
-.ft B
-.nf
-\&.ds xx aa
-\&.ds yy bb
-\&.dei xx yy
-.fi
-.RE
-.IP
-is equivalent to
-.RS
-.IP
-.B
-\&.de aa bb
-.RE
-.TP
-.BI .de1\ xx\ yy
-Similar to
-.BR .de ,
-but compatibility mode is switched off during execution.
-On entry, the current compatibility mode is saved and restored at exit.
-.TP
-.BI .do\ xxx
-Interpret
-.I .xxx
-with compatibility mode disabled.
-For example,
-.RS
-.IP
-.B
-\&.do fam T
-.LP
-would have the same effect as
-.IP
-.B
-\&.fam T
-.LP
-except that it would work even if compatibility mode had been enabled.
-Note that the previous compatibility mode is restored before any files
-sourced by
-.I xxx
-are interpreted.
-.RE
-.TP
-.B .ecs
-Save current escape character.
-.TP
-.B .ecr
-Restore escape character saved with
-.BR ecs .
-Without a previous call to
-.BR ecs ,
-.RB ` \e '
-will be the new escape character.
-.TP
-.BI .evc\ xx
-Copy the contents of environment
-.I xx
-to the current environment.
-No pushing or popping of environents will be done.
-.TP
-.BI .fam\ xx
-Set the current font family to
-.IR xx .
-The current font family is part of the current environment.
-If
-.I xx
-is missing, switch back to previous font family.
-See the description of the
-.B sty
-request for more information on font families.
-.TP
-.BI .fspecial\ f\ s1\ s2\|.\|.\|.
-When the current font is
-.IR f ,
-fonts
-.IR s1 ,
-.IR s2 ,\|.\|.\|.
-will be special, that is, they will searched for characters not in
-the current font.
-Any fonts specified in the
-.B special
-request will be searched after fonts specified in the
-.B fspecial
-request.
-.TP
-.BI .ftr\ f\ g
-Translate font
-.I f
-to
-.IR g .
-Whenever a font named
-.I f
-is referred to in
-.B \ef
-escape sequence,
-or in the
-.BR ft ,
-.BR ul ,
-.BR bd ,
-.BR cs ,
-.BR tkf ,
-.BR special ,
-.BR fspecial ,
-.BR fp ,
-or
-.BR sty
-requests,
-font
-.I g
-will be used.
-If
-.I g
-is missing,
-or equal to
-.I f
-then font
-.I f
-will not be translated.
-.TP
-.BI .hcode \ c1\ code1\ c2\ code2\|.\|.\|.
-Set the hyphenation code of character
-.I c1
-to
-.I code1
-and that of
-.I c2
-to
-.IR code2 .
-A hyphenation code must be a single input
-character (not a special character) other than a digit or a space.
-Initially each lower-case letter has a hyphenation code, which
-is itself, and each upper-case letter has a hyphenation code
-which is the lower case version of itself.
-See also the
-.B hpf
-request.
-.TP
-.BI .hla\ lang
-Set the current hyphenation language to
-.IR lang .
-Hyphenation exceptions specified with the
-.B hw
-request and hyphenation patterns specified with the
-.B hpf
-request are both associated with the current hyphenation language.
-The
-.B hla
-request is usually invoked by the
-.B troffrc
-file.
-.TP
-.BI .hlm\ n
-Set the maximum number of consecutive hyphenated lines to
-.IR n .
-If
-.I n
-is negative, there is no maximum.
-The default value is \-1.
-This value is associated with the current environment.
-Only lines output from an environment count towards the maximum associated
-with that environment.
-Hyphens resulting from
-.B \e%
-are counted; explicit hyphens are not.
-.TP
-.BI .hpf\ file
-Read hyphenation patterns from
-.IR file ;
-this will be searched for in the same way that
-.IB name .tmac
-is searched for when the
-.BI \-m name
-option is specified.
-It should have the same format as the argument to
-the \epatterns primitive in \*(tx;
-the letters appearing in this file are interpreted as hyphenation
-codes.
-A
-.B %
-character in the patterns file introduces a comment that continues
-to the end of the line.
-The set of hyphenation patterns is associated with the current language
-set by the
-.B hla
-request.
-The
-.B hpf
-request
-is usually invoked by the
-.B troffrc
-file.
-.TP
-.BI .hym\ n
-Set the
-.I hyphenation margin
-to
-.IR n :
-when the current adjustment mode is not
-.BR b ,
-the line will not be hyphenated if the line is no more than
-.I n
-short.
-The default hyphenation margin is 0.
-The default scaling indicator for this request is
-.IR m .
-The hyphenation margin is associated with the current environment.
-The current hyphenation margin is available in the
-.B \en[.hym]
-register.
-.TP
-.BI .hys\ n
-Set the
-.I hyphenation space
-to
-.IR n :
-when the current adjustment mode is
-.B b
-don't hyphenate the line if the line can be justified by adding no more than
-.I n
-extra space to each word space.
-The default hyphenation space is 0.
-The default scaling indicator for this request is
-.BR m .
-The hyphenation space is associated with the current environment.
-The current hyphenation space is available in the
-.B \en[.hys]
-register.
-.TP
-.BI .kern\ n
-If
-.I n
-is non-zero or missing, enable pairwise kerning, otherwise disable it.
-.TP
-.BI .length\ xx\ string
-Compute the length of
-.I string
-and return it in the number register
-.I xx
-(which is not necessarily defined before).
-.TP
-.BI .linetabs\ n
-If
-.I n
-is non-zero or missing, enable line-tabs mode, otherwise disable it (which
-is the default).
-In line-tabs mode, tab distances are computed relative to the (current)
-output line.
-Otherwise they are taken relative to the input line.
-For example, the following
-.RS
-.IP
-.ne 6v+\n(.Vu
-.ft B
-.nf
-\&.ds x a\et\ec
-\&.ds y b\et\ec
-\&.ds z c
-\&.ta 1i 3i
-\e*x
-\e*y
-\e*z
-.fi
-.RE
-.IP
-yields
-.RS
-.IP
-a b c
-.RE
-.IP
-In line-tabs mode, the same code gives
-.RS
-.IP
-a b c
-.RE
-.IP
-Line-tabs mode is associated with the current environment; the read-only
-number register
-.B \\en[.linetabs]
-is set to\~1 if in line-tabs mode, and 0 otherwise.
-.TP
-.BI .mso\ file
-The same as the
-.B so
-request except that
-.I file
-is searched for in the same directories as macro files for the
-the
-.B \-m
-command line option.
-If the file name to be included
-has the form
-.IB name .tmac
-and it isn't found,
-.B mso
-tries to include
-.BI tmac. name
-instead and vice versa.
-.TP
-.BI .nop \ anything
-Execute
-.IR anything .
-This is similar to `.if\ 1'.
-.TP
-.B .nroff
-Make the
-.B n
-built-in condition true
-and the
-.B t
-built-in condition false.
-This can be reversed using the
-.B troff
-request.
-.TP
-.BI .open\ stream\ filename
-Open
-.I filename
-for writing and associate the stream named
-.I stream
-with it.
-See also the
-.B close
-and
-.B write
-requests.
-.TP
-.BI .opena\ stream\ filename
-Like
-.BR open ,
-but if
-.I filename
-exists, append to it instead of truncating it.
-.TP
-.B .pnr
-Print the names and contents of all currently defined number registers
-on stderr.
-.TP
-.BI .psbb \ filename
-Get the bounding box of a PostScript image
-.IR filename .
-This file must conform to Adobe's Document Structuring Conventions; the
-command looks for a
-.B %%BoundingBox
-comment to extract the bounding box values.
-After a successful call, the coordinates (in PostScript units) of the lower
-left and upper right corner can be found in the registers
-.BR \en[llx] ,
-.BR \en[lly] ,
-.BR \en[urx] ,
-and
-.BR \en[ury] ,
-respectively.
-If some error has occurred, the four registers are set to zero.
-.TP
-.BI .pso \ command
-This behaves like the
-.B so
-request except that input comes from the standard output of
-.IR command .
-.TP
-.B .ptr
-Print the names and positions of all traps (not including input line
-traps and diversion traps) on stderr. Empty slots in the page trap
-list are printed as well, because they can affect the priority of
-subsequently planted traps.
-.TP
-.BI .rchar\ c1\ c2\|.\|.\|.
-Remove the definitions of characters
-.IR c1 ,
-.IR c2 ,\|.\|.\|.
-This undoes the effect of a
-.B char
-request.
-.TP
-.B .return
-Within a macro, return immediately.
-No effect otherwise.
-.TP
-.B .rj
-.TQ
-.BI .rj\ n
-Right justify the next
-.I n
-input lines.
-Without an argument right justify the next input line.
-The number of lines to be right justified is available in the
-.B \en[.rj]
-register.
-This implicitly does
-.BR .ce\ 0 .
-The
-.B ce
-request implicitly does
-.BR .rj\ 0 .
-.TP
-.BI .rnn \ xx\ yy
-Rename number register
-.I xx
-to
-.IR yy .
-.TP
-.BI .shc\ c
-Set the soft hyphen character to
-.IR c .
-If
-.I c
-is omitted,
-the soft hyphen character will be set to the default
-.BR \e(hy .
-The soft hyphen character is the character which will be inserted
-when a word is hyphenated at a line break.
-If the soft hyphen character does not exist in the font of the character
-immediately preceding a potential break point,
-then the line will not be broken at that point.
-Neither definitions (specified with the
-.B char
-request)
-nor translations (specified with the
-.B tr
-request)
-are considered when finding the soft hyphen character.
-.TP
-.BI .shift\ n
-In a macro, shift the arguments by
-.I n
-positions:
-argument
-.I i
-becomes argument
-.IR i \- n ;
-arguments 1 to
-.I n
-will no longer be available.
-If
-.I n
-is missing,
-arguments will be shifted by 1.
-Shifting by negative amounts is currently undefined.
-.TP
-.BI .special\ s1\ s2\|.\|.\|.
-Fonts
-.IR s1 ,
-.IR s2 ,
-are special and will be searched for characters not in the
-current font.
-.TP
-.BI .sty\ n\ f
-Associate style
-.I f
-with font position
-.IR n .
-A font position can be associated either with a font or
-with a style.
-The current font is the index of a font position and so is also
-either a font or a style.
-When it is a style, the font that is actually used is the font the
-name of which is the concatenation of the name of the current family
-and the name of the current style.
-For example, if the current font is 1 and font position 1 is
-associated with style
-.B R
-and the current
-font family is
-.BR T ,
-then font
-.BR TR
-will be used.
-If the current font is not a style, then the current family is ignored.
-When the requests
-.BR cs ,
-.BR bd ,
-.BR tkf ,
-.BR uf ,
-or
-.B fspecial
-are applied to a style,
-then they will instead be applied to the member of the
-current family corresponding to that style.
-The default family can be set with the
-.B \-f
-option.
-The styles command in the
-.SM DESC
-file controls which font positions
-(if any) are initially associated with styles rather than fonts.
-.TP
-.BI .substring\ xx\ n1\ [ n2 ]
-Replace the string in register
-.I xx
-with the substring defined by the indices
-.I n1
-and
-.IR n2 .
-The first character in the string has index one.
-If
-.I n2
-is omitted, it is taken to be equal to the string's length. If the
-index value
-.I n1
-or
-.I n2
-is negative or zero, it will be counted from the end of the string,
-going backwards: The last character has index 0, the character before
-the last character has index -1, etc.
-.TP
-.BI .tkf\ f\ s1\ n1\ s2\ n2
-Enable track kerning for font
-.IR f .
-When the current font is
-.I f
-the width of every character will be increased by an amount
-between
-.I n1
-and
-.IR n2 ;
-when the current point size is less than or equal to
-.I s1
-the width will be increased by
-.IR n1 ;
-when it is greater than or equal to
-.I s2
-the width will be increased by
-.IR n2 ;
-when the point size is greater than or equal to
-.I s1
-and less than or equal to
-.I s2
-the increase in width is a linear function of the point size.
-.TP
-.BI .tm1\ string
-Similar to the
-.B tm
-request,
-.I string
-is read in copy mode and written on the standard error, but an initial
-double quote in
-.I string
-is stripped off to allow initial blanks.
-.TP
-.BI .tmc\ string
-Similar to
-.BR tm1
-but without writing a final newline.
-.TP
-.BI .trf\ filename
-Transparently output the contents of file
-.IR filename .
-Each line is output as it would be were it preceded by
-.BR \e! ;
-however, the lines are not subject to copy-mode interpretation.
-If the file does not end with a newline, then a newline will
-be added.
-For example, you can define a macro
-.I x
-containing the contents of file
-.IR f ,
-using
-.RS
-.IP
-.BI .di\ x
-.br
-.BI .trf\ f
-.br
-.B .di
-.LP
-Unlike with the
-.B cf
-request,
-the file cannot contain characters such as
-.SM NUL
-that are not legal troff input characters.
-.RE
-.TP
-.B .trnt abcd
-This is the same as the
-.B tr
-request except that the translations do not apply to text that is
-transparently throughput into a diversion with
-.BR \e! .
-For example,
-.RS
-.IP
-.nf
-.ft B
-\&.tr ab
-\&.di x
-\e!.tm a
-\&.di
-\&.x
-.fi
-.ft
-.LP
-will print
-.BR b ;
-if
-.B trnt
-is used instead of
-.B tr
-it will print
-.BR a .
-.RE
-.TP
-.B .troff
-Make the
-.B n
-built-in condition false,
-and the
-.B t
-built-in condition true.
-This undoes the effect of the
-.B nroff
-request.
-.TP
-.BI .unformat\ xx
-This request `unformats' the diversion
-.IR xx .
-Contrary to the
-.B .asciify
-request, which tries to convert formatted elements of the diversion back
-to input tokens as much as possible,
-.B .unformat
-will only handle tabs and spaces between words (usually caused by spaces
-or newlines in the input) specially.
-The former are treated as if they were input tokens, and the latter are
-stretchable again.
-Note that the vertical size of lines is not preserved.
-Glyph information (font, font size, space width, etc.) is retained.
-Useful in conjunction with the
-.B .box
-and
-.B .boxa
-requests.
-.TP
-.BI .vpt\ n
-Enable vertical position traps if
-.I n
-is non-zero, disable them otherwise.
-Vertical position traps are traps set by the
-.B wh
-or
-.B dt
-requests.
-Traps set by the
-.B it
-request are not vertical position traps.
-The parameter that controls whether vertical position traps are enabled
-is global.
-Initially vertical position traps are enabled.
-.TP
-.BI .warn\ n
-Control warnings.
-.I n
-is the sum of the numbers associated with each warning that is to be enabled;
-all other warnings will be disabled.
-The number associated with each warning is listed in the `Warnings' section.
-For example,
-.B .warn 0
-will disable all warnings, and
-.B .warn 1
-will disable all warnings except that about missing characters.
-If
-.I n
-is not given,
-all warnings will be enabled.
-.TP
-.BI .while \ c\ anything
-While condition
-.I c
-is true, accept
-.I anything
-as input;
-.I c
-can be any condition acceptable to an
-.B if
-request;
-.I anything
-can comprise multiple lines if the first line starts with
-.B \e{
-and the last line ends with
-.BR \e} .
-See also the
-.B break
-and
-.B continue
-requests.
-.TP
-.BI .write\ stream\ anything
-Write
-.I anything
-to the stream named
-.IR stream .
-.I stream
-must previously have been the subject of an
-.B open
-request.
-.I anything
-is read in copy mode;
-a leading
-.B \(ts
-will be stripped.
-.TP
-.BI .writem\ stream\ xx
-Write the contents of the macro or string
-.I xx
-to the stream named
-.IR stream .
-.I stream
-must previously have been the subject of an
-.B open
-request.
-.I xx
-is read in copy mode.
+.BI \-w name
+Enable warning
+.IR name .
+Available warnings are described in the section
+.I WARNINGS
+below.
.
-.SS Extended requests
+For example, to enable all warnings, use
+.B \-w
+.BR all .
+Multiple
+.B \-w
+options are allowed.
.
.TP
-.BI .cf\ filename
-When used in a diversion, this will embed in the diversion an object which,
-when reread, will cause the contents of
-.I filename
-to be transparently copied through to the output.
-In UNIX troff, the
-contents of
-.I filename
-is immediately copied through to the output regardless of whether
-there is a current diversion; this behaviour is so anomalous that it
-must be considered a bug.
-.TP
-.BI .ev\ xx
-If
-.I xx
-is not a number, this will switch to a named environment called
-.IR xx .
-The environment should be popped with a matching
-.B ev
-request without any arguments, just as for numbered environments.
-There is no limit on the number of named environments; they will be
-created the first time that they are referenced.
-.TP
-.BI .fp\ n\ f1\ f2
-The
-.B fp
-request has an optional third argument.
-This argument gives the external name of the font,
-which is used for finding the font description file.
-The second argument gives the internal name of the font
-which is used to refer to the font in troff after it has been mounted.
-If there is no third argument then the internal name will be used
-as the external name.
-This feature allows you to use fonts with long names in compatibility mode.
-.TP
-.BI .ss\ m\ n
-When two arguments are given to the
-.B ss
-request, the second argument gives the
-.IR "sentence space size" .
-If the second argument is not given, the sentence space size
-will be the same as the word space size.
-Like the word space size, the sentence space is in units of
-one twelfth of the spacewidth parameter for the current font.
-Initially both the word space size and the sentence
-space size are 12.
-Contrary to UNIX troff, GNU troff handles this request in nroff mode
-also; a given value is then rounded down to the nearest multiple of\~12.
-The sentence space size is used in two circumstances:
-if the end of a sentence occurs at the end of a line in fill mode, then
-both an inter-word space and a sentence space will be added;
-if two spaces follow the end of a sentence in the middle of a line,
-then the second space will be a sentence space.
-Note that the behaviour of UNIX troff will be exactly
-that exhibited by GNU troff if a second argument is never given to the
-.B ss
-request.
-In GNU troff, as in UNIX troff, you should always
-follow a sentence with either a newline or two spaces.
-.TP
-.BI .ta\ n1\ n2\|.\|.\|.nn \ T\ r1\ r2\|.\|.\|.\|rn
-Set tabs at positions
-.IR n1 ,
-.IR n2 ,\|.\|.\|.\|,
-.I nn
-and then set tabs at
-.IR nn + r1 ,
-.IR nn + r2 ,\|.\|.\|.\|.\|,
-.IR nn + rn
-and then at
-.IR nn + rn + r1 ,
-.IR nn + rn + r2 ,\|.\|.\|.\|,
-.IR nn + rn + rn ,
-and so on.
-For example,
-.RS
-.IP
-.B
-\&.ta T .5i
-.LP
-will set tabs every half an inch.
-.RE
-.
-.SS New number registers
+.BI \-W name
+Inhibit warning
+.IR name .
+Multiple
+.B \-W
+options are allowed.
.
-The following read-only registers are available:
-.TP
-.B \en[.C]
-1 if compatibility mode is in effect, 0 otherwise.
-.TP
-.B \en[.cdp]
-The depth of the last character added to the current environment.
-It is positive if the character extends below the baseline.
-.TP
-.B \en[.ce]
-The number of lines remaining to be centered, as set by the
-.B ce
-request.
-.TP
-.B \en[.cht]
-The height of the last character added to the current environment.
-It is positive if the character extends above the baseline.
-.TP
-.B \en[.csk]
-The skew of the last character added to the current environment.
-The
-.I skew
-of a character is how far to the right of the center of a character
-the center of an accent over that character should be placed.
-.TP
-.B \en[.ev]
-The name or number of the current environment.
-This is a string-valued register.
-.TP
-.B \en[.fam]
-The current font family.
-This is a string-valued register.
-.TP
-.B \en[.fp]
-The number of the next free font position.
-.TP
-.B \en[.g]
-Always 1.
-Macros should use this to determine whether they are running
-under GNU troff.
-.TP
-.B \en[.hla]
-The current hyphenation language as set by the
-.B hla
-request.
-.TP
-.B \en[.hlc]
-The number of immediately preceding consecutive hyphenated lines.
-.TP
-.B \en[.hlm]
-The maximum allowed number of consecutive hyphenated lines, as set by the
-.B hlm
-request.
-.TP
-.B \en[.hy]
-The current hyphenation flags (as set by the
-.B hy
-request).
-.TP
-.B \en[.hym]
-The current hyphenation margin (as set by the
-.B hym
-request).
-.TP
-.B \en[.hys]
-The current hyphenation space (as set by the
-.B hys
-request).
-.TP
-.B \en[.in]
-The indent that applies to the current output line.
-.TP
-.B \en[.int]
-Set to a positive value if last output line is interrupted (i.e., if it
-contains
-.IR \ec ).
-.TP
-.B \en[.kern]
-.B 1
-if pairwise kerning is enabled,
-.B 0
-otherwise.
-.TP
-.B \en[.lg]
-The current ligature mode (as set by the
-.B lg
-request).
-.TP
-.B \en[.linetabs]
-The current line-tabs mode (as set by the
-.B linetabs
-request).
-.TP
-.B \en[.ll]
-The line length that applies to the current output line.
-.TP
-.B \en[.lt]
-The title length as set by the
-.B lt
-request.
-.TP
-.B \en[.ne]
-The amount of space that was needed in the last
-.B ne
-request that caused a trap to be sprung.
-Useful in conjunction with the
-.B \en[.trunc]
-register.
-.TP
-.B \en[.ns]
-.B 1
-if no-space mode is active,
-.B 0
-otherwise.
-.TP
-.B \en[.pn]
-The number of the next page:
-either the value set by a
-.B pn
-request, or the number of the current page plus 1.
-.TP
-.B \en[.ps]
-The current pointsize in scaled points.
-.TP
-.B \en[.psr]
-The last-requested pointsize in scaled points.
-.TP
-.B \en[.rj]
-The number of lines to be right-justified as set by the
-.B rj
-request.
-.TP
-.B \en[.sr]
-The last requested pointsize in points as a decimal fraction.
-This is a string-valued register.
-.TP
-.B \en[.tabs]
-A string representation of the current tab settings suitable for use as
-an argument to the
-.B ta
-request.
-.TP
-.B \en[.trunc]
-The amount of vertical space truncated by the most recently sprung
-vertical position trap, or,
-if the trap was sprung by a
-.B ne
-request,
-minus the amount of vertical motion produced by the
-.B ne
-request.
-In other words, at the point a trap is sprung, it represents the difference
-of what the vertical position would have been but for the trap,
-and what the vertical position actually is.
-Useful in conjunction with the
-.B \en[.ne]
-register.
-.TP
-.B \en[.ss]
-.TQ
-.B \en[.sss]
-These give the values of the parameters set by the
-first and second arguments of the
-.B ss
-request.
-.TP
-.B \en[.vpt]
-1 if vertical position traps are enabled, 0 otherwise.
-.TP
-.B \en[.warn]
-The sum of the numbers associated with each of the currently enabled
-warnings.
-The number associated with each warning is listed in the `Warnings'
-subsection.
-.TP
-.B \en[.x]
-The major version number.
-For example, if the version number is
-.B 1.03
-then
-.B \en[.x]
-will contain
-.BR 1 .
-.TP
-.B \en[.y]
-The minor version number.
-For example, if the version number is
-.B 1.03
-then
-.B \en[.y]
-will contain
-.BR 03 .
-.TP
-.B \en[.Y]
-The revision number of groff.
-.TP
-.B \en[llx]
-.TQ
-.B \en[lly]
-.TQ
-.B \en[urx]
-.TQ
-.B \en[ury]
-These four registers are set by the
-.B \&.psbb
-request and contain the bounding box values (in PostScript units) of a given
-PostScript image.
-.LP
-The following read/write registers are set by the
-.B \ew
-escape sequence:
-.TP
-.B \en[rst]
-.TQ
-.B \en[rsb]
-Like the
-.B st
-and
-.B sb
-registers, but takes account of the heights and depths of characters.
-.TP
-.B \en[ssc]
-The amount of horizontal space (possibly negative) that should
-be added to the last character before a subscript.
-.TP
-.B \en[skw]
-How far to right of the center of the last character
-in the
-.B \ew
-argument,
-the center of an accent from a roman font should be placed over that character.
-.LP
-Other available read/write number registers are:
-.TP
-.B \en[c.]
-The current input line number.
-.B \en[.c]
-is a read-only alias to this register.
.TP
-.B \en[hp]
-The current horizontal position at input line.
-.TP
-.B \en[systat]
-The return value of the system() function executed by the last
-.B sy
-request.
-.TP
-.B \en[slimit]
-If greater than 0, the maximum number of objects on the input stack.
-If less than or equal to 0, there is no limit on the number of objects
-on the input stack. With no limit, recursion can continue until
-virtual memory is exhausted.
-.TP
-.B \en[year]
-The current year.
-Note that the traditional
-.B troff
-number register
-.B \en[yr]
-is the current year minus 1900.
-.
-.SS Miscellaneous
+.B \-z
+Suppress formatted output.
.
-.B @g@troff
-predefines a single (read/write) string-based register,
-.BR \e*(.T ,
-which contains the argument given to the
-.B -T
-command line option, namely the current output device (for example,
-.I latin1
-or
-.IR ascii ).
-Note that this is not the same as the (read-only) number register
-.B \en[.T]
-which is defined to be\ 1 if
-.B troff
-is called with the
-.B -T
-command line option, and zero otherwise. This behaviour is different to
-UNIX troff.
-.LP
-Fonts not listed in the
-.SM DESC
-file are automatically mounted on the next available font position
-when they are referenced.
-If a font is to be mounted explicitly with the
-.B fp
-request on an unused font position,
-it should be mounted on the first unused font position,
-which can be found in the
-.B \en[.fp]
-register;
-although
-.B troff
-does not enforce this strictly,
-it will not allow a font to be mounted at a position whose number is much
-greater than that of any currently used position.
-.LP
-Interpolating a string does not hide existing macro arguments.
-Thus in a macro, a more efficient way of doing
-.IP
-.BI . xx\ \e\e$@
-.LP
-is
-.IP
-.BI \e\e*[ xx ]\e\e
-.LP
-If the font description file contains pairwise kerning information,
-characters from that font will be kerned.
-Kerning between two characters can be inhibited by placing a
-.B \e&
-between them.
-.LP
-In a string comparison in a condition,
-characters that appear at different input levels
-to the first delimiter character will not be recognised
-as the second or third delimiters.
-This applies also to the
-.B tl
-request.
-In a
-.B \ew
-escape sequence,
-a character that appears at a different input level to
-the starting delimiter character will not be recognised
-as the closing delimiter character.
-When decoding a macro argument that is delimited
-by double quotes, a character that appears at a different
-input level to the starting delimiter character will not
-be recognised as the closing delimiter character.
-The implementation of
-.B \e$@
-ensures that the double quotes surrounding an argument
-will appear the same input level, which will be different
-to the input level of the argument itself.
-In a long escape name
-.B ]
-will not be recognized as a closing delimiter except
-when it occurs at the same input level as the opening
-.BR ] .
-In compatibility mode, no attention is paid to the input-level.
-.LP
-There are some new types of condition:
-.TP
-.BI .if\ r xxx
-True if there is a number register named
-.IR xxx .
-.TP
-.BI .if\ d xxx
-True if there is a string, macro, diversion, or request named
-.IR xxx .
-.TP
-.BI .if\ c ch
-True if there is a character
-.IR ch
-available;
-.I ch
-is either an
-.SM ASCII
-character
-or a special character
-.BI \e( xx
-or
-.BI \e[ xxx ]\fR;
-the condition will also be true if
-.I ch
-has been defined by the
-.B char
-request.
-.LP
-The
-.B tr
-request can now map characters onto
-.BR \e~ .
.
-.SS Warnings
+.\" --------------------------------------------------------------------
+.SH WARNINGS
+.\" --------------------------------------------------------------------
.
The warnings that can be given by
-.B troff
+.B @g@troff
are divided into the following categories.
+.
The name associated with each warning is used by the
.B \-w
and
.B \-W
-options;
-the number is used by the
+options; the number is used by the
.B warn
request, and by the
.B .warn
-register.
-.nr x \w'\fBright-brace'+1n+\w'0000'u
+register; it is always a power of 2 to allow bitwise composition.
+.
+.P
+.TS
+tab(@), center, box;
+c c c | c c c
+r rI lB | r rI lB.
+Bit@Code@Warning@Bit@Code@Warning
+_
+0@1@char@10@1024@reg
+1@2@number@11@2048@tab
+2@4@break@12@4096@right-brace
+3@8@delim@13@8192@missing
+4@16@el@14@16384@input
+5@32@scale@15@32768@escape
+6@64@range@16@65536@space
+7@128@syntax@17@131072@font
+8@256@di@18@262144@ig
+9@512@mac@19@524288@color
+.TE
+.
+.P
+.nr x \w'\fBright-brace'+1n+\w'00000'u
.ta \nxuR
+.
.TP \nxu+3n
-.BR char \t1
-Non-existent characters.
+.BR break "\t4"
+In fill mode, lines which could not be broken so that their length was
+less than the line length.
+.
This is enabled by default.
+.
.TP
-.BR number \t2
-Invalid numeric expressions.
+.BR char "\t1"
+Non-existent characters.
+.
This is enabled by default.
+.
.TP
-.BR break \t4
-In fill mode, lines which could not be broken so that their length was
-less than the line length.
-This is enabled by default.
+.BR color "\t524288"
+Color related warnings.
+.
.TP
-.BR delim \t8
+.BR delim "\t8"
Missing or mismatched closing delimiters.
+.
+.TP
+.BR di "\t256"
+Use of
+.B di
+or
+.B da
+without an argument when there is no current diversion.
+.
.TP
-.BR el \t16
+.BR el "\t16"
Use of the
.B el
request with no matching
.B ie
request.
+.
.TP
-.BR scale \t32
-Meaningless scaling indicators.
+.BR escape "\t32768"
+Unrecognized escape sequences.
+.
+When an unrecognized escape sequence is encountered, the escape
+character is ignored.
+.
.TP
-.BR range \t64
-Out of range arguments.
+.BR font "\t131072"
+Non-existent fonts.
+.
+This is enabled by default.
+.
.TP
-.BR syntax \t128
-Dubious syntax in numeric expressions.
+.BR ig "\t262144"
+Invalid escapes in text ignored with the
+.B ig
+request.
+.
+These are conditions that are errors when they do not occur in ignored
+text.
+.
.TP
-.BR di \t256
-Use of
-.B di
-or
-.B da
-without an argument when there is no current diversion.
+.BR input "\t16384"
+Invalid input characters.
+.
.TP
-.BR mac \t512
+.BR mac "\t512"
Use of undefined strings, macros and diversions.
-When an undefined string, macro or diversion is used,
-that string is automatically defined as empty.
-So, in most cases, at most one warning will be given for
-each name.
+.
+When an undefined string, macro or diversion is used, that string is
+automatically defined as empty.
+.
+So, in most cases, at most one warning will be given for each name.
+.
.TP
-.BR reg \t1024
-Use of undefined number registers.
-When an undefined number register is used,
-that register is automatically defined to have a value of 0.
-a definition is automatically made with a value of 0.
-So, in most cases, at most one warning will be given for
-use of a particular name.
+.BR missing "\t8192"
+Requests that are missing non-optional arguments.
+.
.TP
-.BR tab \t2048
-Inappropriate use of a tab character.
-Either use of a tab character where a number was expected,
-or use of tab character in an unquoted macro argument.
+.BR number "\t2"
+Invalid numeric expressions.
+.
+This is enabled by default.
+.
.TP
-.BR right-brace \t4096
-Use of
-.B \e}
-where a number was expected.
+.BR range "\t64"
+Out of range arguments.
+.
.TP
-.BR missing \t8192
-Requests that are missing non-optional arguments.
+.BR reg "\t1024"
+Use of undefined number registers.
+.
+When an undefined number register is used, that register is
+automatically defined to have a value of\~0.
+.
+So, in most cases, at most one warning will be given for use of a
+particular name.
+.
.TP
-.BR input \t16384
-Illegal input characters.
+.BR right-brace "\t4096"
+Use of
+.B \[rs]}
+where a number was expected.
+.
.TP
-.BR escape \t32768
-Unrecognized escape sequences.
-When an unrecognized escape sequence is encountered,
-the escape character is ignored.
+.BR scale "\t32"
+Meaningless scaling indicators.
+.
.TP
-.BR space \t65536
+.BR space "\t65536"
Missing space between a request or macro and its argument.
-This warning will be given
-when an undefined name longer than two characters is encountered,
-and the first two characters of the name make a defined name.
+.
+This warning will be given when an undefined name longer than two
+characters is encountered, and the first two characters of the name
+make a defined name.
+.
The request or macro will not be invoked.
+.
When this warning is given, no macro is automatically defined.
+.
This is enabled by default.
+.
This warning will never occur in compatibility mode.
+.
.TP
-.BR font \t131072
-Non-existent fonts.
-This is enabled by default.
+.BR syntax "\t128"
+Dubious syntax in numeric expressions.
+.
.TP
-.BR ig \t262144
-Illegal escapes in text ignored with the
-.B ig
-request.
-These are conditions that are errors when they do not occur
-in ignored text.
-.LP
+.BR tab "\t2048"
+Inappropriate use of a tab character.
+Either use of a tab character where a number was expected, or use of tab
+character in an unquoted macro argument.
+.
+.P
There are also names that can be used to refer to groups of warnings:
+.
.TP
.B all
All warnings except
.BR di ,
-.B mac
+.BR mac ,
and
.BR reg .
-It is intended that this covers all warnings
-that are useful with traditional macro packages.
+It is intended that this covers all warnings that are useful with
+traditional macro packages.
+.
.TP
.B w
All warnings.
.
-.SS Incompatibilities
-.
-.LP
-Long names cause some incompatibilities.
-UNIX troff will interpret
-.IP
-.B
-\&.dsabcd
-.LP
-as defining a string
-.B ab
-with contents
-.BR cd .
-Normally, GNU troff will interpret this as a call of a macro named
-.BR dsabcd .
-Also UNIX troff will interpret
-.B \e*[
-or
-.B \en[
-as references to a string or number register called
-.BR [ .
-In GNU troff, however, this will normally be interpreted as the start
-of a long name.
-In
-.I compatibility mode
-GNU troff will interpret these things in the traditional way.
-In compatibility mode, however, long names are not recognised.
-Compatibility mode can be turned on with the
-.B \-C
-command line option, and turned on or off with the
-.B cp
-request.
-The number register
-.B \en[.C]
-is 1 if compatibility mode is on, 0 otherwise.
-.LP
-GNU troff
-does not allow the use of the escape sequences
-.BR \\e\e|\e^\e&\e}\e{\e (space) \e'\e`\e-\e_\e!\e%\ec
-in names of strings, macros, diversions, number registers,
-fonts or environments; UNIX troff does.
-The
-.B \eA
-escape sequence may be helpful in avoiding use of these
-escape sequences in names.
-.LP
-Fractional pointsizes cause one noteworthy incompatibility.
-In UNIX troff the
-.B ps
-request ignores scale indicators and so
-.IP
-.B .ps\ 10u
-.LP
-will set the pointsize to 10 points, whereas in
-GNU troff it will set the pointsize to 10 scaled points.
-.LP
-In GNU troff there is a fundamental difference between unformatted,
-input characters, and formatted, output characters.
-Everything that affects how an output character
-will be output is stored with the character; once an output
-character has been constructed it is unaffected by any subsequent
-requests that are executed, including
-.BR bd ,
-.BR cs ,
-.BR tkf ,
-.BR tr ,
-or
-.B fp
-requests.
-Normally output characters are constructed from input
-characters at the moment immediately before the character
-is added to the current output line.
-Macros, diversions and strings are all, in fact, the same type
-of object; they contain lists of input characters and output
-characters in any combination.
-An output character does not behave like an input character
-for the purposes of macro processing; it does not inherit any
-of the special properties that the input character from which it
-was constructed might have had.
-For example,
-.IP
-.nf
-.ft B
-\&.di x
-\e\e\e\e
-\&.br
-\&.di
-\&.x
-.ft
-.fi
-.LP
-will print
-.B \e\e
-in GNU troff;
-each pair of input
-.BR \e s
-is turned into one output
-.B \e
-and the resulting output
-.BR \e s
-are not interpreted as escape characters when they are reread.
-UNIX troff would interpret them as escape characters
-when they were reread and would end up printing one
-.BR \e .
-The correct way to obtain a printable
-.B \e
-is to use the
-.B \ee
-escape sequence: this will always print a single instance of the
-current escape character, regardless of whether or not it is used in a
-diversion; it will also work in both GNU troff and UNIX troff.
-If you wish for some reason to store in a diversion an escape
-sequence that will be interpreted when the diversion is reread,
-you can either use the traditional
-.B \e!\&
-transparent output facility, or, if this is unsuitable, the new
-.B \e?\&
-escape sequence.
-.
.
+.\" --------------------------------------------------------------------
.SH ENVIRONMENT
-.
+.\" --------------------------------------------------------------------
.
.TP
.SM
.B GROFF_TMAC_PATH
A colon separated list of directories in which to search for
macro files.
-.B troff
-will scan directories given in
-the
+.B @g@troff
+will scan directories given in the
.B \-M
-option before these, and in standard directories (current directory if in
-unsafe mode, home directory,
-.BR @LOCALMACRODIR@ ,
+option before these, and in standard directories (current directory if
+in unsafe mode, home directory,
.BR @SYSTEMMACRODIR@ ,
+.BR @LOCALMACRODIR@ ,
.BR @MACRODIR@ )
after these.
+.
.TP
.SM
.B GROFF_TYPESETTER
Default device.
+.
.TP
.SM
.B GROFF_FONT_PATH
A colon separated list of directories in which to search for the
.BI dev name
directory.
-.B troff
+.B @g@troff
will scan directories given in the
.B \-F
option before these, and in standard directories
-.RB ( @FONTPATH@ )
+.RB ( @LOCALFONTDIR@ ,
+.BR @FONTDIR@ ,
+.BR @LEGACYFONTDIR@ )
after these.
.
.
+.\" --------------------------------------------------------------------
.SH FILES
-.
+.\" --------------------------------------------------------------------
.
.Tp \w'@FONTDIR@/devname/DESC'u+3n
.B @MACRODIR@/troffrc
Initialization file (called before any other macro package).
+.
.TP
.B @MACRODIR@/troffrc-end
Initialization file (called after any other macro package).
+.
.TP
.BI @MACRODIR@/ name .tmac
.TQ
.BI @MACRODIR@/tmac. name
Macro files
+.
.TP
.BI @FONTDIR@/dev name /DESC
Device description file for device
.IR name .
+.
.TP
.BI @FONTDIR@/dev name / F
Font file for font
.I F
of device
.IR name .
-.LP
+.P
Note that
.B troffrc
and
.B troffrc-end
-are neither searched in the current nor in the home directory by default for
-security reasons (even if the
+are neither searched in the current nor in the home directory by
+default for security reasons (even if the
.B \-U
option is given).
+.
Use the
.B \-M
command line option or the
@@ -2463,28 +600,86 @@ environment variable to add these directories to the search path if
necessary.
.
.
+.\" --------------------------------------------------------------------
+.SH AUTHOR
+.\" --------------------------------------------------------------------
+.
+Copyright (C) 1989, 2001, 2002 Free Software Foundation, Inc.
+.
+.P
+This document is distributed under the terms of the FDL (GNU Free
+Documentation License) version 1.1 or later.
+.
+You should have received a copy of the FDL on your system, it is also
+available on-line at the
+.URL http://www.gnu.org/copyleft/fdl.html "GNU copyleft site" .
+This document was written by James Clark, with modifications from
+.MTO wl@gnu.org "Werner Lemberg"
+and
+.MTO bwarken@mayn.de "Bernd Warken"
+.
+.P
+This document is part of
+.IR groff ,
+the GNU roff distribution.
+.
+.
+.\" --------------------------------------------------------------------
.SH "SEE ALSO"
+.\" --------------------------------------------------------------------
.
+.TP
+.BR groff (@MAN1EXT@)
+The main program of the
+.I groff
+system, a wrapper around
+.IR @g@troff .
.
+.TP
.BR groff (@MAN7EXT@)
--- This is a short but complete reference of all requests, registers, and
-escapes.
-.PP
-.BR groff (@MAN1EXT@),
-.BR @g@tbl (@MAN1EXT@),
-.BR @g@pic (@MAN1EXT@),
-.BR @g@eqn (@MAN1EXT@),
-.BR @g@refer (@MAN1EXT@),
-.BR @g@soelim (@MAN1EXT@),
-.BR @g@grn (@MAN1EXT@),
-.BR grops (@MAN1EXT@),
-.BR grodvi (@MAN1EXT@),
-.BR grotty (@MAN1EXT@),
-.BR grohtml (@MAN1EXT@),
-.BR grolj4 (@MAN1EXT@),
-.BR groff_font (@MAN5EXT@),
-.BR groff_out (@MAN5EXT@),
-.BR groff_char (@MAN7EXT@)
+A description of the
+.I groff
+language, including a short but complete reference of all predefined
+requests, registers, and escapes of plain
+.IR groff .
+From the command line, this is called by
+.RS
+.IP
+.B man 7 groff
+.RE
+.
+.TP
+.BR \%groff_diff (@MAN7EXT@)
+The differences of the
+.I groff
+language and the
+.I classical troff
+language.
+.
+Currently, this is the most actual document of the
+.I groff
+system.
+.
+.TP
+.BR roff (@MAN7EXT@)
+An overview over
+.I groff
+and other
+.I roff
+systems, including pointers to further related documentation.
+.
+.P
+The
+.I groff info
+.IR file ,
+cf.\&
+.BR info (@MAN1EXT@),
+presents all groff documentation within a single document.
+.
+.
+.\" --------------------------------------------------------------------
+.\" Emacs variables
+.\" --------------------------------------------------------------------
.
.\" Local Variables:
.\" mode: nroff
OpenPOWER on IntegriCloud