summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog99
-rw-r--r--NEWS17
-rw-r--r--doc/groff.texinfo11
-rw-r--r--doc/pic.ms8
-rw-r--r--font/devps/prologue.ps25
-rw-r--r--man/groff.man3
-rw-r--r--man/groff_diff.man11
-rw-r--r--man/groff_out.man8
-rw-r--r--src/devices/grohtml/html-text.cc16
-rw-r--r--src/devices/grohtml/post-html.cc12
-rw-r--r--src/devices/grops/ps.cc153
-rw-r--r--src/devices/grops/ps.h3
-rw-r--r--src/include/color.h65
-rw-r--r--src/include/lib.h3
-rw-r--r--src/libs/libdriver/input.cc1961
-rw-r--r--src/libs/libgroff/color.cc434
-rw-r--r--src/libs/libgroff/geometry.cc32
-rw-r--r--src/libs/libgroff/itoa.c17
-rw-r--r--src/preproc/pic/object.cc22
-rw-r--r--src/preproc/pic/pic.man13
-rw-r--r--src/roff/troff/env.cc10
-rw-r--r--src/roff/troff/input.cc73
-rw-r--r--src/roff/troff/node.cc112
-rw-r--r--tmac/andoc.tmac5
-rw-r--r--tmac/groff_www.man2
25 files changed, 2192 insertions, 923 deletions
diff --git a/ChangeLog b/ChangeLog
index 51c853fe..2e2bd5d9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,105 @@
+2002-01-24 Werner LEMBERG <wl@gnu.org>
+
+ * tmac/groff_www.man, NEWS: Fix typos.
+
+2002-01-21 Werner LEMBERG <wl@gnu.org>
+
+ Complete revision of color support:
+
+ Adapt programs to the new libdriver/input.cc.
+
+ Color spaces are no longer converted to RGB but transferred as-is
+ in the troff intermediate output format.
+
+ Handle default color gracefully. troff now supports a `default'
+ color (which can't be changed).
+
+ grops will now use the proper color space functions if available.
+
+ Update pic.
+
+ Note that currently grohtml doesn't handle colors properly. This
+ has to be fixed.
+
+ * src/libgroff/itoa.c (UINT_DIGITS): New macro.
+ (ui_to_a): New function.
+ * src/include/lib.h: Updated.
+
+ * src/include/color.h (color_scheme): Replace `NONE' with `DEFAULT'.
+ (color): Simplified; removed all `double' members and methods.
+ A new array `components' now holds the color parameters.
+ (color::is_default, color::get_components): New methods.
+ (color::operator==, color:operator!=): New.
+ (Red, Green, Blue, Cyan, Magenta, Yellow, Black, Gray): New macros
+ to make access to the `components' array more comprehensible.
+ * src/libgroff/color.cc: Implement new color support.
+ (atoh): Small fixes.
+ (color::read_encoding): Simplified for new troff intermediate color
+ output format.
+ (default_color): New global variable.
+
+ * src/roff/troff/input.cc (default_symbol): New global variable.
+ (lookup_color): Use it.
+ (default_black): Removed.
+ (do_glyph_color, do_fill_color): Simplified.
+ (define_color): Handle default color.
+ Improve warnings.
+ (do_if_request): Handle default color.
+ * src/roff/troff/env.cc (environment::environment): Initialize
+ colors with `default_color'.
+ * src/roff/troff/node.cc (troff_output_file::put): Add method
+ for `unsigned int'.
+ (troff_output_file::hex): Removed.
+ (troff_output_file::fill_color, troff_output_file::glyph_color):
+ Updated to include/color.h and libdriver/input.cc.
+
+ * src/preproc/pic/object.cc (draw_arrow): New parameter to set
+ fill color properly (identically to the outline color). \D'f...'
+ doesn't work any more.
+ All function calls to it updated.
+
+ * src/devices/grohtml/post-html.cc (html_printer::do_body, main):
+ Updated.
+ * src/devices/grohtml/html-text.cc (html_text::issue_color_begin):
+ Updated.
+
+ * src/devices/grops/ps.cc (ps_output::put_color): New method.
+ (ps_printer::sbuf_color): Make a real member instead of pointer.
+ (ps_printer::fill_color, ps_printer::output_color): Removed.
+ (ps_printer::ps_printer): Updated.
+ (ps_printer::set_char): Ditto.
+ (ps_printer::set_color): Use various color schemes.
+ Use `put_color' method.
+ (ps_printer::flush_sbuf): Don't set color.
+ (ps_printer::fill_path): Take `environment' as parameter.
+ Simplify color handling.
+ (ps_printer::set_line_thickness): Renamed to ...
+ (ps_printer::set_line_thickness_and_color): This (and updated).
+ (ps_printer::set_color): Change second parameter from `complete'
+ to `fill' which better describes what it does.
+ (ps_printer::draw): Call `flush_sbuf' to output graphic commands
+ and text in the right order.
+ Updated.
+ Remove branches for `f' and `F'; this is handled by
+ libdriver/input.cc.
+ * src/devices/grops/ps.h: Updated.
+ * font/devps/prologue (FL): Redefined
+ ({F,C}r,k,g: New color functions (with and without filling).
+
+ * doc/pic.ms, src/preproc/pic/pic.man: Small fixes.
+ * man/groff_diff.man, man/groff.man, man/groff_out.man,
+ doc/groff.texinfo, NEWS: Updated.
+
+2002-01-20 Bernd Warken <bwarken@mayn.de>
+
+ * src/libs/libdriver/input.cc: Completely rewritten. See comments
+ in this file for what has been changed.
+
2002-01-19 Werner LEMBERG <wl@gnu.org>
* test-groff: Fix GROFF_FONT_PATH.
+ * tmac/andoc.tmac: Add dummy macros for equation support -- eqnrc
+ is read before .TH or .Dd is parsed.
2002-01-18 Gaius Mulley <gaius@glam.ac.uk>
diff --git a/NEWS b/NEWS
index f9d7f9b5..36da9cfd 100644
--- a/NEWS
+++ b/NEWS
@@ -13,7 +13,8 @@ o Color support has been added to troff and pic (and to two device drivers,
drawing color, the escape sequence `\M' specifies the background color for
closed objects created with \D'...' commands. Similar to fonts, `\mP' and
`\MP' switch back to the previous color. `\m' and `\M' correspond to the
- new troff output commands `m' and `DF'.
+ new troff output commands `m' and `DF'. The device-specific default color
+ is called `default' and can't be redefined.
Outputting color can be disabled in troff and groff with the option -c
(it is always disabled in compatibility mode).
@@ -23,7 +24,8 @@ o Color support has been added to troff and pic (and to two device drivers,
is defined (with .if and .ie), a new conditional operator `m' is
available.
- More details can be found in the troff manual page.
+ More details can be found in the groff_diff.7 manual page and in
+ groff.texinfo.
o Two new glyph symbols are available: `eu' is the official Euro symbol;
`Eu' is a font-specific glyph variant.
@@ -56,7 +58,7 @@ o The new request `itc' is a variant of `.it' for which a line interrupted
with \c counts as one input line.
o A new escape sequence `\O' is available (mainly for internal use with
- grohtml). Please see groff_diff.man and groff.texinfo for more details.
+ grohtml). Please see groff_diff.7 and groff.texinfo for more details.
o Two macros `AT' (AT&T) and `UC' (Univ. of California) have been added to
the man macros for compatibility with older BSD releases.
@@ -68,12 +70,15 @@ o The `-xwidth' specifier in the mdoc macro package has been removed. Its
o A new macro `Ex' has been added to the mdoc macro package to document an
exit status.
-o `troff.man' has been split. Differences to UNIX troff are now documented
- in the new man page `groff_diff.man'.
+o `troff.1' has been split. Differences to UNIX troff are now documented
+ in the new man page `groff_diff.7'.
-o `groff_mwww.man' has been renamed to `groff_www.man'. The file mwww.tmac
+o `groff_mwww.1' has been renamed to `groff_www.1'. The file mwww.tmac
has been removed.
+o `groff_ms.7' has been completely rewritten. It now contains a complete
+ reference to the ms macros.
+
o The macro `NO-AUTO-RULE' has been added to www.tmac; it suppresses the
generation of top and bottom rules which grohtml emits by default.
diff --git a/doc/groff.texinfo b/doc/groff.texinfo
index 91369cff..07f38aef 100644
--- a/doc/groff.texinfo
+++ b/doc/groff.texinfo
@@ -8696,7 +8696,7 @@ The @code{als} request can make a macro have more than one name.
This would be called as
@Example
-.vl $Id: groff.texinfo,v 1.90 2002/01/13 08:22:10 wlemb Exp $
+.vl $Id: groff.texinfo,v 1.91 2002/01/24 22:37:30 wlemb Exp $
@endExample
@endDefesc
@@ -9655,17 +9655,20 @@ following values: @code{rgb} (three components), @code{cym} (three
components), @code{cmyk} (four components), and @code{gray} or
@code{grey} (one component).
+@cindex default color
+@cindex color, default
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
@code{#} or @code{##}; the former specifies hex values in the range
0--255 (which are internally multiplied by@w{ }257), the latter in the
range 0--65535. Examples: @code{#FFC0CB} (pink), @code{##ffff0000ffff}
-(magenta).
+(magenta). The default color name @c{default} can't be redefined; its
+value is device-specific (usually black). It is possible that the
+default color for @code{\m} and @code{\M} is not identical.
@cindex @code{f} unit, and colors
@cindex unit, @code{f}, and colors
-
A new scaling indicator @code{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@w{ }1 (1f equals 65536u). Example:
@@ -9674,7 +9677,7 @@ as fractions in the range 0 to@w{ }1 (1f equals 65536u). Example:
.defcolor darkgreen rgb 0.1f 0.5f 0.2f
@endExample
-Note that @code{f} is the default scaling indicator for the
+Note that @code{f} is the default scaling indicator for the
@code{defcolor} request, thus the above statement is equivalent to
@Example
diff --git a/doc/pic.ms b/doc/pic.ms
index 142ee0f1..21cd7b19 100644
--- a/doc/pic.ms
+++ b/doc/pic.ms
@@ -10,7 +10,7 @@
.\" This document was written for free use and redistribution by
.\" Eric S. Raymond <esr@thyrsus.com> in August 1995.
.\"
-.\" $Id: pic.ms,v 1.10 2002/01/13 08:22:10 wlemb Exp $
+.\" $Id: pic.ms,v 1.11 2002/01/24 22:37:30 wlemb Exp $
.\"
.\" Set a proper TeX
.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X
@@ -670,9 +670,9 @@ Alternative spellings are \fBcolour\fP, \fBcolored\fP, \fBcoloured\fP,
and \fBoutlined\fP.
.PP
Currently, color support is not available in \*(tx mode. Predefined color
-names for \fIgroff\fP(1) are in the file \f(CWcolor.tmac\fP; additional
-colors can be defined with the \f(CW.defcolor\fP request (see the manual
-page of GNU \fItroff\fP(1) for more details).
+names for \fIgroff\fP(1) are in the device macro files, for example
+\f(CWps.tmac\fP; additional colors can be defined with the \f(CW.defcolor\fP
+request (see the manual page of GNU \fItroff\fP(1) for more details).
.NH 1
More About Text Placement
.PP
diff --git a/font/devps/prologue.ps b/font/devps/prologue.ps
index d95b8fd2..41adab26 100644
--- a/font/devps/prologue.ps
+++ b/font/devps/prologue.ps
@@ -148,24 +148,33 @@
% fill the last path
-% amount FL -
+% r g b Fr -
-/FL {
- currentgray exch setgray fill setgray
+/Fr {
+ setrgbcolor fill
} bind def
-% r g b FC -
+% c m y k Fk -
-/FC {
- setrgbcolor fill
+/Fk {
+ setcmykcolor fill
+} bind def
+
+% g Fg -
+
+/Fg {
+ setgray fill
} bind def
% fill with the ``current color''
-/BL /fill load def
+/FL /fill load def
/LW /setlinewidth load def
-/CO /setrgbcolor load def
+
+/Cr /setrgbcolor load def
+/Ck /setcmykcolor load def
+/Cg /setgray load def
% new_font_name encoding_vector old_font_name RE -
diff --git a/man/groff.man b/man/groff.man
index abd1c423..7bc08750 100644
--- a/man/groff.man
+++ b/man/groff.man
@@ -1371,6 +1371,9 @@ as a string of two-digit hexadecimal color components with a leading
.BR # ,
or as a string of four-digit hexadecimal components with two leading
.BR # .
+The color
+.B default
+can't be redefined.
.
.REQ .dei macro
Define or redefine a macro whose name is contained in the string register
diff --git a/man/groff_diff.man b/man/groff_diff.man
index c4f687ce..6049c423 100644
--- a/man/groff_diff.man
+++ b/man/groff_diff.man
@@ -1127,6 +1127,17 @@ request, thus the above statement is equivalent to
.ft
.RE
.
+.IP
+The color named
+.B default
+(which is device-specific) can't be redefined.
+.
+It is possible that the default color for
+.esc M
+and
+.esc m
+is not the same.
+.
.TP
.BI .dei\ xx\ yy
Define macro indirectly.
diff --git a/man/groff_out.man b/man/groff_out.man
index 99d77d8b..cc0d9c91 100644
--- a/man/groff_out.man
+++ b/man/groff_out.man
@@ -628,8 +628,8 @@ where all arguments are integers between 0 and \n[@maxcolor] with black
having all arguments\~0.
.
.command md
-Set color for glyphs and line drawing to the default color value
-(black).
+Set color for glyphs and line drawing to the default drawing color value
+(black in most cases).
.
.command mg "gray"
Set color for glyphs and line drawing to the shade of gray given by
@@ -893,8 +893,8 @@ having all arguments\~0.
No position changing.
.
.D-command Fd
-Set fill color for solid drawing objects to the default color value
-(black).
+Set fill color for solid drawing objects to the default fill color value
+(black in most cases).
.
No position changing.
.
diff --git a/src/devices/grohtml/html-text.cc b/src/devices/grohtml/html-text.cc
index e78bddad..0d550230 100644
--- a/src/devices/grohtml/html-text.cc
+++ b/src/devices/grohtml/html-text.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
*
* Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cc
*
@@ -105,15 +105,17 @@ void html_text::issue_tag (char *tagname, char *arg)
void html_text::issue_color_begin (color *c)
{
- double r, g, b;
+ unsigned int r, g, b;
char buf[6+1];
out->put_string("<font color=\"#");
- c->get_rgb(&r, &g, &b);
- sprintf(buf, "%.2X%.2X%.2X",
- (unsigned int)(((double) 0xff)*r),
- (unsigned int)(((double) 0xff)*g),
- (unsigned int)(((double) 0xff)*b));
+ if (c->is_default())
+ sprintf(buf, "000000");
+ else {
+ c->get_rgb(&r, &g, &b);
+ // we have to scale 0..0xFFFF to 0..0xFF
+ sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101);
+ }
out->put_string(buf);
out->put_string("\">");
}
diff --git a/src/devices/grohtml/post-html.cc b/src/devices/grohtml/post-html.cc
index 8d8b77fe..9d734ace 100644
--- a/src/devices/grohtml/post-html.cc
+++ b/src/devices/grohtml/post-html.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
*
* Gaius Mulley (gaius@glam.ac.uk) wrote post-html.cc
* but it owes a huge amount of ideas and raw code from
@@ -2687,14 +2687,12 @@ void html_printer::do_body (void)
if (background == NULL)
fputs("<body>\n\n", stdout);
else {
- double r, g, b;
+ unsigned int r, g, b;
char buf[6+1];
background->get_rgb(&r, &g, &b);
- sprintf(buf, "%.2X%.2X%.2X",
- (unsigned int)(((double) 0xff)*r),
- (unsigned int)(((double) 0xff)*g),
- (unsigned int)(((double) 0xff)*b));
+ // we have to scale 0..0xFFFF to 0..0xFF
+ sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101);
fputs("<body bgcolor=\"#", stdout);
fputs(buf, stdout);
@@ -2842,7 +2840,7 @@ int main(int argc, char **argv)
case 'b':
// set background color to white
default_background = new color;
- default_background->set_rgb(1.0, 1.0, 1.0);
+ default_background->set_gray(color::MAX_COLOR_VAL);
break;
case 'F':
font::command_line_font_dir(optarg);
diff --git a/src/devices/grops/ps.cc b/src/devices/grops/ps.cc
index 8f893197..2d6abf93 100644
--- a/src/devices/grops/ps.cc
+++ b/src/devices/grops/ps.cc
@@ -354,6 +354,26 @@ ps_output &ps_output::put_symbol(const char *s)
return *this;
}
+ps_output &ps_output::put_color(unsigned int c)
+{
+ char buf[128];
+ sprintf(buf, "%.3g", double(c) / color::MAX_COLOR_VAL);
+ int len = strlen(buf);
+ if (col > 0 && col + len + need_space > max_line_length) {
+ putc('\n', fp);
+ col = 0;
+ need_space = 0;
+ }
+ if (need_space) {
+ putc(' ', fp);
+ col++;
+ }
+ fputs(buf, fp);
+ col += len;
+ need_space = 1;
+ return *this;
+}
+
ps_output &ps_output::put_literal_symbol(const char *s)
{
int len = strlen(s);
@@ -476,15 +496,13 @@ class ps_printer : public printer {
int sbuf_space_code;
int sbuf_kern;
style sbuf_style;
- color *sbuf_color;
+ color sbuf_color; // the current PS color
style output_style;
int output_hpos;
int output_vpos;
int output_draw_point_size;
int line_thickness;
int output_line_thickness;
- color *fill_color;
- color *output_color;
unsigned char output_space_code;
enum { MAX_DEFINED_STYLES = 50 };
style defined_styles[MAX_DEFINED_STYLES];
@@ -506,12 +524,12 @@ class ps_printer : public printer {
void do_file(char *, const environment *);
void do_invis(char *, const environment *);
void do_endinvis(char *, const environment *);
- void set_line_thickness(const environment *);
- void fill_path();
+ void set_line_thickness_and_color(const environment *);
+ void fill_path(const environment *);
void encode_fonts();
void define_encoding(const char *, int);
void reencode_font(ps_font *);
- void set_color(color *c, int complete = 1);
+ void set_color(color *c, int fill = 0);
public:
ps_printer();
@@ -560,11 +578,6 @@ ps_printer::ps_printer()
if (paper_length == 0)
paper_length = 11*font::res;
equalise_spaces = font::res >= 72000;
- fill_color = new color;
- fill_color->set_gray(1.0); // black
- output_color = new color;
- output_color->set_gray(1.0);
- sbuf_color = output_color;
}
int ps_printer::set_encoding_index(ps_font *f)
@@ -599,7 +612,7 @@ void ps_printer::set_char(int i, font *f, const environment *env, int w, const c
if (sbuf_len < SBUF_SIZE
&& sty == sbuf_style
&& sbuf_vpos == env->vpos
- && sbuf_color->is_equal(env->col)) {
+ && sbuf_color == *env->col) {
if (sbuf_end_hpos == env->hpos) {
sbuf[sbuf_len++] = code;
sbuf_end_hpos += w + sbuf_kern;
@@ -654,7 +667,8 @@ void ps_printer::set_char(int i, font *f, const environment *env, int w, const c
sbuf_space_width = 0;
sbuf_space_count = sbuf_space_diff_count = 0;
sbuf_kern = 0;
- sbuf_color = env->col;
+ if (sbuf_color != *env->col)
+ set_color(env->col);
}
static char *make_encoding_name(int encoding_index)
@@ -782,18 +796,41 @@ void ps_printer::set_style(const style &sty)
defined_styles[ndefined_styles++] = sty;
}
-void ps_printer::set_color(color *col, int complete)
+void ps_printer::set_color(color *col, int fill)
{
- output_color = col;
- if (col) {
- double r, g, b;
- col->get_rgb(&r, &g, &b);
- out.put_float(r)
- .put_float(g)
- .put_float(b);
- if (complete)
- out.put_symbol("CO");
+ sbuf_color = *col;
+ unsigned int components[4];
+ char s[3];
+ color_scheme cs = col->get_components(components);
+ s[0] = fill ? 'F' : 'C';
+ s[2] = 0;
+ switch (cs) {
+ case DEFAULT: // black
+ out.put_symbol("0");
+ s[1] = 'g';
+ break;
+ case RGB:
+ out.put_color(Red)
+ .put_color(Green)
+ .put_color(Blue);
+ s[1] = 'r';
+ break;
+ case CMY:
+ col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black);
+ // fall through
+ case CMYK:
+ out.put_color(Cyan)
+ .put_color(Magenta)
+ .put_color(Yellow)
+ .put_color(Black);
+ s[1] = 'k';
+ break;
+ case GRAY:
+ out.put_color(Gray);
+ s[1] = 'g';
+ break;
}
+ out.put_symbol(s);
}
void ps_printer::set_space_code(unsigned char c)
@@ -826,8 +863,6 @@ void ps_printer::flush_sbuf()
set_style(sbuf_style);
output_style = sbuf_style;
}
- if (!output_color->is_equal(sbuf_color))
- set_color(sbuf_color);
int extra_space = 0;
if (output_hpos < 0 || output_vpos < 0)
motion = ABSOLUTE;
@@ -895,7 +930,7 @@ void ps_printer::flush_sbuf()
sbuf_len = 0;
}
-void ps_printer::set_line_thickness(const environment *env)
+void ps_printer::set_line_thickness_and_color(const environment *env)
{
if (line_thickness < 0) {
if (output_draw_point_size != env->size) {
@@ -915,32 +950,23 @@ void ps_printer::set_line_thickness(const environment *env)
output_draw_point_size = -1;
}
}
- if (!env->col->is_equal(output_color))
+ if (sbuf_color != *env->col)
set_color(env->col);
}
-void ps_printer::fill_path()
+void ps_printer::fill_path(const environment *env)
{
- double k;
- if (fill_color->is_gray()) {
- // gray shade is a special case
- fill_color->get_gray(&k);
- output_color = fill_color;
- out.put_float(1.0-k)
- .put_symbol("FL");
- }
- else if (fill_color->is_equal(output_color))
- out.put_symbol("BL");
- else {
- set_color(fill_color, 0);
- out.put_symbol("FC");
- }
+ if (sbuf_color == *env->fill)
+ out.put_symbol("FL");
+ else
+ set_color(env->fill, 1);
}
void ps_printer::draw(int code, int *p, int np, const environment *env)
{
if (invis_count > 0)
return;
+ flush_sbuf();
int fill_flag = 0;
switch (code) {
case 'C':
@@ -956,11 +982,10 @@ void ps_printer::draw(int code, int *p, int np, const environment *env)
.put_fix_number(env->vpos)
.put_fix_number(p[0]/2)
.put_symbol("DC");
- if (fill_flag) {
- fill_path();
- }
+ if (fill_flag)
+ fill_path(env);
else {
- set_line_thickness(env);
+ set_line_thickness_and_color(env);
out.put_symbol("ST");
}
break;
@@ -969,7 +994,7 @@ void ps_printer::draw(int code, int *p, int np, const environment *env)
error("2 arguments required for line");
break;
}
- set_line_thickness(env);
+ set_line_thickness_and_color(env);
out.put_fix_number(p[0] + env->hpos)
.put_fix_number(p[1] + env->vpos)
.put_fix_number(env->hpos)
@@ -989,11 +1014,10 @@ void ps_printer::draw(int code, int *p, int np, const environment *env)
.put_fix_number(env->hpos + p[0]/2)
.put_fix_number(env->vpos)
.put_symbol("DE");
- if (fill_flag) {
- fill_path();
- }
+ if (fill_flag)
+ fill_path(env);
else {
- set_line_thickness(env);
+ set_line_thickness_and_color(env);
out.put_symbol("ST");
}
break;
@@ -1018,11 +1042,10 @@ void ps_printer::draw(int code, int *p, int np, const environment *env)
.put_fix_number(p[i+1])
.put_symbol("RL");
out.put_symbol("CL");
- if (fill_flag) {
- fill_path();
- }
+ if (fill_flag)
+ fill_path(env);
else {
- set_line_thickness(env);
+ set_line_thickness_and_color(env);
out.put_symbol("ST");
}
break;
@@ -1060,7 +1083,7 @@ void ps_printer::draw(int code, int *p, int np, const environment *env)
out.put_fix_number(p[np - 2] - p[np - 2]/2)
.put_fix_number(p[np - 1] - p[np - 1]/2)
.put_symbol("RL");
- set_line_thickness(env);
+ set_line_thickness_and_color(env);
out.put_symbol("ST");
}
break;
@@ -1070,7 +1093,7 @@ void ps_printer::draw(int code, int *p, int np, const environment *env)
error("4 arguments required for arc");
break;
}
- set_line_thickness(env);
+ set_line_thickness_and_color(env);
double c[2];
if (adjust_arc_center(p, c))
out.put_fix_number(env->hpos + int(c[0]))
@@ -1099,22 +1122,6 @@ void ps_printer::draw(int code, int *p, int np, const environment *env)
line_thickness = p[0];
}
break;
- case 'f':
- if (np != 1 && np != 2) {
- error("1 argument required for fill");
- break;
- }
- if (p[0] < 0 || p[0] > FILL_MAX) {
- // This means fill with the current color.
- fill_color->set_gray(1.0);
- }
- else
- fill_color->set_gray(double(p[0]) / FILL_MAX);
- break;
- case 'F':
- // fill with color env->fill
- fill_color = env->fill;
- break;
default:
error("unrecognised drawing command `%1'", char(code));
break;
diff --git a/src/devices/grops/ps.h b/src/devices/grops/ps.h
index 6e78597d..0e149fc1 100644
--- a/src/devices/grops/ps.h
+++ b/src/devices/grops/ps.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.
@@ -26,6 +26,7 @@ public:
ps_output &put_fix_number(int);
ps_output &put_float(double);
ps_output &put_symbol(const char *);
+ ps_output &put_color(unsigned int);
ps_output &put_literal_symbol(const char *);
ps_output &set_fixed_point(int);
ps_output &simple_comment(const char *);
diff --git a/src/include/color.h b/src/include/color.h
index bd54be4d..9da07be5 100644
--- a/src/include/color.h
+++ b/src/include/color.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 2001 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
Written by Gaius Mulley <gaius@glam.ac.uk>
This file is part of groff.
@@ -19,57 +19,54 @@ with groff; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-enum color_scheme {NONE, CMY, CMYK, RGB, GRAY};
-
-// colors are internally held as CMYK values.
+enum color_scheme {DEFAULT, CMY, CMYK, RGB, GRAY};
class color {
private:
- unsigned int cyan;
- unsigned int magenta;
- unsigned int yellow;
- unsigned int black;
- color_scheme scheme; // how was the color originally defined?
- // and now the data structures necessary for the state machine
- // inside the read routines
- unsigned int color_space_num; // how many numbers have been read?
- enum {REAL, HEX, UNDEFINED} encoding;
- unsigned int hex_length;
- unsigned int c[4];
- double d[4];
-
- int read_encoding(const char *s, unsigned int n);
-
- public:
+ color_scheme scheme;
+ unsigned int components[4];
+
+ int read_encoding(color_scheme cs, const char *s, unsigned int n);
+
+public:
enum {MAX_COLOR_VAL = 0xffff};
color();
- int is_equal(color *c);
- int is_gray (void);
+ int operator==(const color & c) const;
+ int operator!=(const color & c) const;
+
+ int is_default() { return scheme == DEFAULT; }
+
+ void set_default();
void set_rgb(unsigned int r, unsigned int g, unsigned int b);
void set_cmy(unsigned int c, unsigned int m, unsigned int y);
void set_cmyk(unsigned int c, unsigned int m,
unsigned int y, unsigned int k);
- void set_gray(unsigned int l);
-
- void set_rgb(double r, double g, double b);
- void set_cmy(double c, double m, double y);
- void set_cmyk(double c, double m, double y, double k);
- void set_gray(double l);
+ void set_gray(unsigned int g);
int read_rgb(const char *s);
int read_cmy(const char *s);
int read_cmyk(const char *s);
int read_gray(const char *s);
+ color_scheme get_components(unsigned int *c);
+
void get_rgb(unsigned int *r, unsigned int *g, unsigned int *b);
void get_cmy(unsigned int *c, unsigned int *m, unsigned int *y);
void get_cmyk(unsigned int *c, unsigned int *m,
unsigned int *y, unsigned int *k);
- void get_gray(unsigned int *l);
-
- void get_rgb(double *r, double *g, double *b);
- void get_cmy(double *c, double *m, double *y);
- void get_cmyk(double *c, double *m, double *y, double *k);
- void get_gray(double *l);
+ void get_gray(unsigned int *g);
};
+
+#define Cyan components[0]
+#define Magenta components[1]
+#define Yellow components[2]
+#define Black components[3]
+
+#define Red components[0]
+#define Green components[1]
+#define Blue components[2]
+
+#define Gray components[0]
+
+extern color default_color;
diff --git a/src/include/lib.h b/src/include/lib.h
index e507ee84..f785d481 100644
--- a/src/include/lib.h
+++ b/src/include/lib.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989-2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2000, 2001, 2002 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -27,6 +27,7 @@ extern "C" {
char *strerror(int);
#endif
const char *i_to_a(int);
+ const char *ui_to_a(unsigned int);
const char *if_to_a(int, int);
}
diff --git a/src/libs/libdriver/input.cc b/src/libs/libdriver/input.cc
index efe63c38..629453df 100644
--- a/src/libs/libdriver/input.cc
+++ b/src/libs/libdriver/input.cc
@@ -1,190 +1,1446 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2001 Free Software Foundation, Inc.
- Written by James Clark (jjc@jclark.com)
-This file is part of groff.
+// <groff_src_dir>/src/libs/libdriver/input.cc
-groff is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
-version.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
+ Free Software Foundation, Inc.
-groff is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-for more details.
+ Written by James Clark (jjc@jclark.com)
+ Major rewrite 2001 by Bernd Warken (bwarken@mayn.de)
-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. */
+ Last update: 14 Jan 2002
+
+ This file is part of groff, the GNU roff text processing system.
+
+ groff is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ groff is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ 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.
+*/
+
+/* Description
+
+ This file implements the parser for the intermediate groff output,
+ see groff_out(5), and does the printout for the given device.
+
+ All parsed information is processed within the function do_file() by
+ using the global object `pr' of class `printer'. So a device
+ postprocessor just needs to fill in the methods for the class
+ `printer' without having to worry about the syntax of the
+ intermediate output format. Consequently, the programming of groff
+ postprocessors is similar to the development of device-drivers.
+
+ The prototyping for this file is done in driver.h (and error.h).
+
+ Postprocessor programs must deallocate the global variables `pr' and
+ `device' using `delete', and `current_filename' using
+ `free((char *))'.
+*/
+
+/* Changes of the 2001 rewrite of this file.
+
+ The interface to the outside and the handling of the global
+ variables was not changed, but internally many necessary changes
+ were performed.
+
+ The main aim for this rewrite is to provide a first step towards
+ making groff fully compatible with classical troff without pain.
+
+ Bugs fixed
+ - Unknown subcommands of `D' and `x' are now ignored like in the
+ classical case, but a warning is issued. This was also
+ implemented for the other commands.
+ - `DC' and `DE' commands didn't position to the right end after
+ drawing (now they do), see discussion below.
+ - So far, `x stop' was ignored. Now it terminates the processing
+ of the current intermediate output file like the classical troff.
+ - The command `c' didn't check correctly on white-space.
+ - The environment stack wasn't suitable for the color extensions
+ (replaced by a class).
+ - The old groff parser could only handle a prologue with the first
+ 3 lines having a fixed structure, while classical troff specified
+ the sequence of the first 3 commands without further
+ restrictions. Now the parser is smart about additional
+ white space, comments, and empty lines in the prologue.
+ - The old parser allowed space characters only as syntactical
+ separators, while classical troff had tab characters as well.
+ Now any sequence of tabs and/or spaces is a syntactical
+ separator between commands and/or arguments.
+ - Range checks for numbers implemented.
+
+ New and improved features
+ - The color commands `m' and `DF' are added.
+ - The old color command `Df' is now converted and delegated to `DFg'.
+ - The command `F' is implemented as `use intended file name'. It
+ checks whether its argument agrees with the file name used so far,
+ otherwise a warning is issued. Then the new name is remembered
+ and used for the following error messages.
+ - Positioning of drawing commands is corrected according to the
+ classical rule, see the discussion below.
+ - Setting commands (`Dt', `Df', `DF') and polygons (`Dp' and `DP')
+ do not change position now.
+ - Filled circles and ellipses (`DC' and `DE') position at their
+ most right point (outlined ones `Dc' and `De' did this anyway).
+ - As before, all open graphical objects position to their final
+ drawing point (alternate sum of the command arguments).
+ There is a macro STUPID_DRAWING_POSITIONING that implements the
+ old behavior for testing purposes.
+ - For the `D' commands that only set the environment, the calling of
+ pr->send_draw() was removed because this doesn't make sense for
+ the `DF' commands, and the (changed) environment is sent with the
+ next command anyway.
+ - Error handling was clearly separated into warnings and fatal.
+ - The error behavior on additional arguments for `D' and `x'
+ commands with a fixed number of arguments was changed from being
+ ignored (former groff) to issue a warning and ignore (now), see
+ skip_line_x(). No fatal was chosen because both string and
+ integer arguments can occur.
+ - All D commands with a variable number of args expect an even
+ number of trailing integer arguments, so fatal on error was
+ implemented.
+
+ Cosmetics
+ - Nested `switch' commands are avoided by using more functions.
+ Dangerous fall-thrus avoided.
+ - Commands and functions are sorted alphabetically (where possible).
+ - Dynamic arrays/buffers are now implemented as container classes.
+ - Some functions had an ugly return structure; this has been
+ streamlined by using classes.
+ - Use standard C math functions for number handling, so getting rid
+ of differences to '0'.
+ - The macro `IntArg' has been created for an easier transition
+ to guaranteed 32 bits integers (`int' is enough for GNU, while
+ ANSI only guarantees `long int' to have a length of 32 bits).
+ - The many usages of type `int' are differentiated by using `Char',
+ `bool', and `IntArg' where appropriate.
+ - To ease the calls of the local utility functions, the parser
+ variables `current_file', `npages', and `current_env'
+ (formerly env) were made global to the file (formerly they were
+ local to the do_file() function)
+ - Various comments were added.
+
+ TODO
+ - Should a missing `x stop' be warned?
+ - Get rid of the stupid drawing positioning.
+ - Can the `Dt' command be completely handled by setting environment
+ within do_file() instead of sending to pr?
+ - Integer arguments must be >= 32 bits, use conditional #define.
+ - Classical troff output had a quasi device independence by scaling
+ the intermediate output to the resolution of the postprocessor
+ device if different from the one specified with `x T', groff does
+ not. So implement full quasi device indepedence, including
+ the mapping of the strange classical devices to the postprocessor
+ device (seems to be reasonably easy).
+ - The external, global pointer variables are not optimally handled.
+ - `pr' isn't used outside besides initialization and deletion.
+ So it could be replaced by a static local variable. For
+ example, a wrapper class `Postprocessor' for class `printer' with
+ internal make_printer() and automatic clean-up would make sense.
+ - The global variables `current_filename' and `current_lineno' are
+ only used for error reporting. So implement a static class
+ `Error' (`::' calls).
+ - Can the global `device' be made independent of libgroff?
+ - Implement the B-spline drawing `D~' for all graphical devices.
+ - The class definitions of this document could go into a new file.
+ - Once things will have been settled the comments in this document
+ could be strongly reduced.
+*/
+
+/*
+ Discussion of the positioning by drawing commands
+
+ There was some confusion about the positioning of the graphical
+ pointer at the printout after having executed a `D' command.
+ The classical troff manual of Osanna & Kernighan specified,
+
+ `The position after a graphical object has been drawn is
+ at its end; for circles and ellipses, the "end" is at the
+ right side.'
+
+ From this, it follows that
+ - all open figures (args, splines, and lines) should position at their
+ final point.
+ - all circles and ellipses should position at their right-most point
+ (as if 2 halves had been drawn).
+ - all closed figures apart from circles and ellipses shouldn't change
+ the position because they return to their origin.
+ - all setting commands should not change position because they do not
+ draw any graphical object.
+
+ In the case of the open figures, this means that the horizontal
+ displacement is the sum of all odd arguments and the vertical offset
+ the sum of all even arguments, called the alternate arguments sum
+ displacement in the following.
+
+ Unfortunately, groff did not implement this simple rule. The former
+ documentation in groff_out(5) differed from the source code, and
+ neither of them is compatible with the classical rule.
+
+ The former groff_out(5) specified to use the alternative arguments
+ sum displacement for calculating the drawing positioning of
+ non-classical commands, including the `Dt' command (setting-only)
+ and closed polygons. Applying this to the new groff color commands
+ will lead to disaster. For their arguments can take large values (>
+ 65000). On low resolution devices, the displacement of such large
+ values will corrupt the display or kill the printer. So the
+ nonsense specification has come to a natural end anyway.
+
+ The groff source code, however, had no positioning for the
+ setting-only commands (esp. `Dt'), the right-end positioning for
+ outlined circles and ellipses, and the alternative argument sum
+ displacement for all other commands (including filled circles and
+ ellipses).
+
+ The reason why no one seems to have suffered from this mayhem so
+ far is that the graphical objects are usually generated by
+ preprocessors like pic that do not depend on the automatic
+ positioning. When using the low level `\D' escape sequences or `D'
+ output commands, the strange positionings can be circumvented by
+ absolute positionings or by tricks like `\Z'.
+
+ So doing an exorcism on the strange, incompatible displacements might
+ not harm any existing documents, but will make the usage of the
+ graphical escape sequences and commands natural.
+
+ That's why the rewrite of this file returned to the reasonable,
+ classical specification with its clear end-of-drawing rule that is
+ suitable for all cases. But a macro STUPID_DRAWING_POSITIONING is
+ provided for testing the funny former behavior.
+*/
+
+#ifndef STUPID_DRAWING_POSITIONING
+// uncomment next line if all non-classical D commands shall position
+// to the strange alternate sum of args displacement
+#define STUPID_DRAWING_POSITIONING
+#endif
#include "driver.h"
#include "device.h"
-#include "cset.h"
-const char *current_filename=0;
-int current_lineno;
-const char *device = 0;
-FILE *current_file;
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <math.h>
+
+/**********************************************************************
+ local types
+ **********************************************************************/
+
+// integer arguments of groff_out commands, must be >= 32 bits
+typedef int IntArg;
+
+// color components of groff_out color commands, must be >= 32 bits
+typedef unsigned int ColorArg;
-int get_integer(); // don't read the newline
-int possibly_get_integer(int *);
-char *get_string(int is_long = 0);
-void skip_line();
+class EnvStack {
+ environment **data;
+ size_t num_allocated;
+ size_t num_stored;
+public:
+ EnvStack(void);
+ ~EnvStack(void);
+ environment *pop(void);
+ void push(environment *e);
+};
+
+// Array for IntArg values.
+class IntArray {
+ size_t num_allocated;
+public:
+ IntArg *data;
+ size_t num_stored;
+ IntArray(void);
+ IntArray(const int);
+ ~IntArray(void);
+ void append(IntArg);
+};
-struct environment_list {
- environment env;
- environment_list *next;
+// Characters read from the input queue.
+class Char {
+ int data;
+public:
+ Char(void) : data('\0') {}
+ Char(const int c) : data(c) {}
+ bool operator==(int c) { return (data == c) ? true : false; }
+ bool operator==(Char c) { return (data == c.data) ? true : false; }
+ operator int() const { return (int) data; }
+ operator unsigned char() const { return (unsigned char) data; }
+ operator char() const { return (char) data; }
+};
- environment_list(const environment &, environment_list *);
+// Buffer for string arguments (Char, not char).
+class StringBuf {
+ size_t num_allocated;
+ size_t num_stored;
+ Char *data; // not terminated by '\0'
+public:
+ StringBuf(void); // allocate without storing
+ ~StringBuf(void);
+ void append(const Char); // append character to `data'
+ char *make_string(void); // return new copy of `data' with '\0'
+ bool is_empty(void) { // true if none stored
+ return (num_stored > 0) ? false : true;
+ }
+ void reset(void); // set `num_stored' to 0
};
-environment_list::environment_list(const environment &e, environment_list *p)
-: env(e), next(p)
+/**********************************************************************
+ external variables
+ **********************************************************************/
+
+// exported as extern by error.h (called from driver.h)
+// needed for error messages (see ../libgroff/error.cc)
+const char *current_filename = 0; // printable name of the current file
+int current_lineno = 0; // current line number of printout
+
+// exported as extern by device.h;
+const char *device = 0; // cancel former init with literal
+
+// from driver.h; pr is kept between several runs of do_file()
+// extern printer *pr;
+
+// Note:
+//
+// We rely on an implementation of the `new' operator which aborts
+// gracefully if it can't allocate memory (e.g. from libgroff/new.cc).
+
+
+/**********************************************************************
+ static local variables
+ **********************************************************************/
+
+FILE *current_file = 0; // current input stream for parser
+
+// parser environment, created and deleted by each run of do_file()
+environment *current_env = 0;
+
+// npages: number of pages processed so far (including current page),
+// _not_ the page number in the printout (can be set with `p').
+int npages = 0;
+
+const ColorArg
+COLORARG_MAX = (ColorArg) 65536U; // == 0xFFFF + 1 == 0x10000
+
+const IntArg
+INTARG_MAX = (IntArg) 0x7FFFFFFF; // maximal signed 32 bits number
+
+const size_t
+envp_size = sizeof(environment *);
+
+
+/**********************************************************************
+ function declarations
+ **********************************************************************/
+
+// utility functions
+ColorArg color_from_Df_command(IntArg); // transform old color into new
+void fatal_command(char); // abort for illegal command
+inline Char get_char(void); // read next character from input stream
+ColorArg get_color_arg(void); // read in argument for new color cmds
+IntArray *get_D_fixed_args(const int, const bool = false); // read in fixed no. of int args
+IntArray *get_D_variable_args(void); // variable, even no. of int args
+char *get_extended_arg(void); // argument for `x X' (several lines)
+IntArg get_integer_arg(void); // read in next integer argument
+char *get_string_arg(void); // read in next string arg, ended by WS
+inline bool is_space_or_tab(const Char); // test on space/tab char
+Char next_arg_begin(void); // skip white space on current line
+Char next_command(void); // go to next command, evt. diff. line
+inline bool odd(const int); // test if integer is odd
+void position_to_end_of_args(const IntArray *); // after drawing
+void remember_filename(const char *); // set global current_filename
+void send_draw(const Char, const IntArray *); // call pr->draw
+void skip_line(void); // unconditionally skip to next line
+bool skip_line_checked(void); // skip line, false if args are left
+void skip_line_fatal(void); // skip line, fatal if args are left
+void skip_line_warn(void); // skip line, warn if args are left
+void skip_line_x(); // skip line in x and D commands
+inline void unget_char(const Char); // restore character onto input
+
+// parser subcommands
+void parse_color_command(color *); // color sub(sub)commands m and DF
+void parse_D_command(void); // graphical subcommands
+bool parse_x_command(void); // device controller subcommands
+
+/**********************************************************************
+ class methods
+ **********************************************************************/
+
+EnvStack::EnvStack(void) {
+ num_allocated = 4;
+ // allocate pointer to array of num_allocated pointers to environment
+ data = (environment **) malloc(envp_size * num_allocated);
+ if (data == 0)
+ fatal("could not allocate environment data");
+ num_stored = 0;
+}
+
+EnvStack::~EnvStack(void) {
+ for (size_t i = 0; i < num_stored; i++)
+ delete data[i];
+ free(data);
+}
+
+// return top element from stack and decrease stack pointer
+//
+// the calling function must take care of properly deleting the result
+environment *
+EnvStack::pop(void) {
+ num_stored--;
+ environment *result = data[num_stored];
+ data[num_stored] = 0;
+ return result;
+}
+
+// copy argument and push this onto the stack
+void
+EnvStack::push(environment *e) {
+ environment *e_copy = new environment;
+ if (num_stored >= num_allocated) {
+ environment **old_data = data;
+ num_allocated *= 2;
+ data = (environment **) malloc(envp_size * num_allocated);
+ if (data == 0)
+ fatal("could not allocate data");
+ for (size_t i = 0; i < num_stored; i++)
+ data[i] = old_data[i];
+ free(old_data);
+ }
+ e_copy->col = new color;
+ e_copy->fill = new color;
+ *e_copy->col = *e->col;
+ *e_copy->fill = *e->fill;
+ e_copy->fontno = e->fontno;
+ e_copy->height = e->height;
+ e_copy->hpos = e->hpos;
+ e_copy->size = e->size;
+ e_copy->slant = e->slant;
+ e_copy->vpos = e->vpos;
+ data[num_stored] = e_copy;
+ num_stored++;
+}
+
+IntArray::IntArray(void) {
+ num_allocated = 4;
+ data = new IntArg[num_allocated];
+ num_stored = 0;
+}
+
+IntArray::IntArray(const int n) {
+ if (n <= 0)
+ fatal("number of integers to be allocated must be > 0");
+ num_allocated = n;
+ data = new IntArg[num_allocated];
+ num_stored = 0;
+}
+
+IntArray::~IntArray(void) {
+ a_delete data;
+}
+
+void
+IntArray::append(IntArg x) {
+ if (num_stored >= num_allocated) {
+ IntArg *old_data = data;
+ num_allocated *= 2;
+ data = new IntArg[num_allocated];
+ for (size_t i = 0; i < num_stored; i++)
+ data[i] = old_data[i];
+ a_delete old_data;
+ }
+ data[num_stored] = x;
+ num_stored++;
+}
+
+StringBuf::StringBuf(void) {
+ num_stored = 0;
+ num_allocated = 128;
+ data = new Char[num_allocated];
+}
+
+StringBuf::~StringBuf(void) {
+ a_delete data;
+}
+
+void
+StringBuf::append(const Char c) {
+ if (num_stored >= num_allocated) {
+ Char *old_data = data;
+ num_allocated *= 2;
+ data = new Char[num_allocated];
+ for (size_t i = 0; i < num_stored; i++)
+ data[i] = old_data[i];
+ a_delete old_data;
+ }
+ data[num_stored] = c;
+ num_stored++;
+}
+
+char *
+StringBuf::make_string(void) {
+ char *result = new char[num_stored + 1];
+ for (size_t i = 0; i < num_stored; i++)
+ result[i] = (char) data[i];
+ result[num_stored] = '\0';
+ return result;
+}
+
+void
+StringBuf::reset(void) {
+ num_stored = 0;
+}
+
+/**********************************************************************
+ utility functions
+ **********************************************************************/
+
+//////////////////////////////////////////////////////////////////////
+/* color_from_Df_command:
+ Process the gray shade setting command Df.
+
+ Transform Df style color into DF style color.
+ Df color: 0-1000, 0 is white
+ DF color: 0-65536, 0 is black
+
+ The Df command is obsoleted by command DFg, but kept for
+ compatibility.
+
+ XXX: Add proper handling for values < 0 or > 1000 as documented in
+ groff_out(5).
+*/
+ColorArg
+color_from_Df_command(IntArg Df_gray)
{
+ if (Df_gray <= 0)
+ return COLORARG_MAX;
+ if (Df_gray >= 1000)
+ return 0;
+ return ColorArg((1000-Df_gray) * COLORARG_MAX / 1000); // scaling
}
-inline int get_char()
+//////////////////////////////////////////////////////////////////////
+/* fatal_command():
+ Emit error message about illegal command and abort.
+*/
+void
+fatal_command(char command)
{
- return getc(current_file);
+ fatal("`%1' command illegal before first `p' command", command);
}
-/*
- * remember_filename - is needed as get_string might overwrite the
- * filename eventually.
- */
+//////////////////////////////////////////////////////////////////////
+/* get_char():
+ Retrieve the next character from the input queue.
-void remember_filename(const char *filename)
+ Return: The retrieved character (incl. EOF), converted to Char.
+*/
+inline Char
+get_char(void)
{
- if (current_filename != 0) {
- free((char *)current_filename);
+ return (Char) getc(current_file);
+}
+
+//////////////////////////////////////////////////////////////////////
+/* get_color_arg():
+ Retrieve an argument suitable for the color commands m and DF.
+
+ Return: The retrieved color argument.
+*/
+ColorArg
+get_color_arg(void) {
+ IntArg x = get_integer_arg();
+ if (x < 0 || x > (IntArg)COLORARG_MAX) {
+ error("color component argument out of range");
+ x = 0;
}
- if (strcmp(filename, "-") == 0) {
- filename = "<standard input>";
+ return (ColorArg) x;
+}
+
+//////////////////////////////////////////////////////////////////////
+/* get_D_fixed_args():
+ Get a fixed number of integer args for D commands.
+
+ Fatal if wrong number of arguments.
+ Too many arguments on the line raise a warning.
+ A line skip is done.
+
+ number: In-parameter, the number of args to be retrieved.
+ ignore: In-parameter, ignore next argument -- GNU troff always emits
+ pairs of parameters for `D' extensions. Default is `false'.
+
+ Return: New IntArray containing the arguments.
+*/
+IntArray *
+get_D_fixed_args(const int number, const bool ignore) {
+ if (number <= 0)
+ fatal("requested number of arguments must be > 0");
+ IntArray *args = new IntArray(number);
+ for (int i = 0; i < number; i++)
+ args->append(get_integer_arg());
+ if (ignore)
+ (void) get_integer_arg();
+ skip_line_x();
+ return args;
+}
+
+//////////////////////////////////////////////////////////////////////
+/* get_D_variable_args():
+ Get a variable even number of integer args for D commands.
+
+ Get as many integer arguments as possible from the rest of the
+ current line.
+ - The arguments are separated by an arbitrary sequence of space or
+ tab characters.
+ - A comment, a newline, or EOF indicates the end of processing.
+ - Error on non-digit characters different from these.
+ - A final line skip is performed (except for EOF).
+
+ Return: New IntArray of the retrieved arguments.
+*/
+IntArray *
+get_D_variable_args()
+{
+ bool done = false;
+ StringBuf buf = StringBuf();
+ Char c = get_char();
+ IntArray *args = new IntArray();
+ while (!done) {
+ buf.reset();
+ while (is_space_or_tab(c))
+ c = get_char();
+ if (c == '-') {
+ Char c1 = get_char();
+ if (isdigit((int) c1)) {
+ buf.append(c);
+ c = c1;
+ }
+ else
+ unget_char(c1);
+ }
+ while (isdigit((int) c)) {
+ buf.append(c);
+ c = get_char();
+ }
+ if (!buf.is_empty()) {
+ char *s = buf.make_string();
+ errno = 0;
+ long int x = strtol(s, 0, 10);
+ if (errno
+ || x > INTARG_MAX || x < -INTARG_MAX) {
+ error("invalid integer argument, set to 0");
+ x = 0;
+ }
+ args->append((IntArg) x);
+ delete s;
+ }
+ // Here, c is not a digit.
+ // Terminate on comment, end of line, or end of file, while
+ // space or tab indicate continuation; otherwise error.
+ switch((int) c) {
+ case '#':
+ skip_line();
+ done = true;
+ break;
+ case '\n':
+ current_lineno++;
+ done = true;
+ break;
+ case EOF:
+ done = true;
+ break;
+ case ' ':
+ case '\t':
+ break;
+ default:
+ error("integer argument expected");
+ break;
+ }
}
- current_filename = (const char *)malloc(strlen(filename) + 1);
- if (current_filename == 0) {
+ if (args->num_stored <= 0)
+ error("no arguments found");
+ if (odd(args->num_stored))
+ error("even number of arguments expected");
+ return args;
+}
+
+//////////////////////////////////////////////////////////////////////
+/* get_extended_arg():
+ Retrieve extended arg for `x X' command.
+
+ - Skip leading spaces and tabs, error on EOL or newline.
+ - Return everything before the next NL or EOF ('#' is not a comment);
+ as long as the following line starts with '+' this is returned
+ as well, with the '+' replaced by a newline.
+ - Final line skip is always performed.
+
+ Return: Allocated (new) string of retrieved text argument.
+*/
+char *
+get_extended_arg(void)
+{
+ StringBuf buf = StringBuf();
+ Char c = next_arg_begin();
+ while ((int) c != EOF) {
+ if ((int) c == '\n') {
+ current_lineno++;
+ c = get_char();
+ if ((int) c == '+')
+ buf.append((Char) '\n');
+ else {
+ unget_char(c); // first character of next line
+ break;
+ }
+ }
+ buf.append(c);
+ c = get_char();
+ }
+ return buf.make_string();
+}
+
+//////////////////////////////////////////////////////////////////////
+/* get_integer_arg(): Retrieve integer argument.
+
+ Skip leading spaces and tabs, collect an optional '-' and all
+ following decimal digits (at least one) up to the next non-digit,
+ which is restored onto the input queue.
+
+ Fatal error on all other situations.
+
+ Return: Retrieved integer.
+*/
+IntArg
+get_integer_arg(void)
+{
+ StringBuf buf = StringBuf();
+ Char c = next_arg_begin();
+ if ((int) c == '-') {
+ buf.append(c);
+ c = get_char();
+ }
+ if (!isdigit((int) c))
+ error("integer argument expected");
+ while (isdigit((int) c)) {
+ buf.append(c);
+ c = get_char();
+ }
+ // c is not a digit
+ unget_char(c);
+ char *s = buf.make_string();
+ errno = 0;
+ long int number = strtol(s, 0, 10);
+ if (errno != 0
+ || number > INTARG_MAX || number < -INTARG_MAX) {
+ error("integer argument too large");
+ number = 0;
+ }
+ delete s;
+ return (IntArg) number;
+}
+
+//////////////////////////////////////////////////////////////////////
+/* get_string_arg():
+ Retrieve string arg.
+
+ - Skip leading spaces and tabs; error on EOL or newline.
+ - Return all following characters before the next space, tab,
+ newline, or EOF character (in-word '#' is not a comment character).
+ - The terminating space, tab, newline, or EOF character is restored
+ onto the input queue, so no line skip.
+
+ Return: Retrieved string as char *, allocated by 'new'.
+*/
+char *
+get_string_arg(void)
+{
+ StringBuf buf = StringBuf();
+ Char c = next_arg_begin();
+ while (!is_space_or_tab(c)
+ && c != Char('\n') && c != Char(EOF)) {
+ buf.append(c);
+ c = get_char();
+ }
+ unget_char(c); // restore white space
+ return buf.make_string();
+}
+
+//////////////////////////////////////////////////////////////////////
+/* is_space_or_tab():
+ Test a character if it is a space or tab.
+
+ c: In-parameter, character to be tested.
+
+ Return: True, if c is a space or tab character, false otherwise.
+*/
+inline bool
+is_space_or_tab(const Char c)
+{
+ return (c == (Char) ' ' || c == (Char) '\t') ? true : false;
+}
+
+//////////////////////////////////////////////////////////////////////
+/* next_arg_begin():
+ Return first character of next argument.
+
+ Skip space and tab characters; error on newline or EOF.
+
+ Return: The first character different from these (including '#').
+*/
+Char
+next_arg_begin(void)
+{
+ Char c;
+ while (1) {
+ c = get_char();
+ switch ((int) c) {
+ case ' ':
+ case '\t':
+ break;
+ case '\n':
+ case EOF:
+ error("missing argument");
+ break;
+ default: // first essential character
+ return c;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+/* next_command():
+ Find the first character of the next command.
+
+ Skip spaces, tabs, comments (introduced by #), and newlines.
+
+ Return: The first character different from these (including EOF).
+*/
+Char
+next_command(void)
+{
+ Char c;
+ while (1) {
+ c = get_char();
+ switch ((int) c) {
+ case ' ':
+ case '\t':
+ break;
+ case '\n':
+ current_lineno++;
+ break;
+ case '#': // comment
+ skip_line();
+ break;
+ default: // EOF or first essential character
+ return c;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+/* odd():
+ Test whether argument is an odd number.
+
+ n: In-parameter, the integer to be tested.
+
+ Return: True if odd, false otherwise.
+*/
+inline bool
+odd(const int n)
+{
+ return (n & 1 == 1) ? true : false;
+}
+
+//////////////////////////////////////////////////////////////////////
+/* position_to_end_of_args():
+ Move graphical pointer to end of drawn figure.
+
+ This is used by the D commands that draw open geometrical figures.
+ The algorithm simply sums up all horizontal displacements (arguments
+ with even number) for the horizontal component. Similarly, the
+ vertical component is the sum of the odd arguments.
+
+ args: In-parameter, the arguments of a former drawing command.
+*/
+void
+position_to_end_of_args(const IntArray *args)
+{
+ int i;
+ int nr = args->num_stored;
+ for (i = 0; i < nr; i += 2)
+ current_env->hpos += args->data[i];
+ for (i = 1; i < nr; i += 2)
+ current_env->vpos += args->data[i];
+}
+
+//////////////////////////////////////////////////////////////////////
+/* remember_filename():
+ Set global variable current_filename.
+
+ The actual filename is stored in current_filename. This is used by
+ the postprocessors, expecting the name "<standard input>" for stdin.
+
+ filename: In-out-parameter; is changed to the new value also.
+*/
+void
+remember_filename(const char *filename)
+{
+ char *fname;
+ if (strcmp(filename, "-") == 0)
+ fname = "<standard input>";
+ else
+ fname = (char *) filename;
+ size_t len = strlen(fname) + 1;
+ if (current_filename != 0)
+ free((char *)current_filename);
+ current_filename = (const char *) malloc(len);
+ if (current_filename == 0)
fatal("can't malloc space for filename");
+ strncpy((char *)current_filename, (char *)fname, len);
+}
+
+//////////////////////////////////////////////////////////////////////
+/* send_draw():
+ Call draw method of printer class.
+
+ subcmd: Letter of actual D subcommand.
+ args: Array of integer arguments of actual D subcommand.
+*/
+void
+send_draw(const Char subcmd, const IntArray *args) {
+ pr->draw((int) subcmd, args->data, args->num_stored,
+ current_env);
+}
+
+//////////////////////////////////////////////////////////////////////
+/* skip_line():
+ Go to next line within the input queue.
+
+ Skip the rest of the current line, including the newline character.
+ The global variable current_lineno is adjusted.
+ No errors are raised.
+*/
+void
+skip_line(void)
+{
+ Char c = get_char();
+ while (1) {
+ if (c == '\n') {
+ current_lineno++;
+ break;
+ }
+ if (c == EOF)
+ break;
+ c = get_char();
}
- strcpy((char *)current_filename, (char *)filename);
}
-void do_file(const char *filename)
+//////////////////////////////////////////////////////////////////////
+/* skip_line_checked ():
+ Check that the rest of the line has no args left, then skip line.
+
+ Spaces, tabs, and a comment are allowed before newline or EOF.
+ All other characters raise an error.
+*/
+bool
+skip_line_checked()
{
- int npages = 0;
- if (filename[0] == '-' && filename[1] == '\0') {
- remember_filename(filename);
- current_file = stdin;
+ bool ok = true;
+ Char c = get_char();
+ while (is_space_or_tab(c))
+ c = get_char();
+ switch((int) c) {
+ case '#': // comment
+ skip_line();
+ break;
+ case '\n':
+ current_lineno++;
+ break;
+ case EOF:
+ break;
+ default:
+ ok = false;
+ skip_line();
+ break;
+ }
+ return ok;
+}
+
+//////////////////////////////////////////////////////////////////////
+/* skip_line_fatal ():
+ Fatal error if args left, otherwise skip line.
+
+ Spaces, tabs, and a comment are allowed before newline or EOF.
+ All other characters trigger the error.
+*/
+void
+skip_line_fatal()
+{
+ bool ok = skip_line_checked();
+ if (!ok) {
+ current_lineno--;
+ error("too many arguments");
+ current_lineno++;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+/* skip_line_warn ():
+ Skip line, but warn if args are left on actual line.
+
+ Spaces, tabs, and a comment are allowed before newline or EOF.
+ All other characters raise a warning
+*/
+void
+skip_line_warn()
+{
+ bool ok = skip_line_checked();
+ if (!ok) {
+ current_lineno--;
+ warning("too many arguments on current line");
+ current_lineno++;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+/* skip_line_x ():
+ Skip line in `x' or `D' commands.
+
+ Decide whether in case of an additional argument a fatal error is
+ raised (the documented classical behavior), only a warning is
+ issued, or the line is just skipped (former groff behavior).
+ Actually decided for the warning.
+*/
+void
+skip_line_x()
+{
+ skip_line_warn();
+ // or: skip_line_fatal();
+ // or: skip_line();
+}
+
+//////////////////////////////////////////////////////////////////////
+/* unget_char(c):
+ Restore character c onto input queue.
+
+ Write a character back onto the input stream.
+ EOF is gracefully handled.
+
+ c: In-parameter; character to be pushed onto the input queue.
+*/
+inline void
+unget_char(const Char c)
+{
+ if (c != EOF) {
+ int ch = (int) c;
+ if (ungetc(ch, current_file) == EOF)
+ fatal("could not unget character");
+ }
+}
+
+
+/**********************************************************************
+ parser subcommands
+ **********************************************************************/
+
+//////////////////////////////////////////////////////////////////////
+/* parse_color_command:
+ Process the commands m and DF, but not Df.
+
+ col: In-out-parameter; the color object to be set, must have
+ been initialized before.
+*/
+void
+parse_color_command(color *col)
+{
+ ColorArg gray = 0;
+ ColorArg red = 0, green = 0, blue = 0;
+ ColorArg cyan = 0, magenta = 0, yellow = 0, black = 0;
+ Char subcmd = next_arg_begin();
+ switch((int) subcmd) {
+ case 'c': // DFc or mc: CMY
+ cyan = get_color_arg();
+ magenta = get_color_arg();
+ yellow = get_color_arg();
+ col->set_cmy(cyan, magenta, yellow);
+ break;
+ case 'd': // DFd or md: set default color
+ col->set_default();
+ break;
+ case 'g': // DFg or mg: gray
+ gray = get_color_arg();
+ col->set_gray(gray);
+ break;
+ case 'k': // DFk or mk: CMYK
+ cyan = get_color_arg();
+ magenta = get_color_arg();
+ yellow = get_color_arg();
+ black = get_color_arg();
+ col->set_cmyk(cyan, magenta, yellow, black);
+ break;
+ case 'r': // DFr or mr: RGB
+ red = get_color_arg();
+ green = get_color_arg();
+ blue = get_color_arg();
+ col->set_rgb(red, green, blue);
+ break;
+ default:
+ error("illegal color scheme `%1'", (int) subcmd);
+ break;
+ } // end of color subcommands
+}
+
+//////////////////////////////////////////////////////////////////////
+/* parse_D_command():
+ Parse the subcommands of graphical command D.
+
+ This is the part of the do_file() parser that scans the graphical
+ subcommands.
+ - Error on lacking or wrong arguments.
+ - Warning on too many arguments.
+ - Line is always skipped.
+*/
+void
+parse_D_command()
+{
+ Char subcmd = next_arg_begin();
+ switch((int) subcmd) {
+ case '~': // D~: draw B-spline
+ // actually, this isn't available for some postprocessors
+ {
+ IntArray *args = get_D_variable_args();
+ send_draw(subcmd, args);
+ position_to_end_of_args(args);
+ delete args;
+ break;
+ }
+ case 'a': // Da: draw arc
+ {
+ IntArray *args = get_D_fixed_args(4);
+ send_draw(subcmd, args);
+ position_to_end_of_args(args);
+ delete args;
+ break;
+ }
+ case 'c': // Dc: draw circle line
+ case 'C': // DC: draw solid circle
+ {
+ IntArray *args = get_D_fixed_args(1, subcmd == 'C' ? true : false);
+ send_draw(subcmd, args);
+ // move to right end
+ current_env->hpos += args->data[0];
+ delete args;
+ break;
+ }
+ case 'e': // De: draw ellipse line
+ case 'E': // DE: draw solid ellipse
+ {
+ IntArray *args = get_D_fixed_args(2);
+ send_draw(subcmd, args);
+ // move to right end
+ current_env->hpos += args->data[0];
+ delete args;
+ break;
+ }
+ case 'f': // Df: set fill gray; obsoleted by DFg
+ {
+ // convert arg and treat it like DFg
+ ColorArg gray = color_from_Df_command(get_integer_arg());
+ // skip the unused `vertical' component -- \D'...' always emits pairs
+ (void) get_integer_arg();
+ current_env->fill->set_gray(gray);
+ // no positioning
+ skip_line_x();
+ break;
+ }
+ case 'F': // DF: set fill color, several formats
+ parse_color_command(current_env->fill);
+ // no positioning (setting-only command)
+ skip_line_x();
+ break;
+ case 'l': // DFl: draw line
+ {
+ IntArray *args = get_D_fixed_args(2);
+ send_draw(subcmd, args);
+ position_to_end_of_args(args);
+ delete args;
+ break;
+ }
+ case 'p': // Dp: draw closed polygon line
+ case 'P': // DP: draw solid closed polygon
+ {
+ IntArray *args = get_D_variable_args();
+ send_draw(subcmd, args);
+# ifdef STUPID_DRAWING_POSITIONING
+ // final args positioning
+ position_to_end_of_args(args);
+# endif
+ delete args;
+ break;
+ }
+ case 't': // Dt: set line thickness
+ {
+ IntArray *args = get_D_fixed_args(1, true);
+ send_draw(subcmd, args);
+# ifdef STUPID_DRAWING_POSITIONING
+ // final args positioning
+ position_to_end_of_args(args);
+# endif
+ // no positioning?
+ delete args;
+ break;
+ }
+ default: // ignore unknown D commands, but warn
+ warning("unknown command `D%1'", (char) subcmd);
+ skip_line();
+ // no positioning
+ break;
+ } // end of D subcommands
+}
+
+//////////////////////////////////////////////////////////////////////
+/* parse_x_command():
+ Parse subcommands of the device control command x.
+
+ This is the part of the do_file() parser that scans the device
+ controlling commands.
+ - Error on duplicate prologue commands.
+ - Error on wrong or lacking arguments.
+ - Warning on too many arguments.
+ - Line is always skipped.
+
+ Globals:
+ - current_env: is set by many subcommands.
+ - npages: page counting variable
+
+ Return: boolean in the meaning of `stopped'
+ - true if parsing should be stopped (`x stop').
+ - false if parsing should continue.
+*/
+bool
+parse_x_command(void)
+{
+ bool stopped = false;
+ char *subcmd_str = get_string_arg();
+ char subcmd = subcmd_str[0];
+ switch (subcmd) {
+ case 'f': // x font: mount font
+ {
+ IntArg n = get_integer_arg();
+ char *name = get_string_arg();
+ pr->load_font(n, name);
+ delete name;
+ skip_line_x();
+ break;
+ }
+ case 'F': // x Filename: set filename for errors
+ {
+ char *str_arg = get_string_arg();
+ if (str_arg == 0)
+ warning("empty argument for `x F' command");
+ else {
+ remember_filename(str_arg);
+ delete str_arg;
+ }
+ break;
+ }
+ case 'H': // x Height: set character height
+ current_env->height = get_integer_arg();
+ if (current_env->height == current_env->size)
+ current_env->height = 0;
+ skip_line_x();
+ break;
+ case 'i': // x init: initialize device
+ error("duplicate `x init' command");
+ skip_line_x();
+ break;
+ case 'p': // x pause: pause device
+ skip_line_x();
+ break;
+ case 'r': // x res: set resolution
+ error("duplicate `x res' command");
+ skip_line_x();
+ break;
+ case 's': // x stop: stop device
+ stopped = true;
+ skip_line_x();
+ break;
+ case 'S': // x Slant: set slant
+ current_env->slant = get_integer_arg();
+ skip_line_x();
+ break;
+ case 't': // x trailer: generate trailer info
+ skip_line_x();
+ break;
+ case 'T': // x Typesetter: set typesetter
+ error("duplicate `x T' command");
+ skip_line();
+ break;
+ case 'u': // x underline: from .cu
+ {
+ char *str_arg = get_string_arg();
+ pr->special(str_arg, current_env, 'u');
+ delete str_arg;
+ skip_line_x();
+ break;
+ }
+ case 'X': // x X: send uninterpretedly to device
+ {
+ char *str_arg = get_extended_arg(); // includes line skip
+ if (npages <= 0)
+ error("`x X' command illegal before first `p' command");
+ else
+ pr->special(str_arg, current_env);
+ delete str_arg;
+ break;
+ }
+ default: // ignore unknown x commands, but warn
+ warning("unknown command `x %1'", subcmd);
+ skip_line();
}
+ delete subcmd_str;
+ return stopped;
+}
+
+
+/**********************************************************************
+ exported part (by driver.h)
+ **********************************************************************/
+
+////////////////////////////////////////////////////////////////////////
+/* do_file():
+ Parse and postprocess groff intermediate output.
+
+ filename: "-" for standard input, normal file name otherwise
+*/
+void
+do_file(const char *filename)
+{
+ Char command;
+ EnvStack env_stack = EnvStack();
+ bool stopped = false; // terminating condition
+
+ // setup of global variables
+ npages = 0;
+ current_lineno = 1;
+ // `pr' is initialized after the prologue.
+ // `device' is set by the 1st prologue command.
+
+ if (filename[0] == '-' && filename[1] == '\0')
+ current_file = stdin;
else {
errno = 0;
current_file = fopen(filename, "r");
- if (current_file == 0) {
- error("can't open `%1'", filename);
+ if (errno != 0 || current_file == 0) {
+ error("can't open file `%1'", filename);
return;
}
- remember_filename(filename);
}
- environment env;
- env.vpos = -1;
- env.hpos = -1;
- env.fontno = -1;
- env.height = 0;
- env.slant = 0;
- env.col = new color;
- env.col->set_gray(1.0);
- env.fill = new color;
- env.fill->set_gray(1.0);
- environment_list *env_list = 0;
- current_lineno = 1;
- int command;
- char *s;
- command = get_char();
- if (command == EOF)
- return;
- if (command != 'x')
- fatal("the first command must be `x T'");
- s = get_string();
- if (s[0] != 'T')
- fatal("the first command must be `x T'");
- char *dev = get_string();
- if (pr == 0) {
- device = strsave(dev);
- if (!font::load_desc())
- fatal("sorry, I can't continue");
+ remember_filename(filename);
+
+ if (current_env != 0) {
+ delete current_env->col;
+ delete current_env->fill;
+ delete current_env;
}
- else {
- if (device == 0 || strcmp(device, dev) != 0)
- fatal("all files must use the same device");
+ current_env = new environment;
+ current_env->col = new color;
+ current_env->fill = new color;
+ current_env->fontno = -1;
+ current_env->height = 0;
+ current_env->hpos = -1;
+ current_env->slant = 0;
+ current_env->size = 0;
+ current_env->vpos = -1;
+
+ // parsing of prologue (first 3 commands)
+ {
+ char *str_arg;
+ IntArg int_arg;
+
+ // 1st command `x T'
+ command = next_command();
+ if ((int) command == EOF)
+ return;
+ if ((int) command != 'x')
+ fatal("the first command must be `x T'");
+ str_arg = get_string_arg();
+ if (str_arg[0] != 'T')
+ fatal("the first command must be `x T'");
+ delete str_arg;
+ char *tmp_dev = get_string_arg();
+ if (pr == 0) { // note: `pr' initialized after prologue
+ device = tmp_dev;
+ if (!font::load_desc())
+ fatal("couldn't load DESC file, can't continue");
+ }
+ else {
+ if (device == 0 || strcmp(device, tmp_dev) != 0)
+ fatal("all files must use the same device");
+ delete tmp_dev;
+ }
+ skip_line_x(); // ignore further args
+ current_env->size = 10 * font::sizescale;
+
+ // 2nd command `x res'
+ command = next_command();
+ if ((int) command != 'x')
+ fatal("the second command must be `x res'");
+ str_arg = get_string_arg();
+ if (str_arg[0] != 'r')
+ fatal("the second command must be `x res'");
+ delete str_arg;
+ int_arg = get_integer_arg();
+ if (int_arg != font::res)
+ fatal("resolution does not match");
+ int_arg = get_integer_arg();
+ if (int_arg != font::hor)
+ fatal("minimum horizontal motion does not match");
+ int_arg = get_integer_arg();
+ if (int_arg != font::vert)
+ fatal("minimum vertical motion does not match");
+ skip_line_x(); // ignore further args
+
+ // 3rd command `x init'
+ command = next_command();
+ if (command != 'x')
+ fatal("the third command must be `x init'");
+ str_arg = get_string_arg();
+ if (str_arg[0] != 'i')
+ fatal("the third command must be `x init'");
+ delete str_arg;
+ skip_line_x();
}
- skip_line();
- env.size = 10*font::sizescale;
- command = get_char();
- if (command != 'x')
- fatal("the second command must be `x res'");
- s = get_string();
- if (s[0] != 'r')
- fatal("the second command must be `x res'");
- int n = get_integer();
- if (n != font::res)
- fatal("resolution does not match");
- n = get_integer();
- if (n != font::hor)
- fatal("horizontal resolution does not match");
- n = get_integer();
- if (n != font::vert)
- fatal("vertical resolution does not match");
- skip_line();
- command = get_char();
- if (command != 'x')
- fatal("the third command must be `x init'");
- s = get_string();
- if (s[0] != 'i')
- fatal("the third command must be `x init'");
- skip_line();
+
+ // parsing of body
if (pr == 0)
pr = make_printer();
- while ((command = get_char()) != EOF) {
- switch (command) {
- case 's':
- env.size = get_integer();
- if (env.height == env.size)
- env.height = 0;
- break;
- case 'f':
- env.fontno = get_integer();
- break;
- case 'F':
- remember_filename(get_string());
- break;
- case 'C':
- {
- if (npages == 0)
- fatal("`C' command illegal before first `p' command");
- char *s = get_string();
- pr->set_special_char(s, &env);
- }
- break;
- case 'N':
- {
- if (npages == 0)
- fatal("`N' command illegal before first `p' command");
- pr->set_numbered_char(get_integer(), &env);
- }
- break;
- case 'H':
- env.hpos = get_integer();
+ while (!stopped) {
+ command = next_command();
+ if (command == EOF)
break;
- case 'h':
- env.hpos += get_integer();
+ // spaces, tabs, comments, and newlines are skipped here
+ switch ((int) command) {
+ case '#': // #: comment, ignore up to end of line
+ skip_line();
break;
- case 'V':
- env.vpos = get_integer();
+ case '{': // {: start a new environment (a copy)
+ env_stack.push(current_env);
break;
- case 'v':
- env.vpos += get_integer();
+ case '}': // }: pop previous env from stack
+ delete current_env->fill;
+ delete current_env->col;
+ delete current_env;
+ current_env = env_stack.pop();
break;
- case '0':
+ case '0': // ddc: obsolete jump and print command
case '1':
case '2':
case '3':
@@ -194,328 +1450,155 @@ void do_file(const char *filename)
case '7':
case '8':
case '9':
+ { // expect 2 digits and a character
+ char s[3];
+ Char c = next_arg_begin();
+ if (npages <= 0)
+ fatal_command(command);
+ if (!isdigit((int) c)) {
+ error("digit expected");
+ c = 0;
+ }
+ s[0] = (char) command;
+ s[1] = (char) c;
+ s[2] = '\0';
+ errno = 0;
+ long int hor_pos = strtol(s, 0, 10);
+ if (errno != 0)
+ error("couldn't convert 2 digits");
+ current_env->hpos += (IntArg) hor_pos;
+ c = next_arg_begin();
+ if ((int) c == '\n' || (int) c == EOF)
+ error("character argument expected");
+ else
+ pr->set_ascii_char((unsigned char) c, current_env);
+ break;
+ }
+ case 'c': // c: print ascii char without moving
{
- int c = get_char();
- if (!csdigit(c))
- fatal("digit expected");
- env.hpos += (command - '0')*10 + (c - '0');
+ if (npages <= 0)
+ fatal_command(command);
+ Char c = next_arg_begin();
+ if (c == '\n' || c == EOF)
+ error("missing argument to `c' command");
+ else
+ pr->set_ascii_char((unsigned char) c, current_env);
+ break;
}
- // fall through
- case 'c':
+ case 'C': // C: print named special character
{
- if (npages == 0)
- fatal("`c' command illegal before first `p' command");
- int c = get_char();
- if (c == EOF)
- fatal("missing argument to `c' command");
- pr->set_ascii_char(c, &env);
+ if (npages <= 0)
+ fatal_command(command);
+ char *str_arg = get_string_arg();
+ pr->set_special_char(str_arg, current_env);
+ delete str_arg;
+ break;
}
+ case 'D': // drawing commands
+ if (npages <= 0)
+ fatal_command(command);
+ parse_D_command();
break;
- case 'm':
- // glyph color
- env.col = new color;
- env.col->read_rgb(get_string());
+ case 'f': // f: set font to number
+ current_env->fontno = get_integer_arg();
break;
- case 'n':
- if (npages == 0)
- fatal("`n' command illegal before first `p' command");
- pr->end_of_line();
- (void)get_integer();
- (void)get_integer();
+ case 'F': // F: obsolete, replaced by `x F'
+ {
+ char *str_arg = get_string_arg();
+ remember_filename(str_arg);
+ delete str_arg;
+ break;
+ }
+ case 'h': // h: relative horizontal move
+ current_env->hpos += get_integer_arg();
break;
- case 'w':
- case ' ':
+ case 'H': // H: absolute horizontal positioning
+ current_env->hpos = get_integer_arg();
break;
- case '\n':
- current_lineno++;
+ case 'm': // m: glyph color
+ parse_color_command(current_env->col);
break;
- case 'p':
- if (npages)
- pr->end_page(env.vpos);
- npages++;
- pr->begin_page(get_integer());
- env.vpos = 0;
+ case 'n': // n: print end of line, ignore 2 args
+ if (npages <= 0)
+ fatal_command(command);
+ pr->end_of_line();
+ (void) get_integer_arg();
+ (void) get_integer_arg();
break;
- case '{':
- env_list = new environment_list(env, env_list);
+ case 'N': // N: print char with given int code
+ if (npages <= 0)
+ fatal_command(command);
+ pr->set_numbered_char(get_integer_arg(), current_env);
break;
- case '}':
- if (!env_list) {
- fatal("can't pop");
- }
- else {
- env = env_list->env;
- environment_list *tem = env_list;
- env_list = env_list->next;
- delete tem;
- }
+ case 'p': // p: start new page with given number
+ if (npages > 0)
+ pr->end_page(current_env->vpos);
+ npages++; // increment # of processed pages
+ pr->begin_page(get_integer_arg());
+ current_env->vpos = 0;
+ break;
+ case 's': // s: set point size
+ current_env->size = get_integer_arg();
+ if (current_env->height == current_env->size)
+ current_env->height = 0;
break;
- case 'u':
+ case 't': // t: print a text word
{
- if (npages == 0)
- fatal("`u' command illegal before first `p' command");
- int kern = get_integer();
- int c = get_char();
- while (c == ' ')
- c = get_char();
- while (c != EOF) {
- if (c == '\n') {
- current_lineno++;
- break;
- }
+ char c;
+ if (npages <= 0)
+ fatal_command(command);
+ char *str_arg = get_string_arg();
+ int i = 0;
+ while ((c = str_arg[i++]) != '\0') {
int w;
- pr->set_ascii_char(c, &env, &w);
- env.hpos += w + kern;
- c = get_char();
- if (c == ' ')
- break;
+ pr->set_ascii_char((unsigned char) c, current_env, &w);
+ current_env->hpos += w;
}
+ delete str_arg;
+ break;
}
- break;
- case 't':
+ case 'u': // u: print spaced word
{
- if (npages == 0)
- fatal("`t' command illegal before first `p' command");
- int c;
- while ((c = get_char()) != EOF && c != ' ') {
- if (c == '\n') {
- current_lineno++;
- break;
- }
+ char c;
+ if (npages <= 0)
+ fatal_command(command);
+ int kern = get_integer_arg();
+ char *str_arg = get_string_arg();
+ int i = 0;
+ while ((c = str_arg[i++]) != '\0') {
int w;
- pr->set_ascii_char(c, &env, &w);
- env.hpos += w;
+ pr->set_ascii_char((unsigned char) c, current_env, &w);
+ current_env->hpos += w + kern;
}
+ delete str_arg;
+ break;
}
+ case 'v': // v: relative vertical move
+ current_env->vpos += get_integer_arg();
break;
- case '#':
- skip_line();
+ case 'V': // V: absolute vertical positioning
+ current_env->vpos = get_integer_arg();
break;
- case 'D':
- {
- if (npages == 0)
- fatal("`D' command illegal before first `p' command");
- int c;
- while ((c = get_char()) == ' ')
- ;
- int n = 0;
- int *p = 0;
- int szp = 0;
- int np = 0;
-
- if (c == 'F') {
- // fill color
- env.fill = new color;
- env.fill->read_rgb(get_string());
- }
- else {
- for (np = 0; possibly_get_integer(&n); np++) {
- if (np >= szp) {
- if (szp == 0) {
- szp = 16;
- p = new int[szp];
- }
- else {
- int *oldp = p;
- p = new int[szp*2];
- memcpy(p, oldp, szp*sizeof(int));
- szp *= 2;
- a_delete oldp;
- }
- }
- p[np] = n;
- }
- }
- pr->draw(c, p, np, &env);
- if (c == 'e') {
- if (np > 0)
- env.hpos += p[0];
- }
- else if (c == 'f' || c == 'F' || c == 't')
- ;
- else {
- int i;
- for (i = 0; i < np/2; i++) {
- env.hpos += p[i*2];
- env.vpos += p[i*2 + 1];
- }
- // there might be an odd number of characters
- if (i*2 < np)
- env.hpos += p[i*2];
- }
- a_delete p;
- skip_line();
- }
+ case 'w': // w: inform about paddable space
break;
- case 'x':
- {
- char *s = get_string();
- int suppress_skip = 0;
- switch (s[0]) {
- case 'i':
- error("duplicate `x init' command");
- break;
- case 'T':
- error("duplicate `x T' command");
- break;
- case 'r':
- error("duplicate `x res' command");
- break;
- case 'p':
- break;
- case 's':
- break;
- case 't':
- break;
- case 'f':
- {
- int n = get_integer();
- char *name = get_string();
- pr->load_font(n, name);
- }
- break;
- case 'H':
- env.height = get_integer();
- if (env.height == env.size)
- env.height = 0;
- break;
- case 'S':
- env.slant = get_integer();
- break;
- case 'X':
- if (npages == 0)
- fatal("`x X' command illegal before first `p' command");
- pr->special(get_string(1), &env);
- suppress_skip = 1;
- break;
- case 'u':
- // .cu
- pr->special(get_string(), &env, 'u');
- break;
- default:
- error("unrecognised x command `%1'", s);
- }
- if (!suppress_skip)
- skip_line();
- }
+ case 'x': // device controlling commands
+ stopped = parse_x_command();
break;
default:
- error("unrecognised command code %1", int(command));
+ warning("unrecognized command `%1'", (unsigned char) command);
skip_line();
break;
- }
- }
- if (npages)
- pr->end_page(env.vpos);
-}
-
-int get_integer()
-{
- int c = get_char();
- while (c == ' ')
- c = get_char();
- int neg = 0;
- if (c == '-') {
- neg = 1;
- c = get_char();
- }
- if (!csdigit(c))
- fatal("integer expected");
- int total = 0;
- do {
- total = total*10;
- if (neg)
- total -= c - '0';
- else
- total += c - '0';
- c = get_char();
- } while (csdigit(c));
- if (c != EOF)
- ungetc(c, current_file);
- return total;
-}
-
-int possibly_get_integer(int *res)
-{
- int c = get_char();
- while (c == ' ')
- c = get_char();
- int neg = 0;
- if (c == '-') {
- neg = 1;
- c = get_char();
- }
- if (!csdigit(c)) {
- if (c != EOF)
- ungetc(c, current_file);
- return 0;
- }
- int total = 0;
- do {
- total = total*10;
- if (neg)
- total -= c - '0';
- else
- total += c - '0';
- c = get_char();
- } while (csdigit(c));
- if (c != EOF)
- ungetc(c, current_file);
- *res = total;
- return 1;
-}
-
-
-char *get_string(int is_long)
-{
- static char *buf;
- static int buf_size;
- int c = get_char();
- while (c == ' ')
- c = get_char();
- for (int i = 0;; i++) {
- if (i >= buf_size) {
- if (buf_size == 0) {
- buf_size = 16;
- buf = new char[buf_size];
- }
- else {
- char *old_buf = buf;
- int old_size = buf_size;
- buf_size *= 2;
- buf = new char[buf_size];
- memcpy(buf, old_buf, old_size);
- a_delete old_buf;
- }
- }
- if ((!is_long && (c == ' ' || c == '\n')) || c == EOF) {
- buf[i] = '\0';
- break;
- }
- if (is_long && c == '\n') {
- current_lineno++;
- c = get_char();
- if (c == '+')
- c = '\n';
- else {
- buf[i] = '\0';
- break;
- }
- }
- buf[i] = c;
- c = get_char();
- }
- if (c != EOF)
- ungetc(c, current_file);
- return buf;
-}
+ } // end of switch
+ } // end of while
-void skip_line()
-{
- int c;
- while ((c = get_char()) != EOF)
- if (c == '\n') {
- current_lineno++;
- break;
- }
+ // end of file reached
+ if (npages > 0)
+ pr->end_page(current_env->vpos);
+ fclose(current_file);
+ // If `stopped' is not `true' here then there wasn't any `x stop'.
+ if (!stopped)
+ warning("no final `x stop' command");
+ delete current_env->col;
+ delete current_env->fill;
+ delete current_env;
}
diff --git a/src/libs/libgroff/color.cc b/src/libs/libgroff/color.cc
index 46f80b55..bfd79dcb 100644
--- a/src/libs/libgroff/color.cc
+++ b/src/libs/libgroff/color.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 2001 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
Written by Gaius Mulley <gaius@glam.ac.uk>
This file is part of groff.
@@ -40,115 +40,100 @@ static inline unsigned int min(unsigned int a, unsigned int b)
}
color::color()
-: cyan(0), magenta(0), yellow(0), black(0), scheme(NONE),
- color_space_num(0), encoding(UNDEFINED), hex_length(0)
+: scheme(DEFAULT)
{
}
-int color::is_equal(color *c)
+int color::operator==(const color & c) const
{
- return (c->cyan == cyan)
- && (c->magenta == magenta)
- && (c->yellow == yellow)
- && (c->black == black);
+ if (scheme != c.scheme)
+ return 0;
+ switch (scheme) {
+ case DEFAULT:
+ break;
+ case RGB:
+ if (Red != c.Red || Green != c.Green || Blue != c.Blue)
+ return 0;
+ break;
+ case CMYK:
+ if (Cyan != c.Cyan || Magenta != c.Magenta
+ || Yellow != c.Yellow || Black != c.Black)
+ return 0;
+ break;
+ case GRAY:
+ if (Gray != c.Gray)
+ return 0;
+ break;
+ case CMY:
+ if (Cyan != c.Cyan || Magenta != c.Magenta || Yellow != c.Yellow)
+ return 0;
+ break;
+ }
+ return 1;
}
-int color::is_gray(void)
+int color::operator!=(const color & c) const
{
- return (scheme == GRAY)
- || ((magenta == cyan) && (cyan == yellow));
+ return !(*this == c);
}
-void color::set_rgb(unsigned int r, unsigned int g, unsigned int b)
+color_scheme color::get_components(unsigned int *c)
{
- scheme = RGB;
- r = min(MAX_COLOR_VAL, r);
- g = min(MAX_COLOR_VAL, g);
- b = min(MAX_COLOR_VAL, b);
- black = min(MAX_COLOR_VAL - r, min(MAX_COLOR_VAL - g, MAX_COLOR_VAL - b));
- if (MAX_COLOR_VAL - black == 0) {
- cyan = MAX_COLOR_VAL;
- magenta = MAX_COLOR_VAL;
- yellow = MAX_COLOR_VAL;
- }
- else {
- cyan = (MAX_COLOR_VAL * (MAX_COLOR_VAL - r - black))
- / (MAX_COLOR_VAL - black);
- magenta = (MAX_COLOR_VAL * (MAX_COLOR_VAL - g - black))
- / (MAX_COLOR_VAL - black);
- yellow = (MAX_COLOR_VAL * (MAX_COLOR_VAL - b - black))
- / (MAX_COLOR_VAL - black);
- }
+ c[0] = components[0];
+ c[1] = components[1];
+ c[2] = components[2];
+ c[3] = components[3];
+ return scheme;
}
-void color::set_cmy(unsigned int c, unsigned int m, unsigned int y)
+void color::set_default()
{
- scheme = CMY;
- c = min(MAX_COLOR_VAL, c);
- m = min(MAX_COLOR_VAL, m);
- y = min(MAX_COLOR_VAL, y);
- black = min(c, min(m, y));
- if (MAX_COLOR_VAL - black == 0) {
- cyan = MAX_COLOR_VAL;
- magenta = MAX_COLOR_VAL;
- yellow = MAX_COLOR_VAL;
- }
- else {
- cyan = (MAX_COLOR_VAL * (c - black)) / (MAX_COLOR_VAL - black);
- magenta = (MAX_COLOR_VAL * (m - black)) / (MAX_COLOR_VAL - black);
- yellow = (MAX_COLOR_VAL * (y - black)) / (MAX_COLOR_VAL - black);
- }
+ scheme = DEFAULT;
}
-void color::set_cmyk(unsigned int c, unsigned int m,
- unsigned int y, unsigned int k)
-{
- scheme = CMYK;
- cyan = c;
- magenta = m;
- yellow = y;
- black = k;
-}
+// (0, 0, 0) is black
-void color::set_gray(unsigned int b)
+void color::set_rgb(unsigned int r, unsigned int g, unsigned int b)
{
- scheme = GRAY;
- cyan = 0;
- magenta = 0;
- yellow = 0;
- black = min(MAX_COLOR_VAL, b);
+ scheme = RGB;
+ Red = min(MAX_COLOR_VAL, r);
+ Green = min(MAX_COLOR_VAL, g);
+ Blue = min(MAX_COLOR_VAL, b);
}
-void color::set_rgb(double r, double g, double b)
-{
- set_rgb((unsigned int)(r * MAX_COLOR_VAL),
- (unsigned int)(g * MAX_COLOR_VAL),
- (unsigned int)(b * MAX_COLOR_VAL));
-}
+// (0, 0, 0) is white
-void color::set_cmy(double c, double m, double y)
+void color::set_cmy(unsigned int c, unsigned int m, unsigned int y)
{
- set_cmy((unsigned int)(c * MAX_COLOR_VAL),
- (unsigned int)(m * MAX_COLOR_VAL),
- (unsigned int)(y * MAX_COLOR_VAL));
+ scheme = CMY;
+ Cyan = min(MAX_COLOR_VAL, c);
+ Magenta = min(MAX_COLOR_VAL, m);
+ Yellow = min(MAX_COLOR_VAL, y);
}
-void color::set_cmyk(double c, double m, double y, double k)
+// (0, 0, 0, 0) is white
+
+void color::set_cmyk(unsigned int c, unsigned int m,
+ unsigned int y, unsigned int k)
{
- set_cmyk((unsigned int)(c * MAX_COLOR_VAL),
- (unsigned int)(m * MAX_COLOR_VAL),
- (unsigned int)(y * MAX_COLOR_VAL),
- (unsigned int)(k * MAX_COLOR_VAL));
+ scheme = CMYK;
+ Cyan = min(MAX_COLOR_VAL, c);
+ Magenta = min(MAX_COLOR_VAL, m);
+ Yellow = min(MAX_COLOR_VAL, y);
+ Black = min(MAX_COLOR_VAL, k);
}
-void color::set_gray(double l)
+// (0) is black
+
+void color::set_gray(unsigned int g)
{
- set_gray((unsigned int)(l * MAX_COLOR_VAL));
+ scheme = GRAY;
+ Gray = min(MAX_COLOR_VAL, g);
}
/*
- * atoh - computes the value of the hex number S in N. Returns 1 if
- * successful.
+ * atoh - computes the value of the hex number S in N. LENGTH characters
+ * are read. Returns 1 if successful.
*/
static int atoh(unsigned int *n, const char *s, unsigned int length)
@@ -156,8 +141,6 @@ static int atoh(unsigned int *n, const char *s, unsigned int length)
unsigned int i = 0;
unsigned int val = 0;
while ((i < length) && csxdigit(s[i])) {
- if (!s[i])
- return 0;
if (csdigit(s[i]))
val = val*0x10 + (s[i]-'0');
else if (csupper(s[i]))
@@ -166,191 +149,192 @@ static int atoh(unsigned int *n, const char *s, unsigned int length)
val = val*0x10 + (s[i]-'a') + 10;
i++;
}
+ if (i != length)
+ return 0;
*n = val;
return 1;
}
/*
- * read_encoding - read the next component of the color encoding from S.
- * Returns 1 when finished.
+ * read_encoding - reads a hexadecimal color string in S, using color
+ * scheme CS with N components. Returns 1 if successful.
*/
-int color::read_encoding(const char *s, unsigned int n)
+int color::read_encoding(color_scheme cs, const char *s, unsigned int n)
{
- if ((scheme == NONE) && (color_space_num == 0)) {
- if (*s == '#') {
- s++;
- encoding = HEX;
- if (*s == '#') {
- hex_length = 4;
- s++;
- }
- else
- hex_length = 2;
- }
- else
- encoding = REAL;
+ int hex_length = 2;
+ scheme = cs;
+ s++;
+ if (*s == '#') {
+ hex_length = 4;
+ s++;
}
- if (encoding == REAL) {
- d[color_space_num] = atof(s);
- color_space_num++;
- return (color_space_num == n);
- }
- else {
- for (unsigned int i = 0; i < n; i++) {
- if (!atoh(&c[i], s, hex_length))
- return 0;
- if (hex_length == 2)
- c[i] *= 0x101; // scale up -- 0xff should become 0xffff
- s += hex_length;
- }
- return 1;
+ for (unsigned int i = 0; i < n; i++) {
+ if (!atoh(&components[i], s, hex_length))
+ return 0;
+ if (hex_length == 2)
+ components[i] *= 0x101; // scale up -- 0xff should become 0xffff
+ s += hex_length;
}
+ return 1;
}
-/*
- * read_rgb - read an rgb color description from S. It returns 1
- * when the complete color has been read.
- */
-
int color::read_rgb(const char *s)
{
- assert(scheme == NONE);
- int finished = read_encoding(s, 3);
- if (finished) {
- if (encoding == HEX)
- set_rgb(c[0], c[1], c[2]);
- else
- set_rgb(d[0], d[1], d[2]);
- }
- return finished;
+ return read_encoding(RGB, s, 3);
}
-/*
- * read_cmy - read a cmy color description from S. It returns 1
- * when the complete color has been read.
- */
-
int color::read_cmy(const char *s)
{
- assert(scheme == NONE);
- int finished = read_encoding(s, 3);
- if (finished) {
- if (encoding == HEX)
- set_cmy(c[0], c[1], c[2]);
- else
- set_cmy(d[0], d[1], d[2]);
- }
- return finished;
+ return read_encoding(CMY, s, 3);
}
-/*
- * read_cmyk - read a cmyk color description from S. It returns 1
- * when the complete color has been read.
- */
-
int color::read_cmyk(const char *s)
{
- assert(scheme == NONE);
- int finished = read_encoding(s, 4);
- if (finished) {
- if (encoding == HEX)
- set_cmyk(c[0], c[1], c[2], c[3]);
- else
- set_cmyk(d[0], d[1], d[2], d[3]);
- }
- return finished;
+ return read_encoding(CMYK, s, 4);
}
-/*
- * read_gray - read a gray scale from S. It returns 1.
- */
-
int color::read_gray(const char *s)
{
- assert(scheme == NONE);
- int finished = read_encoding(s, 1);
- if (finished) {
- if (encoding == HEX)
- set_gray(c[0]);
- else
- set_gray(d[0]);
- }
- return finished;
+ return read_encoding(GRAY, s, 1);
}
void color::get_rgb(unsigned int *r, unsigned int *g, unsigned int *b)
{
- assert(scheme != NONE);
- *r = MAX_COLOR_VAL
- - min(MAX_COLOR_VAL,
- cyan * (MAX_COLOR_VAL - black) / MAX_COLOR_VAL + black);
- *g = MAX_COLOR_VAL
- - min(MAX_COLOR_VAL,
- magenta * (MAX_COLOR_VAL - black) / MAX_COLOR_VAL + black);
- *b = MAX_COLOR_VAL
- - min(MAX_COLOR_VAL,
- yellow * (MAX_COLOR_VAL - black) / MAX_COLOR_VAL + black);
+ switch (scheme) {
+ case RGB:
+ *r = Red;
+ *g = Green;
+ *b = Blue;
+ break;
+ case CMY:
+ *r = MAX_COLOR_VAL - Cyan;
+ *g = MAX_COLOR_VAL - Magenta;
+ *b = MAX_COLOR_VAL - Yellow;
+ break;
+ case CMYK:
+ *r = MAX_COLOR_VAL
+ - min(MAX_COLOR_VAL,
+ Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
+ *g = MAX_COLOR_VAL
+ - min(MAX_COLOR_VAL,
+ Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
+ *b = MAX_COLOR_VAL
+ - min(MAX_COLOR_VAL,
+ Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
+ break;
+ case GRAY:
+ *r = *g = *b = Gray;
+ break;
+ default:
+ assert(0);
+ break;
+ }
}
void color::get_cmy(unsigned int *c, unsigned int *m, unsigned int *y)
{
- assert(scheme != NONE);
- *c = min(MAX_COLOR_VAL,
- cyan * (MAX_COLOR_VAL - black) / MAX_COLOR_VAL + black);
- *m = min(MAX_COLOR_VAL,
- magenta * (MAX_COLOR_VAL - black) / MAX_COLOR_VAL + black);
- *y = min(MAX_COLOR_VAL,
- yellow * (MAX_COLOR_VAL - black) / MAX_COLOR_VAL + black);
+ switch (scheme) {
+ case RGB:
+ *c = MAX_COLOR_VAL - Red;
+ *m = MAX_COLOR_VAL - Green;
+ *y = MAX_COLOR_VAL - Blue;
+ break;
+ case CMY:
+ *c = Cyan;
+ *m = Magenta;
+ *y = Yellow;
+ break;
+ case CMYK:
+ *c = min(MAX_COLOR_VAL,
+ Cyan * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
+ *m = min(MAX_COLOR_VAL,
+ Magenta * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
+ *y = min(MAX_COLOR_VAL,
+ Yellow * (MAX_COLOR_VAL - Black) / MAX_COLOR_VAL + Black);
+ break;
+ case GRAY:
+ *c = *m = *y = MAX_COLOR_VAL - Gray;
+ break;
+ default:
+ assert(0);
+ break;
+ }
}
void color::get_cmyk(unsigned int *c, unsigned int *m,
unsigned int *y, unsigned int *k)
{
- assert(scheme != NONE);
- *c = cyan;
- *m = magenta;
- *y = yellow;
- *k = black;
-}
-
-void color::get_gray(unsigned int *l)
-{
- assert(scheme != NONE);
- *l = black;
-}
-
-void color::get_rgb(double *r, double *g, double *b)
-{
- assert(scheme != NONE);
- unsigned int ir, ig, ib;
- get_rgb(&ir, &ig, &ib);
- *r = (double)ir / MAX_COLOR_VAL;
- *g = (double)ig / MAX_COLOR_VAL;
- *b = (double)ib / MAX_COLOR_VAL;
+ switch (scheme) {
+ case RGB:
+ *k = min(MAX_COLOR_VAL - Red,
+ min(MAX_COLOR_VAL - Green, MAX_COLOR_VAL - Blue));
+ if (MAX_COLOR_VAL == *k) {
+ *c = MAX_COLOR_VAL;
+ *m = MAX_COLOR_VAL;
+ *y = MAX_COLOR_VAL;
+ }
+ else {
+ *c = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Red - *k))
+ / (MAX_COLOR_VAL - *k);
+ *m = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Green - *k))
+ / (MAX_COLOR_VAL - *k);
+ *y = (MAX_COLOR_VAL * (MAX_COLOR_VAL - Blue - *k))
+ / (MAX_COLOR_VAL - *k);
+ }
+ break;
+ case CMY:
+ *k = min(Cyan, min(Magenta, Yellow));
+ if (MAX_COLOR_VAL == *k) {
+ *c = MAX_COLOR_VAL;
+ *m = MAX_COLOR_VAL;
+ *y = MAX_COLOR_VAL;
+ }
+ else {
+ *c = (MAX_COLOR_VAL * (Cyan - *k)) / (MAX_COLOR_VAL - *k);
+ *m = (MAX_COLOR_VAL * (Magenta - *k)) / (MAX_COLOR_VAL - *k);
+ *y = (MAX_COLOR_VAL * (Yellow - *k)) / (MAX_COLOR_VAL - *k);
+ }
+ break;
+ case CMYK:
+ *c = Cyan;
+ *m = Magenta;
+ *y = Yellow;
+ *k = Black;
+ break;
+ case GRAY:
+ *c = *m = *y = 0;
+ *k = MAX_COLOR_VAL - Gray;
+ break;
+ default:
+ assert(0);
+ break;
+ }
}
-void color::get_cmy(double *c, double *m, double *y)
-{
- assert(scheme != NONE);
- unsigned int ic, im, iy;
- get_cmy(&ic, &im, &iy);
- *c = (double)ic / MAX_COLOR_VAL;
- *m = (double)im / MAX_COLOR_VAL;
- *y = (double)iy / MAX_COLOR_VAL;
-}
+// we use `0.222r + 0.707g + 0.071b' (this is the ITU standard)
+// as an approximation for gray
-void color::get_cmyk(double *c, double *m, double *y, double *k)
+void color::get_gray(unsigned int *g)
{
- assert(scheme != NONE);
- *c = (double)cyan / MAX_COLOR_VAL;
- *m = (double)magenta / MAX_COLOR_VAL;
- *y = (double)yellow / MAX_COLOR_VAL;
- *k = (double)black / MAX_COLOR_VAL;
+ switch (scheme) {
+ case RGB:
+ *g = (222*Red + 707*Green + 71*Blue) / 1000;
+ break;
+ case CMY:
+ *g = MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000;
+ break;
+ case CMYK:
+ *g = (MAX_COLOR_VAL - (222*Cyan + 707*Magenta + 71*Yellow) / 1000)
+ * (MAX_COLOR_VAL - Black);
+ break;
+ case GRAY:
+ *g = Gray;
+ break;
+ default:
+ assert(0);
+ break;
+ }
}
-void color::get_gray(double *l)
-{
- assert(scheme != NONE);
- *l = (double)black / MAX_COLOR_VAL;
-}
+color default_color;
diff --git a/src/libs/libgroff/geometry.cc b/src/libs/libgroff/geometry.cc
index 7aa0d2b8..58a94a4a 100644
--- a/src/libs/libgroff/geometry.cc
+++ b/src/libs/libgroff/geometry.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 Gaius Mulley <gaius@glam.ac.uk>
using adjust_arc_center() from printer.cc, written by James Clark.
@@ -136,14 +136,22 @@ void check_output_arc_limits(int x1, int y1,
*miny = y1 + yv1 - radius;
*maxy = y1 + yv1 + radius;
- // now see which min/max can be reduced and increased for the limits of
- // the arc
- //
- // Q2 | Q1
- // -----+-----
- // Q3 | Q4
- //
- if (xv1 >= 0 && yv1 >= 0) {
+ /* now to see which min/max can be reduced and increased for the limits of
+ * the arc
+ *
+ * Q2 | Q1
+ * -----+-----
+ * Q3 | Q4
+ *
+ *
+ * NB. (x1+xv1, y1+yv1) is at the origin
+ *
+ * below we ask a nested question
+ * (i) from which quadrant does the first vector start?
+ * (ii) into which quadrant does the second vector go?
+ * from the 16 possible answers we determine the limits of the arc
+ */
+ if (xv1 > 0 && yv1 > 0) {
// first vector in Q3
if (xv2 >= 0 && yv2 >= 0 ) {
// second in Q1
@@ -172,7 +180,7 @@ void check_output_arc_limits(int x1, int y1,
}
}
}
- else if (xv1 >= 0 && yv1 < 0) {
+ else if (xv1 > 0 && yv1 < 0) {
// first vector in Q2
if (xv2 >= 0 && yv2 >= 0) {
// second in Q1
@@ -202,7 +210,7 @@ void check_output_arc_limits(int x1, int y1,
*minx = MIN(x1, x2);
}
}
- else if (xv1 < 0 && yv1 < 0) {
+ else if (xv1 <= 0 && yv1 <= 0) {
// first vector in Q1
if (xv2 >= 0 && yv2 >= 0) {
// second in Q1
@@ -232,7 +240,7 @@ void check_output_arc_limits(int x1, int y1,
*maxy = y1;
}
}
- else if (xv1 < 0 && yv1 >= 0) {
+ else if (xv1 <= 0 && yv1 > 0) {
// first vector in Q4
if (xv2 >= 0 && yv2 >= 0) {
// second in Q1
diff --git a/src/libs/libgroff/itoa.c b/src/libs/libgroff/itoa.c
index 72826b74..245c7dfe 100644
--- a/src/libs/libgroff/itoa.c
+++ b/src/libs/libgroff/itoa.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2002
+ Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -18,6 +19,7 @@ with groff; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#define INT_DIGITS 19 /* enough for 64 bit integer */
+#define UINT_DIGITS 20
char *i_to_a(i)
int i;
@@ -41,3 +43,16 @@ char *i_to_a(i)
}
return p;
}
+
+char *ui_to_a(i)
+ unsigned int i;
+{
+ /* Room for UINT_DIGITS digits and '\0' */
+ static char buf[UINT_DIGITS + 1];
+ char *p = buf + UINT_DIGITS; /* points to terminating '\0' */
+ do {
+ *--p = '0' + (i % 10);
+ i /= 10;
+ } while (i != 0);
+ return p;
+}
diff --git a/src/preproc/pic/object.cc b/src/preproc/pic/object.cc
index 38b0963b..4eae9564 100644
--- a/src/preproc/pic/object.cc
+++ b/src/preproc/pic/object.cc
@@ -211,7 +211,8 @@ struct arrow_head_type {
};
void draw_arrow(const position &pos, const distance &dir,
- const arrow_head_type &aht, const line_type &lt)
+ const arrow_head_type &aht, const line_type &lt,
+ char *outline_color_for_fill)
{
double hyp = hypot(dir);
if (hyp == 0.0) {
@@ -229,8 +230,9 @@ void draw_arrow(const position &pos, const distance &dir,
v[0] = pos;
v[1] = pos + base + n;
v[2] = pos + base - n;
- // A value > 1 means fill with the current color.
- out->polygon(v, 3, slt, 2.0);
+ // fill with outline color
+ out->set_color(outline_color_for_fill, outline_color_for_fill);
+ out->polygon(v, 3, slt, 1);
}
else {
position v[2];
@@ -1253,9 +1255,10 @@ void line_object::print()
out->set_color(0, graphic_object::get_outline_color());
out->line(strt, v, n, lt);
if (arrow_at_start)
- draw_arrow(strt, strt-v[0], aht, lt);
+ draw_arrow(strt, strt-v[0], aht, lt, graphic_object::get_outline_color());
if (arrow_at_end)
- draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt);
+ draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt,
+ graphic_object::get_outline_color());
out->reset_color();
}
@@ -1322,9 +1325,10 @@ void spline_object::print()
out->set_color(0, graphic_object::get_outline_color());
out->spline(strt, v, n, lt);
if (arrow_at_start)
- draw_arrow(strt, strt-v[0], aht, lt);
+ draw_arrow(strt, strt-v[0], aht, lt, graphic_object::get_outline_color());
if (arrow_at_end)
- draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt);
+ draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt,
+ graphic_object::get_outline_color());
out->reset_color();
}
@@ -1541,13 +1545,13 @@ void arc_object::print()
position c = cent - strt;
draw_arrow(strt,
(clockwise ? position(c.y, -c.x) : position(-c.y, c.x)),
- aht, lt);
+ aht, lt, graphic_object::get_outline_color());
}
if (arrow_at_end) {
position e = en - cent;
draw_arrow(en,
(clockwise ? position(e.y, -e.x) : position(-e.y, e.x)),
- aht, lt);
+ aht, lt, graphic_object::get_outline_color());
}
out->reset_color();
}
diff --git a/src/preproc/pic/pic.man b/src/preproc/pic/pic.man
index e7ca94dd..1804e660 100644
--- a/src/preproc/pic/pic.man
+++ b/src/preproc/pic/pic.man
@@ -1,5 +1,5 @@
.ig
-Copyright (C) 1989-2000, 2001 Free Software Foundation, Inc.
+Copyright (C) 1989-2000, 2001, 2002 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
@@ -693,8 +693,8 @@ All three keywords expect a suffix specifying the color, for example
Currently, color support isn't available in \*(tx mode.
Predefined color names for
.B groff
-are in the file
-.BR color.tmac ;
+are in the device macro files, for example
+.BR ps.tmac ;
additional colors can be defined with the
.B .defcolor
request (see the manual page of
@@ -703,10 +703,9 @@ for more details).
.LP
Arrow heads will be drawn as solid triangles if the variable
.B arrowhead
-is non-zero and either \*(tx mode is enabled or
-the
-.B \-x
-option has been given.
+is non-zero and either \*(tx mode is enabled or the
+.B \-n
+option has not been given.
Initially
.B arrowhead
has a value of 1.
diff --git a/src/roff/troff/env.cc b/src/roff/troff/env.cc
index 1bd12cb6..69cfa205 100644
--- a/src/roff/troff/env.cc
+++ b/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)
@@ -636,10 +636,10 @@ environment::environment(symbol nm)
#endif /* WIDOW_CONTROL */
ignore_next_eol(0),
emitted_node(0),
- cur_glyph_color(0),
- prev_glyph_color(0),
- cur_fill_color(0),
- prev_fill_color(0),
+ cur_glyph_color(&default_color),
+ prev_glyph_color(&default_color),
+ cur_fill_color(&default_color),
+ prev_fill_color(&default_color),
name(nm),
control_char('.'),
no_break_control_char('\''),
diff --git a/src/roff/troff/input.cc b/src/roff/troff/input.cc
index c2e7f6e2..0758a02f 100644
--- a/src/roff/troff/input.cc
+++ b/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)
@@ -1014,54 +1014,33 @@ 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;
}
-static color *default_black(color *c)
-{
- symbol b = symbol("black");
- if (c == 0) {
- color *black = (color *)color_dictionary.lookup(b);
- if (black == 0) {
- warning(WARN_COLOR, "default color `black' not defined");
- color *tem = new color;
- tem->set_cmyk((unsigned int)0, (unsigned int)0,
- (unsigned int)0, (unsigned int)0);
- (void)color_dictionary.lookup(b, tem);
- return tem;
- }
- else
- return 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()));
+ curenv->set_glyph_color(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);
- }
+ else
+ (void)color_dictionary.lookup(nm, new color);
}
- return new glyph_color_node(default_black(curenv->get_glyph_color()));
+ return new glyph_color_node(curenv->get_glyph_color());
}
static node *do_fill_color(symbol nm)
@@ -1069,35 +1048,31 @@ 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()));
+ curenv->set_fill_color(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);
- }
+ else
+ (void)color_dictionary.lookup(nm, new color);
}
- return new fill_color_node(default_black(curenv->get_fill_color()));
+ return new fill_color_node(curenv->get_fill_color());
}
-static unsigned int get_color_element(const char *scheme, const char *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", color, scheme);
+ 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", color);
+ 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", color);
+ warning(WARN_RANGE, "%1 cannot be greater than 1", col);
// we change 0x10000 to 0xffff
return color::MAX_COLOR_VAL;
}
@@ -1218,6 +1193,11 @@ static void define_color()
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();
@@ -1236,8 +1216,8 @@ static void define_color()
col = read_cmy();
else {
warning(WARN_COLOR,
- "unknown color space definition `%1', "
- "use rgb, cmyk or gray", style.contents());
+ "unknown color space `%1'; use rgb, cmyk, gray or cmy",
+ style.contents());
skip_line();
return;
}
@@ -2505,7 +2485,7 @@ void process_input_stack()
else
interpolate_macro(nm);
suppress_next = 1;
- have_input = 0;
+ have_input = 0;
}
else {
if (possibly_handle_first_page_transition())
@@ -2582,7 +2562,7 @@ void process_input_stack()
break;
}
suppress_next = 1;
- have_input = 0;
+ have_input = 0;
break;
}
case token::TOKEN_SPACE:
@@ -4846,7 +4826,8 @@ int do_if_request()
skip_alternative();
return 0;
}
- result = (color_dictionary.lookup(nm) != 0);
+ result = (nm == default_symbol
+ || color_dictionary.lookup(nm) != 0);
}
else if (c == 'c') {
tok.next();
diff --git a/src/roff/troff/node.cc b/src/roff/troff/node.cc
index 14dce56a..a0a48e09 100644
--- a/src/roff/troff/node.cc
+++ b/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)
@@ -753,8 +753,8 @@ 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 put_hex(int i, int length);
void set_font(tfont *tf);
void flush_tbuf();
public:
@@ -813,21 +813,9 @@ 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)
+inline void troff_output_file::put(unsigned int i)
{
- 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;
+ put_string(ui_to_a(i), fp);
}
void troff_output_file::start_special(tfont *tf, int no_init_string)
@@ -1148,30 +1136,96 @@ void troff_output_file::set_font(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("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_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);
+ 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_glyphcolor = col;
}
diff --git a/tmac/andoc.tmac b/tmac/andoc.tmac
index f6a16db6..bfb869ab 100644
--- a/tmac/andoc.tmac
+++ b/tmac/andoc.tmac
@@ -12,3 +12,8 @@
.do mso an-old.tmac
\\*(TH\\
..
+.\" dummy equation macros -- eqnrc is read before .TH or .Dd is parsed.
+.de EQ
+..
+.de EN
+..
diff --git a/tmac/groff_www.man b/tmac/groff_www.man
index 5ce157de..f531b981 100644
--- a/tmac/groff_www.man
+++ b/tmac/groff_www.man
@@ -1,4 +1,4 @@
-.TH GROFF_MWWW @MAN7EXT@ "@MDATE@" "Groff Version @VERSION@"
+.TH GROFF_WWW @MAN7EXT@ "@MDATE@" "Groff Version @VERSION@"
.\" Copyright (C) 2000, 2001 Free Software Foundation, Inc.
.\" Written by Gaius Mulley (gaius@glam.ac.uk)
.\"