summaryrefslogtreecommitdiff
path: root/src/roff
diff options
context:
space:
mode:
Diffstat (limited to 'src/roff')
-rw-r--r--src/roff/groff/groff.cc8
-rw-r--r--src/roff/groff/groff.man4
-rw-r--r--src/roff/troff/dictionary.cc2
-rw-r--r--src/roff/troff/div.cc2
-rw-r--r--src/roff/troff/env.cc52
-rw-r--r--src/roff/troff/env.h10
-rw-r--r--src/roff/troff/input.cc420
-rw-r--r--src/roff/troff/node.cc170
-rw-r--r--src/roff/troff/node.h28
-rw-r--r--src/roff/troff/number.cc5
-rw-r--r--src/roff/troff/troff.h7
-rw-r--r--src/roff/troff/troff.man90
12 files changed, 686 insertions, 112 deletions
diff --git a/src/roff/groff/groff.cc b/src/roff/groff/groff.cc
index ec8d34af..71529a0d 100644
--- a/src/roff/groff/groff.cc
+++ b/src/roff/groff/groff.cc
@@ -125,7 +125,7 @@ int main(int argc, char **argv)
{ NULL, 0, 0, 0 }
};
while ((opt = getopt_long(argc, argv,
- "abCd:eEf:F:gGhiI:lL:m:M:n:No:pP:r:RsStT:UvVw:W:XzZ",
+ "abcCd:eEf:F:gGhiI:lL:m:M:n:No:pP:r:RsStT:UvVw:W:XzZ",
long_options, NULL))
!= EOF) {
char buf[3];
@@ -208,6 +208,9 @@ int main(int argc, char **argv)
case 'b':
commands[TROFF_INDEX].append_arg(buf);
break;
+ case 'c':
+ commands[TROFF_INDEX].append_arg(buf);
+ break;
case 'S':
safer_flag = 1;
break;
@@ -674,7 +677,7 @@ char **possible_command::get_argv()
void synopsis(FILE *stream)
{
fprintf(stream,
-"usage: %s [-abeghilpstvzCENRSUVXZ] [-Fdir] [-mname] [-Tdev] [-ffam]\n"
+"usage: %s [-abceghilpstvzCENRSUVXZ] [-Fdir] [-mname] [-Tdev] [-ffam]\n"
" [-wname] [-Wname] [-Mdir] [-dcs] [-rcn] [-nnum] [-olist] [-Parg]\n"
" [-Larg] [-Idir] [files...]\n",
program_name);
@@ -712,6 +715,7 @@ void help()
"-E\tinhibit all errors\n"
"-b\tprint backtraces with errors or warnings\n"
"-l\tspool the output\n"
+"-c\tdisable color output\n"
"-C\tenable compatibility mode\n"
"-V\tprint commands on stdout instead of running them\n"
"-Parg\tpass arg to the postprocessor\n"
diff --git a/src/roff/groff/groff.man b/src/roff/groff/groff.man
index ffb683e8..575e7a9a 100644
--- a/src/roff/groff/groff.man
+++ b/src/roff/groff/groff.man
@@ -41,7 +41,7 @@ groff \- front end for the groff document formatting system
.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]"
.el .RB "[\ " "\\$1" "\ ]"
..
-.OP \-abeghilpstvzCEGNRSUVXZ
+.OP \-abceghilpstvzCEGNRSUVXZ
.OP \-w name
.OP \-W name
.OP \-m name
@@ -293,6 +293,8 @@ Unsafe mode. Reverts to the old unsafe behaviour.
.TQ
.B \-b
.TQ
+.B \-c
+.TQ
.B \-i
.TQ
.B \-C
diff --git a/src/roff/troff/dictionary.cc b/src/roff/troff/dictionary.cc
index bca38451..a70ebb0e 100644
--- a/src/roff/troff/dictionary.cc
+++ b/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/src/roff/troff/div.cc b/src/roff/troff/div.cc
index c885ca80..d3650662 100644
--- a/src/roff/troff/div.cc
+++ b/src/roff/troff/div.cc
@@ -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)
{
}
diff --git a/src/roff/troff/env.cc b/src/roff/troff/env.cc
index c0743441..477453c7 100644
--- a/src/roff/troff/env.cc
+++ b/src/roff/troff/env.cc
@@ -532,6 +532,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 cur_glyph_color;
+}
+
+color *environment::get_prev_fill_color()
+{
+ return prev_fill_color;
+}
+
+color *environment::get_fill_color()
+{
+ return cur_fill_color;
+}
+
+void environment::set_glyph_color(color *c)
+{
+ if (interrupted)
+ return;
+ curenv->prev_glyph_color = curenv->prev_glyph_color;
+ curenv->cur_glyph_color = c;
+}
+
+void environment::set_fill_color(color *c)
+{
+ if (interrupted)
+ return;
+ curenv->prev_fill_color = curenv->prev_fill_color;
+ curenv->cur_fill_color = c;
+}
+
environment::environment(symbol nm)
: dummy(0),
prev_line_length((units_per_inch*13)/2),
@@ -600,6 +636,10 @@ environment::environment(symbol nm)
need_eol(0),
ignore_next_eol(0),
emitted_node(0),
+ cur_glyph_color(0),
+ prev_glyph_color(0),
+ cur_fill_color(0),
+ prev_fill_color(0),
name(nm),
control_char('.'),
no_break_control_char('\''),
@@ -685,6 +725,10 @@ environment::environment(const environment *e)
#endif /* WIDOW_CONTROL */
need_eol(0),
ignore_next_eol(0),
+ cur_glyph_color(e->cur_glyph_color),
+ prev_glyph_color(e->prev_glyph_color),
+ cur_fill_color(e->cur_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),
@@ -765,6 +809,10 @@ void environment::copy(const environment *e)
hyphenation_space = e->hyphenation_space;
hyphenation_margin = e->hyphenation_margin;
composite = 0;
+ cur_glyph_color= e->cur_glyph_color;
+ prev_glyph_color = e->prev_glyph_color;
+ cur_fill_color = e->cur_fill_color;
+ prev_fill_color = e->prev_fill_color;
}
environment::~environment()
@@ -2371,7 +2419,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);
}
@@ -2476,7 +2524,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;
diff --git a/src/roff/troff/env.h b/src/roff/troff/env.h
index 851a9a0a..166eafb5 100644
--- a/src/roff/troff/env.h
+++ b/src/roff/troff/env.h
@@ -184,6 +184,10 @@ class environment {
int need_eol;
int ignore_next_eol;
int emitted_node; // have we emitted a node since the last html eol tag?
+ color *cur_glyph_color;
+ color *prev_glyph_color;
+ color *cur_fill_color;
+ color *prev_fill_color;
tab_type distance_to_next_tab(hunits *);
void start_line();
@@ -261,6 +265,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();
diff --git a/src/roff/troff/input.cc b/src/roff/troff/input.cc
index 58f88565..ff7413b1 100644
--- a/src/roff/troff/input.cc
+++ b/src/roff/troff/input.cc
@@ -92,6 +92,7 @@ void transparent_file();
const char *program_name = 0;
token tok;
int break_flag = 0;
+int disable_color_flag = 0;
static int backtrace_flag = 0;
#ifndef POPEN_MISSING
char *pipe_command = 0;
@@ -185,7 +186,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 +198,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 +217,6 @@ input_iterator::input_iterator()
{
}
-input_iterator::~input_iterator()
-{
-}
-
int input_iterator::fill(node **)
{
return EOF;
@@ -517,7 +512,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;
@@ -679,7 +674,7 @@ void shift()
static int get_char_for_escape_name()
{
- int c = get_copy(NULL);
+ int c = get_copy(0);
switch (c) {
case EOF:
copy_mode_error("end of input in escape name");
@@ -826,19 +821,19 @@ 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())
interpolate_arg(s);
@@ -846,24 +841,24 @@ static int get_copy(node **nd, int defining)
}
case '*':
{
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
symbol s = read_escape_name();
if (!s.is_null())
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())
@@ -872,85 +867,85 @@ static int get_copy(node **nd, int defining)
}
case 'g':
{
- (void)input_stack::get(NULL);
+ (void)input_stack::get(0);
symbol s = read_escape_name();
if (!s.is_null())
interpolate_number_format(s);
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())
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
@@ -1007,6 +1002,226 @@ static node *do_special();
static node *do_suppress();
static void do_register();
+dictionary color_dictionary(501);
+
+static color *lookup_color(symbol nm)
+{
+ assert(!nm.is_null());
+ color *c = (color *)color_dictionary.lookup(nm);
+ if (c == 0)
+ warning(WARN_COLOR, "`%1' not defined", nm.contents());
+ return c;
+}
+
+static color *default_black(color *c)
+{
+ if (c == 0)
+ return lookup_color(symbol("black"));
+ else
+ return c;
+}
+
+static node *do_glyph_color(symbol nm)
+{
+ if (nm.is_null())
+ return 0;
+ if (nm == symbol("P"))
+ curenv->set_glyph_color(default_black(curenv->get_prev_glyph_color()));
+ else {
+ color *tem = lookup_color(nm);
+ if (tem)
+ curenv->set_glyph_color(tem);
+ else {
+ tem = new color;
+ tem->set_cmyk((unsigned int)0, (unsigned int)0,
+ (unsigned int)0, (unsigned int)0);
+ (void)color_dictionary.lookup(nm, tem);
+ }
+ }
+ return new glyph_color_node(default_black(curenv->get_glyph_color()));
+}
+
+static node *do_fill_color(symbol nm)
+{
+ if (nm.is_null())
+ return 0;
+ if (nm == symbol("P"))
+ curenv->set_fill_color(default_black(curenv->get_prev_fill_color()));
+ else {
+ color *tem = lookup_color(nm);
+ if (tem)
+ curenv->set_fill_color(tem);
+ else {
+ tem = new color;
+ tem->set_cmyk((unsigned int)0, (unsigned int)0,
+ (unsigned int)0, (unsigned int)0);
+ (void)color_dictionary.lookup(nm, tem);
+ }
+ }
+ return new fill_color_node(default_black(curenv->get_fill_color()));
+}
+
+static unsigned int get_color_element(const char *scheme, const char *color)
+{
+ units val;
+ if (!get_number(&val, 'f')) {
+ warning(WARN_COLOR, "%1 in %2 definition set to 0", color, scheme);
+ tok.next();
+ return 0;
+ }
+ if (val < 0) {
+ warning(WARN_RANGE, "%1 cannot be negative: set to 0", color);
+ return 0;
+ }
+ if (val > 65536) {
+ warning(WARN_RANGE, "%1 cannot be greater than 1", color);
+ return 65535; // this is 0xffff
+ }
+ 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));
+ 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));
+ 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));
+ 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(" "));
+ input_stack::push(make_temp_iterator(s));
+ unsigned int g = get_color_element("gray", "gray value");
+ col->set_gray(g);
+ }
+ return col;
+}
+
+static void define_color()
+{
+ symbol color_name = get_long_name(1);
+ if (color_name.is_null()) {
+ 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 definition `%1', "
+ "use rgb, cmyk or gray", style.contents());
+ skip_line();
+ return;
+ }
+ if (col)
+ (void)color_dictionary.lookup(color_name, col);
+ skip_line();
+}
+
static node *do_overstrike()
{
token start;
@@ -1447,7 +1662,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();
@@ -1497,7 +1712,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 +1720,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;
@@ -1623,6 +1838,18 @@ void token::next()
nd = new vline_node(x, n);
return;
}
+ case 'm':
+ nd = do_glyph_color(read_escape_name());
+ if (!nd)
+ break;
+ type = TOKEN_NODE;
+ return;
+ case 'M':
+ nd = do_fill_color(read_escape_name());
+ if (!nd)
+ break;
+ type = TOKEN_NODE;
+ return;
case 'n':
{
int inc;
@@ -3229,16 +3456,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 (reading_from_terminal)
fputc(c, stderr);
had_prompt = 1;
}
- c = get_copy(NULL);
+ c = get_copy(0);
}
if (c == ' ') {
tok.make_space();
@@ -4122,6 +4349,11 @@ static symbol get_delim_file_name()
char *buf = abuf;
int buf_size = ABUF_SIZE;
int i = 0;
+ // move over initial spaces
+ while (tok.ch() == 0)
+ tok.next();
+ if ((buf[i] = start.ch()) != 0)
+ i++;
for (;;) {
if (i + 1 > buf_size) {
if (buf == abuf) {
@@ -4137,9 +4369,6 @@ static symbol get_delim_file_name()
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)
@@ -4147,6 +4376,9 @@ static symbol get_delim_file_name()
return NULL_SYMBOL;
}
i++;
+ tok.next();
+ if (tok.ch() == ']' && input_stack::get_level() == start_level)
+ break;
}
buf[i] = '\0';
if (buf == abuf) {
@@ -4431,18 +4663,17 @@ 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':
+ {
+ symbol filename = get_delim_file_name();
+ if (filename.is_null()) {
+ error("missing filename as second argument to \\O");
+ return 0;
+ }
+ if (begin_level == 1)
+ return new suppress_node(filename, 'i');
}
- if (begin_level == 1)
- return new suppress_node(filename, 'i');
- return 0;
break;
- }
default:
error("`%1' is an invalid argument to \\O", char(c));
}
@@ -4454,7 +4685,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++)
@@ -4504,7 +4735,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)
@@ -4512,7 +4743,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;
@@ -4520,7 +4751,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)
;
}
/*
@@ -4594,6 +4825,15 @@ 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 = (color_dictionary.lookup(nm) != 0);
+ }
else if (c == 'c') {
tok.next();
tok.skip();
@@ -4786,7 +5026,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;
}
@@ -4810,7 +5050,7 @@ void while_break_request()
}
else {
while_break_flag = 1;
- while (input_stack::get(NULL) != EOF)
+ while (input_stack::get(0) != EOF)
;
tok.next();
}
@@ -4823,7 +5063,7 @@ void while_continue_request()
skip_line();
}
else {
- while (input_stack::get(NULL) != EOF)
+ while (input_stack::get(0) != EOF)
;
tok.next();
}
@@ -4866,12 +5106,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) {
@@ -5011,7 +5251,8 @@ 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;
}
@@ -5207,15 +5448,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)
@@ -5312,11 +5553,11 @@ 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);
fflush(fp);
@@ -5788,7 +6029,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);
@@ -6122,7 +6363,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;
}
@@ -6201,7 +6442,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);
}
@@ -6237,10 +6478,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':
@@ -6256,6 +6497,9 @@ int main(int argc, char **argv)
break;
case 'C':
compatible_flag = 1;
+ // fall through
+ case 'c':
+ disable_color_flag = 1;
break;
case 'M':
macro_path.command_line_dir(optarg);
@@ -6565,6 +6809,7 @@ void init_input_requests()
init_request("pso", pipe_source);
#endif /* not POPEN_MISSING */
init_request("psbb", ps_bbox_request);
+ init_request("defcolor", define_color);
number_reg_dictionary.define("systat", new variable_reg(&system_status));
number_reg_dictionary.define("slimit",
new variable_reg(&input_stack::limit));
@@ -6782,6 +7027,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 },
diff --git a/src/roff/troff/node.cc b/src/roff/troff/node.cc
index 255c4d28..9102869f 100644
--- a/src/roff/troff/node.cc
+++ b/src/roff/troff/node.cc
@@ -36,6 +36,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "font.h"
#include "reg.h"
#include "input.h"
+#include "geometry.h"
#include "nonposix.h"
@@ -728,6 +729,8 @@ class troff_output_file : public real_output_file {
int current_slant;
int current_height;
tfont *current_tfont;
+ color *current_pagecolor;
+ color *current_glyphcolor;
int current_font_number;
symbol *font_position;
int nfont_positions;
@@ -741,6 +744,7 @@ class troff_output_file : public real_output_file {
void put(unsigned char c);
void put(int i);
void put(const char *s);
+ void put_hex(int i, int length);
void set_font(tfont *tf);
void flush_tbuf();
public:
@@ -767,6 +771,8 @@ public:
void draw(char, hvpair *, int, font_size);
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; }
};
@@ -797,6 +803,23 @@ inline void troff_output_file::put(int i)
put_string(i_to_a(i), fp);
}
+inline void troff_output_file::put_hex(int i, int length)
+{
+ char *a = new char[length+1];
+ a[length] = '\0';
+ while (length > 0) {
+ length--;
+ int j = i % 0x10;
+ if (j <= 9)
+ a[length] = '0' + j;
+ else
+ a[length] = 'a' + (j - 10);
+ i /= 0x10;
+ }
+ put_string(a, fp);
+ a_delete a;
+}
+
void troff_output_file::start_special(tfont *tf, int no_init_string)
{
flush_tbuf();
@@ -931,7 +954,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]);
@@ -941,15 +964,11 @@ void troff_output_file::flush_tbuf()
void troff_output_file::check_charinfo(tfont *tf, charinfo *ci)
{
- int size = tf->get_size().to_scaled_points();
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);
}
void troff_output_file::put_char_width(charinfo *ci, tfont *tf, hunits w,
@@ -1116,6 +1135,36 @@ void troff_output_file::set_font(tfont *tf)
current_tfont = tf;
}
+void troff_output_file::fill_color(color *col)
+{
+ unsigned int r, g, b;
+ if ((current_pagecolor == col) || disable_color_flag)
+ return;
+ col->get_rgb(&r, &g, &b);
+ flush_tbuf();
+ put("DF ##");
+ put_hex(r, 4);
+ put_hex(g, 4);
+ put_hex(b, 4);
+ put('\n');
+ current_pagecolor = col;
+}
+
+void troff_output_file::glyph_color(color *col)
+{
+ unsigned int r, g, b;
+ if ((current_glyphcolor == col) || disable_color_flag)
+ return;
+ col->get_rgb(&r, &g, &b);
+ flush_tbuf();
+ put("m ##");
+ put_hex(r, 4);
+ put_hex(g, 4);
+ put_hex(b, 4);
+ put('\n');
+ current_glyphcolor = 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,
@@ -1158,8 +1207,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++) {
@@ -3590,6 +3668,80 @@ hunits suppress_node::width()
return H0;
}
+/* glyph color_node */
+
+glyph_color_node::glyph_color_node(color *col)
+: c(col)
+{
+}
+
+int glyph_color_node::same(node *n)
+{
+ return (c == ((glyph_color_node *)n)->c);
+}
+
+const char *glyph_color_node::type()
+{
+ return "glyph_color_node";
+}
+
+int glyph_color_node::force_tprint()
+{
+ return 0;
+}
+
+node *glyph_color_node::copy()
+{
+ return new glyph_color_node(c);
+}
+
+hunits glyph_color_node::width()
+{
+ return H0;
+}
+
+void glyph_color_node::tprint(troff_output_file *out)
+{
+ out->glyph_color(c);
+}
+
+/* page color_node */
+
+fill_color_node::fill_color_node(color *col)
+: c(col)
+{
+}
+
+int fill_color_node::same(node *n)
+{
+ return (c == ((fill_color_node *)n)->c);
+}
+
+const char *fill_color_node::type()
+{
+ return "fill_color_node";
+}
+
+int fill_color_node::force_tprint()
+{
+ return 0;
+}
+
+node *fill_color_node::copy()
+{
+ return new fill_color_node(c);
+}
+
+hunits fill_color_node::width()
+{
+ return H0;
+}
+
+void fill_color_node::tprint(troff_output_file *out)
+{
+ out->fill_color(c);
+}
+
/* composite_node */
class composite_node : public charinfo_node {
@@ -5346,7 +5498,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/src/roff/troff/node.h b/src/roff/troff/node.h
index a58afed1..0d9793c9 100644
--- a/src/roff/troff/node.h
+++ b/src/roff/troff/node.h
@@ -281,9 +281,9 @@ protected:
unsigned char unformat;
public:
hmotion_node(hunits i, node *next = 0)
- : node(next), n(i), was_tab(0), unformat(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) {}
+ : node(next), n(i), was_tab(flag1), unformat(flag2) {}
node *copy();
int reread(int *);
int set_unformat_flag();
@@ -493,6 +493,30 @@ private:
void put(troff_output_file *out, const char *s);
};
+class glyph_color_node : public node {
+ color *c;
+public:
+ glyph_color_node(color *col);
+ node *copy();
+ void tprint(troff_output_file *);
+ hunits width();
+ int same(node *);
+ const char *type();
+ int force_tprint();
+};
+
+class fill_color_node : public node {
+ color *c;
+public:
+ fill_color_node(color *col);
+ node *copy();
+ void tprint(troff_output_file *);
+ hunits width();
+ int same(node *);
+ const char *type();
+ int force_tprint();
+};
+
struct hvpair {
hunits h;
vunits v;
diff --git a/src/roff/troff/number.cc b/src/roff/troff/number.cc
index 53938428..d79298e6 100644
--- a/src/roff/troff/number.cc
+++ b/src/roff/troff/number.cc
@@ -234,7 +234,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);
@@ -590,6 +590,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/src/roff/troff/troff.h b/src/roff/troff/troff.h
index 17d45da2..48e72a6e 100644
--- a/src/roff/troff/troff.h
+++ b/src/roff/troff/troff.h
@@ -29,6 +29,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <errno.h>
#include "assert.h"
+#include "color.h"
#include "device.h"
#include "searchpath.h"
@@ -42,6 +43,7 @@ extern units units_per_inch;
extern int ascii_output_flag;
extern int suppress_output_flag;
+extern int disable_color_flag;
extern int is_html;
extern int tcommand_flag;
@@ -75,11 +77,12 @@ 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,
diff --git a/src/roff/troff/troff.man b/src/roff/troff/troff.man
index fc663153..7f81c228 100644
--- a/src/roff/troff/troff.man
+++ b/src/roff/troff/troff.man
@@ -65,7 +65,7 @@ the original English.
.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]"
.el .RB "[\ " "\\$1" "\ ]"
..
-.OP \-abivzCERU
+.OP \-abcivzCERU
.OP \-w name
.OP \-W name
.OP \-d cs
@@ -118,6 +118,9 @@ or
.B am
requests.
.TP
+.B \-c
+Disable color output (always disabled in compatibility mode).
+.TP
.B \-i
Read the standard input after all the named input files have been
processed.
@@ -278,9 +281,9 @@ 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
+The names of number registers, fonts, strings/\:macros/\:diversions,
+special characters, and colors can be of any length.
+In escape sequences, where you can use
.BI ( xx
for a two character name, you can use
.BI [ xxx ]
@@ -394,6 +397,12 @@ Spaces are permitted in a number expression within parentheses.
.LP
.B M
indicates a scale of 100ths of an em.
+.B f
+indicates a scale of 65536 units, providing fractions for color definitions
+with
+.B defcolor
+request.
+For example, 0.5f = 32768u.
.TP
.IB e1 >? e2
The maximum of
@@ -482,6 +491,26 @@ gets interpreted in copy-mode
(for example, by being used in a macro argument).
.RE
.TP
+.BI \em x
+.TQ
+.BI \em( xx
+.TQ
+.BI \em[ xxx ]
+Set drawing color.
+.B \emP
+switches back to the previous color.
+.TP
+.BI \eM x
+.TQ
+.BI \eM( xx
+.TQ
+.BI \eM[ xxx ]
+Set background color for filled objects drawn with the
+.BI \eD' ... '
+commands.
+.B \eMP
+switches back to the previous color.
+.TP
.BI \eN' n '
Typeset the character with code
.I n
@@ -965,6 +994,52 @@ disable it.
In compatibility mode, long names are not recognised, and the
incompatibilities caused by long names do not arise.
.TP
+.BI .defcolor\ xxx\ scheme\ color_components
+Define color.
+.I scheme
+can be one of the following values:
+.B rgb
+(three components),
+.B cym
+(three components),
+.B cmyk
+(four components), and
+.B gray
+or
+.B grey
+(one component).
+Color components can be given either as a hexadecimal string or as positive
+decimal integers in the range 0-65535.
+A hexadecimal string contains all color components concatenated.
+It must start with either
+.B #
+or
+.BR ## ;
+the former specifies hex values in the range 0-255 (which are internally
+multiplied by\~257), the latter in the range 0-65535.
+Examples: #FFC0CB (pink), ##ffff0000ffff (magenta).
+A new scaling indicator
+.B f
+has been introduced which multiplies its value by 65536; this makes it
+convenient to specify color components as fractions in the range 0 to\~1.
+Example:
+.RS
+.IP
+.B
+\&.defcolor darkgreen rgb 0.1f 0.5f 0.2f
+.RE
+.IP
+Note that
+.B f
+is the default scaling indicator for the
+.B defcolor
+request, thus the above statement is equivalent to
+.RS
+.IP
+.B
+\&.defcolor darkgreen rgb 0.1 0.5 0.2
+.RE
+.TP
.BI .dei\ xx\ yy
Define macro indirectly.
The following example
@@ -2125,6 +2200,10 @@ True if there is a number register named
True if there is a string, macro, diversion, or request named
.IR xxx .
.TP
+.BI .if\ m xxx
+True if there is a color named
+.IR xxx .
+.TP
.BI .if\ c ch
True if there is a character
.IR ch
@@ -2260,6 +2339,9 @@ Illegal escapes in text ignored with the
request.
These are conditions that are errors when they do not occur
in ignored text.
+.TP
+.BR color \t524288
+Color related warnings.
.LP
There are also names that can be used to refer to groups of warnings:
.TP