summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwlemb <wlemb>2002-01-24 22:37:29 +0000
committerwlemb <wlemb>2002-01-24 22:37:29 +0000
commit7482010e8f31df2ac357c1f652c20f2d4fd6e713 (patch)
treed134edbf57061a0a29ced6b9bf92f37eeda3909a
parent1878e2b7b01e7a8975aa29a57ea6b307226b88c8 (diff)
downloadgroff-7482010e8f31df2ac357c1f652c20f2d4fd6e713.tar.gz
* tmac/groff_www.man, NEWS: Fix typos.
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. * src/libs/libdriver/input.cc: Completely rewritten. See comments in this file for what has been changed.
-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)
.\"