diff options
Diffstat (limited to 'src/roff')
-rw-r--r-- | src/roff/groff/groff.cc | 8 | ||||
-rw-r--r-- | src/roff/groff/groff.man | 4 | ||||
-rw-r--r-- | src/roff/troff/dictionary.cc | 2 | ||||
-rw-r--r-- | src/roff/troff/div.cc | 2 | ||||
-rw-r--r-- | src/roff/troff/env.cc | 52 | ||||
-rw-r--r-- | src/roff/troff/env.h | 10 | ||||
-rw-r--r-- | src/roff/troff/input.cc | 420 | ||||
-rw-r--r-- | src/roff/troff/node.cc | 170 | ||||
-rw-r--r-- | src/roff/troff/node.h | 28 | ||||
-rw-r--r-- | src/roff/troff/number.cc | 5 | ||||
-rw-r--r-- | src/roff/troff/troff.h | 7 | ||||
-rw-r--r-- | src/roff/troff/troff.man | 90 |
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 |