summaryrefslogtreecommitdiffstats
path: root/contrib/groff/src/devices
diff options
context:
space:
mode:
authorru <ru@FreeBSD.org>2002-10-11 08:52:17 +0000
committerru <ru@FreeBSD.org>2002-10-11 08:52:17 +0000
commit49694bd3ad767a896dc092289a2b59c780a3ba02 (patch)
tree3ab4ff2268c18cde66cbf296cc57caf69acdea70 /contrib/groff/src/devices
parentb6731a278e1260409b42bb486cc7592dd1a19203 (diff)
parent127e61728bacf1fb90edd8be1b0c406619e78bc8 (diff)
downloadFreeBSD-src-49694bd3ad767a896dc092289a2b59c780a3ba02.zip
FreeBSD-src-49694bd3ad767a896dc092289a2b59c780a3ba02.tar.gz
This commit was generated by cvs2svn to compensate for changes in r104862,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib/groff/src/devices')
-rw-r--r--contrib/groff/src/devices/grodvi/Makefile.sub4
-rw-r--r--contrib/groff/src/devices/grodvi/dvi.cc82
-rw-r--r--contrib/groff/src/devices/grodvi/grodvi.man239
-rw-r--r--contrib/groff/src/devices/grohtml/Makefile.sub11
-rw-r--r--contrib/groff/src/devices/grohtml/grohtml.man96
-rw-r--r--contrib/groff/src/devices/grohtml/html-table.cc687
-rw-r--r--contrib/groff/src/devices/grohtml/html-table.h130
-rw-r--r--contrib/groff/src/devices/grohtml/html-text.cc581
-rw-r--r--contrib/groff/src/devices/grohtml/html-text.h124
-rw-r--r--contrib/groff/src/devices/grohtml/html.h3
-rw-r--r--contrib/groff/src/devices/grohtml/output.cc56
-rw-r--r--contrib/groff/src/devices/grohtml/post-html.cc2417
-rw-r--r--contrib/groff/src/devices/grolbp/Makefile.sub4
-rw-r--r--contrib/groff/src/devices/grolbp/grolbp.man79
-rw-r--r--contrib/groff/src/devices/grolbp/lbp.cc1038
-rw-r--r--contrib/groff/src/devices/grolbp/lbp.h2
-rw-r--r--contrib/groff/src/devices/grolj4/Makefile.sub4
-rw-r--r--contrib/groff/src/devices/grolj4/grolj4.man21
-rw-r--r--contrib/groff/src/devices/grolj4/lj4.cc59
-rw-r--r--contrib/groff/src/devices/grops/Makefile.sub6
-rw-r--r--contrib/groff/src/devices/grops/TODO3
-rw-r--r--contrib/groff/src/devices/grops/grops.man381
-rw-r--r--contrib/groff/src/devices/grops/ps.cc258
-rw-r--r--contrib/groff/src/devices/grops/ps.h3
-rw-r--r--contrib/groff/src/devices/grops/psrm.cc34
-rw-r--r--contrib/groff/src/devices/grotty/Makefile.sub4
-rw-r--r--contrib/groff/src/devices/grotty/tty.cc319
27 files changed, 4645 insertions, 2000 deletions
diff --git a/contrib/groff/src/devices/grodvi/Makefile.sub b/contrib/groff/src/devices/grodvi/Makefile.sub
index 0e5d32c..74e627d 100644
--- a/contrib/groff/src/devices/grodvi/Makefile.sub
+++ b/contrib/groff/src/devices/grodvi/Makefile.sub
@@ -1,6 +1,6 @@
-PROG=grodvi
+PROG=grodvi$(EXEEXT)
MAN1=grodvi.n
XLIBS=$(LIBDRIVER) $(LIBGROFF)
MLIB=$(LIBM)
-OBJS=dvi.o
+OBJS=dvi.$(OBJEXT)
CCSRCS=$(srcdir)/dvi.cc
diff --git a/contrib/groff/src/devices/grodvi/dvi.cc b/contrib/groff/src/devices/grodvi/dvi.cc
index b5b7c49..8412636 100644
--- a/contrib/groff/src/devices/grodvi/dvi.cc
+++ b/contrib/groff/src/devices/grodvi/dvi.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)
@@ -44,8 +44,6 @@ width in the tfm file. */
#define SIZESCALE 100
#define MULTIPLIER 1
-#define FILL_MAX 1000
-
class dvi_font : public font {
dvi_font(const char *);
public:
@@ -123,6 +121,7 @@ class dvi_printer : public printer {
output_font output_font_table[FONTS_MAX];
font *cur_font;
int cur_point_size;
+ color cur_color;
int pushed;
int pushed_h;
int pushed_v;
@@ -132,6 +131,7 @@ class dvi_printer : public printer {
void define_font(int);
void set_font(int);
void possibly_begin_line();
+ void set_color(color *);
protected:
enum {
id_byte = 2,
@@ -179,9 +179,8 @@ public:
class draw_dvi_printer : public dvi_printer {
int output_pen_size;
- int fill;
void set_line_thickness(const environment *);
- void fill_next();
+ void fill_next(const environment *);
public:
draw_dvi_printer();
~draw_dvi_printer();
@@ -214,7 +213,7 @@ dvi_printer::~dvi_printer()
draw_dvi_printer::draw_dvi_printer()
-: output_pen_size(-1), fill(FILL_MAX)
+: output_pen_size(-1)
{
}
@@ -302,9 +301,45 @@ int scale(int x, int z)
return sw;
}
+void dvi_printer::set_color(color *col)
+{
+ cur_color = *col;
+ char buf[256];
+ unsigned int components[4];
+ color_scheme cs = col->get_components(components);
+ switch (cs) {
+ case DEFAULT:
+ sprintf(buf, "color gray 0");
+ break;
+ case RGB:
+ sprintf(buf, "color rgb %.3g %.3g %.3g",
+ double(Red) / color::MAX_COLOR_VAL,
+ double(Green) / color::MAX_COLOR_VAL,
+ double(Blue) / color::MAX_COLOR_VAL);
+ break;
+ case CMY:
+ col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black);
+ // fall through
+ case CMYK:
+ sprintf(buf, "color cmyk %.3g %.3g %.3g %.3g",
+ double(Cyan) / color::MAX_COLOR_VAL,
+ double(Magenta) / color::MAX_COLOR_VAL,
+ double(Yellow) / color::MAX_COLOR_VAL,
+ double(Black) / color::MAX_COLOR_VAL);
+ break;
+ case GRAY:
+ sprintf(buf, "color gray %.3g",
+ double(Gray) / color::MAX_COLOR_VAL);
+ break;
+ }
+ do_special(buf);
+}
-void dvi_printer::set_char(int index, font *f, const environment *env, int w, const char *name)
+void dvi_printer::set_char(int index, font *f, const environment *env,
+ int w, const char *name)
{
+ if (*env->col != cur_color)
+ set_color(env->col);
int code = f->get_code(index);
if (env->size != cur_point_size || f != cur_font) {
cur_font = f;
@@ -345,7 +380,7 @@ void dvi_printer::set_char(int index, font *f, const environment *env, int w, co
possibly_begin_line();
end_h = env->hpos + w;
cur_h += scale(f->get_width(index, UNITWIDTH)/MULTIPLIER,
- cur_point_size*RES_7227);
+ cur_point_size*RES_7227);
if (cur_h > max_h)
max_h = cur_h;
if (cur_v > max_v)
@@ -464,6 +499,8 @@ void dvi_printer::begin_page(int i)
out4(0);
out4(last_bop);
last_bop = tem;
+ if (cur_color != default_color)
+ set_color(&cur_color);
// By convention position (0,0) in a dvi file is placed at (1in, 1in).
cur_h = font::res;
cur_v = font::res;
@@ -472,6 +509,7 @@ void dvi_printer::begin_page(int i)
void dvi_printer::end_page(int)
{
+ set_color(&default_color);
if (pushed)
end_of_line();
out1(eop);
@@ -629,10 +667,17 @@ void draw_dvi_printer::set_line_thickness(const environment *env)
}
}
-void draw_dvi_printer::fill_next()
+void draw_dvi_printer::fill_next(const environment *env)
{
+ unsigned int g;
+ if (env->fill->is_default())
+ g = 0;
+ else {
+ // currently, only BW support
+ env->fill->get_gray(&g);
+ }
char buf[256];
- sprintf(buf, "sh %.3f", double(fill)/FILL_MAX);
+ sprintf(buf, "sh %.3g", 1 - double(g)/color::MAX_COLOR_VAL);
do_special(buf);
}
@@ -652,7 +697,7 @@ void draw_dvi_printer::draw(int code, int *p, int np, const environment *env)
}
moveto(env->hpos+p[0]/2, env->vpos);
if (fill_flag)
- fill_next();
+ fill_next(env);
else
set_line_thickness(env);
int rad;
@@ -685,7 +730,7 @@ void draw_dvi_printer::draw(int code, int *p, int np, const environment *env)
}
moveto(env->hpos+p[0]/2, env->vpos);
if (fill_flag)
- fill_next();
+ fill_next(env);
sprintf(buf, "%s 0 0 %d %d 0 6.28319",
(fill_flag ? "ia" : "ar"),
milliinches(p[0]/2),
@@ -707,7 +752,7 @@ void draw_dvi_printer::draw(int code, int *p, int np, const environment *env)
}
moveto(env->hpos, env->vpos);
if (fill_flag)
- fill_next();
+ fill_next(env);
else
set_line_thickness(env);
do_special("pa 0 0");
@@ -790,17 +835,6 @@ void draw_dvi_printer::draw(int code, int *p, int np, const environment *env)
}
break;
}
- case 'f':
- {
- if (np != 1 && np != 2) {
- error("1 argument required for fill");
- break;
- }
- fill = p[0];
- if (fill < 0 || fill > FILL_MAX)
- fill = FILL_MAX;
- break;
- }
case 'R':
{
if (np != 2) {
diff --git a/contrib/groff/src/devices/grodvi/grodvi.man b/contrib/groff/src/devices/grodvi/grodvi.man
index a4488ce..f732a42 100644
--- a/contrib/groff/src/devices/grodvi/grodvi.man
+++ b/contrib/groff/src/devices/grodvi/grodvi.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
@@ -16,6 +16,8 @@ versions, except that this permission notice may be included in
translations approved by the Free Software Foundation instead of in
the original English.
..
+.
+.
.ie t .ds tx T\h'-.1667m'\v'.224m'E\v'-.224m'\h'-.125m'X
.el .ds tx TeX
.\" Like TP, but if specified indent is more than half
@@ -24,9 +26,13 @@ the original English.
.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
.el .TP "\\$1"
..
+.
+.
.TH GRODVI @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
.SH NAME
grodvi \- convert groff output to TeX dvi format
+.
+.
.SH SYNOPSIS
.B grodvi
[
@@ -36,18 +42,22 @@ grodvi \- convert groff output to TeX dvi format
] [
.BI \-F dir
] [
-.IR files \|.\|.\|.
+.IR files \|.\|.\|.\&
]
.PP
It is possible to have whitespace between a command line option and its
parameter.
+.
+.
.SH DESCRIPTION
.B grodvi
is a driver for
.B groff
that produces \*(tx dvi format.
+.
Normally it should be run by
.BR groff\ \-Tdvi .
+.
This will run
.BR @g@troff\ \-Tdvi ;
it will also input the macros
@@ -56,115 +66,312 @@ if the input is being preprocessed with
.B @g@eqn
it will also input
.BR @FONTDIR@/devdvi/eqnchar .
+.
.LP
The dvi file generated by
.B grodvi
can be printed by any correctly-written dvi driver.
+.
The troff drawing primitives are implemented
-using the tpic version 2 specials.
+using the tpic version\~2 specials.
+.
If the driver does not support these, the
-.B \eD
+.B \[rs]D
commands will not produce any output.
+.
.LP
There is an additional drawing command available:
+.
.TP
-.BI \eD'R\ dh\ dv '
+.BI \[rs]D'R\ dh\ dv '
Draw a rule (solid black rectangle), with one corner
at the current position, and the diagonally opposite corner
-at the current position
+at the current position
.RI +( dh , dv ).
-Afterwards the current position will be at the opposite corner. This
-produces a rule in the dvi file and so can be printed even with a
+.
+Afterwards the current position will be at the opposite corner.
+.
+This produces a rule in the dvi file and so can be printed even with a
driver that does not support the tpic specials unlike the other
-.B \eD
+.B \[rs]D
commands.
+.
.LP
The groff command
-.BI \eX' anything '
+.BI \[rs]X' anything '
is translated into the same command in the dvi file as would be
produced by
-.BI \especial{ anything }
+.BI \[rs]special{ anything }
in \*(tx;
-.I anything may not contain a newline.
+.I anything
+may not contain a newline.
+.
+.LP
+For inclusion of EPS image files,
+.B grodvi
+loads
+.B pspic.tmac
+automatically, providing the
+.B PSPIC
+macro.
+.
+Please check
+.B grops (@MAN1EXT@)
+for a detailed description of this macro.
+.
.LP
Font files for
.B grodvi
can be created from tfm files using
.BR tfmtodit (@MAN1EXT@).
+.
The font description file should contain the following
additional commands:
+.
.Tp \w'\fBinternalname'u+2n
.BI internalname\ name
The name of the tfm file (without the
.B .tfm
extension) is
.IR name .
+.
.TP
.BI checksum\ n
The checksum in the tfm file is
.IR n .
+.
.TP
.BI designsize\ n
The designsize in the tfm file is
.IR n .
+.
.LP
These are automatically generated by
.B tfmtodit.
+.
+.LP
+The default color for
+.B \[rs]m
+and
+.B \[rs]M
+is black.
+.
+Currently, the drawing color for
+.B \[rs]D
+commands is always black, and fill color values are translated to gray.
+.
.LP
In
.B troff
the
-.B \eN
+.B \[rs]N
escape sequence can be used to access characters by their position
in the corresponding tfm file;
all characters in the tfm file can be accessed this way.
+.
+.
.SH OPTIONS
.TP
.B \-d
Do not use tpic specials to implement drawing commands.
+.
Horizontal and vertical lines will be implemented by rules.
+.
Other drawing commands will be ignored.
+.
.TP
.B \-v
Print the version number.
+.
.TP
.BI \-w n
Set the default line thickness to
.I n
-thousandths of an em.
+thousandths of an em.
+If this option isn't specified, the line thickness defaults to 0.04\~em.
+.
.TP
.BI \-F dir
Prepend directory
-.IB dir /devdvi
-to the search path for font and device description files.
+.IB dir /dev name
+to the search path for font and device description files;
+.I name
+is the name of the device, usually
+.BR dvi .
+.
+.
+.SH USAGE
+There are styles called
+.BR R ,
+.BR I ,
+.BR B ,
+and
+.B BI
+mounted at font positions 1 to 4.
+The fonts are grouped into families
+.B T
+and
+.B H
+having members in each of these styles:
+.
+.de FT
+.if '\\*(.T'dvi' .ft \\$1
+..
+.
+.RS
+.TP
+.B TR
+.FT TR
+CM Roman (cmr10)
+.FT
+.
+.TP
+.B TI
+.FT TI
+CM Text Italic (cmti10)
+.FT
+.
+.TP
+.B TB
+.FT TB
+CM Bold Extended Roman (cmbx10)
+.FT
+.
+.TP
+.B TBI
+.FT TBI
+CM Bold Extended Text Italic (cmbxti10)
+.FT
+.
+.TP
+.B HR
+.FT HR
+CM Sans Serif (cmss10)
+.FT
+.
+.TP
+.B HI
+.FT HI
+CM Slanted Sans Serif (cmssi10)
+.FT
+.
+.TP
+.B HB
+.FT HB
+CM Sans Serif Bold Extended (cmssbx10)
+.FT
+.
+.TP
+.B HBI
+.FT HBI
+CM Slanted Sans Serif Bold Extended (cmssbxo10)
+.FT
+.RE
+.
+.LP
+There are also the following fonts which are not members of a family:
+.
+.RS
+.TP
+.B CW
+CM Typewriter Text (cmtt10)
+.FT CW
+.FT
+.
+.TP
+.B CWI
+CM Italic Typewriter Text (cmitt10)
+.FT CWI
+.FT
+.RE
+.
+.LP
+Special fonts are
+.B MI
+(cmmi10),
+.B S
+(cmsy10),
+.B EX
+(cmex10),
+and, perhaps surprisingly,
+.BR TR ,
+.BR TI ,
+and
+.BR CW ,
+due to the different font encodings of text fonts.
+.
+For italic fonts,
+.B CWI
+is used instead of
+.BR CW .
+.
+.LP
+Finally, the symbol fonts of the American Mathematical Society are available
+as special fonts
+.B SA
+(msam10) and
+.B SB
+(msbm10).
+.
+These two fonts are not mounted by default.
+.
+.LP
+Using the option
+.B \-mec
+(loading the file
+.BR ec.tmac )
+EC and TC fonts are used.
+.
+The design of the EC family is very similar to that of the CM fonts;
+additionally, they give a much better coverage of groff symbols.
+.
+Note that
+.B ec.tmac
+must be called before any language-specific files; it doesn't take care of
+hcode values.
+.
+.
.SH FILES
.TP
.B @FONTDIR@/devdvi/DESC
Device description file.
+.
.TP
.BI @FONTDIR@/devdvi/ F
Font description file for font
.IR F .
+.
.TP
.B @MACRODIR@/dvi.tmac
Macros for use with
.BR grodvi .
+.
+.TP
+.B @MACRODIR@/ec.tmac
+Macros to switch to EC fonts.
+.
+.
.SH BUGS
Dvi files produced by
.B grodvi
use a different resolution (57816 units per inch) to those produced by
\*(tx.
+.
Incorrectly written drivers which assume the resolution used by \*(tx,
rather than using the resolution specified in the dvi file will not
work with
.BR grodvi .
+.
.LP
When using the
.B \-d
option with boxed tables,
vertical and horizontal lines can sometimes protrude by one pixel.
+.
This is a consequence of the way \*(tx requires that the heights
and widths of rules be rounded.
+.
+.
.SH "SEE ALSO"
.BR tfmtodit (@MAN1EXT@),
.BR groff (@MAN1EXT@),
diff --git a/contrib/groff/src/devices/grohtml/Makefile.sub b/contrib/groff/src/devices/grohtml/Makefile.sub
index 10f28ce..33e41f8 100644
--- a/contrib/groff/src/devices/grohtml/Makefile.sub
+++ b/contrib/groff/src/devices/grohtml/Makefile.sub
@@ -1,15 +1,18 @@
-PROG=post-grohtml
+PROG=post-grohtml$(EXEEXT)
MAN1=grohtml.n
XLIBS=$(LIBDRIVER) $(LIBGROFF)
MLIB=$(LIBM)
OBJS=\
- post-html.o \
- html-text.o \
- output.o
+ post-html.$(OBJEXT) \
+ html-table.$(OBJEXT) \
+ html-text.$(OBJEXT) \
+ output.$(OBJEXT)
CCSRCS=\
$(srcdir)/post-html.cc \
+ $(srcdir)/html-table.cc \
$(srcdir)/html-text.cc \
$(srcdir)/output.cc
HDRS=\
$(srcdir)/html.h \
+ $(srcdir)/html-table.h \
$(srcdir)/html-text.h
diff --git a/contrib/groff/src/devices/grohtml/grohtml.man b/contrib/groff/src/devices/grohtml/grohtml.man
index 7b0f5e1..976990a 100644
--- a/contrib/groff/src/devices/grohtml/grohtml.man
+++ b/contrib/groff/src/devices/grohtml/grohtml.man
@@ -1,5 +1,5 @@
.ig
-Copyright (C) 1999-2000, 2001 Free Software Foundation, Inc.
+Copyright (C) 1999-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 are
@@ -23,8 +23,10 @@ the original English.
.el .TP "\\$1"
..
.TH GROHTML @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.
.SH NAME
grohtml \- html driver for groff
+.
.SH SYNOPSIS
.nr a \n(.j
.ad l
@@ -36,17 +38,25 @@ grohtml \- html driver for groff
.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]"
.el .RB "[\ " "\\$1" "\ ]"
..
-.OP \-v?lrn
+.OP \-vhlrn
.OP \-D dir
.OP \-F dir
.OP \-i resolution
-.OP \-I image stem
-.OP \-o image vertical offset
+.OP \-I \%image-stem
+.OP \-o \%image-vertical-offset
+.OP \-a \%aa-text-bits
+.OP \-a \%aa-graphic-bits
.RI "[\ " files\|.\|.\|. "\ ]"
.br
.ad \na
+.
.SH DESCRIPTION
+The
.B grohtml
+front end (which consists of a preprocessor,
+.BR pre-grohtml ,
+and a device driver,
+.BR post-grohtml )
translates the output of GNU
.B troff
to html.
@@ -76,11 +86,51 @@ using
option.
.SH OPTIONS
.TP
-.B \-v
-Displays the version.
+.BI \-a aa-text-bits
+Number of bits of antialiasing information to be used by
+.I text
+when generating png images.
+The default is\~4 but legal values are 0, 1, 2, and\~4.
+Note your version of
+.B gs
+needs to support the
+.B \%\-dTextAlphaBits
+and
+.B \%\-dGraphicAlphaBits
+options in order to exploit antialiasing.
+A value of\~0 stops
+.B grohtml
+from issuing antialiasing commands to
+.BR gs .
+.TP
+.BI \-g aa-graphic-bits
+Number of bits of antialiasing information to be used by
+.I graphics
+when generating png images.
+The default is\~4 but legal values are 0, 1, 2, and\~4.
+Note your version of
+.B gs
+needs to support the
+.B \%\-dTextAlphaBits
+and
+.B \%\-dGraphicAlphaBits
+options in order to exploit antialiasing.
+A value of\~0 stops
+.B grohtml
+from issuing antialiasing commands to
+.BR gs .
+.TP
+.B -b
+Initialize the background color to white.
.TP
-.B \-?
-Emits a usage synopsis.
+.B -h
+Generates section and number headings by using
+.BR <B> .\|.\|. </B>
+and increasing the font size, rather than using the
+.BI <H n >\c
+\&.\|.\|.\c
+.BI </H n >
+tags.
.TP
.B -l
Turns off the production of automatic section links at the top of the document.
@@ -91,10 +141,15 @@ Turns off the automatic header and footer line (html rule).
.B -n
Generate simple heading anchors whenever a section/number heading is found.
Without the option the anchor value is the textual heading.
-This can cause problems when a heading contains a `?' on some brousers
+This can cause problems when a heading contains a `?' on some browsers
(netscape).
This flag is automatically turned on if a heading contains an image.
.TP
+.B -p
+Display page rendering progress to stderr.
+.B grohtml
+only displays a page number when an image is required.
+.TP
.BI \-F dir
Prepend directory
.IB dir /dev name
@@ -105,8 +160,8 @@ is the name of the device, usually
.TP
.BI \-i resolution
Select the resolution for all images.
-By default this is 80 pixels per inch.
-Example: -i100 indicates 100 pixels per inch.
+By default this is 100 pixels per inch.
+Example: -i200 indicates 200 pixels per inch.
.TP
.BI \-I stem
Determine the image stem name.
@@ -115,6 +170,9 @@ If omitted grohtml uses
.RI ( XXX
is the process ID).
.TP
+.BI \-o vertical-offset
+Specify the vertical offset of images in points.
+.TP
.BI \-D dir
Inform
.B grohtml
@@ -123,9 +181,7 @@ to place all image files into directory
.TP
.B \-v
Print the version number.
-.TP
-.B \-?
-Display usage.
+.
.SH USAGE
There are styles called
.BR R ,
@@ -137,9 +193,19 @@ mounted at font positions 1 to 4.
.SH DEPENDENCIES
.B grohtml
is dependent upon the png utilities
-.RB ( \&\%pnmcut ,\ \%pnmtopng )
+.RB ( \&\%pnmcut ,\ \%pnmcrop ,\ \%pnmtopng )
and GhostScript
.RB ( gs ).
+.B \%pnmtopng
+(version 2.37.6 or greater)
+and
+.B \%pnmcut
+from the netpbm package (version 9.16 or greater) will work also.
+It is also dependent upon
+.B \%psselect
+from the
+.B PSUtils
+package.
Images are generated whenever a table, picture, equation or line is
encountered.
.SH BUGS
diff --git a/contrib/groff/src/devices/grohtml/html-table.cc b/contrib/groff/src/devices/grohtml/html-table.cc
new file mode 100644
index 0000000..a2bb255
--- /dev/null
+++ b/contrib/groff/src/devices/grohtml/html-table.cc
@@ -0,0 +1,687 @@
+// -*- C++ -*-
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * Gaius Mulley (gaius@glam.ac.uk) wrote html-table.cc
+ *
+ * html-table.h
+ *
+ * provides the methods necessary to handle indentation and tab
+ * positions using html tables.
+ */
+
+/*
+This file is part of groff.
+
+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. */
+
+#include "driver.h"
+#include "stringclass.h"
+#include "cset.h"
+#include "html-table.h"
+#include "ctype.h"
+#include "html.h"
+
+#if !defined(TRUE)
+# define TRUE (1==1)
+#endif
+#if !defined(FALSE)
+# define FALSE (1==0)
+#endif
+
+tabs::tabs ()
+ : tab(NULL)
+{
+}
+
+tabs::~tabs ()
+{
+ delete_list();
+}
+
+/*
+ * delete_list - frees the tab list and sets tab to NULL.
+ */
+
+void tabs::delete_list (void)
+{
+ tab_position *p = tab;
+ tab_position *q;
+
+ while (p != NULL) {
+ q = p;
+ p = p->next;
+ free(q);
+ }
+ tab = NULL;
+}
+
+void tabs::clear (void)
+{
+ delete_list();
+}
+
+/*
+ * compatible - returns TRUE if the tab stops in, s, do
+ * not conflict with the current tab stops.
+ * The new tab stops are _not_ placed into
+ * this class.
+ */
+
+int tabs::compatible (const char *s)
+{
+ char align;
+ int total=0;
+ tab_position *last = tab;
+
+ if (last == NULL)
+ return FALSE; // no tab stops defined
+
+ // move over tag name
+ while ((*s != (char)0) && !isspace(*s))
+ s++;
+
+ while (*s != (char)0 && last != NULL) {
+ // move over white space
+ while ((*s != (char)0) && isspace(*s))
+ s++;
+ // collect alignment
+ align = *s;
+ // move over alignment
+ s++;
+ // move over white space
+ while ((*s != (char)0) && isspace(*s))
+ s++;
+ // collect tab position
+ total += atoi(s);
+ // move over tab position
+ while ((*s != (char)0) && !isspace(*s))
+ s++;
+ if (last->alignment != align || last->position != total)
+ return FALSE;
+
+ last = last->next;
+ }
+ return TRUE;
+}
+
+/*
+ * init - scans the string, s, and initializes the tab stops.
+ */
+
+void tabs::init (const char *s)
+{
+ char align;
+ int total=0;
+ tab_position *last = NULL;
+
+ clear(); // remove any tab stops
+
+ // move over tag name
+ while ((*s != (char)0) && !isspace(*s))
+ s++;
+
+ while (*s != (char)0) {
+ // move over white space
+ while ((*s != (char)0) && isspace(*s))
+ s++;
+ // collect alignment
+ align = *s;
+ // move over alignment
+ s++;
+ // move over white space
+ while ((*s != (char)0) && isspace(*s))
+ s++;
+ // collect tab position
+ total = atoi(s);
+ // move over tab position
+ while ((*s != (char)0) && !isspace(*s))
+ s++;
+ if (last == NULL) {
+ tab = (tab_position *)malloc(sizeof(tab_position));
+ last = tab;
+ } else {
+ last->next = (tab_position *)malloc(sizeof(tab_position));
+ last = last->next;
+ }
+ last->alignment = align;
+ last->position = total;
+ last->next = NULL;
+ }
+}
+
+/*
+ * find_tab - returns the tab number corresponding to the position, pos.
+ */
+
+int tabs::find_tab (int pos)
+{
+ tab_position *p;
+ int i=0;
+
+ for (p = tab; p != NULL; p = p->next) {
+ i++;
+ if (p->position == pos)
+ return i;
+ }
+ return 0;
+}
+
+/*
+ * get_tab_pos - returns the, nth, tab position
+ */
+
+int tabs::get_tab_pos (int n)
+{
+ tab_position *p;
+
+ n--;
+ for (p = tab; (p != NULL) && (n>0); p = p->next) {
+ n--;
+ if (n == 0)
+ return p->position;
+ }
+ return 0;
+}
+
+char tabs::get_tab_align (int n)
+{
+ tab_position *p;
+
+ n--;
+ for (p = tab; (p != NULL) && (n>0); p = p->next) {
+ n--;
+ if (n == 0)
+ return p->alignment;
+ }
+ return 'L';
+}
+
+/*
+ * dump_tab - display tab positions
+ */
+
+void tabs::dump_tabs (void)
+{
+ int i=1;
+ tab_position *p;
+
+ for (p = tab; p != NULL; p = p->next) {
+ printf("tab %d is %d\n", i, p->position);
+ i++;
+ }
+}
+
+/*
+ * html_table - methods
+ */
+
+html_table::html_table (simple_output *op, int linelen)
+ : columns(NULL), out(op), linelength(linelen), last_col(NULL), start_space(FALSE)
+{
+ tab_stops = new tabs();
+}
+
+html_table::~html_table ()
+{
+ if (tab_stops != NULL)
+ delete tab_stops;
+}
+
+/*
+ * remove_cols - remove a list of columns as defined by, c.
+ */
+
+void html_table::remove_cols (cols *c)
+{
+ cols *p;
+
+ while (c != NULL) {
+ p = c;
+ c = c->next;
+ free(p);
+ }
+}
+
+/*
+ * set_linelength - sets the line length value in this table.
+ * It also adds an extra blank column to the
+ * table should linelen exceed the last column.
+ */
+
+void html_table::set_linelength (int linelen)
+{
+ cols *p = NULL;
+ cols *c;
+ linelength = linelen;
+
+ for (c = columns; c != NULL; c = c->next) {
+ if (c->right > linelength) {
+ c->right = linelength;
+ remove_cols(c->next);
+ c->next = NULL;
+ return;
+ }
+ p = c;
+ }
+ if (p != NULL && p->right != 0)
+ add_column(p->no+1, p->right+1, linelen, 'L');
+}
+
+/*
+ * get_effective_linelength -
+ */
+
+int html_table::get_effective_linelength (void)
+{
+ if (columns != NULL)
+ return linelength - columns->left;
+ else
+ return linelength;
+}
+
+/*
+ * add_indent - adds the indent to a table.
+ */
+
+void html_table::add_indent (int indent)
+{
+ if (columns != NULL && columns->left > indent)
+ add_column(0, indent, columns->left-1, 'L');
+}
+
+/*
+ * emit_table_header - emits the html header for this table.
+ */
+
+void html_table::emit_table_header (int space)
+{
+ if (columns == NULL)
+ return;
+
+ // dump_table();
+
+ last_col = NULL;
+ if (linelength > 0) {
+ int n = no_columns() + no_gaps();
+
+ out->nl();
+ out->nl();
+ if (space)
+ out->put_string("<p>");
+ start_space = space;
+ out->put_string("<table width=\"100%\" border=0 rules=\"none\" frame=\"void\"\n cols=\"").put_number(n).put_string("\" cellspacing=\"0\" cellpadding=\"0\">").nl();
+ out->put_string("<tr valign=\"top\" align=\"left\">").nl();
+ }
+}
+
+/*
+ * get_right - returns the right most position of this column.
+ */
+
+int html_table::get_right (cols *c)
+{
+ if (c != NULL && c->right > 0)
+ return c->right;
+ if (c->next != NULL)
+ return c->left;
+ return linelength;
+}
+
+/*
+ * emit_col - moves onto column, n.
+ */
+
+void html_table::emit_col (int n)
+{
+ cols *c = columns;
+ cols *b = columns;
+ int width = 0;
+
+ // must be a different row
+ if (last_col != NULL && n <= last_col->no)
+ emit_new_row();
+
+ while (c != NULL && c->no < n)
+ c = c->next;
+
+ // can we find column, n?
+ if (c != NULL && c->no == n) {
+ // shutdown previous column
+ if (last_col != NULL)
+ out->put_string("</td>").nl();
+
+ // find previous column
+ if (last_col == NULL)
+ b = columns;
+ else
+ b = last_col;
+
+ // have we a gap?
+ if (last_col != NULL) {
+ if (is_gap(b))
+ out->put_string("<td width=\"").put_number(is_gap(b)).put_string("%\"></td>").nl();
+ b = b->next;
+ }
+
+ // move across to column n
+ while (b != c) {
+ width = ((get_right(b) - b->left) * 100)/get_effective_linelength();
+ out->put_string("<td width=\"").put_number(width).put_string("%\"></td>").nl();
+ // have we a gap?
+ if (is_gap(b))
+ out->put_string("<td width=\"").put_number(is_gap(b)).put_string("%\"></td>").nl();
+ b = b->next;
+ }
+ width = ((get_right(b) - b->left) * 100)/get_effective_linelength();
+ switch (b->alignment) {
+
+ case 'C': out->put_string("<td width=\"").put_number(width).put_string("%\" align=center>").nl();
+ break;
+ case 'R': out->put_string("<td width=\"").put_number(width).put_string("%\" align=right>").nl();
+ break;
+ default:
+ out->put_string("<td width=\"").put_number(width).put_string("%\">").nl();
+ }
+ // remember column, b
+ last_col = b;
+ }
+}
+
+/*
+ * finish_row -
+ */
+
+void html_table::finish_row (void)
+{
+ int n = 0;
+ cols *c;
+
+ if (last_col != NULL) {
+ for (c = last_col->next; c != NULL; c = c->next)
+ n = c->no;
+
+ if (n > 0)
+ emit_col(n);
+ out->put_string("</td>").nl();
+ }
+}
+
+/*
+ * emit_new_row - move to the next row.
+ */
+
+void html_table::emit_new_row (void)
+{
+ finish_row();
+ out->put_string("<tr valign=\"top\" align=\"left\">").nl();
+ last_col = NULL;
+}
+
+void html_table::emit_finish_table (void)
+{
+ finish_row();
+ // out->put_string("linelength = ").put_number(linelength).nl();
+ out->put_string("</table>");
+ if (start_space)
+ out->put_string("</p>");
+ out->nl();
+}
+
+/*
+ * add_column - adds a column. It returns FALSE if hstart..hend
+ * crosses into a different columns.
+ */
+
+int html_table::add_column (int coln, int hstart, int hend, char align)
+{
+ cols *c = get_column(coln);
+
+ if (c == NULL)
+ return insert_column(coln, hstart, hend, align);
+ else
+ return modify_column(c, hstart, hend, align);
+}
+
+/*
+ * get_column - returns the column, coln.
+ */
+
+cols *html_table::get_column (int coln)
+{
+ cols *c = columns;
+
+ while (c != NULL && coln != c->no)
+ c = c->next;
+
+ if (c != NULL && coln == c->no)
+ return c;
+ else
+ return NULL;
+}
+
+/*
+ * insert_column - inserts a column, coln.
+ * It returns TRUE if it does not bump into
+ * another column.
+ */
+
+int html_table::insert_column (int coln, int hstart, int hend, char align)
+{
+ cols *c = columns;
+ cols *l = NULL;
+ cols *n = NULL;
+
+ while (c != NULL && c->no < coln) {
+ l = c;
+ c = c->next;
+ }
+ if ((l != NULL) && (hstart < l->right))
+ return FALSE; // new column bumps into previous one
+
+ if ((l != NULL) && (l->next != NULL) &&
+ (l->next->left < hend))
+ return FALSE; // new column bumps into next one
+
+ n = (cols *)malloc(sizeof(cols));
+ if (l == NULL) {
+ n->next = columns;
+ columns = n;
+ } else {
+ n->next = l->next;
+ l->next = n;
+ }
+ n->left = hstart;
+ n->right = hend;
+ n->no = coln;
+ n->alignment = align;
+ return TRUE;
+}
+
+/*
+ * modify_column - given a column, c, modify the width to
+ * contain hstart..hend.
+ * It returns TRUE if it does not clash with
+ * the next or previous column.
+ */
+
+int html_table::modify_column (cols *c, int hstart, int hend, char align)
+{
+ cols *l = columns;
+
+ while (l != NULL && l->next != c)
+ l = l->next;
+
+ if ((l != NULL) && (hstart < l->right))
+ return FALSE; // new column bumps into previous one
+
+ if ((c->next != NULL) && (c->next->left < hend))
+ return FALSE; // new column bumps into next one
+
+ if (c->left > hstart)
+ c->left = hstart;
+
+ if (c->right < hend)
+ c->right = hend;
+
+ c->alignment = align;
+
+ return TRUE;
+}
+
+/*
+ * find_tab_column - finds the column number for position, pos.
+ * It searches through the list tab stops.
+ */
+
+int html_table::find_tab_column (int pos)
+{
+ // remember the first column is reserved for un tabbed glyphs
+ return tab_stops->find_tab(pos)+1;
+}
+
+/*
+ * find_column - find the column number for position, pos.
+ * It searches through the list of columns.
+ */
+
+int html_table::find_column (int pos)
+{
+ int p=0;
+ cols *c;
+
+ for (c = columns; c != NULL; c = c->next) {
+ if (c->left > pos)
+ return p;
+ p = c->no;
+ }
+ return p;
+}
+
+/*
+ * no_columns - returns the number of table columns (rather than tabs)
+ */
+
+int html_table::no_columns (void)
+{
+ int n=0;
+ cols *c;
+
+ for (c = columns; c != NULL; c = c->next)
+ n++;
+ return n;
+}
+
+/*
+ * is_gap - returns the gap between column, c, and the next column.
+ */
+
+int html_table::is_gap (cols *c)
+{
+ if (c == NULL || c->right == 0 || c->next == NULL)
+ return 0;
+ else
+ return (c->next->left - c->right)*100/get_effective_linelength();
+}
+
+/*
+ * no_gaps - returns the number of table gaps between the columns
+ */
+
+int html_table::no_gaps (void)
+{
+ int n=0;
+ cols *c;
+
+ for (c = columns; c != NULL; c = c->next)
+ if (is_gap(c))
+ n++;
+ return n;
+}
+
+/*
+ * get_tab_pos - returns the, nth, tab position
+ */
+
+int html_table::get_tab_pos (int n)
+{
+ return tab_stops->get_tab_pos(n);
+}
+
+char html_table::get_tab_align (int n)
+{
+ return tab_stops->get_tab_align(n);
+}
+
+
+void html_table::dump_table (void)
+{
+ if (columns != NULL) {
+ cols *c;
+ for (c = columns; c != NULL; c = c->next) {
+ printf("column %d %d..%d %c\n", c->no, c->left, c->right, c->alignment);
+ }
+ } else
+ tab_stops->dump_tabs();
+}
+
+/*
+ * html_indent - creates an indent with indentation, ind, given
+ * a line length of linelength.
+ */
+
+html_indent::html_indent (simple_output *op, int ind, int pageoffset, int linelength)
+{
+ table = new html_table(op, linelength);
+
+ table->add_column(1, ind+pageoffset, linelength, 'L');
+ table->add_indent(pageoffset);
+ in = ind;
+ pg = pageoffset;
+ ll = linelength;
+ is_used = FALSE;
+}
+
+html_indent::~html_indent (void)
+{
+ end();
+ delete table;
+}
+
+void html_indent::begin (int space)
+{
+ if (! is_used) {
+ table->emit_table_header(space);
+ table->emit_col(1);
+ is_used = TRUE;
+ }
+}
+
+void html_indent::end (void)
+{
+ if (is_used)
+ table->emit_finish_table();
+ is_used = FALSE;
+}
+
+/*
+ * get_reg - collects the registers as supplied during initialization.
+ */
+
+void html_indent::get_reg (int *ind, int *pageoffset, int *linelength)
+{
+ *ind = in;
+ *pageoffset = pg;
+ *linelength = ll;
+}
diff --git a/contrib/groff/src/devices/grohtml/html-table.h b/contrib/groff/src/devices/grohtml/html-table.h
new file mode 100644
index 0000000..3152060
--- /dev/null
+++ b/contrib/groff/src/devices/grohtml/html-table.h
@@ -0,0 +1,130 @@
+// -*- C++ -*-
+/* Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * Gaius Mulley (gaius@glam.ac.uk) wrote html-table.cc
+ *
+ * html-table.h
+ *
+ * provides the methods necessary to handle indentation and tab
+ * positions using html tables.
+ */
+
+/*
+This file is part of groff.
+
+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. */
+
+#include "html.h"
+
+#if !defined(HTML_TABLE_H)
+#define HTML_TABLE_H
+
+typedef struct tab_position {
+ char alignment;
+ int position;
+ struct tab_position *next;
+} tab_position;
+
+
+class tabs {
+public:
+ tabs ();
+ ~tabs ();
+ void clear (void);
+ int compatible (const char *s);
+ void init (const char *s);
+ int find_tab (int pos);
+ int get_tab_pos (int n);
+ char get_tab_align (int n);
+ void dump_tabs (void);
+
+private:
+ void delete_list (void);
+ tab_position *tab;
+};
+
+/*
+ * define a column
+ */
+
+typedef struct cols {
+ int left, right;
+ int no;
+ char alignment;
+ struct cols *next;
+} cols;
+
+class html_table {
+public:
+ html_table (simple_output *op, int linelen);
+ ~html_table (void);
+ int add_column (int coln, int hstart, int hend, char align);
+ cols *get_column (int coln);
+ int insert_column (int coln, int hstart, int hend, char align);
+ int modify_column (cols *c, int hstart, int hend, char align);
+ int find_tab_column (int pos);
+ int find_column (int pos);
+ int get_tab_pos (int n);
+ char get_tab_align (int n);
+ void set_linelength (int linelen);
+ int no_columns (void);
+ int no_gaps (void);
+ int is_gap (cols *c);
+ void dump_table (void);
+ void emit_table_header (int space);
+ void emit_col (int n);
+ void emit_new_row (void);
+ void emit_finish_table (void);
+ int get_right (cols *c);
+ void add_indent (int indent);
+ void finish_row (void);
+ int get_effective_linelength (void);
+
+ tabs *tab_stops; /* tab stop positions */
+private:
+ cols *columns; /* column entries */
+ simple_output *out;
+ int linelength;
+ cols *last_col; /* last column started */
+ int start_space; /* encapsulate with <p> </p> */
+
+ void remove_cols (cols *c);
+};
+
+/*
+ * the indentation wrapper.
+ * Builds an indentation from a html-table.
+ * This table is only emitted if the paragraph is emitted.
+ */
+
+class html_indent {
+public:
+ html_indent (simple_output *op, int ind, int pageoffset, int linelength);
+ ~html_indent (void);
+ void begin (int space); // called if we need to use the indent
+ void get_reg (int *ind, int *pageoffset, int *linelength);
+
+ // the indent is shutdown when it is deleted
+
+private:
+ void end (void);
+ int is_used;
+ int pg; // values of the registers as passed via initialization
+ int ll;
+ int in;
+ html_table *table;
+};
+
+#endif
diff --git a/contrib/groff/src/devices/grohtml/html-text.cc b/contrib/groff/src/devices/grohtml/html-text.cc
index 56d6c78..31e4311 100644
--- a/contrib/groff/src/devices/grohtml/html-text.cc
+++ b/contrib/groff/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
*
@@ -40,10 +40,12 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "html-text.h"
+// #define DEBUGGING
html_text::html_text (simple_output *op) :
stackptr(NULL), lastptr(NULL), out(op), space_emitted(TRUE),
- current_indentation(-1), pageoffset(-1), linelength(-1)
+ current_indentation(-1), pageoffset(-1), linelength(-1),
+ blank_para(TRUE), start_space(FALSE)
{
}
@@ -52,6 +54,87 @@ html_text::~html_text ()
flush_text();
}
+
+#if defined(DEBUGGING)
+static int debugStack = FALSE;
+
+
+/*
+ * turnDebug - flip the debugStack boolean and return the new value.
+ */
+
+static int turnDebug (void)
+{
+ debugStack = 1-debugStack;
+ return debugStack;
+}
+
+/*
+ * dump_stack_element - display an element of the html stack, p.
+ */
+
+void html_text::dump_stack_element (tag_definition *p)
+{
+ fprintf(stderr, " | ");
+ switch (p->type) {
+
+ case P_TAG: if (p->indent == NULL) {
+ fprintf(stderr, "<P %s>", (char *)p->arg1); break;
+ } else {
+ fprintf(stderr, "<P %s [TABLE]>", (char *)p->arg1); break;
+ }
+ case I_TAG: fprintf(stderr, "<I>"); break;
+ case B_TAG: fprintf(stderr, "<B>"); break;
+ case SUB_TAG: fprintf(stderr, "<SUB>"); break;
+ case SUP_TAG: fprintf(stderr, "<SUP>"); break;
+ case TT_TAG: fprintf(stderr, "<TT>"); break;
+ case PRE_TAG: if (p->indent == NULL) {
+ fprintf(stderr, "<PRE>"); break;
+ } else {
+ fprintf(stderr, "<PRE [TABLE]>"); break;
+ }
+ case SMALL_TAG: fprintf(stderr, "<SMALL>"); break;
+ case BIG_TAG: fprintf(stderr, "<BIG>"); break;
+ case BREAK_TAG: fprintf(stderr, "<BREAK>"); break;
+ case COLOR_TAG: {
+ if (p->col.is_default())
+ fprintf(stderr, "<COLOR (default)>");
+ else {
+ unsigned int r, g, b;
+
+ p->col.get_rgb(&r, &g, &b);
+ fprintf(stderr, "<COLOR %x %x %x>", r/0x101, g/0x101, b/0x101);
+ }
+ break;
+ }
+ default: fprintf(stderr, "unknown tag");
+ }
+ if (p->text_emitted)
+ fprintf(stderr, "[t] ");
+}
+
+/*
+ * dump_stack - debugging function only.
+ */
+
+void html_text::dump_stack (void)
+{
+ if (debugStack) {
+ tag_definition *p = stackptr;
+
+ while (p != NULL) {
+ dump_stack_element(p);
+ p = p->next;
+ }
+ }
+ fprintf(stderr, "\n");
+ fflush(stderr);
+}
+#else
+void html_text::dump_stack (void) {}
+#endif
+
+
/*
* end_tag - shuts down the tag.
*/
@@ -62,19 +145,21 @@ void html_text::end_tag (tag_definition *t)
case I_TAG: out->put_string("</i>"); break;
case B_TAG: out->put_string("</b>"); break;
- case P_TAG: out->put_string("</p>").nl().enable_newlines(FALSE); break;
+ case P_TAG: out->put_string("</p>");
+ if (t->indent != NULL) {
+ delete t->indent;
+ t->indent = NULL;
+ }
+ out->nl(); out->enable_newlines(FALSE);
+ blank_para = TRUE; break;
case SUB_TAG: out->put_string("</sub>"); break;
case SUP_TAG: out->put_string("</sup>"); break;
case TT_TAG: out->put_string("</tt>"); break;
- case PRE_TAG: out->put_string("</pre>");
- if (! is_present(TABLE_TAG)) {
- out->nl();
- out->enable_newlines(TRUE);
- }
- break;
+ case PRE_TAG: out->put_string("</pre>"); out->nl(); out->enable_newlines(TRUE);
+ blank_para = TRUE; break;
case SMALL_TAG: out->put_string("</small>"); break;
case BIG_TAG: out->put_string("</big>"); break;
- case TABLE_TAG: issue_table_end(); break;
+ case COLOR_TAG: out->put_string("</font>"); break;
default:
error("unrecognised tag");
@@ -99,6 +184,27 @@ void html_text::issue_tag (char *tagname, char *arg)
}
/*
+ * issue_color_begin - writes out an html color tag.
+ */
+
+void html_text::issue_color_begin (color *c)
+{
+ unsigned int r, g, b;
+ char buf[6+1];
+
+ out->put_string("<font color=\"#");
+ 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("\">");
+}
+
+/*
* start_tag - starts a tag.
*/
@@ -106,60 +212,42 @@ void html_text::start_tag (tag_definition *t)
{
switch (t->type) {
- case I_TAG: issue_tag("<i", t->arg1); break;
- case B_TAG: issue_tag("<b", t->arg1); break;
- case P_TAG: issue_tag("\n<p", t->arg1);
+ case I_TAG: issue_tag("<i", (char *)t->arg1); break;
+ case B_TAG: issue_tag("<b", (char *)t->arg1); break;
+ case P_TAG: if (t->indent == NULL) {
+ out->nl();
+ issue_tag("\n<p", (char *)t->arg1);
+ } else {
+ out->nl();
+ out->simple_comment("INDENTATION");
+ t->indent->begin(FALSE);
+ start_space = FALSE;
+ issue_tag("<p", (char *)t->arg1);
+ }
+
out->enable_newlines(TRUE); break;
- case SUB_TAG: issue_tag("<sub", t->arg1); break;
- case SUP_TAG: issue_tag("<sup", t->arg1); break;
- case TT_TAG: issue_tag("<tt", t->arg1); break;
- case PRE_TAG: out->nl(); issue_tag("<pre", t->arg1);
+ case SUB_TAG: issue_tag("<sub", (char *)t->arg1); break;
+ case SUP_TAG: issue_tag("<sup", (char *)t->arg1); break;
+ case TT_TAG: issue_tag("<tt", (char *)t->arg1); break;
+ case PRE_TAG: if (t->indent != NULL) {
+ out->nl();
+ out->simple_comment("INDENTATION");
+ t->indent->begin(FALSE);
+ start_space = FALSE;
+ }
+ out->enable_newlines(TRUE);
+ out->nl(); issue_tag("<pre", (char *)t->arg1);
out->enable_newlines(FALSE); break;
- case SMALL_TAG: issue_tag("<small", t->arg1); break;
- case BIG_TAG: issue_tag("<big", t->arg1); break;
- case TABLE_TAG: issue_table_begin(t); break;
+ case SMALL_TAG: issue_tag("<small", (char *)t->arg1); break;
+ case BIG_TAG: issue_tag("<big", (char *)t->arg1); break;
case BREAK_TAG: break;
+ case COLOR_TAG: issue_color_begin(&t->col); break;
default:
error("unrecognised tag");
}
}
-int html_text::table_is_void (tag_definition *t)
-{
- if (linelength > 0) {
- return( current_indentation*100/linelength <= 0 );
- } else {
- return( FALSE );
- }
-}
-
-void html_text::issue_table_begin (tag_definition *t)
-{
- if (linelength > 0) {
- int width=current_indentation*100/linelength;
-
- if (width > 0) {
- out->put_string("<table width=\"100%\" border=0 rules=\"none\" frame=\"void\"\n cols=\"2\" cellspacing=\"0\" cellpadding=\"0\">").nl();
- out->put_string("<tr valign=\"top\" align=\"left\">").nl();
- if ((t->arg1 == 0) || (strcmp(t->arg1, "") == 0))
- out->put_string("<td width=\"").put_number(width).put_string("%\"></td>");
- else {
- out->put_string("<td width=\"").put_number(width).put_string("%\">").nl();
- out->put_string(t->arg1).put_string("</td>");
- t->arg1[0] = (char)0;
- }
- out->put_string("<td width=\"").put_number(100-width).put_string("%\">").nl();
- }
- }
-}
-
-void html_text::issue_table_end (void)
-{
- out->put_string("</td></table>").nl();
- out->enable_newlines(TRUE);
-}
-
/*
* flush_text - flushes html tags which are outstanding on the html stack.
*/
@@ -190,116 +278,94 @@ int html_text::is_present (HTML_TAG t)
tag_definition *p=stackptr;
while (p != NULL) {
- if (t == p->type) {
- return( TRUE );
- }
+ if (t == p->type)
+ return TRUE;
p = p->next;
}
- return( FALSE );
+ return FALSE;
}
+extern void stop();
+
/*
- * push_para - adds a new entry onto the html paragraph stack.
+ * do_push - places, tag_definition, p, onto the stack
*/
-void html_text::push_para (HTML_TAG t, char *arg)
+void html_text::do_push (tag_definition *p)
{
- tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition));
+ HTML_TAG t = p->type;
- p->type = t;
- p->arg1 = arg;
- p->text_emitted = FALSE;
+#if defined(DEBUGGING)
+ if (t == PRE_TAG)
+ stop();
+ debugStack = TRUE;
+ fprintf(stderr, "\nentering do_push (");
+ dump_stack_element(p);
+ fprintf(stderr, ")\n");
+ dump_stack();
+ fprintf(stderr, ")\n");
+ fflush(stderr);
+#endif
/*
- * if t is a P_TAG or TABLE_TAG or PRE_TAG make sure it goes on the end of the stack.
- * But we insist that a TABLE_TAG is always after a PRE_TAG
- * and that a P_TAG is always after a TABLE_TAG
+ * if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack.
*/
- if (((t == P_TAG) || (t == PRE_TAG) || (t == TABLE_TAG)) &&
- (lastptr != NULL)) {
- if (((lastptr->type == TABLE_TAG) && (t == PRE_TAG)) ||
- ((lastptr->type == P_TAG) && (t == TABLE_TAG))) {
- /*
- * insert p before the lastptr
- */
- if (stackptr == lastptr) {
- /*
- * only on element of the stack
- */
- p->next = stackptr;
- stackptr = p;
- } else {
- /*
- * more than one element is on the stack
- */
- tag_definition *q = stackptr;
-
- while (q->next != lastptr) {
- q = q->next;
- }
- q->next = p;
- p->next = lastptr;
- }
- } else {
- /*
- * store, p, at the end
- */
- lastptr->next = p;
- lastptr = p;
- p->next = NULL;
- }
+ if (((t == P_TAG) || (t == PRE_TAG)) && (lastptr != NULL)) {
+ /*
+ * store, p, at the end
+ */
+ lastptr->next = p;
+ lastptr = p;
+ p->next = NULL;
} else {
p->next = stackptr;
if (stackptr == NULL)
lastptr = p;
stackptr = p;
}
+
+#if defined(DEBUGGING)
+ dump_stack();
+ fprintf(stderr, "exiting do_push\n");
+#endif
}
/*
- * do_indent - remember the indent parameters and if
- * indent is > pageoff and indent has changed
- * then we start a html table to implement the indentation.
+ * push_para - adds a new entry onto the html paragraph stack.
*/
-void html_text::do_indent (char *arg, int indent, int pageoff, int linelen)
+void html_text::push_para (HTML_TAG t, void *arg, html_indent *in)
{
- if ((current_indentation != -1) &&
- (pageoffset+current_indentation != indent+pageoff)) {
- /*
- * actual indentation of text has changed, we need to put
- * a table tag onto the stack.
- */
- do_table(arg);
- }
- current_indentation = indent;
- pageoffset = pageoff;
- linelength = linelen;
+ tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition));
+
+ p->type = t;
+ p->arg1 = arg;
+ p->text_emitted = FALSE;
+ p->indent = in;
+
+ if (t == PRE_TAG && is_present(PRE_TAG))
+ fatal("cannot have multiple PRE_TAGs");
+
+ do_push(p);
}
-void html_text::do_table (char *arg)
+void html_text::push_para (HTML_TAG t)
{
- int in_pre = is_in_pre();
- // char *para_type = done_para();
- done_pre();
- shutdown(TABLE_TAG); // shutdown a previous table, if present
- remove_break();
- if (in_pre) {
- do_pre();
- }
- // do_para(para_type);
- push_para(TABLE_TAG, arg);
+ push_para(t, (void *)"", NULL);
}
-/*
- * done_table - terminates a possibly existing table.
- */
-
-void html_text::done_table (void)
+void html_text::push_para (color *c)
{
- shutdown(TABLE_TAG);
- space_emitted = TRUE;
+ tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition));
+
+ p->type = COLOR_TAG;
+ p->arg1 = NULL;
+ p->col = *c;
+ p->text_emitted = FALSE;
+ p->indent = NULL;
+
+ do_push(p);
}
/*
@@ -308,11 +374,8 @@ void html_text::done_table (void)
void html_text::do_italic (void)
{
- done_bold();
- done_tt();
- if (! is_present(I_TAG)) {
- push_para(I_TAG, "");
- }
+ if (! is_present(I_TAG))
+ push_para(I_TAG);
}
/*
@@ -321,11 +384,8 @@ void html_text::do_italic (void)
void html_text::do_bold (void)
{
- done_italic();
- done_tt();
- if (! is_present(B_TAG)) {
- push_para(B_TAG, "");
- }
+ if (! is_present(B_TAG))
+ push_para(B_TAG);
}
/*
@@ -334,11 +394,8 @@ void html_text::do_bold (void)
void html_text::do_tt (void)
{
- done_bold();
- done_italic();
- if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG))) {
- push_para(TT_TAG, "");
- }
+ if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG)))
+ push_para(TT_TAG);
}
/*
@@ -347,13 +404,15 @@ void html_text::do_tt (void)
void html_text::do_pre (void)
{
- done_bold();
- done_italic();
done_tt();
- (void)done_para();
- if (! is_present(PRE_TAG)) {
- push_para(PRE_TAG, "");
- }
+ if (is_present(P_TAG)) {
+ html_indent *i = remove_indent(P_TAG);
+ (void)done_para();
+ if (! is_present(PRE_TAG))
+ push_para(PRE_TAG, NULL, i);
+ } else if (! is_present(PRE_TAG))
+ push_para(PRE_TAG, NULL, NULL);
+ dump_stack();
}
/*
@@ -363,16 +422,26 @@ void html_text::do_pre (void)
int html_text::is_in_pre (void)
{
- return( is_present(PRE_TAG) );
+ return is_present(PRE_TAG);
+}
+
+/*
+ * do_color - initiates a new color tag.
+ */
+
+void html_text::do_color (color *c)
+{
+ shutdown(COLOR_TAG); // shutdown a previous color tag, if present
+ push_para(c);
}
/*
- * is_in_table - returns TRUE if we are currently within a table.
+ * done_color - shutdown an outstanding color tag, if it exists.
*/
-int html_text::is_in_table (void)
+void html_text::done_color (void)
{
- return( is_present(TABLE_TAG) );
+ shutdown(COLOR_TAG);
}
/*
@@ -388,6 +457,7 @@ char *html_text::shutdown (HTML_TAG t)
tag_definition *temp =NULL;
int notext =TRUE;
+ dump_stack();
while ((stackptr != NULL) && (stackptr->type != t)) {
notext = (notext && (! stackptr->text_emitted));
if (! notext) {
@@ -417,12 +487,14 @@ char *html_text::shutdown (HTML_TAG t)
end_tag(stackptr);
}
if (t == P_TAG) {
- arg = stackptr->arg1;
+ arg = (char *)stackptr->arg1;
}
p = stackptr;
stackptr = stackptr->next;
if (stackptr == NULL)
lastptr = NULL;
+ if (p->indent != NULL)
+ delete p->indent;
free(p);
}
@@ -430,13 +502,16 @@ char *html_text::shutdown (HTML_TAG t)
* and restore unaffected tags
*/
while (temp != NULL) {
- push_para(temp->type, temp->arg1);
+ if (temp->type == COLOR_TAG)
+ push_para(&temp->col);
+ else
+ push_para(temp->type, temp->arg1, temp->indent);
p = temp;
temp = temp->next;
free(p);
}
}
- return( arg );
+ return arg;
}
/*
@@ -519,37 +594,9 @@ void html_text::done_big (void)
void html_text::check_emit_text (tag_definition *t)
{
if ((t != NULL) && (! t->text_emitted)) {
- /*
- * we peep and see whether there is a <p> before the <table>
- * in which case we skip the <p>
- */
- if (t->type == TABLE_TAG) {
- if (table_is_void(t)) {
- tag_definition *n = t->next;
- remove_def(t);
- check_emit_text(n);
- } else {
- /*
- * a table which will be emitted, is there a <p> succeeding it?
- */
- if ((t->next != NULL) &&
- (t->next->type == P_TAG) &&
- ((t->next->arg1 == 0) || strcmp(t->next->arg1, "") == 0)) {
- /*
- * yes skip the <p>
- */
- check_emit_text(t->next->next);
- } else {
- check_emit_text(t->next);
- }
- t->text_emitted = TRUE;
- start_tag(t);
- }
- } else {
- check_emit_text(t->next);
- t->text_emitted = TRUE;
- start_tag(t);
- }
+ check_emit_text(t->next);
+ t->text_emitted = TRUE;
+ start_tag(t);
}
}
@@ -557,7 +604,7 @@ void html_text::check_emit_text (tag_definition *t)
* do_emittext - tells the class that text was written during the current tag.
*/
-void html_text::do_emittext (char *s, int length)
+void html_text::do_emittext (const char *s, int length)
{
if ((! is_present(P_TAG)) && (! is_present(PRE_TAG)))
do_para("");
@@ -577,25 +624,47 @@ void html_text::do_emittext (char *s, int length)
}
out->put_string(s, length);
space_emitted = FALSE;
+ blank_para = FALSE;
}
/*
- * do_para- starts a new paragraph
+ * do_para - starts a new paragraph
*/
-void html_text::do_para (char *arg)
+void html_text::do_para (const char *arg, html_indent *in)
{
- done_pre();
if (! is_present(P_TAG)) {
- remove_sub_sup();
- if ((arg != 0) && (strcmp(arg, "") != 0)) {
- remove_tag(TABLE_TAG);
+ if (is_present(PRE_TAG)) {
+ html_indent *i = remove_indent(PRE_TAG);
+ done_pre();
+ if (i == in || in == NULL)
+ in = i;
+ else
+ delete i;
}
- push_para(P_TAG, arg);
+ remove_sub_sup();
+ push_para(P_TAG, (void *)arg, in);
space_emitted = TRUE;
}
}
+void html_text::do_para (const char *arg)
+{
+ do_para(arg, NULL);
+}
+
+void html_text::do_para (simple_output *op, const char *arg1,
+ int indentation, int pageoffset, int linelength)
+{
+ html_indent *indent;
+
+ if (indentation == 0)
+ indent = NULL;
+ else
+ indent = new html_indent(op, indentation, pageoffset, linelength);
+ do_para(arg1, indent);
+}
+
/*
* done_para - shuts down a paragraph tag.
*/
@@ -603,7 +672,27 @@ void html_text::do_para (char *arg)
char *html_text::done_para (void)
{
space_emitted = TRUE;
- return( shutdown(P_TAG) );
+ return shutdown(P_TAG);
+}
+
+/*
+ * remove_indent - returns the indent associated with, tag.
+ * The indent associated with tag is set to NULL.
+ */
+
+html_indent *html_text::remove_indent (HTML_TAG tag)
+{
+ tag_definition *p=stackptr;
+
+ while (p != NULL) {
+ if (tag == p->type) {
+ html_indent *i = p->indent;
+ p->indent = NULL;
+ return i;
+ }
+ p = p->next;
+ }
+ return NULL;
}
/*
@@ -613,11 +702,19 @@ char *html_text::done_para (void)
void html_text::do_space (void)
{
if (is_in_pre()) {
- do_emittext("", 0);
+ if (blank_para)
+ start_space = TRUE;
+ else {
+ do_emittext("", 0);
+ out->nl();
+ }
} else {
- do_para(done_para());
+ html_indent *i = remove_indent(P_TAG);
+
+ do_para(done_para(), i);
+ space_emitted = TRUE;
+ start_space = TRUE;
}
- space_emitted = TRUE;
}
/*
@@ -629,7 +726,7 @@ void html_text::do_break (void)
if (! is_present(PRE_TAG)) {
if (emitted_text()) {
if (! is_present(BREAK_TAG)) {
- push_para(BREAK_TAG, "");
+ push_para(BREAK_TAG);
}
}
}
@@ -654,7 +751,25 @@ void html_text::do_newline (void)
int html_text::emitted_text (void)
{
- return( ! space_emitted);
+ return !space_emitted;
+}
+
+/*
+ * ever_emitted_text - returns TRUE if we have ever emitted text in this paragraph.
+ */
+
+int html_text::ever_emitted_text (void)
+{
+ return !blank_para;
+}
+
+/*
+ * starts_with_space - returns TRUE if we have start this paragraph with a .sp
+ */
+
+int html_text::starts_with_space (void)
+{
+ return start_space;
}
/*
@@ -758,9 +873,9 @@ int html_text::remove_break (void)
if (stackptr == NULL)
lastptr = NULL;
q = stackptr;
- } else if (l == 0) {
+ } else if (l == 0)
error("stack list pointers are wrong");
- } else {
+ else {
l->next = p->next;
q = p->next;
if (l->next == NULL)
@@ -772,13 +887,35 @@ int html_text::remove_break (void)
* now determine whether text was issued before <br>
*/
while (q != 0) {
- if (q->text_emitted) {
- return( TRUE );
- } else {
+ if (q->text_emitted)
+ return TRUE;
+ else
q = q->next;
+ }
+ return FALSE;
+}
+
+/*
+ * remove_para_align - removes a paragraph which has a text
+ * argument. If the paragraph has no text
+ * argument then it is left alone.
+ */
+
+void html_text::remove_para_align (void)
+{
+ if (is_present(P_TAG)) {
+ tag_definition *p=stackptr;
+
+ while (p != NULL) {
+ if (p->type == P_TAG && p->arg1 != NULL) {
+ html_indent *i = remove_indent(P_TAG);
+ done_para();
+ do_para("", i);
+ return;
+ }
+ p = p->next;
}
}
- return( FALSE );
}
/*
@@ -789,11 +926,10 @@ int html_text::remove_break (void)
void html_text::do_small (void)
{
- if (is_present(BIG_TAG)) {
+ if (is_present(BIG_TAG))
done_big();
- } else {
- push_para(SMALL_TAG, "");
- }
+ else
+ push_para(SMALL_TAG);
}
/*
@@ -802,11 +938,10 @@ void html_text::do_small (void)
void html_text::do_big (void)
{
- if (is_present(SMALL_TAG)) {
+ if (is_present(SMALL_TAG))
done_small();
- } else {
- push_para(BIG_TAG, "");
- }
+ else
+ push_para(BIG_TAG);
}
/*
@@ -815,7 +950,7 @@ void html_text::do_big (void)
void html_text::do_sup (void)
{
- push_para(SUP_TAG, "");
+ push_para(SUP_TAG);
}
/*
@@ -824,6 +959,6 @@ void html_text::do_sup (void)
void html_text::do_sub (void)
{
- push_para(SUB_TAG, "");
+ push_para(SUB_TAG);
}
diff --git a/contrib/groff/src/devices/grohtml/html-text.h b/contrib/groff/src/devices/grohtml/html-text.h
index 5bbcd43..c43cbda 100644
--- a/contrib/groff/src/devices/grohtml/html-text.h
+++ b/contrib/groff/src/devices/grohtml/html-text.h
@@ -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
*
@@ -26,18 +26,22 @@ with groff; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "html.h"
+#include "html-table.h"
/*
* html tags
*/
typedef enum {I_TAG, B_TAG, P_TAG, SUB_TAG, SUP_TAG, TT_TAG,
- PRE_TAG, SMALL_TAG, BIG_TAG, BREAK_TAG, TABLE_TAG} HTML_TAG;
+ PRE_TAG, SMALL_TAG, BIG_TAG, BREAK_TAG,
+ COLOR_TAG} HTML_TAG;
typedef struct tag_definition {
HTML_TAG type;
- char *arg1;
+ void *arg1;
int text_emitted;
+ color col;
+ html_indent *indent;
tag_definition *next;
} tag_definition ;
@@ -49,61 +53,73 @@ typedef struct tag_definition {
class html_text {
public:
- html_text (simple_output *op);
- ~html_text (void);
- void flush_text (void);
- void do_emittext (char *s, int length);
- void do_italic (void);
- void do_bold (void);
- void do_roman (void);
- void do_tt (void);
- void do_pre (void);
- void do_small (void);
- void do_big (void);
- void do_para (char *arg1);
- void do_sup (void);
- void do_sub (void);
- void do_space (void);
- void do_break (void);
- void do_newline (void);
- void do_table (char *arg);
- void done_bold (void);
- void done_italic (void);
- char *done_para (void);
- void done_sup (void);
- void done_sub (void);
- void done_tt (void);
- void done_pre (void);
- void done_small (void);
- void done_big (void);
- void do_indent (char *arg, int indent, int pageoff, int linelen);
- int emitted_text (void);
- void emit_space (void);
- int is_in_pre (void);
- void remove_tag (HTML_TAG tag);
- void remove_sub_sup (void);
- void done_table (void);
- int is_in_table (void);
+ html_text (simple_output *op);
+ ~html_text (void);
+ void flush_text (void);
+ void do_emittext (const char *s, int length);
+ void do_italic (void);
+ void do_bold (void);
+ void do_roman (void);
+ void do_tt (void);
+ void do_pre (void);
+ void do_small (void);
+ void do_big (void);
+ void do_para (const char *arg); // used for no indentation
+ void do_para (simple_output *op, const char *arg1,
+ int indentation, int pageoffset, int linelength);
+ void do_sup (void);
+ void do_sub (void);
+ void do_space (void);
+ void do_break (void);
+ void do_newline (void);
+ void do_table (const char *arg);
+ void done_bold (void);
+ void done_italic (void);
+ char *done_para (void);
+ void done_sup (void);
+ void done_sub (void);
+ void done_tt (void);
+ void done_pre (void);
+ void done_small (void);
+ void done_big (void);
+ void do_color (color *c);
+ void done_color (void);
+ int emitted_text (void);
+ int ever_emitted_text (void);
+ int starts_with_space (void);
+ void emit_space (void);
+ int is_in_pre (void);
+ void remove_tag (HTML_TAG tag);
+ void remove_sub_sup (void);
+ void remove_para_align (void);
private:
tag_definition *stackptr; /* the current paragraph state */
tag_definition *lastptr; /* the end of the stack */
simple_output *out;
- int space_emitted;
- int current_indentation; /* current .in value */
- int pageoffset; /* .po value */
- int linelength; /* current line length */
+ int space_emitted; /* just emitted a space? */
+ int current_indentation; /* current .in value */
+ int pageoffset; /* .po value */
+ int linelength; /* current line length */
+ int blank_para; /* have we ever written text? */
+ int start_space; /* does para start with a .sp */
+ html_indent *indent; /* our indent class */
- int is_present (HTML_TAG t);
- void end_tag (tag_definition *t);
- void start_tag (tag_definition *t);
- void push_para (HTML_TAG t, char *arg);
- char *shutdown (HTML_TAG t);
- void check_emit_text (tag_definition *t);
- int remove_break (void);
- void issue_tag (char *tagname, char *arg);
- void issue_table_begin (tag_definition *t);
- void issue_table_end (void);
- int table_is_void (tag_definition *t);
- void remove_def (tag_definition *t);
+ int is_present (HTML_TAG t);
+ void end_tag (tag_definition *t);
+ void start_tag (tag_definition *t);
+ void do_para (const char *arg, html_indent *in);
+ void push_para (HTML_TAG t);
+ void push_para (HTML_TAG t, void *arg, html_indent *in);
+ void push_para (color *c);
+ void do_push (tag_definition *p);
+ char *shutdown (HTML_TAG t);
+ void check_emit_text (tag_definition *t);
+ int remove_break (void);
+ void issue_tag (char *tagname, char *arg);
+ void issue_color_begin (color *c);
+ void remove_def (tag_definition *t);
+ html_indent *remove_indent (HTML_TAG tag);
+ void dump_stack_element (tag_definition *p);
+ void dump_stack (void);
};
diff --git a/contrib/groff/src/devices/grohtml/html.h b/contrib/groff/src/devices/grohtml/html.h
index 69b6e35..431647c 100644
--- a/contrib/groff/src/devices/grohtml/html.h
+++ b/contrib/groff/src/devices/grohtml/html.h
@@ -20,8 +20,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#if !defined(HTML_H)
# define HTML_H
-# undef DEBUGGING
-// # define DEBUGGING
/*
* class and structure needed to buffer words
@@ -53,6 +51,7 @@ public:
simple_output(FILE *, int max_line_length);
simple_output &put_string(const char *, int);
simple_output &put_string(const char *s);
+ simple_output &put_string(const string &s);
simple_output &put_troffps_char (const char *s);
simple_output &put_translated_string(const char *s);
simple_output &put_number(int);
diff --git a/contrib/groff/src/devices/grohtml/output.cc b/contrib/groff/src/devices/grohtml/output.cc
index 88ab7d6..67d5874 100644
--- a/contrib/groff/src/devices/grohtml/output.cc
+++ b/contrib/groff/src/devices/grohtml/output.cc
@@ -38,6 +38,9 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <unistd.h>
#endif
+#undef DEBUGGING
+// #define DEBUGGING
+
#if !defined(TRUE)
# define TRUE (1==1)
#endif
@@ -45,6 +48,18 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
# define FALSE (1==0)
#endif
+
+#if defined(DEBUGGING)
+# define FPUTC(X,Y) do { fputc((X),(Y)); fputc((X), stderr); fflush(stderr); } while (0)
+# define FPUTS(X,Y) do { fputs((X),(Y)); fputs((X), stderr); fflush(stderr); } while (0)
+# define PUTC(X,Y) do { putc((X),(Y)); putc((X), stderr); fflush(stderr); } while (0)
+#else
+# define FPUTC(X,Y) do { fputc((X),(Y)); } while (0)
+# define FPUTS(X,Y) do { fputs((X),(Y)); } while (0)
+# define PUTC(X,Y) do { putc((X),(Y)); } while (0)
+#endif
+
+
/*
* word - initialise a word and set next to NULL
*/
@@ -88,7 +103,7 @@ int word_list::flush (FILE *f)
while (head != 0) {
t = head;
head = head->next;
- fputs(t->s, f);
+ FPUTS(t->s, f);
delete t;
}
head = 0;
@@ -146,7 +161,7 @@ simple_output &simple_output::copy_file(FILE *infp)
{
int c;
while ((c = getc(infp)) != EOF)
- putc(c, fp);
+ PUTC(c, fp);
return *this;
}
@@ -154,7 +169,7 @@ simple_output &simple_output::end_line()
{
flush_last_word();
if (col != 0) {
- putc('\n', fp);
+ PUTC('\n', fp);
col = 0;
}
return *this;
@@ -169,10 +184,10 @@ simple_output &simple_output::simple_comment(const char *s)
{
flush_last_word();
if (col != 0)
- putc('\n', fp);
- fputs("<!-- ", fp);
- fputs(s, fp);
- fputs(" -->\n", fp);
+ PUTC('\n', fp);
+ FPUTS("<!-- ", fp);
+ FPUTS(s, fp);
+ FPUTS(" -->\n", fp);
col = 0;
return *this;
}
@@ -181,7 +196,7 @@ simple_output &simple_output::begin_comment(const char *s)
{
flush_last_word();
if (col != 0)
- putc('\n', fp);
+ PUTC('\n', fp);
col = 0;
put_string("<!--");
space_or_newline();
@@ -205,7 +220,7 @@ simple_output &simple_output::end_comment()
simple_output &simple_output::check_newline(int n)
{
if ((col + n + last_word.get_length() + 1 > max_line_length) && (newlines)) {
- fputc('\n', fp);
+ FPUTC('\n', fp);
col = last_word.flush(fp);
}
return *this;
@@ -218,11 +233,8 @@ simple_output &simple_output::check_newline(int n)
simple_output &simple_output::space_or_newline (void)
{
-#if defined(DEBUGGING)
- fflush(fp); // just for testing
-#endif
if ((col + last_word.get_length() + 1 > max_line_length) && (newlines)) {
- fputc('\n', fp);
+ FPUTC('\n', fp);
if (last_word.get_length() > 0) {
col = last_word.flush(fp);
} else {
@@ -231,7 +243,7 @@ simple_output &simple_output::space_or_newline (void)
} else {
if (last_word.get_length() != 0) {
if (col > 0) {
- fputc(' ', fp);
+ FPUTC(' ', fp);
col++;
}
col += last_word.flush(fp);
@@ -250,7 +262,7 @@ simple_output &simple_output::nl (void)
space_or_newline();
col += last_word.flush(fp);
if (col != 0) {
- fputc('\n', fp);
+ FPUTC('\n', fp);
col = 0;
}
return *this ;
@@ -266,7 +278,7 @@ simple_output &simple_output::set_fixed_point(int n)
simple_output &simple_output::put_raw_char(char c)
{
col += last_word.flush(fp);
- putc(c, fp);
+ PUTC(c, fp);
col++;
return *this;
}
@@ -283,6 +295,12 @@ simple_output &simple_output::put_string(const char *s)
return *this;
}
+simple_output &simple_output::put_string(const string &s)
+{
+ last_word.add_word(s.contents(), s.length());
+ return *this;
+}
+
simple_output &simple_output::put_number(int n)
{
char buf[1 + INT_DIGITS + 1];
@@ -322,15 +340,15 @@ void simple_output::flush_last_word (void)
if (len > 0) {
if (newlines) {
if (col + len + 1 > max_line_length) {
- fputs("\n", fp);
+ FPUTS("\n", fp);
col = 0;
} else {
- fputs(" ", fp);
+ FPUTS(" ", fp);
col++;
}
len += last_word.flush(fp);
} else {
- fputs(" ", fp);
+ FPUTS(" ", fp);
col++;
col += last_word.flush(fp);
}
diff --git a/contrib/groff/src/devices/grohtml/post-html.cc b/contrib/groff/src/devices/grohtml/post-html.cc
index 0c36941..4431f17 100644
--- a/contrib/groff/src/devices/grohtml/post-html.cc
+++ b/contrib/groff/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
@@ -28,6 +28,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "cset.h"
#include "html.h"
#include "html-text.h"
+#include "html-table.h"
#include <time.h>
@@ -47,25 +48,26 @@ extern "C" const char *Version_string;
# define FALSE (1==0)
#endif
-#define MAX_STRING_LENGTH 4096
#define MAX_LINE_LENGTH 60 /* maximum characters we want in a line */
#define SIZE_INCREMENT 2 /* font size increment <big> = +2 */
#define BASE_POINT_SIZE 10 /* 10 points is the base size ie html size 3 */
#define CENTER_TOLERANCE 2 /* how many pixels off center will we still */
-#define ANCHOR_TEMPLATE "heading%d" /* if simple anchor is set we use this */
+#define ANCHOR_TEMPLATE "heading" /* if simple anchor is set we use this */
#define UNICODE_DESC_START 0x80 /* all character entities above this are */
/* either encoded by their glyph names or if */
/* there is no name then we use &#nnn; */
-#define INDENTATION /* #undef INDENTATION to remove .in handling */
-
typedef enum {CENTERED, LEFT, RIGHT, INLINE} TAG_ALIGNMENT;
+typedef enum {col_tag, tab_tag, tab0_tag, none} colType;
+
+#undef DEBUG_TABLES
+
/*
* prototypes
*/
-void str_translate_to_html (font *f, char *buf, int buflen, char *str, int len, int and_single);
-char *get_html_translation (font *f, const char *name);
+char *get_html_translation (font *f, const string &name);
+int char_translate_to_html (font *f, char *buf, int buflen, unsigned char ch, int b, int and_single);
static int auto_links = TRUE; /* by default we enable automatic links at */
@@ -73,6 +75,9 @@ static int auto_links = TRUE; /* by default we enable aut
static int auto_rule = TRUE; /* by default we enable an automatic rule */
/* at the top and bottom of the document */
static int simple_anchors = FALSE; /* default to anchors with heading text */
+static int manufacture_headings = FALSE; /* default is to use the Hn html headings, */
+ /* rather than manufacture our own. */
+static color *default_background = NULL; /* has user requested initial bg color? */
/*
@@ -83,41 +88,27 @@ void stop () {}
static int min (int a, int b)
{
- if (a < b) {
- return( a );
- } else {
- return( b );
- }
+ if (a < b)
+ return a;
+ else
+ return b;
}
static int max (int a, int b)
{
- if (a > b) {
- return( a );
- } else {
- return( b );
- }
+ if (a > b)
+ return a;
+ else
+ return b;
}
/*
- * is_subsection - returns TRUE if a1..a2 is within b1..b2
- */
-
-#if 0
-static int is_subsection (int a1, int a2, int b1, int b2)
-{
- // easier to see whether this is not the case
- return( !((a1 < b1) || (a1 > b2) || (a2 < b1) || (a2 > b2)) );
-}
-#endif
-
-/*
* is_intersection - returns TRUE if range a1..a2 intersects with b1..b2
*/
static int is_intersection (int a1, int a2, int b1, int b2)
{
- // again easier to prove NOT outside limits
+ // easier to prove NOT outside limits
return( ! ((a1 > b2) || (a2 < b1)) );
}
@@ -230,8 +221,9 @@ struct style {
int font_no;
int height;
int slant;
+ color col;
style ();
- style (font *, int, int, int, int);
+ style (font *, int, int, int, int, color);
int operator == (const style &) const;
int operator != (const style &) const;
};
@@ -241,15 +233,15 @@ style::style()
{
}
-style::style(font *p, int sz, int h, int sl, int no)
- : f(p), point_size(sz), font_no(no), height(h), slant(sl)
+style::style(font *p, int sz, int h, int sl, int no, color c)
+ : f(p), point_size(sz), font_no(no), height(h), slant(sl), col(c)
{
}
int style::operator==(const style &s) const
{
return (f == s.f && point_size == s.point_size
- && height == s.height && slant == s.slant);
+ && height == s.height && slant == s.slant && col == s.col);
}
int style::operator!=(const style &s) const
@@ -263,23 +255,33 @@ int style::operator!=(const style &s) const
struct char_block {
enum { SIZE = 256 };
- char buffer[SIZE];
+ char *buffer;
int used;
char_block *next;
char_block();
+ char_block::char_block(int length);
};
char_block::char_block()
+: buffer(NULL), used(0), next(0)
+{
+}
+
+char_block::char_block(int length)
: used(0), next(0)
{
+ buffer = (char *)malloc(max(length, char_block::SIZE));
+ if (buffer == NULL)
+ fatal("out of memory error");
}
class char_buffer {
public:
char_buffer();
~char_buffer();
- char *add_string(char *, unsigned int);
+ char *add_string(const char *, unsigned int);
+ char *add_string(const string &);
private:
char_block *head;
char_block *tail;
@@ -299,24 +301,23 @@ char_buffer::~char_buffer()
}
}
-char *char_buffer::add_string (char *s, unsigned int length)
+char *char_buffer::add_string (const char *s, unsigned int length)
{
int i=0;
unsigned int old_used;
+ if (s == NULL || length == 0)
+ return NULL;
+
if (tail == 0) {
- tail = new char_block;
+ tail = new char_block(length+1);
head = tail;
} else {
if (tail->used + length+1 > char_block::SIZE) {
- tail->next = new char_block;
- tail = tail->next;
+ tail->next = new char_block(length+1);
+ tail = tail->next;
}
}
- // at this point we have a tail which is ready for the string.
- if (tail->used + length+1 > char_block::SIZE) {
- fatal("need to increase char_block::SIZE");
- }
old_used = tail->used;
do {
@@ -336,59 +337,196 @@ char *char_buffer::add_string (char *s, unsigned int length)
return( &tail->buffer[old_used] );
}
+char *char_buffer::add_string (const string &s)
+{
+ return add_string(s.contents(), s.length());
+}
+
/*
* the classes and methods for maintaining glyph positions.
*/
class text_glob {
public:
- text_glob (style *s, char *string, unsigned int length,
- int min_vertical , int min_horizontal,
- int max_vertical , int max_horizontal,
- int is_html , int is_troff_command,
- int is_auto_image,
- int is_a_line , int thickness);
- text_glob (void);
- ~text_glob (void);
- int is_a_line (void);
- int is_a_tag (void);
- int is_raw (void);
- int is_eol (void);
- int is_auto_img (void);
- int is_br (void);
+ void text_glob_html (style *s, char *str, int length,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal);
+ void text_glob_special (style *s, char *str, int length,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal);
+ void text_glob_line (style *s,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal,
+ int thickness);
+ void text_glob_auto_image(style *s, char *str, int length,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal);
+ void text_glob_tag (style *s, char *str, int length,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal);
+
+ text_glob (void);
+ ~text_glob (void);
+ int is_a_line (void);
+ int is_a_tag (void);
+ int is_eol (void);
+ int is_auto_img (void);
+ int is_br (void);
+ int is_in (void);
+ int is_po (void);
+ int is_ti (void);
+ int is_ce (void);
+ int is_eol_ce (void);
+ int is_col (void);
+ int is_tab (void);
+ int is_tab0 (void);
+ int is_ta (void);
+ int is_tab_ts (void);
+ int is_tab_te (void);
+ int is_nf (void);
+ int is_fi (void);
+ int get_arg (void);
+ int get_tab_args (char *align);
+
+ void remember_table (html_table *t);
+ html_table *get_table (void);
style text_style;
- char *text_string;
+ const char *text_string;
unsigned int text_length;
int minv, minh, maxv, maxh;
- int is_raw_command; // should the text be sent directly to the device?
int is_tag; // is this a .br, .sp, .tl etc
int is_img_auto; // image created by eqn delim
+ int is_special; // text has come via 'x X html:'
int is_line; // is the command a <line>?
int thickness; // the thickness of a line
+ html_table *tab; // table description
+
+private:
+ text_glob (style *s, char *str, int length,
+ int min_vertical , int min_horizontal,
+ int max_vertical , int max_horizontal,
+ bool is_troff_command,
+ bool is_auto_image, bool is_special_command,
+ bool is_a_line , int thickness);
};
-text_glob::text_glob (style *s, char *string, unsigned int length,
+text_glob::text_glob (style *s, char *str, int length,
int min_vertical, int min_horizontal,
int max_vertical, int max_horizontal,
- int is_html, int is_troff_command,
- int is_auto_image,
- int is_a_line, int line_thickness)
- : text_style(*s), text_string(string), text_length(length),
+ bool is_troff_command,
+ bool is_auto_image, bool is_special_command,
+ bool is_a_line, int line_thickness)
+ : text_style(*s), text_string(str), text_length(length),
minv(min_vertical), minh(min_horizontal), maxv(max_vertical), maxh(max_horizontal),
- is_raw_command(is_html), is_tag(is_troff_command), is_img_auto(is_auto_image),
- is_line(is_a_line), thickness(line_thickness)
+ is_tag(is_troff_command), is_img_auto(is_auto_image), is_special(is_special_command),
+ is_line(is_a_line), thickness(line_thickness), tab(NULL)
{
}
text_glob::text_glob ()
: text_string(0), text_length(0), minv(-1), minh(-1), maxv(-1), maxh(-1),
- is_raw_command(FALSE), is_tag(FALSE), is_line(FALSE), thickness(0)
+ is_tag(FALSE), is_special(FALSE), is_line(FALSE), thickness(0), tab(NULL)
{
}
text_glob::~text_glob ()
{
+ if (tab != NULL)
+ delete tab;
+}
+
+/*
+ * text_glob_html - used to place html text into the glob buffer.
+ */
+
+void text_glob::text_glob_html (style *s, char *str, int length,
+ int min_vertical , int min_horizontal,
+ int max_vertical , int max_horizontal)
+{
+ text_glob *g = new text_glob(s, str, length,
+ min_vertical, min_horizontal, max_vertical, max_horizontal,
+ FALSE, FALSE, FALSE, FALSE, 0);
+ *this = *g;
+}
+
+/*
+ * text_glob_html - used to place html specials into the glob buffer.
+ * This text is essentially html commands coming through
+ * from the macro sets, with special designated sequences of
+ * characters translated into html. See add_and_encode.
+ */
+
+void text_glob::text_glob_special (style *s, char *str, int length,
+ int min_vertical , int min_horizontal,
+ int max_vertical , int max_horizontal)
+{
+ text_glob *g = new text_glob(s, str, length,
+ min_vertical, min_horizontal, max_vertical, max_horizontal,
+ FALSE, FALSE, TRUE, FALSE, 0);
+ *this = *g;
+}
+
+/*
+ * text_glob_line - record horizontal draw line commands.
+ */
+
+void text_glob::text_glob_line (style *s,
+ int min_vertical , int min_horizontal,
+ int max_vertical , int max_horizontal,
+ int thickness)
+{
+ text_glob *g = new text_glob(s, "", 0,
+ min_vertical, min_horizontal, max_vertical, max_horizontal,
+ FALSE, FALSE, FALSE, TRUE, thickness);
+ *this = *g;
+}
+
+/*
+ * text_glob_auto_image - record the presence of a .auto-image tag command.
+ * Used to mark that an image has been created automatically
+ * by a preprocessor and (pre-grohtml/troff) combination.
+ * Under some circumstances images may not be created.
+ * (consider .EQ
+ * delim $$
+ * .EN
+ * .TS
+ * tab(!), center;
+ * l!l.
+ * $1 over x$!recripical of x
+ * .TE
+ *
+ * the first auto-image marker is created via .EQ/.EN pair
+ * and no image is created.
+ * The second auto-image marker occurs at $1 over x$
+ * Currently this image will not be created
+ * as the whole of the table is created as an image.
+ * (Once html tables are handled by grohtml this will change.
+ * Shortly this will be the case).
+ */
+
+void text_glob::text_glob_auto_image(style *s, char *str, int length,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal)
+{
+ text_glob *g = new text_glob(s, str, length,
+ min_vertical, min_horizontal, max_vertical, max_horizontal,
+ TRUE, TRUE, FALSE, FALSE, 0);
+ *this = *g;
+}
+
+/*
+ * text_glob_tag - records a troff tag.
+ */
+
+void text_glob::text_glob_tag (style *s, char *str, int length,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal)
+{
+ text_glob *g = new text_glob(s, str, length,
+ min_vertical, min_horizontal, max_vertical, max_horizontal,
+ TRUE, FALSE, FALSE, FALSE, 0);
+ *this = *g;
}
/*
@@ -397,7 +535,7 @@ text_glob::~text_glob ()
int text_glob::is_a_line (void)
{
- return( is_line );
+ return is_line;
}
/*
@@ -406,7 +544,7 @@ int text_glob::is_a_line (void)
int text_glob::is_a_tag (void)
{
- return( is_tag );
+ return is_tag;
}
/*
@@ -419,12 +557,121 @@ int text_glob::is_eol (void)
}
/*
- * is_raw - returns TRUE if glob contains raw html.
+ * is_eol_ce - returns TRUE if glob contains the tag eol.ce
+ */
+
+int text_glob::is_eol_ce (void)
+{
+ return( is_tag && (strcmp(text_string, "html-tag:eol.ce") == 0) );
+}
+
+
+/*
+ * is_nf - returns TRUE if glob contains the tag .nf
+ */
+
+int text_glob::is_nf (void)
+{
+ return( is_tag && (strcmp(text_string, "html-tag:.nf") == 0) );
+}
+
+/*
+ * is_fi - returns TRUE if glob contains the tag .fi
+ */
+
+int text_glob::is_fi (void)
+{
+ return( is_tag && (strcmp(text_string, "html-tag:.fi") == 0) );
+}
+
+/*
+ * is_ce - returns TRUE if glob contains the tag .ce
+ */
+
+int text_glob::is_ce (void)
+{
+ return( is_tag && (strcmp(text_string, "html-tag:.ce") == 0) );
+}
+
+/*
+ * is_in - returns TRUE if glob contains the tag .in
+ */
+
+int text_glob::is_in (void)
+{
+ return( is_tag && (strncmp(text_string, "html-tag:.in ", strlen("html-tag:.in ")) == 0) );
+}
+
+/*
+ * is_po - returns TRUE if glob contains the tag .po
*/
-int text_glob::is_raw (void)
+int text_glob::is_po (void)
{
- return( is_raw_command );
+ return( is_tag && (strncmp(text_string, "html-tag:.po ", strlen("html-tag:.po ")) == 0) );
+}
+
+/*
+ * is_ti - returns TRUE if glob contains the tag .ti
+ */
+
+int text_glob::is_ti (void)
+{
+ return( is_tag && (strncmp(text_string, "html-tag:.ti ", strlen("html-tag:.ti ")) == 0) );
+}
+
+/*
+ * is_col - returns TRUE if glob contains the tag .col
+ */
+
+int text_glob::is_col (void)
+{
+ return( is_tag && (strncmp(text_string, "html-tag:.col", strlen("html-tag:.col")) == 0) );
+}
+
+/*
+ * is_tab_ts - returns TRUE if glob contains the tag .tab_ts
+ */
+
+int text_glob::is_tab_ts (void)
+{
+ return( is_tag && (strcmp(text_string, "html-tag:.tab-ts") == 0) );
+}
+
+/*
+ * is_tab_te - returns TRUE if glob contains the tag .tab_te
+ */
+
+int text_glob::is_tab_te (void)
+{
+ return( is_tag && (strcmp(text_string, "html-tag:.tab-te") == 0) );
+}
+
+/*
+ * is_ta - returns TRUE if glob contains the tag .ta
+ */
+
+int text_glob::is_ta (void)
+{
+ return( is_tag && (strncmp(text_string, "html-tag:.ta ", strlen("html-tag:.ta ")) == 0) );
+}
+
+/*
+ * is_tab - returns TRUE if glob contains the tag tab
+ */
+
+int text_glob::is_tab (void)
+{
+ return( is_tag && (strncmp(text_string, "html-tag:tab ", strlen("html-tag:tab ")) == 0) );
+}
+
+/*
+ * is_tab0 - returns TRUE if glob contains the tag tab0
+ */
+
+int text_glob::is_tab0 (void)
+{
+ return( is_tag && (strncmp(text_string, "html-tag:tab0", strlen("html-tag:tab0")) == 0) );
}
/*
@@ -434,16 +681,82 @@ int text_glob::is_raw (void)
int text_glob::is_auto_img (void)
{
- return( is_img_auto );
+ return is_img_auto;
}
/*
* is_br - returns TRUE if the glob is a tag containing a .br
+ * or an implied .br. Note that we do not include .nf or .fi
+ * as grohtml will place a .br after these commands if they
+ * should break the line.
*/
int text_glob::is_br (void)
{
- return( is_a_tag() && (strcmp("html-tag:.br", text_string) == 0) );
+ return( is_a_tag() && ((strcmp ("html-tag:.br", text_string) == 0) ||
+ (strncmp("html-tag:.sp", text_string, 11) == 0) ||
+ (strcmp ("html-tag:.ce", text_string) == 0)) );
+}
+
+int text_glob::get_arg (void)
+{
+ if (strncmp("html-tag:", text_string, strlen("html-tag:")) == 0) {
+ const char *p = text_string;
+
+ while ((*p != (char)0) && (!isspace(*p)))
+ p++;
+ while ((*p != (char)0) && (isspace(*p)))
+ p++;
+ if (*p == (char)0)
+ return -1;
+ return atoi(p);
+ }
+ return -1;
+}
+
+/*
+ * get_tab_args - returns the tab position and alignment of the tab tag
+ */
+
+int text_glob::get_tab_args (char *align)
+{
+ if (strncmp("html-tag:", text_string, strlen("html-tag:")) == 0) {
+ const char *p = text_string;
+
+ // firstly the alignment C|R|L
+ while ((*p != (char)0) && (!isspace(*p)))
+ p++;
+ while ((*p != (char)0) && (isspace(*p)))
+ p++;
+ *align = *p;
+ // now the int value
+ while ((*p != (char)0) && (!isspace(*p)))
+ p++;
+ while ((*p != (char)0) && (isspace(*p)))
+ p++;
+ if (*p == (char)0)
+ return -1;
+ return atoi(p);
+ }
+ return -1;
+}
+
+/*
+ * remember_table - saves table, t, in the text_glob.
+ */
+
+void text_glob::remember_table (html_table *t)
+{
+ tab = t;
+}
+
+/*
+ * get_table - returns the stored table description.
+ */
+
+html_table *text_glob::get_table (void)
+{
+ return tab;
}
/*
@@ -502,6 +815,8 @@ public:
int is_equal_to_head (void);
void start_from_head (void);
void start_from_tail (void);
+ void insert (text_glob *in);
+ void move_to (text_glob *in);
text_glob *move_right_get_data (void);
text_glob *move_left_get_data (void);
text_glob *get_data (void);
@@ -569,6 +884,7 @@ void list::add (text_glob *in, int line_number, int min_vertical, int min_horizo
if (head == 0) {
head = t;
tail = t;
+ ptr = t;
t->left = t;
t->right = t;
} else {
@@ -719,7 +1035,7 @@ text_glob* list::move_right_get_data (void)
/*
* move_left_get_data - returns the datum referenced via ptr and moves
- * ptr right.
+ * ptr right.
*/
text_glob* list::move_left_get_data (void)
@@ -733,21 +1049,55 @@ text_glob* list::move_left_get_data (void)
}
/*
+ * insert - inserts data after the current position.
+ */
+
+void list::insert (text_glob *in)
+{
+ if (is_empty())
+ fatal("list must not be empty if we are inserting data");
+ else {
+ if (ptr == 0)
+ ptr = head;
+
+ element_list *t = new element_list(in, ptr->lineno, ptr->minv, ptr->minh, ptr->maxv, ptr->maxh);
+ if (ptr == tail)
+ tail = t;
+ ptr->right->left = t;
+ t->right = ptr->right;
+ ptr->right = t;
+ t->left = ptr;
+ }
+}
+
+/*
+ * move_to - moves the current position to the point where data, in, exists.
+ * This is an expensive method and should be used sparingly.
+ */
+
+void list::move_to (text_glob *in)
+{
+ ptr = head;
+ while (ptr != tail && ptr->datum != in)
+ ptr = ptr->right;
+}
+
+/*
* page class and methods
*/
class page {
public:
page (void);
- void add (style *s, char *string, unsigned int length,
+ void add (style *s, const string &str,
int line_number,
int min_vertical, int min_horizontal,
int max_vertical, int max_horizontal);
- void add_html (style *s, char *string, unsigned int length,
+ void add_tag (style *s, const string &str,
int line_number,
int min_vertical, int min_horizontal,
int max_vertical, int max_horizontal);
- void add_tag (style *s, char *string, unsigned int length,
+ void add_and_encode (style *s, const string &str,
int line_number,
int min_vertical, int min_horizontal,
int max_vertical, int max_horizontal);
@@ -755,6 +1105,7 @@ public:
int line_number,
int x1, int y1, int x2, int y2,
int thickness);
+ void insert_tag (const string &str);
void dump_page (void); // debugging method
// and the data
@@ -767,32 +1118,34 @@ page::page()
{
}
-void page::add (style *s, char *string, unsigned int length,
- int line_number,
- int min_vertical, int min_horizontal,
- int max_vertical, int max_horizontal)
+/*
+ * insert_tag - inserts a tag after the current position.
+ */
+
+void page::insert_tag (const string &str)
{
- if (length > 0) {
- text_glob *g=new text_glob(s, buffer.add_string(string, length), length,
- min_vertical, min_horizontal, max_vertical, max_horizontal,
- FALSE, FALSE, FALSE, FALSE, 0);
- glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal);
+ if (str.length() > 0) {
+ text_glob *g=new text_glob();
+ text_glob *f=glyphs.get_data();
+ g->text_glob_tag(&f->text_style, buffer.add_string(str), str.length(),
+ f->minv, f->minh, f->maxv, f->maxh);
+ glyphs.insert(g);
}
}
/*
- * add_html - add a raw html command, for example mailto, line, background, image etc.
+ * add - add html text to the list of glyphs.
*/
-void page::add_html (style *s, char *string, unsigned int length,
- int line_number,
- int min_vertical, int min_horizontal,
- int max_vertical, int max_horizontal)
+void page::add (style *s, const string &str,
+ int line_number,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal)
{
- if (length > 0) {
- text_glob *g=new text_glob(s, buffer.add_string(string, length), length,
- min_vertical, min_horizontal, max_vertical, max_horizontal,
- TRUE, FALSE, FALSE, FALSE, 0);
+ if (str.length() > 0) {
+ text_glob *g=new text_glob();
+ g->text_glob_html(s, buffer.add_string(str), str.length(),
+ min_vertical, min_horizontal, max_vertical, max_horizontal);
glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal);
}
}
@@ -801,17 +1154,23 @@ void page::add_html (style *s, char *string, unsigned int length,
* add_tag - adds a troff tag, for example: .tl .sp .br
*/
-void page::add_tag (style *s, char *string, unsigned int length,
+void page::add_tag (style *s, const string &str,
int line_number,
int min_vertical, int min_horizontal,
int max_vertical, int max_horizontal)
{
- if (length > 0) {
- text_glob *g=new text_glob(s, buffer.add_string(string, length), length,
- min_vertical, min_horizontal, max_vertical, max_horizontal,
- FALSE, TRUE,
- (strncmp(string, "html-tag:.auto-image", 20) == 0),
- FALSE, 0);
+ if (str.length() > 0) {
+ text_glob *g;
+
+ if (strncmp((str+'\0').contents(), "html-tag:.auto-image", 20) == 0) {
+ g = new text_glob();
+ g->text_glob_auto_image(s, buffer.add_string(str), str.length(),
+ min_vertical, min_horizontal, max_vertical, max_horizontal);
+ } else {
+ g = new text_glob();
+ g->text_glob_tag(s, buffer.add_string(str), str.length(),
+ min_vertical, min_horizontal, max_vertical, max_horizontal);
+ }
glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal);
}
}
@@ -826,29 +1185,115 @@ void page::add_line (style *s,
int thickness)
{
if (y1 == y2) {
- text_glob *g = new text_glob(s, "", 0,
- min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2),
- FALSE, TRUE, FALSE, FALSE, thickness);
+ text_glob *g = new text_glob();
+ g->text_glob_line(s,
+ min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2),
+ thickness);
glyphs.add(g, line_number, min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2));
}
}
/*
+ * to_unicode - returns a unicode translation of int, ch.
+ */
+
+static char *to_unicode (unsigned int ch)
+{
+ static char buf[30];
+
+ sprintf(buf, "&#%u;", ch);
+ return buf;
+}
+
+/*
+ * add_and_encode - adds a special string to the page, it translates the string
+ * into html glyphs. The special string will have come from x X html:
+ * and can contain troff character encodings which appear as
+ * \(char\). A sequence of \\ represents \.
+ * So for example we can write:
+ * "cost = \(Po\)3.00 file = \\foo\\bar"
+ * which is translated into:
+ * "cost = &pound;3.00 file = \foo\bar"
+ */
+
+void page::add_and_encode (style *s, const string &str,
+ int line_number,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal)
+{
+ string html_string;
+ char *html_glyph;
+ int i=0;
+
+ if (s->f == NULL)
+ return;
+ while (i < str.length()) {
+ if ((i+1<str.length()) && (str.substring(i, 2) == string("\\("))) {
+ // start of escape
+ i += 2; // move over \(
+ int a = i;
+ while ((i+1<str.length()) && (str.substring(i, 2) != string("\\)"))) {
+ i++;
+ }
+ int n = i;
+ if ((i+1<str.length()) && (str.substring(i, 2) == string("\\)")))
+ i++;
+ else
+ n = -1;
+ if (n > 0) {
+ string troff_charname = str.substring(a, n-a);
+ html_glyph = get_html_translation(s->f, troff_charname);
+ if (html_glyph)
+ html_string += html_glyph;
+ else {
+ int index=s->f->name_to_index((troff_charname + '\0').contents());
+
+ if (s->f->contains(index) && (index != 0))
+ html_string += s->f->get_code(index);
+ }
+ }
+ } else
+ html_string += str[i];
+ i++;
+ }
+ if (html_string.length() > 0) {
+ text_glob *g=new text_glob();
+ g->text_glob_special(s, buffer.add_string(html_string), html_string.length(),
+ min_vertical, min_horizontal, max_vertical, max_horizontal);
+ glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal);
+ }
+}
+
+/*
* dump_page - dump the page contents for debugging purposes.
*/
void page::dump_page(void)
{
+#if defined(DEBUG_TABLES)
+ text_glob *old_pos = glyphs.get_data();
text_glob *g;
+ printf("\n<!--\n");
printf("\n\ndebugging start\n");
glyphs.start_from_head();
do {
g = glyphs.get_data();
+ if (g->is_tab_ts()) {
+ printf("\n\n");
+ if (g->get_table() != NULL)
+ g->get_table()->dump_table();
+ }
printf("%s ", g->text_string);
+ if (g->is_tab_te())
+ printf("\n\n");
glyphs.move_right();
} while (! glyphs.is_equal_to_head());
+ glyphs.move_to(old_pos);
printf("\ndebugging end\n\n");
+ printf("\n-->\n");
+ fflush(stdout);
+#endif
}
/*
@@ -895,12 +1340,13 @@ public:
int has_been_written;
int has_been_found;
- char text[MAX_STRING_LENGTH];
+ int with_h1;
+ string text;
};
title_desc::title_desc ()
- : has_been_written(FALSE), has_been_found(FALSE)
+ : has_been_written(FALSE), has_been_found(FALSE), with_h1(FALSE)
{
}
@@ -918,7 +1364,7 @@ public:
list headers; // list of headers built from .NH and .SH
int header_level; // current header level
int written_header; // have we written the header yet?
- char header_buffer[MAX_STRING_LENGTH]; // current header text
+ string header_buffer; // current header text
void write_headings (FILE *f, int force);
};
@@ -948,9 +1394,13 @@ void header_desc::write_headings (FILE *f, int force)
do {
g = headers.get_data();
fputs("<a href=\"#", f);
- if (simple_anchors)
- fprintf(f, ANCHOR_TEMPLATE, h);
- else
+ if (simple_anchors) {
+ string buffer(ANCHOR_TEMPLATE);
+
+ buffer += as_string(h);
+ buffer += '\0';
+ fprintf(f, buffer.contents());
+ } else
fputs(g->text_string, f);
h++;
fputs("\">", f);
@@ -968,16 +1418,18 @@ class html_printer : public printer {
simple_output html;
int res;
int space_char_index;
+ int space_width;
int no_of_printed_pages;
int paper_length;
- enum { SBUF_SIZE = 8192 };
- char sbuf[SBUF_SIZE];
- int sbuf_len;
+ string sbuf;
int sbuf_start_hpos;
int sbuf_vpos;
int sbuf_end_hpos;
+ int sbuf_prev_hpos;
int sbuf_kern;
style sbuf_style;
+ int last_sbuf_length;
+ int overstrike_detected;
style output_style;
int output_hpos;
int output_vpos;
@@ -986,21 +1438,22 @@ class html_printer : public printer {
int line_thickness;
int output_line_thickness;
unsigned char output_space_code;
- string defs;
char *inside_font_style;
int page_number;
title_desc title;
- title_desc indent; // use title class to remember $1 of .ip
header_desc header;
int header_indent;
int supress_sub_sup;
int cutoff_heading;
page *page_contents;
html_text *current_paragraph;
+ html_indent *indent;
+ html_table *table;
int end_center;
int end_tempindent;
TAG_ALIGNMENT next_tag;
int fill_on;
+ int max_linelength;
int linelength;
int pageoffset;
int indentation;
@@ -1008,6 +1461,7 @@ class html_printer : public printer {
int pointsize;
int vertical_spacing;
int line_number;
+ color *background;
void flush_sbuf ();
void set_style (const style &);
@@ -1020,19 +1474,15 @@ class html_printer : public printer {
void set_line_thickness (const environment *);
void terminate_current_font (void);
void flush_font (void);
- void add_char_to_sbuf (unsigned char code);
- void add_to_sbuf (unsigned char code, const char *name);
+ void add_to_sbuf (int index, const string &s);
void write_title (int in_head);
- void determine_diacritical_mark (const char *name, const environment *env);
- int sbuf_continuation (unsigned char code, const char *name, const environment *env, int w);
- char *remove_last_char_from_sbuf ();
- int seen_backwards_escape (char *s, int l);
+ int sbuf_continuation (int index, const char *name, const environment *env, int w);
void flush_page (void);
void troff_tag (text_glob *g);
void flush_globs (void);
void emit_line (text_glob *g);
void emit_raw (text_glob *g);
- void translate_to_html (text_glob *g);
+ void emit_html (text_glob *g);
void determine_space (text_glob *g);
void start_font (const char *name);
void end_font (const char *name);
@@ -1043,6 +1493,7 @@ class html_printer : public printer {
void do_center (char *arg);
void do_break (void);
void do_eol (void);
+ void do_eol_ce (void);
void do_title (void);
void do_fill (int on);
void do_heading (char *arg);
@@ -1067,19 +1518,42 @@ class html_printer : public printer {
int end_subscript (text_glob *g);
int start_superscript (text_glob *g);
int end_superscript (text_glob *g);
-
+ void outstanding_eol (int n);
+ int is_bold (font *f);
+ font *make_bold (font *f);
+ int overstrike (int index, const char *name, const environment *env, int w);
+ void do_body (void);
+ int next_horiz_pos (text_glob *g, int nf);
+ void lookahead_for_tables (void);
+ void insert_tab_te (void);
+ text_glob *insert_tab_ts (text_glob *where);
+ void insert_tab0_foreach_tab (void);
+ void insert_tab_0 (text_glob *where);
+ void do_indent (int in, int pageoff, int linelen);
+ void shutdown_table (void);
+ void do_tab_ts (text_glob *g);
+ void do_tab_te (void);
+ void do_col (char *s);
+ void do_tab (char *s);
+ void do_tab0 (void);
+ int calc_nf (text_glob *g, int nf);
+ void calc_po_in (text_glob *g, int nf);
+ void remove_tabs (void);
+ void remove_courier_tabs (void);
+ void update_min_max (colType type_of_col, int *minimum, int *maximum, text_glob *g);
+ void add_table_end (char *debug_string);
// ADD HERE
public:
- html_printer ();
- ~html_printer ();
- void set_char (int i, font *f, const environment *env, int w, const char *name);
- void draw (int code, int *p, int np, const environment *env);
- void begin_page (int);
- void end_page (int);
- void special (char *arg, const environment *env, char type);
- font *make_font (const char *);
- void end_of_line ();
+ html_printer ();
+ ~html_printer ();
+ void set_char (int i, font *f, const environment *env, int w, const char *name);
+ void draw (int code, int *p, int np, const environment *env);
+ void begin_page (int);
+ void end_page (int);
+ void special (char *arg, const environment *env, char type);
+ font *make_font (const char *);
+ void end_of_line ();
};
printer *make_printer()
@@ -1092,7 +1566,7 @@ static void usage(FILE *stream);
void html_printer::set_style(const style &sty)
{
const char *fontname = sty.f->get_name();
- if (fontname == 0)
+ if (fontname == NULL)
fatal("no internalname specified for font");
#if 0
@@ -1100,6 +1574,33 @@ void html_printer::set_style(const style &sty)
#endif
}
+/*
+ * is_bold - returns TRUE if font, f, is bold.
+ */
+
+int html_printer::is_bold (font *f)
+{
+ const char *fontname = f->get_name();
+ return (strcmp(fontname, "B") == 0) || (strcmp(fontname, "BI") == 0);
+}
+
+/*
+ * make_bold - if a bold font of, f, exists then return it.
+ */
+
+font *html_printer::make_bold (font *f)
+{
+ const char *fontname = f->get_name();
+
+ if (strcmp(fontname, "B") == 0)
+ return f;
+ if (strcmp(fontname, "I") == 0)
+ return font::load_font("BI");
+ if (strcmp(fontname, "BI") == 0)
+ return f;
+ return NULL;
+}
+
void html_printer::end_of_line()
{
flush_sbuf();
@@ -1127,8 +1628,6 @@ void html_printer::emit_raw (text_glob *g)
determine_space(g);
current_paragraph->do_emittext(g->text_string, g->text_length);
} else {
- int in_table=current_paragraph->is_in_table();
-
current_paragraph->done_para();
switch (next_tag) {
@@ -1136,10 +1635,10 @@ void html_printer::emit_raw (text_glob *g)
current_paragraph->do_para("align=center");
break;
case LEFT:
- current_paragraph->do_para("align=left");
+ current_paragraph->do_para(&html, "align=left", indentation, pageoffset, linelength);
break;
case RIGHT:
- current_paragraph->do_para("align=right");
+ current_paragraph->do_para(&html, "align=right", indentation, pageoffset, linelength);
break;
default:
fatal("unknown enumeration");
@@ -1148,13 +1647,14 @@ void html_printer::emit_raw (text_glob *g)
current_paragraph->done_para();
next_tag = INLINE;
supress_sub_sup = TRUE;
-#if defined(INDENTATION)
- if (in_table) {
- stop();
- current_paragraph->do_indent(NULL, 0, pageoffset, linelength);
- current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength);
+ if (indentation > 0) {
+ /*
+ * restore indentation
+ */
+ int newin = indentation;
+ indentation = 0;
+ do_indent(newin, pageoffset, linelength);
}
-#endif
}
}
@@ -1165,16 +1665,16 @@ void html_printer::emit_raw (text_glob *g)
void html_printer::do_center (char *arg)
{
int n = atoi(arg);
-
current_paragraph->do_break();
- current_paragraph->done_para();
- supress_sub_sup = TRUE;
-
+
if (n > 0) {
+ current_paragraph->done_para();
+ supress_sub_sup = TRUE;
current_paragraph->do_para("align=center");
end_center += n;
} else {
end_center = 0;
+ current_paragraph->remove_para_align();
}
}
@@ -1229,23 +1729,16 @@ static int exists (const char *filename)
* providing that the image exists.
*/
-static char *generate_img_src (const char *filename)
+static string &generate_img_src (const char *filename)
{
- static char buffer[MAX_STRING_LENGTH];
+ string *s = new string("");
while (filename && (filename[0] == ' ')) {
filename++;
}
- if (exists(filename)) {
- strcpy(buffer, "<img src=\"");
- strncat(buffer, filename, MAX_STRING_LENGTH-strlen("<img src=\"")-1);
- if (strlen(buffer) < MAX_STRING_LENGTH-3) {
- strncat(buffer, "\">", 3);
- }
- return( (char *)&buffer );
- } else {
- return( 0 );
- }
+ if (exists(filename))
+ *s += string("<img src=\"") + filename + "\">";
+ return *s;
}
/*
@@ -1258,19 +1751,30 @@ static char *generate_img_src (const char *filename)
void html_printer::do_auto_image (text_glob *g, const char *filename)
{
- char *buffer = generate_img_src(filename);
+ string buffer = generate_img_src(filename);
- if (buffer) {
+ if (! buffer.empty()) {
/*
* utilize emit_raw by creating a new text_glob.
*/
text_glob h = *g;
- h.text_string = buffer;
- h.text_length = strlen(buffer);
+ h.text_string = buffer.contents();
+ h.text_length = buffer.length();
emit_raw(&h);
- } else {
+ } else
next_tag = INLINE;
+}
+
+/*
+ * outstanding_eol - call do_eol, n, times.
+ */
+
+void html_printer::outstanding_eol (int n)
+{
+ while (n > 0) {
+ do_eol();
+ n--;
}
}
@@ -1282,7 +1786,7 @@ void html_printer::do_title (void)
{
text_glob *t;
int removed_from_head;
- char buf[MAX_STRING_LENGTH];
+ int eol_ce = 0;
if (page_number == 1) {
int found_title_start = FALSE;
@@ -1292,44 +1796,43 @@ void html_printer::do_title (void)
t = page_contents->glyphs.get_data();
removed_from_head = FALSE;
if (t->is_auto_img()) {
- char *img=generate_img_src((char *)(t->text_string + 20));
+ string img = generate_img_src((char *)(t->text_string + 20));
- if (img) {
- if (found_title_start) {
- strcat(title.text, " ");
- }
+ if (! img.empty()) {
+ if (found_title_start)
+ title.text += " ";
found_title_start = TRUE;
title.has_been_found = TRUE;
- strcat(title.text, img);
+ title.text += img;
}
page_contents->glyphs.sub_move_right(); /* move onto next word */
removed_from_head = ((!page_contents->glyphs.is_empty()) &&
(page_contents->glyphs.is_equal_to_head()));
- } else if (t->is_raw_command) {
- /* skip raw commands
+ } else if (t->is_eol_ce()) {
+ /* process the eol associated with .ce
*/
+ eol_ce++;
page_contents->glyphs.sub_move_right(); /* move onto next word */
} else if (t->is_eol()) {
/* end of title found
*/
title.has_been_found = TRUE;
+ outstanding_eol(eol_ce);
return;
} else if (t->is_a_tag()) {
/* end of title found, but move back so that we read this tag and process it
*/
page_contents->glyphs.move_left(); /* move backwards to last word */
title.has_been_found = TRUE;
+ outstanding_eol(eol_ce);
return;
} else if (found_title_start) {
- strcat(title.text, " ");
- str_translate_to_html(t->text_style.f, buf, MAX_STRING_LENGTH, t->text_string, t->text_length, TRUE);
- strcat(title.text, buf);
- page_contents->glyphs.sub_move_right(); /* move onto next word */
- removed_from_head = ((!page_contents->glyphs.is_empty()) &&
- (page_contents->glyphs.is_equal_to_head()));
+ title.text += " " + string(t->text_string, t->text_length);
+ page_contents->glyphs.sub_move_right(); /* move onto next word */
+ removed_from_head = ((!page_contents->glyphs.is_empty()) &&
+ (page_contents->glyphs.is_equal_to_head()));
} else {
- str_translate_to_html(t->text_style.f, buf, MAX_STRING_LENGTH, t->text_string, t->text_length, TRUE);
- strcpy((char *)title.text, buf);
+ title.text += string(t->text_string, t->text_length);
found_title_start = TRUE;
title.has_been_found = TRUE;
page_contents->glyphs.sub_move_right(); /* move onto next word */
@@ -1338,20 +1841,19 @@ void html_printer::do_title (void)
}
} while ((! page_contents->glyphs.is_equal_to_head()) || (removed_from_head));
}
- // page_contents->glyphs.move_left(); /* move backwards to last word */
+ outstanding_eol(eol_ce);
}
}
void html_printer::write_header (void)
{
- if (strlen(header.header_buffer) > 0) {
+ if (! header.header_buffer.empty()) {
if (header.header_level > 7) {
header.header_level = 7;
}
// firstly we must terminate any font and type faces
current_paragraph->done_para();
- current_paragraph->done_table();
supress_sub_sup = TRUE;
if (cutoff_heading+2 > header.header_level) {
@@ -1359,12 +1861,13 @@ void html_printer::write_header (void)
header.no_of_headings++;
style st;
- text_glob *h=new text_glob(&st,
- header.headings.add_string(header.header_buffer, strlen(header.header_buffer)),
- strlen(header.header_buffer),
- header.no_of_headings, header.header_level,
- header.no_of_headings, header.header_level,
- FALSE, FALSE, FALSE, FALSE, FALSE);
+ text_glob *h=new text_glob();
+ h->text_glob_html(&st,
+ header.headings.add_string(header.header_buffer),
+ header.header_buffer.length(),
+ header.no_of_headings, header.header_level,
+ header.no_of_headings, header.header_level);
+
header.headers.add(h,
header.no_of_headings,
header.no_of_headings, header.no_of_headings,
@@ -1374,26 +1877,45 @@ void html_printer::write_header (void)
html.nl().put_string("<a name=\"");
if (simple_anchors) {
- char buffer[MAX_LINE_LENGTH];
+ string buffer(ANCHOR_TEMPLATE);
- sprintf(buffer, ANCHOR_TEMPLATE, header.no_of_headings);
- html.put_string(buffer);
+ buffer += as_string(header.no_of_headings);
+ buffer += '\0';
+ html.put_string(buffer.contents());
} else {
html.put_string(header.header_buffer);
}
html.put_string("\"></a>").nl();
}
- // and now we issue the real header
- html.put_string("<h");
- html.put_number(header.header_level);
- html.put_string(">");
- html.put_string(header.header_buffer);
- html.put_string("</h");
- html.put_number(header.header_level);
- html.put_string(">").nl();
+ if (manufacture_headings) {
+ // line break before a header
+ if (!current_paragraph->emitted_text())
+ current_paragraph->do_space();
+ // user wants manufactured headings which look better than <Hn></Hn>
+ if (header.header_level<4) {
+ html.put_string("<b><font size=\"+1\">");
+ html.put_string(header.header_buffer);
+ html.put_string("</font></b>").nl();
+ }
+ else {
+ html.put_string("<b>");
+ html.put_string(header.header_buffer);
+ html.put_string("</b>").nl();
+ }
+ }
+ else {
+ // and now we issue the real header
+ html.put_string("<h");
+ html.put_number(header.header_level);
+ html.put_string(">");
+ html.put_string(header.header_buffer);
+ html.put_string("</h");
+ html.put_number(header.header_level);
+ html.put_string(">").nl();
+ }
- current_paragraph->do_para("");
+ current_paragraph->do_para(&html, "", indentation, pageoffset, linelength);
}
}
@@ -1401,9 +1923,10 @@ void html_printer::determine_header_level (int level)
{
if (level == 0) {
int i;
- int l=strlen(header.header_buffer);
- for (i=0; ((i<l) && ((header.header_buffer[i] == '.') || is_digit(header.header_buffer[i]))) ; i++) {
+ for (i=0; ((i<header.header_buffer.length())
+ && ((header.header_buffer[i] == '.')
+ || is_digit(header.header_buffer[i]))) ; i++) {
if (header.header_buffer[i] == '.') {
level++;
}
@@ -1420,35 +1943,33 @@ void html_printer::do_heading (char *arg)
{
text_glob *g;
text_glob *l = 0;
- char buf[MAX_STRING_LENGTH];
int level=atoi(arg);
- strcpy(header.header_buffer, "");
+ header.header_buffer.clear();
page_contents->glyphs.move_right();
if (! page_contents->glyphs.is_equal_to_head()) {
g = page_contents->glyphs.get_data();
do {
if (g->is_auto_img()) {
- char *img=generate_img_src((char *)(g->text_string + 20));
+ string img=generate_img_src((char *)(g->text_string + 20));
- if (img) {
+ if (! img.empty()) {
simple_anchors = TRUE; // we cannot use full heading anchors with images
- if (l != 0) {
- strcat(header.header_buffer, " ");
- }
+ if (l != 0)
+ header.header_buffer += " ";
+
l = g;
- strcat(header.header_buffer, img);
+ header.header_buffer += img;
}
- } else if (! (g->is_a_line() || g->is_a_tag() || g->is_raw())) {
+ } else if (! (g->is_a_line() || g->is_a_tag())) {
/*
- * we ignore raw commands when constructing a heading
+ * we ignore tags commands when constructing a heading
*/
- if (l != 0) {
- strcat(header.header_buffer, " ");
- }
+ if (l != 0)
+ header.header_buffer += " ";
l = g;
- str_translate_to_html(g->text_style.f, buf, MAX_STRING_LENGTH, g->text_string, g->text_length, TRUE);
- strcat(header.header_buffer, (char *)buf);
+
+ header.header_buffer += string(g->text_string, g->text_length);
}
page_contents->glyphs.move_right();
g = page_contents->glyphs.get_data();
@@ -1478,22 +1999,20 @@ int html_printer::is_courier_until_eol (void)
page_contents->glyphs.move_right();
do {
g = page_contents->glyphs.get_data();
- if (! is_font_courier(g->text_style.f)) {
+ if (! g->is_a_tag() && (! is_font_courier(g->text_style.f)))
result = FALSE;
- }
page_contents->glyphs.move_right();
- } while ((result) &&
+ } while (result &&
(! page_contents->glyphs.is_equal_to_head()) &&
- (! g->is_eol()));
+ (! g->is_fi()) && (! g->is_eol()));
/*
* now restore our previous position.
*/
- while (page_contents->glyphs.get_data() != orig) {
+ while (page_contents->glyphs.get_data() != orig)
page_contents->glyphs.move_left();
- }
}
- return( result );
+ return result;
}
/*
@@ -1502,12 +2021,11 @@ int html_printer::is_courier_until_eol (void)
void html_printer::do_linelength (char *arg)
{
-#if defined(INDENTATION)
- if (fill_on) {
- linelength = atoi(arg);
- current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength);
- }
-#endif
+ if (max_linelength == -1)
+ max_linelength = atoi(arg);
+
+ if (fill_on)
+ do_indent(indentation, pageoffset, atoi(arg));
}
/*
@@ -1516,12 +2034,8 @@ void html_printer::do_linelength (char *arg)
void html_printer::do_pageoffset (char *arg)
{
-#if defined(INDENTATION)
- pageoffset = atoi(arg);
- if (fill_on) {
- current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength);
- }
-#endif
+ if (fill_on)
+ do_indent(indentation, atoi(arg), linelength);
}
/*
@@ -1530,12 +2044,8 @@ void html_printer::do_pageoffset (char *arg)
void html_printer::do_indentation (char *arg)
{
-#if defined(INDENTATION)
- if (fill_on) {
- indentation = atoi(arg);
- current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength);
- }
-#endif
+ if (fill_on)
+ do_indent(atoi(arg), pageoffset, linelength);
}
/*
@@ -1544,81 +2054,47 @@ void html_printer::do_indentation (char *arg)
void html_printer::do_tempindent (char *arg)
{
-#if defined(INDENTATION)
if (fill_on) {
end_tempindent = 1;
prev_indent = indentation;
- indentation = atoi(arg);
- current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength);
+ do_indent(atoi(arg), pageoffset, linelength);
}
-#endif
}
/*
- * do_indentedparagraph - handle the .ip tag, this buffers the next line
- * and passes this to text-text as the left hand
- * column table entry.
+ * shutdown_table - shuts down the current table.
*/
-void html_printer::do_indentedparagraph (void)
+void html_printer::shutdown_table (void)
{
-#if defined(INDENTATION)
- text_glob *t;
- int removed_from_head;
- char buf[MAX_STRING_LENGTH];
- int found_indent_start = FALSE;
+ if (table != NULL) {
+ current_paragraph->done_para();
+ table->emit_finish_table();
+ // dont delete this table as it will be deleted when we destroy the text_glob
+ table = NULL;
+ }
+}
- indent.has_been_found = FALSE;
- indent.text[0] = (char)0;
+/*
+ * do_indent - remember the indent parameters and if
+ * indent is > pageoff and indent has changed
+ * then we start a html table to implement the indentation.
+ */
- if (! page_contents->glyphs.is_empty()) {
- page_contents->glyphs.sub_move_right(); /* move onto next word */
- do {
- t = page_contents->glyphs.get_data();
- removed_from_head = FALSE;
- if (t->is_auto_img()) {
- char *img=generate_img_src((char *)(t->text_string + 20));
-
- if (img) {
- if (found_indent_start) {
- strcat(indent.text, " ");
- }
- found_indent_start = TRUE;
- strcat(indent.text, img);
- }
- page_contents->glyphs.sub_move_right(); /* move onto next word */
- } else if (t->is_raw_command) {
- /* skip raw commands
- */
- page_contents->glyphs.sub_move_right(); /* move onto next word */
- } else if (t->is_a_tag() && (strncmp(t->text_string, "html-tag:.br", 12) == 0)) {
- /* end of indented para found, but move back so that we read this tag and process it
- */
- page_contents->glyphs.move_left(); /* move backwards to last word */
- indent.has_been_found = TRUE;
- return;
- } else if (t->is_a_tag()) {
- page_contents->glyphs.sub_move_right(); /* move onto next word */
- } else if (found_indent_start) {
- strcat(indent.text, " ");
- str_translate_to_html(t->text_style.f, buf, MAX_STRING_LENGTH, t->text_string, t->text_length, TRUE);
- strcat(indent.text, buf);
- page_contents->glyphs.sub_move_right(); /* move onto next word */
- removed_from_head = ((!page_contents->glyphs.is_empty()) &&
- (page_contents->glyphs.is_equal_to_head()));
- } else {
- str_translate_to_html(t->text_style.f, buf, MAX_STRING_LENGTH, t->text_string, t->text_length, TRUE);
- strcpy((char *)indent.text, buf);
- found_indent_start = TRUE;
- indent.has_been_found = TRUE;
- page_contents->glyphs.sub_move_right(); /* move onto next word */
- removed_from_head = ((!page_contents->glyphs.is_empty()) &&
- (page_contents->glyphs.is_equal_to_head()));
- }
- } while ((! page_contents->glyphs.is_equal_to_head()) || (removed_from_head));
+void html_printer::do_indent (int in, int pageoff, int linelen)
+{
+ if ((indentation != -1) &&
+ (pageoffset+indentation != in+pageoff)) {
+
+ current_paragraph->done_para();
+
+ indentation = in;
+ pageoffset = pageoff;
+ if (linelen <= max_linelength)
+ linelength = linelen;
+
+ current_paragraph->do_para(&html, "", indentation, pageoffset, max_linelength);
}
- // page_contents->glyphs.move_left(); /* move backwards to last word */
-#endif
}
/*
@@ -1650,13 +2126,12 @@ void html_printer::do_fill (int on)
supress_sub_sup = TRUE;
if (fill_on != on) {
- if (on) {
- current_paragraph->done_pre();
- } else {
+ if (on)
+ current_paragraph->do_para("");
+ else
current_paragraph->do_pre();
- }
+ fill_on = on;
}
- fill_on = on;
}
/*
@@ -1666,14 +2141,25 @@ void html_printer::do_fill (int on)
void html_printer::do_eol (void)
{
if (! fill_on) {
- current_paragraph->do_newline();
- current_paragraph->do_break();
+ if (current_paragraph->ever_emitted_text()) {
+ current_paragraph->do_newline();
+ current_paragraph->do_break();
+ }
}
output_hpos = indentation+pageoffset;
+}
+
+/*
+ * do_eol_ce - handle end of line specifically for a .ce
+ */
+
+void html_printer::do_eol_ce (void)
+{
if (end_center > 0) {
- if (end_center > 1) {
- current_paragraph->do_break();
- }
+ if (end_center > 1)
+ if (current_paragraph->emitted_text())
+ current_paragraph->do_break();
+
end_center--;
if (end_center == 0) {
current_paragraph->done_para();
@@ -1689,7 +2175,6 @@ void html_printer::do_eol (void)
void html_printer::do_flush (void)
{
current_paragraph->done_para();
- current_paragraph->done_table();
}
/*
@@ -1699,12 +2184,9 @@ void html_printer::do_flush (void)
void html_printer::do_links (void)
{
current_paragraph->done_para();
- current_paragraph->done_table();
auto_links = FALSE; /* from now on only emit under user request */
-#if !defined(DEBUGGING)
file_list.add_new_file(xtmpfile());
html.set_file(file_list.get_file());
-#endif
}
/*
@@ -1715,20 +2197,106 @@ void html_printer::do_links (void)
void html_printer::do_break (void)
{
current_paragraph->do_break();
-#if defined(INDENTATION)
if (end_tempindent > 0) {
end_tempindent--;
- if (end_tempindent == 0) {
- indentation = prev_indent;
- current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength);
- }
+ if (end_tempindent == 0)
+ do_indent(prev_indent, pageoffset, linelength);
}
-#endif
output_hpos = indentation+pageoffset;
supress_sub_sup = TRUE;
}
/*
+ * do_tab_ts - start a table, which will have already been defined.
+ */
+
+void html_printer::do_tab_ts (text_glob *g)
+{
+ html_table *t = g->get_table();
+
+ if (t != NULL) {
+ current_paragraph->done_pre();
+ current_paragraph->done_para();
+
+ html.simple_comment("TABS");
+
+ t->set_linelength(max_linelength);
+ t->add_indent(pageoffset);
+ t->emit_table_header(FALSE);
+ }
+
+ table = t;
+}
+
+/*
+ * do_tab_te - finish a table.
+ */
+
+void html_printer::do_tab_te (void)
+{
+ if (table) {
+ current_paragraph->done_para();
+ table->emit_finish_table();
+ }
+
+ table = NULL;
+
+ if (indentation > 0) {
+ /*
+ * restore indentation
+ */
+ int newin = indentation;
+ indentation = 0;
+ do_indent(newin, pageoffset, linelength);
+ }
+}
+
+/*
+ * do_tab - handle the "html-tag:tab" tag
+ */
+
+void html_printer::do_tab (char *s)
+{
+ if (table) {
+ while (isspace(*s))
+ s++;
+ s++;
+ int col = table->find_column(atoi(s) + pageoffset + indentation);
+ if (col > 0) {
+ current_paragraph->done_para();
+ table->emit_col(col);
+ }
+ }
+}
+
+/*
+ * do_tab0 - handle the "html-tag:tab0" tag
+ */
+
+void html_printer::do_tab0 (void)
+{
+ if (table) {
+ int col = table->find_column(pageoffset+indentation);
+ if (col > 0) {
+ current_paragraph->done_para();
+ table->emit_col(col);
+ }
+ }
+}
+
+/*
+ * do_col - start column, s.
+ */
+
+void html_printer::do_col (char *s)
+{
+ if (table) {
+ current_paragraph->done_para();
+ table->emit_col(atoi(s));
+ }
+}
+
+/*
* troff_tag - processes the troff tag and manipulates the troff state machine.
*/
@@ -1741,8 +2309,13 @@ void html_printer::troff_tag (text_glob *g)
if (g->is_eol()) {
do_eol();
+ } else if (g->is_eol_ce()) {
+ do_eol_ce();
} else if (strncmp(t, ".sp", 3) == 0) {
- current_paragraph->do_space();
+ if (g->get_arg() > 0)
+ current_paragraph->do_space();
+ else
+ current_paragraph->do_break();
supress_sub_sup = TRUE;
} else if (strncmp(t, ".br", 3) == 0) {
do_break();
@@ -1761,6 +2334,11 @@ void html_printer::troff_tag (text_glob *g)
do_center(a);
} else if (strncmp(t, ".tl", 3) == 0) {
supress_sub_sup = TRUE;
+ title.with_h1 = TRUE;
+ do_title();
+ } else if (strncmp(t, ".html-tl", 8) == 0) {
+ supress_sub_sup = TRUE;
+ title.with_h1 = FALSE;
do_title();
} else if (strncmp(t, ".fi", 3) == 0) {
do_fill(TRUE);
@@ -1784,10 +2362,25 @@ void html_printer::troff_tag (text_glob *g)
} else if (strncmp(t, ".vs", 3) == 0) {
char *a = (char *)t+3;
do_verticalspacing(a);
- } else if (strncmp(t, ".ip", 3) == 0) {
- do_indentedparagraph();
+ } else if (strncmp(t, ".ps", 3) == 0) {
+ char *a = (char *)t+3;
+ do_pointsize(a);
} else if (strcmp(t, ".links") == 0) {
do_links();
+ } else if (strcmp(t, ".no-auto-rule") == 0) {
+ auto_rule = FALSE;
+ } else if (strcmp(t, ".tab-ts") == 0) {
+ do_tab_ts(g);
+ } else if (strcmp(t, ".tab-te") == 0) {
+ do_tab_te();
+ } else if (strncmp(t, ".col ", 5) == 0) {
+ char *a = (char *)t+4;
+ do_col(a);
+ } else if (strncmp(t, "tab ", 4) == 0) {
+ char *a = (char *)t+3;
+ do_tab(a);
+ } else if (strncmp(t, "tab0", 4) == 0) {
+ do_tab0();
}
}
@@ -1813,18 +2406,15 @@ void html_printer::flush_globs (void)
do {
g = page_contents->glyphs.get_data();
- if (strcmp(g->text_string, "XXXXXXX") == 0) {
+ if (strcmp(g->text_string, "XXXXXXX") == 0)
stop();
- }
- if (g->is_raw()) {
- emit_raw(g);
- } else if (g->is_a_tag()) {
+ if (g->is_a_tag()) {
troff_tag(g);
} else if (g->is_a_line()) {
emit_line(g);
} else {
- translate_to_html(g);
+ emit_html(g);
}
/*
* after processing the title (and removing it) the glyph list might be empty
@@ -1836,29 +2426,474 @@ void html_printer::flush_globs (void)
}
}
+/*
+ * calc_nf - calculates the _no_ format flag, given the
+ * text glob, g.
+ */
+
+int html_printer::calc_nf (text_glob *g, int nf)
+{
+ if (g != NULL) {
+ if (g->is_fi())
+ return FALSE;
+ if (g->is_nf())
+ return TRUE;
+ }
+ return nf;
+}
+
+/*
+ * calc_po_in - calculates the, in, po, registers
+ */
+
+void html_printer::calc_po_in (text_glob *g, int nf)
+{
+ if (g->is_in())
+ indentation = g->get_arg();
+ else if (g->is_po())
+ pageoffset = g->get_arg();
+ else if (g->is_ti()) {
+ prev_indent = indentation;
+ indentation = g->get_arg();
+ end_tempindent = 1;
+ } else if (g->is_br() && ((end_tempindent > 0) || (nf && g->is_eol()))) {
+ end_tempindent = 0;
+ indentation = prev_indent;
+ }
+}
+
+/*
+ * next_horiz_pos - returns the next horiz position.
+ * -1 is returned if it doesn't exist.
+ */
+
+int html_printer::next_horiz_pos (text_glob *g, int nf)
+{
+ int next = -1;
+
+ if ((g != NULL) && (g->is_br() || (nf && g->is_eol())))
+ if (! page_contents->glyphs.is_empty()) {
+ page_contents->glyphs.move_right_get_data();
+ if (g == NULL)
+ page_contents->glyphs.start_from_head();
+ else {
+ next = g->minh;
+ page_contents->glyphs.move_left();
+ }
+ }
+ return next;
+}
+
+/*
+ * insert_tab_ts - inserts a tab-ts before, where.
+ */
+
+text_glob *html_printer::insert_tab_ts (text_glob *where)
+{
+ text_glob *start_of_table;
+ text_glob *old_pos = page_contents->glyphs.get_data();
+
+ page_contents->glyphs.move_to(where);
+ page_contents->glyphs.move_left();
+ page_contents->insert_tag(string("html-tag:.tab-ts")); // tab table start
+ page_contents->glyphs.move_right();
+ start_of_table = page_contents->glyphs.get_data();
+ page_contents->glyphs.move_to(old_pos);
+ return start_of_table;
+}
+
+/*
+ * insert_tab_te - inserts a tab-te before the current position
+ * (it skips backwards over .sp/.br)
+ */
+
+void html_printer::insert_tab_te (void)
+{
+ text_glob *g = page_contents->glyphs.get_data();
+ page_contents->dump_page();
+
+ while (page_contents->glyphs.get_data()->is_a_tag())
+ page_contents->glyphs.move_left();
+
+ page_contents->insert_tag(string("html-tag:.tab-te")); // tab table end
+ while (g != page_contents->glyphs.get_data())
+ page_contents->glyphs.move_right();
+ page_contents->dump_page();
+}
+
+/*
+ * insert_tab_0 - inserts a tab0 before, where.
+ */
+
+void html_printer::insert_tab_0 (text_glob *where)
+{
+ text_glob *old_pos = page_contents->glyphs.get_data();
+
+ page_contents->glyphs.move_to(where);
+ page_contents->glyphs.move_left();
+ page_contents->insert_tag(string("html-tag:tab0")); // tab0 start of line
+ page_contents->glyphs.move_right();
+ page_contents->glyphs.move_to(old_pos);
+}
+
+/*
+ * remove_tabs - removes the tabs tags on this line.
+ */
+
+void html_printer::remove_tabs (void)
+{
+ text_glob *orig = page_contents->glyphs.get_data();
+ text_glob *g;
+
+ if (! page_contents->glyphs.is_equal_to_tail()) {
+ do {
+ g = page_contents->glyphs.get_data();
+ if (g->is_tab()) {
+ page_contents->glyphs.sub_move_right();
+ if (g == orig)
+ orig = page_contents->glyphs.get_data();
+ } else
+ page_contents->glyphs.move_right();
+ } while ((! page_contents->glyphs.is_equal_to_head()) &&
+ (! g->is_eol()));
+
+ /*
+ * now restore our previous position.
+ */
+ while (page_contents->glyphs.get_data() != orig)
+ page_contents->glyphs.move_left();
+ }
+}
+
+void html_printer::remove_courier_tabs (void)
+{
+ text_glob *g;
+ int line_start = TRUE;
+ int nf = FALSE;
+
+ if (! page_contents->glyphs.is_empty()) {
+ page_contents->glyphs.start_from_head();
+ line_start = TRUE;
+ do {
+ g = page_contents->glyphs.get_data();
+
+ nf = calc_nf(g, nf);
+
+ if (line_start) {
+ if (line_start && nf && is_courier_until_eol()) {
+ remove_tabs();
+ g = page_contents->glyphs.get_data();
+ }
+ }
+
+ line_start = g->is_br() || g->is_nf() || g->is_fi() || (nf && g->is_eol());
+ page_contents->glyphs.move_right();
+ } while (! page_contents->glyphs.is_equal_to_head());
+ }
+}
+
+void html_printer::insert_tab0_foreach_tab (void)
+{
+ text_glob *start_of_line = NULL;
+ text_glob *g = NULL;
+ int seen_tab = FALSE;
+ int seen_col = FALSE;
+ int nf = FALSE;
+
+ if (! page_contents->glyphs.is_empty()) {
+ page_contents->glyphs.start_from_head();
+ start_of_line = page_contents->glyphs.get_data();
+ do {
+ g = page_contents->glyphs.get_data();
+
+ nf = calc_nf(g, nf);
+
+ if (g->is_tab())
+ seen_tab = TRUE;
+
+ if (g->is_col())
+ seen_col = TRUE;
+
+ if (g->is_br() || (nf && g->is_eol())) {
+ do {
+ page_contents->glyphs.move_right();
+ g = page_contents->glyphs.get_data();
+ nf = calc_nf(g, nf);
+ if (page_contents->glyphs.is_equal_to_head()) {
+ if (seen_tab && !seen_col)
+ insert_tab_0(start_of_line);
+ return;
+ }
+ } while (g->is_br() || (nf && g->is_eol()) || g->is_ta());
+ // printf("\nstart_of_line is: %s\n", g->text_string);
+ if (seen_tab && !seen_col) {
+ insert_tab_0(start_of_line);
+ page_contents->glyphs.move_to(g);
+ }
+
+ seen_tab = FALSE;
+ seen_col = FALSE;
+ start_of_line = g;
+ }
+ page_contents->glyphs.move_right();
+ } while (! page_contents->glyphs.is_equal_to_head());
+ if (seen_tab && !seen_col)
+ insert_tab_0(start_of_line);
+
+ }
+}
+
+/*
+ * update_min_max - updates the extent of a column, given the left and right
+ * extents of a glyph, g.
+ */
+
+void html_printer::update_min_max (colType type_of_col, int *minimum, int *maximum, text_glob *g)
+{
+ switch (type_of_col) {
+
+ case tab_tag:
+ break;
+ case tab0_tag:
+ *minimum = g->minh;
+ break;
+ case col_tag:
+ *minimum = g->minh;
+ *maximum = g->maxh;
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * add_table_end - moves left one glyph, adds a table end tag and adds a
+ * debugging string.
+ */
+
+void html_printer::add_table_end (char *debug_string)
+{
+ page_contents->glyphs.move_left();
+ insert_tab_te();
+#if defined(DEBUG_TABLES)
+ page_contents->insert_tag(string(debug_string));
+#endif
+}
+
+/*
+ * lookahead_for_tables - checks for .col tags and inserts table start/end tags
+ */
+
+void html_printer::lookahead_for_tables (void)
+{
+ text_glob *g;
+ text_glob *start_of_line = NULL;
+ text_glob *start_of_table = NULL;
+ text_glob *last = NULL;
+ colType type_of_col = none;
+ int left = 0;
+ int found_col = FALSE;
+ int seen_text = FALSE;
+ int ncol = 0;
+ int colmin;
+ int colmax;
+ html_table *table = new html_table(&html, -1);
+ const char *tab_defs = NULL;
+ char align = 'L';
+ int nf = FALSE;
+ int old_pageoffset = pageoffset;
+
+ remove_courier_tabs();
+ page_contents->dump_page();
+ insert_tab0_foreach_tab();
+ page_contents->dump_page();
+ if (! page_contents->glyphs.is_empty()) {
+ page_contents->glyphs.start_from_head();
+ g = page_contents->glyphs.get_data();
+ do {
+#if defined(DEBUG_TABLES)
+ fprintf(stderr, " [") ;
+ fprintf(stderr, g->text_string) ;
+ fprintf(stderr, "] ") ;
+ fflush(stderr);
+ if (strcmp(g->text_string, "XXXXXXX") == 0)
+ stop();
+#endif
+
+ nf = calc_nf(g, nf);
+ calc_po_in(g, nf);
+ if (g->is_col()) {
+ if (type_of_col == tab_tag && start_of_table != NULL) {
+ page_contents->glyphs.move_left();
+ insert_tab_te();
+ start_of_table->remember_table(table);
+ table = new html_table(&html, -1);
+ page_contents->insert_tag(string("*** TAB -> COL ***"));
+ if (tab_defs != NULL)
+ table->tab_stops->init(tab_defs);
+ start_of_table = NULL;
+ last = NULL;
+ }
+ type_of_col = col_tag;
+ found_col = TRUE;
+ ncol = g->get_arg();
+ align = 'L';
+ colmin = 0;
+ colmax = 0;
+ } else if (g->is_tab()) {
+ type_of_col = tab_tag;
+ colmin = g->get_tab_args(&align);
+ align = 'L'; // for now as 'C' and 'R' are broken
+ ncol = table->find_tab_column(colmin);
+ colmin += pageoffset + indentation;
+ colmax = table->get_tab_pos(ncol+1);
+ if (colmax > 0)
+ colmax += pageoffset + indentation;
+ } else if (g->is_tab0()) {
+ if (type_of_col == col_tag && start_of_table != NULL) {
+ page_contents->glyphs.move_left();
+ insert_tab_te();
+ start_of_table->remember_table(table);
+ table = new html_table(&html, -1);
+ page_contents->insert_tag(string("*** COL -> TAB ***"));
+ start_of_table = NULL;
+ last = NULL;
+ }
+ if (tab_defs != NULL)
+ table->tab_stops->init(tab_defs);
+
+ type_of_col = tab0_tag;
+ ncol = 1;
+ colmin = 0;
+ colmax = table->get_tab_pos(2) + pageoffset + indentation;
+ } else if (! g->is_a_tag())
+ update_min_max(type_of_col, &colmin, &colmax, g);
+
+ if ((! g->is_a_tag()) || g->is_tab())
+ seen_text = TRUE;
+
+ if ((g->is_col() || g->is_tab() || g->is_tab0())
+ && (start_of_line != NULL) && (start_of_table == NULL)) {
+ start_of_table = insert_tab_ts(start_of_line);
+ start_of_line = NULL;
+ seen_text = FALSE;
+ } else if (g->is_ce() && (start_of_table != NULL)) {
+ add_table_end("*** CE ***");
+ start_of_table->remember_table(table);
+ start_of_table = NULL;
+ last = NULL;
+ } else if (g->is_ta()) {
+ tab_defs = g->text_string;
+ if (!table->tab_stops->compatible(tab_defs)) {
+ if (start_of_table != NULL) {
+ add_table_end("*** TABS ***");
+ start_of_table->remember_table(table);
+ table = new html_table(&html, -1);
+ start_of_table = NULL;
+ type_of_col = none;
+ last = NULL;
+ }
+ table->tab_stops->init(tab_defs);
+ }
+ }
+
+ if (((! g->is_a_tag()) || g->is_tab()) && (start_of_table != NULL)) {
+ // we are in a table and have a glyph
+ if ((ncol == 0) || (! table->add_column(ncol, colmin, colmax, align))) {
+ if (ncol == 0)
+ add_table_end("*** NCOL == 0 ***");
+ else
+ add_table_end("*** CROSSED COLS ***");
+
+ start_of_table->remember_table(table);
+ table = new html_table(&html, -1);
+ start_of_table = NULL;
+ type_of_col = none;
+ last = NULL;
+ }
+ }
+
+ /*
+ * move onto next glob, check whether we are starting a new line
+ */
+ g = page_contents->glyphs.move_right_get_data();
+
+ if (g == NULL) {
+ if (found_col) {
+ page_contents->glyphs.start_from_head();
+ last = g;
+ found_col = FALSE;
+ }
+ } else if (g->is_br() || (nf && g->is_eol())) {
+ do {
+ g = page_contents->glyphs.move_right_get_data();
+ nf = calc_nf(g, nf);
+ } while ((g != NULL) && (g->is_br() || (nf && g->is_eol())));
+ start_of_line = g;
+ seen_text = FALSE;
+ ncol = 0;
+ left = next_horiz_pos(g, nf);
+ if (found_col)
+ last = g;
+ found_col = FALSE;
+ }
+ } while ((g != NULL) && (! page_contents->glyphs.is_equal_to_head()));
+
+#if defined(DEBUG_TABLES)
+ fprintf(stderr, "finished scanning for tables\n");
+#endif
+
+ page_contents->glyphs.start_from_head();
+ if (start_of_table != NULL) {
+ if (last != NULL)
+ while (last != page_contents->glyphs.get_data())
+ page_contents->glyphs.move_left();
+
+ insert_tab_te();
+ start_of_table->remember_table(table);
+ table = NULL;
+ page_contents->insert_tag(string("*** LAST ***"));
+ }
+ }
+ if (table != NULL)
+ delete table;
+
+ // and reset the registers
+ pageoffset = old_pageoffset;
+ indentation = 0;
+ prev_indent = 0;
+ end_tempindent = 0;
+}
+
void html_printer::flush_page (void)
{
supress_sub_sup = TRUE;
flush_sbuf();
- // page_contents->dump_page();
+ page_contents->dump_page();
+ lookahead_for_tables();
+ page_contents->dump_page();
+
flush_globs();
current_paragraph->done_para();
- current_paragraph->done_table();
// move onto a new page
delete page_contents;
+#if defined(DEBUG_TABLES)
+ fprintf(stderr, "\n\n*** flushed page ***\n\n");
+
+ html.simple_comment("new page called");
+#endif
page_contents = new page;
}
/*
* determine_space - works out whether we need to write a space.
- * If last glyth is ajoining then no space emitted.
+ * If last glyph is ajoining then no space emitted.
*/
void html_printer::determine_space (text_glob *g)
{
if (current_paragraph->is_in_pre()) {
- int space_width = sbuf_style.f->get_space_width(sbuf_style.point_size);
/*
* .nf has been specified
*/
@@ -1902,7 +2937,16 @@ void html_printer::end_font (const char *fontname)
current_paragraph->done_italic();
} else if (strcmp(fontname, "CR") == 0) {
current_paragraph->done_tt();
- current_paragraph->done_pre();
+ } else if (strcmp(fontname, "CI") == 0) {
+ current_paragraph->done_italic();
+ current_paragraph->done_tt();
+ } else if (strcmp(fontname, "CB") == 0) {
+ current_paragraph->done_bold();
+ current_paragraph->done_tt();
+ } else if (strcmp(fontname, "CBI") == 0) {
+ current_paragraph->done_bold();
+ current_paragraph->done_italic();
+ current_paragraph->done_tt();
}
}
@@ -1928,6 +2972,25 @@ void html_printer::start_font (const char *fontname)
current_paragraph->do_pre();
}
current_paragraph->do_tt();
+ } else if (strcmp(fontname, "CI") == 0) {
+ if ((! fill_on) && (is_courier_until_eol())) {
+ current_paragraph->do_pre();
+ }
+ current_paragraph->do_tt();
+ current_paragraph->do_italic();
+ } else if (strcmp(fontname, "CB") == 0) {
+ if ((! fill_on) && (is_courier_until_eol())) {
+ current_paragraph->do_pre();
+ }
+ current_paragraph->do_tt();
+ current_paragraph->do_bold();
+ } else if (strcmp(fontname, "CBI") == 0) {
+ if ((! fill_on) && (is_courier_until_eol())) {
+ current_paragraph->do_pre();
+ }
+ current_paragraph->do_tt();
+ current_paragraph->do_italic();
+ current_paragraph->do_bold();
}
}
@@ -1986,6 +3049,11 @@ void html_printer::do_font (text_glob *g)
output_style.point_size = g->text_style.point_size;
}
}
+ if (output_style.col != g->text_style.col) {
+ current_paragraph->done_color();
+ output_style.col = g->text_style.col;
+ current_paragraph->do_color(&output_style.col);
+ }
}
/*
@@ -2070,18 +3138,14 @@ void html_printer::do_sup_or_sub (text_glob *g)
}
/*
- * translate_to_html - translates a textual string into html text
+ * emit_html - write out the html text
*/
-void html_printer::translate_to_html (text_glob *g)
+void html_printer::emit_html (text_glob *g)
{
- char buf[MAX_STRING_LENGTH];
-
do_font(g);
determine_space(g);
- str_translate_to_html(g->text_style.f, buf, MAX_STRING_LENGTH,
- g->text_string, g->text_length, TRUE);
- current_paragraph->do_emittext(buf, strlen(buf));
+ current_paragraph->do_emittext(g->text_string, g->text_length);
output_vpos = g->minv;
output_hpos = g->maxh;
output_vpos_max = g->maxv;
@@ -2094,18 +3158,26 @@ void html_printer::translate_to_html (text_glob *g)
void html_printer::flush_sbuf()
{
- if (sbuf_len > 0) {
+ if (sbuf.length() > 0) {
int r=font::res; // resolution of the device
set_style(sbuf_style);
+ if (overstrike_detected && (! is_bold(sbuf_style.f))) {
+ font *bold_font = make_bold(sbuf_style.f);
+ if (bold_font != NULL)
+ sbuf_style.f = bold_font;
+ }
- page_contents->add(&sbuf_style, sbuf, sbuf_len,
+ page_contents->add(&sbuf_style, sbuf,
line_number,
sbuf_vpos-sbuf_style.point_size*r/72, sbuf_start_hpos,
sbuf_vpos , sbuf_end_hpos);
output_hpos = sbuf_end_hpos;
output_vpos = sbuf_vpos;
- sbuf_len = 0;
+ last_sbuf_length = 0;
+ sbuf_prev_hpos = sbuf_end_hpos;
+ overstrike_detected = FALSE;
+ sbuf.clear();
}
}
@@ -2119,6 +3191,7 @@ void html_printer::draw(int code, int *p, int np, const environment *env)
switch (code) {
case 'l':
+# if 0
if (np == 2) {
page_contents->add_line(&sbuf_style,
line_number,
@@ -2126,6 +3199,7 @@ void html_printer::draw(int code, int *p, int np, const environment *env)
} else {
error("2 arguments required for line");
}
+# endif
break;
case 't':
{
@@ -2143,125 +3217,30 @@ void html_printer::draw(int code, int *p, int np, const environment *env)
}
case 'P':
- // fall through
+ break;
case 'p':
- {
-#if 0
- if (np & 1) {
- error("even number of arguments required for polygon");
- break;
- }
- if (np == 0) {
- error("no arguments for polygon");
- break;
- }
- // firstly lets add our current position to polygon
- int oh=env->hpos;
- int ov=env->vpos;
- int i=0;
-
- while (i<np) {
- p[i+0] += oh;
- p[i+1] += ov;
- oh = p[i+0];
- ov = p[i+1];
- i += 2;
- }
- // now store polygon in page
- page_contents->add_polygon(code, np, p, env->hpos, env->vpos, env->size, fill);
-#endif
- }
break;
case 'E':
- // fall through
+ break;
case 'e':
-#if 0
- if (np != 2) {
- error("2 arguments required for ellipse");
- break;
- }
- page_contents->add_line(code,
- env->hpos, env->vpos-p[1]/2, env->hpos+p[0], env->vpos+p[1]/2,
- env->size, fill);
-#endif
break;
case 'C':
- // fill circle
-
+ break;
case 'c':
- {
-#if 0
- // troff adds an extra argument to C
- if (np != 1 && !(code == 'C' && np == 2)) {
- error("1 argument required for circle");
- break;
- }
- page_contents->add_line(code,
- env->hpos, env->vpos-p[0]/2, env->hpos+p[0], env->vpos+p[0]/2,
- env->size, fill);
-#endif
- }
break;
case 'a':
- {
-#if 0
- if (np == 4) {
- double c[2];
-
- if (adjust_arc_center(p, c)) {
- page_contents->add_arc('a', env->hpos, env->vpos, p, c, env->size, fill);
- } else {
- // a straignt line
- page_contents->add_line('l', env->hpos, env->vpos, p[0]+p[2], p[1]+p[3], env->size, fill);
- }
- } else {
- error("4 arguments required for arc");
- }
-#endif
- }
break;
case '~':
- {
-#if 0
- if (np & 1) {
- error("even number of arguments required for spline");
- break;
- }
- if (np == 0) {
- error("no arguments for spline");
- break;
- }
- // firstly lets add our current position to spline
- int oh=env->hpos;
- int ov=env->vpos;
- int i=0;
-
- while (i<np) {
- p[i+0] += oh;
- p[i+1] += ov;
- oh = p[i+0];
- ov = p[i+1];
- i += 2;
- }
- page_contents->add_spline('~', env->hpos, env->vpos, np, p, env->size, fill);
-#endif
- }
break;
case 'f':
- {
-#if 0
- if (np != 1 && np != 2) {
- error("1 argument required for fill");
- break;
- }
- fill = p[0];
- if (fill < 0 || fill > FILL_MAX) {
- // This means fill with the current color.
- fill = FILL_MAX + 1;
- }
-#endif
- break;
- }
+ break;
+ case 'F':
+ // fill with color env->fill
+ if (background != NULL)
+ delete background;
+ background = new color;
+ *background = *env->fill;
+ break;
default:
error("unrecognised drawing command `%1'", char(code));
@@ -2272,7 +3251,8 @@ void html_printer::draw(int code, int *p, int np, const environment *env)
html_printer::html_printer()
: html(0, MAX_LINE_LENGTH),
no_of_printed_pages(0),
- sbuf_len(0),
+ last_sbuf_length(0),
+ overstrike_detected(FALSE),
output_hpos(-1),
output_vpos(-1),
output_vpos_max(-1),
@@ -2282,21 +3262,22 @@ html_printer::html_printer()
header_indent(-1),
supress_sub_sup(TRUE),
cutoff_heading(100),
+ indent(NULL),
+ table(NULL),
end_center(0),
end_tempindent(0),
next_tag(INLINE),
fill_on(TRUE),
+ max_linelength(-1),
linelength(0),
pageoffset(0),
indentation(0),
prev_indent(0),
- line_number(0)
+ pointsize(0),
+ line_number(0),
+ background(default_background)
{
-#if defined(DEBUGGING)
- file_list.add_new_file(stdout);
-#else
file_list.add_new_file(xtmpfile());
-#endif
html.set_file(file_list.get_file());
if (font::hor != 24)
fatal("horizontal resolution must be 24");
@@ -2316,6 +3297,7 @@ html_printer::html_printer()
res = r;
html.set_fixed_point(point);
space_char_index = font::name_to_index("space");
+ space_width = font::hor;
paper_length = font::paperlength;
linelength = font::res*13/2;
if (paper_length == 0)
@@ -2325,174 +3307,65 @@ html_printer::html_printer()
}
/*
- * add_char_to_sbuf - adds a single character to the sbuf.
- */
-
-void html_printer::add_char_to_sbuf (unsigned char code)
-{
- if (sbuf_len < SBUF_SIZE) {
- sbuf[sbuf_len] = code;
- sbuf_len++;
- } else {
- fatal("need to increase SBUF_SIZE");
- }
-}
-
-/*
* add_to_sbuf - adds character code or name to the sbuf.
*/
-void html_printer::add_to_sbuf (unsigned char code, const char *name)
+void html_printer::add_to_sbuf (int index, const string &s)
{
- if (name == 0) {
- add_char_to_sbuf(code);
- } else {
- if (sbuf_style.f != NULL) {
- char *html_glyph = get_html_translation(sbuf_style.f, name);
+ if (sbuf_style.f == NULL)
+ return;
- if (html_glyph == NULL) {
- add_char_to_sbuf(code);
- } else {
- int l = strlen(html_glyph);
- int i;
+ char *html_glyph = NULL;
+ unsigned int code = sbuf_style.f->get_code(index);
- // Escape the name, so that "&" doesn't get expanded to "&amp;"
- // later during translate_to_html.
- add_char_to_sbuf('\\'); add_char_to_sbuf('(');
+ if (s.empty()) {
+ if (sbuf_style.f->contains(index))
+ html_glyph = (char *)sbuf_style.f->get_special_device_encoding(index);
+ else
+ html_glyph = NULL;
+
+ if ((html_glyph == NULL) && (code >= UNICODE_DESC_START))
+ html_glyph = to_unicode(code);
+ } else
+ html_glyph = get_html_translation(sbuf_style.f, s);
- for (i=0; i<l; i++) {
- add_char_to_sbuf(html_glyph[i]);
- }
- add_char_to_sbuf('\\'); add_char_to_sbuf(')');
- }
- }
- }
+ last_sbuf_length = sbuf.length();
+ if (html_glyph == NULL)
+ sbuf += ((char)code);
+ else
+ sbuf += html_glyph;
}
-int html_printer::sbuf_continuation (unsigned char code, const char *name,
+int html_printer::sbuf_continuation (int index, const char *name,
const environment *env, int w)
{
- if (sbuf_end_hpos == env->hpos) {
- add_to_sbuf(code, name);
+ /*
+ * lets see whether the glyph is closer to the end of sbuf
+ */
+ if ((sbuf_end_hpos == env->hpos)
+ || ((sbuf_prev_hpos < sbuf_end_hpos)
+ && (env->hpos < sbuf_end_hpos)
+ && ((sbuf_end_hpos-env->hpos < env->hpos-sbuf_prev_hpos)))) {
+ add_to_sbuf(index, name);
+ sbuf_prev_hpos = sbuf_end_hpos;
sbuf_end_hpos += w + sbuf_kern;
- return( TRUE );
+ return TRUE;
} else {
- if ((sbuf_len < SBUF_SIZE-1) && (env->hpos >= sbuf_end_hpos) &&
+ if ((env->hpos >= sbuf_end_hpos) &&
((sbuf_kern == 0) || (sbuf_end_hpos - sbuf_kern != env->hpos))) {
/*
* lets see whether a space is needed or not
*/
- int space_width = sbuf_style.f->get_space_width(sbuf_style.point_size);
- if (env->hpos-sbuf_end_hpos < space_width/2) {
- add_to_sbuf(code, name);
+ if (env->hpos-sbuf_end_hpos < space_width) {
+ add_to_sbuf(index, name);
+ sbuf_prev_hpos = sbuf_end_hpos;
sbuf_end_hpos = env->hpos + w;
- return( TRUE );
+ return TRUE;
}
}
}
- return( FALSE );
-}
-
-/*
- * seen_backwards_escape - returns TRUE if we can see a escape at position i..l in s
- */
-
-int html_printer::seen_backwards_escape (char *s, int l)
-{
- /*
- * this is tricky so it is broken into components for clarity
- * (we let the compiler put in all back into a complex expression)
- */
- if ((l>0) && (sbuf[l] == '(') && (sbuf[l-1] == '\\')) {
- /*
- * ok seen '\(' but we must now check for '\\('
- */
- if ((l>1) && (sbuf[l-2] == '\\')) {
- /*
- * escaped the escape
- */
- return( FALSE );
- } else {
- return( TRUE );
- }
- } else {
- return( FALSE );
- }
-}
-
-/*
- * reverse - return reversed string.
- */
-
-char *reverse (char *s)
-{
- int i=0;
- int j=strlen(s)-1;
- char t;
-
- while (i<j) {
- t = s[i];
- s[i] = s[j];
- s[j] = t;
- i++;
- j--;
- }
- return( s );
-}
-
-/*
- * remove_last_char_from_sbuf - removes the last character from sbuf.
- */
-
-char *html_printer::remove_last_char_from_sbuf ()
-{
- int l=sbuf_len;
- static char last[MAX_STRING_LENGTH];
-
- if (l>0) {
- l--;
- if ((sbuf[l] == ')') && (l>0) && (sbuf[l-1] == '\\')) {
- /*
- * found terminating escape
- */
- int i=0;
-
- l -= 2;
- while ((l>0) && (! seen_backwards_escape(sbuf, l))) {
- if (sbuf[l] == '\\') {
- if (sbuf[l-1] == '\\') {
- last[i] = sbuf[l];
- i++;
- l--;
- }
- } else {
- last[i] = sbuf[l];
- i++;
- }
- l--;
- }
- last[i] = (char)0;
- sbuf_len = l;
- if (seen_backwards_escape(sbuf, l)) {
- sbuf_len--;
- }
- return( reverse(last) );
- } else {
- if ((sbuf[l] == '\\') && (l>0) && (sbuf[l-1] == '\\')) {
- l -= 2;
- sbuf_len = l;
- return( "\\" );
- } else {
- sbuf_len--;
- last[0] = sbuf[sbuf_len];
- last[1] = (char)0;
- return( last );
- }
- }
- } else {
- return( NULL );
- }
+ return FALSE ;
}
/*
@@ -2500,149 +3373,57 @@ char *html_printer::remove_last_char_from_sbuf ()
* return the device encoding for such character.
*/
-char *get_html_translation (font *f, const char *name)
+char *get_html_translation (font *f, const string &name)
{
- int index;
+ int index;
- if ((f == 0) || (name == 0) || (strcmp(name, "") == 0)) {
- return( NULL );
- } else {
- index = f->name_to_index((char *)name);
+ if ((f == 0) || name.empty())
+ return NULL;
+ else {
+ index = f->name_to_index((char *)(name + '\0').contents());
if (index == 0) {
- error("character `%s' not found", name);
- return( NULL );
- } else {
- if (f->contains(index)) {
- return( (char *)f->get_special_device_encoding(index) );
- } else {
- return( NULL );
- }
- }
+ error("character `%s' not found", (name + '\0').contents());
+ return NULL;
+ } else
+ if (f->contains(index))
+ return (char *)f->get_special_device_encoding(index);
+ else
+ return NULL;
}
}
/*
- * to_unicode - returns a unicode translation of char, ch.
- */
-
-static char *to_unicode (unsigned char ch)
-{
- static char buf[20];
-
- sprintf(buf, "&#%u;", (unsigned int)ch);
- return( buf );
-}
-
-/*
- * char_translate_to_html - convert a single non escaped character
- * into the appropriate html character.
+ * overstrike - returns TRUE if the glyph (i, name) is going to overstrike
+ * a previous glyph in sbuf.
+ * If TRUE the font is changed to bold and the previous sbuf
+ * is flushed.
*/
-int char_translate_to_html (font *f, char *buf, int buflen, unsigned char ch, int b, int and_single)
+int html_printer::overstrike(int index, const char *name, const environment *env, int w)
{
- if (and_single) {
- int t, l;
- char *translation;
- char name[2];
-
- name[0] = ch;
- name[1] = (char)0;
- translation = get_html_translation(f, name);
- if ((translation == NULL) && (ch >= UNICODE_DESC_START)) {
- translation = to_unicode(ch);
- }
- if (translation) {
- l = strlen(translation);
- t = max(0, min(l, buflen-b));
- strncpy(&buf[b], translation, t);
- b += t;
- } else {
- if (b<buflen) {
- buf[b] = ch;
- b++;
- }
- }
- } else {
+ if ((env->hpos < sbuf_end_hpos)
+ || ((sbuf_kern != 0) && (sbuf_end_hpos - sbuf_kern < env->hpos))) {
/*
- * do not attempt to encode single characters
+ * at this point we have detected an overlap
*/
- if (b<buflen) {
- buf[b] = ch;
- b++;
- }
- }
- return( b );
-}
-
-/*
- * str_translate_to_html - converts a string, str, into html text. It places
- * the output input buffer, buf. It truncates string, str, if
- * there is not enough space in buf.
- * It looks up the html character encoding of single characters
- * if, and_single, is TRUE. Characters such as < > & etc.
- */
-
-void str_translate_to_html (font *f, char *buf, int buflen, char *str, int len, int and_single)
-{
- char *translation;
- int e;
- char escaped_char[MAX_STRING_LENGTH];
- int l;
- int i=0;
- int b=0;
- int t=0;
-
-#if 0
- if (strcmp(str, "``@,;:\\\\()[]''") == 0) {
- stop();
- }
-#endif
- while (str[i] != (char)0) {
- if ((str[i]=='\\') && (i+1<len)) {
- i++; // skip the leading backslash
- if (str[i] == '(') {
- // start of escape
- i++;
- e = 0;
- while ((str[i] != (char)0) &&
- (! ((str[i] == '\\') && (i+1<len) && (str[i+1] == ')')))) {
- if (str[i] == '\\') {
- i++;
- }
- escaped_char[e] = str[i];
- e++;
- i++;
- }
- if ((str[i] == '\\') && (i+1<len) && (str[i+1] == ')')) {
- i += 2;
- }
- escaped_char[e] = (char)0;
- if (e > 0) {
- translation = get_html_translation(f, escaped_char);
- if (translation) {
- l = strlen(translation);
- t = max(0, min(l, buflen-b));
- strncpy(&buf[b], translation, t);
- b += t;
- } else {
- int index=f->name_to_index(escaped_char);
-
- if (f->contains(index) && (index != 0)) {
- buf[b] = f->get_code(index);
- b++;
- }
- }
- }
- } else {
- b = char_translate_to_html(f, buf, buflen, str[i], b, and_single);
- i++;
- }
+ if (overstrike_detected) {
+ /* already detected, remove previous glyph and use this glyph */
+ sbuf.set_length(last_sbuf_length);
+ add_to_sbuf(index, name);
+ sbuf_end_hpos = env->hpos + w;
+ return TRUE;
} else {
- b = char_translate_to_html(f, buf, buflen, str[i], b, and_single);
- i++;
+ /* first time we have detected an overstrike in the sbuf */
+ sbuf.set_length(last_sbuf_length); /* remove previous glyph */
+ if (! is_bold(sbuf_style.f))
+ flush_sbuf();
+ overstrike_detected = TRUE;
+ add_to_sbuf(index, name);
+ sbuf_end_hpos = env->hpos + w;
+ return TRUE;
}
}
- buf[min(b, buflen)] = (char)0;
+ return FALSE ;
}
/*
@@ -2652,33 +3433,25 @@ void str_translate_to_html (font *f, char *buf, int buflen, char *str, int len,
void html_printer::set_char(int i, font *f, const environment *env, int w, const char *name)
{
- unsigned char code = f->get_code(i);
-
-#if 0
- if (code == ' ') {
- stop();
- }
-#endif
- style sty(f, env->size, env->height, env->slant, env->fontno);
+ style sty(f, env->size, env->height, env->slant, env->fontno, *env->col);
if (sty.slant != 0) {
if (sty.slant > 80 || sty.slant < -80) {
error("silly slant `%1' degrees", sty.slant);
sty.slant = 0;
}
}
- if ((sbuf_len > 0) && (sbuf_len < SBUF_SIZE) && (sty == sbuf_style) &&
- (sbuf_vpos == env->vpos) && (sbuf_continuation(code, name, env, w))) {
+ if (((! sbuf.empty()) && (sty == sbuf_style) && (sbuf_vpos == env->vpos))
+ && (sbuf_continuation(i, name, env, w) || overstrike(i, name, env, w)))
return;
- } else {
- flush_sbuf();
- sbuf_len = 0;
- add_to_sbuf(code, name);
- sbuf_end_hpos = env->hpos + w;
- sbuf_start_hpos = env->hpos;
- sbuf_vpos = env->vpos;
- sbuf_style = sty;
- sbuf_kern = 0;
- }
+
+ flush_sbuf();
+ add_to_sbuf(i, name);
+ sbuf_end_hpos = env->hpos + w;
+ sbuf_start_hpos = env->hpos;
+ sbuf_prev_hpos = env->hpos;
+ sbuf_vpos = env->vpos;
+ sbuf_style = sty;
+ sbuf_kern = 0;
}
/*
@@ -2694,9 +3467,11 @@ void html_printer::write_title (int in_head)
html.put_string("</title>").nl().nl();
} else {
title.has_been_written = TRUE;
- html.put_string("<h1 align=center>");
- html.put_string(title.text);
- html.put_string("</h1>").nl().nl();
+ if (title.with_h1) {
+ html.put_string("<h1 align=center>");
+ html.put_string(title.text);
+ html.put_string("</h1>").nl().nl();
+ }
}
} else if (in_head) {
// place empty title tags to help conform to `tidy'
@@ -2731,9 +3506,7 @@ void html_printer::begin_page(int n)
output_vpos = -1;
output_vpos_max = -1;
current_paragraph = new html_text(&html);
-#if defined(INDENTATION)
- current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength);
-#endif
+ do_indent(indentation, pageoffset, linelength);
current_paragraph->do_para("");
}
@@ -2748,47 +3521,62 @@ font *html_printer::make_font(const char *nm)
return html_font::load_html_font(nm);
}
+void html_printer::do_body (void)
+{
+ if (background == NULL)
+ fputs("<body>\n\n", stdout);
+ else {
+ unsigned int r, g, b;
+ char buf[6+1];
+
+ background->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);
+
+ fputs("<body bgcolor=\"#", stdout);
+ fputs(buf, stdout);
+ fputs("\">\n\n", stdout);
+ }
+}
+
html_printer::~html_printer()
{
+#ifdef LONG_FOR_TIME_T
+ long t;
+#else
+ time_t t;
+#endif
+
current_paragraph->flush_text();
html.end_line();
html.set_file(stdout);
+ html.begin_comment("Creator : ")
+ .put_string("groff ")
+ .put_string("version ")
+ .put_string(Version_string)
+ .end_comment();
+
+ t = time(0);
+ html.begin_comment("CreationDate: ")
+ .put_string(ctime(&t), strlen(ctime(&t))-1)
+ .end_comment();
+
/*
* 'HTML: The definitive guide', O'Reilly, p47. advises against specifying
- * the dtd, so for the moment I'll leave this commented out.
- * If requested we could always emit it if a command line switch
- * was present.
- *
- * fputs("<!doctype html public \"-//IETF//DTD HTML 4.0//EN\">\n", stdout);
+ * the dtd.
*/
+ // fputs("<!doctype html public \"-//IETF//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n", stdout);
fputs("<html>\n", stdout);
fputs("<head>\n", stdout);
fputs("<meta name=\"generator\" content=\"groff -Thtml, see www.gnu.org\">\n", stdout);
fputs("<meta name=\"Content-Style\" content=\"text/css\">\n", stdout);
write_title(TRUE);
fputs("</head>\n", stdout);
- fputs("<body>\n\n", stdout);
+ do_body();
+
write_title(FALSE);
header.write_headings(stdout, FALSE);
write_rule();
- {
- html.begin_comment("Creator : ")
- .put_string("groff ")
- .put_string("version ")
- .put_string(Version_string)
- .end_comment();
- }
- {
-#ifdef LONG_FOR_TIME_T
- long
-#else
- time_t
-#endif
- t = time(0);
- html.begin_comment("CreationDate: ")
- .put_string(ctime(&t), strlen(ctime(&t))-1)
- .end_comment();
- }
#if defined(DEBUGGING)
html.begin_comment("Total number of pages: ").put_string(i_to_a(no_of_printed_pages)).end_comment();
#endif
@@ -2825,13 +3613,13 @@ void html_printer::special(char *s, const environment *env, char type)
if (s != 0) {
flush_sbuf();
if (env->fontno >= 0) {
- style sty(get_font_from_index(env->fontno), env->size, env->height, env->slant, env->fontno);
+ style sty(get_font_from_index(env->fontno), env->size, env->height,
+ env->slant, env->fontno, *env->col);
sbuf_style = sty;
}
if (strncmp(s, "html:", 5) == 0) {
int r=font::res; /* resolution of the device */
- char buf[MAX_STRING_LENGTH];
font *f=sbuf_style.f;
if (f == NULL) {
@@ -2839,28 +3627,26 @@ void html_printer::special(char *s, const environment *env, char type)
f = font::load_font("TR", &found);
}
- str_translate_to_html(f, buf, MAX_STRING_LENGTH,
- &s[5], strlen(s)-5, FALSE);
/*
* need to pass rest of string through to html output during flush
*/
- page_contents->add_html(&sbuf_style, buf, strlen(buf),
- line_number,
- env->vpos-env->size*r/72, env->hpos,
- env->vpos , env->hpos);
+ page_contents->add_and_encode(&sbuf_style, string(&s[5]),
+ line_number,
+ env->vpos-env->size*r/72, env->hpos,
+ env->vpos , env->hpos);
/*
* assume that the html command has no width, if it does then hopefully troff
* will have fudged this in a macro by requesting that the formatting move right by
- * the appropriate width.
+ * the appropriate amount.
*/
} else if (strncmp(s, "index:", 6) == 0) {
cutoff_heading = atoi(&s[6]);
} else if (strncmp(s, "html-tag:", 9) == 0) {
int r=font::res; /* resolution of the device */
- page_contents->add_tag(&sbuf_style, s, strlen(s),
+ page_contents->add_tag(&sbuf_style, string(s),
line_number,
env->vpos-env->size*r/72, env->hpos,
env->vpos , env->hpos);
@@ -2879,15 +3665,24 @@ int main(int argc, char **argv)
{ "version", no_argument, 0, 'v' },
{ NULL, 0, 0, 0 }
};
- while ((c = getopt_long(argc, argv, "o:i:I:D:F:vd?lrn", long_options, NULL))
+ while ((c = getopt_long(argc, argv, "a:g:o:i:I:D:F:vbdhlrnp", long_options, NULL))
!= EOF)
switch(c) {
case 'v':
- {
- printf("GNU post-grohtml (groff) version %s\n", Version_string);
- exit(0);
- break;
- }
+ printf("GNU post-grohtml (groff) version %s\n", Version_string);
+ exit(0);
+ break;
+ case 'a':
+ /* text antialiasing bits - handled by pre-html */
+ break;
+ case 'g':
+ /* graphic antialiasing bits - handled by pre-html */
+ break;
+ case 'b':
+ // set background color to white
+ default_background = new color;
+ default_background->set_gray(color::MAX_COLOR_VAL);
+ break;
case 'F':
font::command_line_font_dir(optarg);
break;
@@ -2897,9 +3692,19 @@ int main(int argc, char **argv)
case 'r':
auto_rule = FALSE;
break;
+ case 'd':
+ /* handled by pre-html */
+ break;
+ case 'h':
+ /* do not use the Hn headings of html, but manufacture our own */
+ manufacture_headings = TRUE;
+ break;
case 'o':
/* handled by pre-html */
break;
+ case 'p':
+ /* handled by pre-html */
+ break;
case 'i':
/* handled by pre-html */
break;
@@ -2935,6 +3740,6 @@ int main(int argc, char **argv)
static void usage(FILE *stream)
{
- fprintf(stream, "usage: %s [-vld?n] [-D dir] [-I image_stem] [-F dir] [files ...]\n",
+ fprintf(stream, "usage: %s [-vblnh] [-D dir] [-I image_stem] [-F dir] [files ...]\n",
program_name);
}
diff --git a/contrib/groff/src/devices/grolbp/Makefile.sub b/contrib/groff/src/devices/grolbp/Makefile.sub
index d60008b..d8000d1 100644
--- a/contrib/groff/src/devices/grolbp/Makefile.sub
+++ b/contrib/groff/src/devices/grolbp/Makefile.sub
@@ -1,6 +1,6 @@
-PROG=grolbp
+PROG=grolbp$(EXEEXT)
MAN1=grolbp.n
XLIBS=$(LIBDRIVER) $(LIBGROFF)
MLIB=$(LIBM)
-OBJS=lbp.o
+OBJS=lbp.$(OBJEXT)
CCSRCS=$(srcdir)/lbp.cc
diff --git a/contrib/groff/src/devices/grolbp/grolbp.man b/contrib/groff/src/devices/grolbp/grolbp.man
index d567c1a..6685c4f 100644
--- a/contrib/groff/src/devices/grolbp/grolbp.man
+++ b/contrib/groff/src/devices/grolbp/grolbp.man
@@ -3,7 +3,7 @@
.\" vim: set syntax=nroff :
.\" The above line should set vim into nroff mode
.ig
-Copyright (C) 1994-2000 Free Software Foundation, Inc.
+Copyright (C) 1994-2000, 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
@@ -35,11 +35,14 @@ program.
.el .TP "\\$1"
..
.TH GROLBP @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.
.SH NAME
grolbp \- groff driver for Canon CAPSL printers (LBP-4 and LBP-8 series laser printers).
+.
.SH SYNOPSIS
.nr a \n(.j
.ad l
+.nh
.nr i \n(.i
.in +\w'\fBgrolbp 'u
.ti \niu
@@ -58,6 +61,8 @@ grolbp \- groff driver for Canon CAPSL printers (LBP-4 and LBP-8 series laser pr
.OP \-\-papersize= paper_size
.OP \-o orientation
.OP \-\-orientation= orientation
+.OP \-w width
+.OP \-\-linewidth= width
.OP \-F dir
.OP \-\-fontdir= dir
.OP \-h
@@ -65,6 +70,8 @@ grolbp \- groff driver for Canon CAPSL printers (LBP-4 and LBP-8 series laser pr
.RI "[\ " files\|.\|.\|. "\ ]"
.br
.ad \na
+.hy
+.
.SH DESCRIPTION
.B grolbp
is a driver for
@@ -111,6 +118,14 @@ Print the document with
.I orientation
orientation, which must be `portrait' or `landscape'.
.TP
+.BI \-w width
+.TQ
+.BI \-\-linewidth= width
+Set the default line thickness to
+.I width
+thousandths of an em.
+If this option isn't specified, the line thickness defaults to 0.04\~em.
+.TP
.B \-v
.TQ
.B \-\-version
@@ -120,8 +135,11 @@ Print the version number.
.TQ
.BI \-\-fontdir= dir
Prepend directory
-.IB dir /devlbp
-to the search path for font and device description files.
+.IB dir /dev name
+to the search path for font and device description files;
+.I name
+is the name of the device, usually
+.BR lbp .
.TP
.B \-h
.TQ
@@ -160,74 +178,35 @@ precedence over the contents of the
.B DESC
file (this applies to the page orientation too).
.PP
-To set the paper size in the
-.B DESC
-file, insert in that file a line containing
-.B papersize
-.IR desired_papersize ,
-where
-.I desired_papersize
-is:
-.IP \(bu 4
-One of the recognized paper sizes: `a4', `letter', `legal' or `executive'.
-.IP \(bu 4
-A custom defined paper size, as described in the
-.B CUSTOM PAPER SIZES
-subsection below.
-.IP \(bu 4
-The name of a file (e.g.
-.IR /etc/papersize )
-whose first line must be the desired paper size in one of the above formats.
-.PP
-If there are various papersize lines in the
+See
+.BR groff_font (@MAN1EXT@)
+how to set the paper dimensions in the
.B DESC
-file, only the first valid one is used.
+file.
.PP
To set the paper size in the command line, add
.sp 1
.in +2m
-.BI \-p \ desired_papersize
+.BI \-p \ paper-size
.in -2m
.sp 1
or
.sp 1
.in +2m
-.BI \-\-papersize= desired_papersize
+.BI \-\-papersize= paper-size
.in -2m
.sp 1
to the other
.B grolbp
options, where
-.B desired_papersize
+.I paper-size
is in the same format as in the
.B DESC
file.
.PP
-Paper sizes are case insensitive (i.e., `A4' is the same as `a4').
-.PP
If no paper size is specified in the
.B DESC
file or the command line, a default size of A4 is used.
-.TP
-.SH CUSTOM PAPER SIZES
-Custom defined paper sizes are in the form
-.BI cust length x width
-where
-.I length
-and
-.I width
-are the dimensions of the paper you want to to use, specified in printer
-units (1/300 of an inch).
-For instance, to print in a postcard sized paper which is two inches long
-and four inches wide you can insert a line containing
-.sp 1
-.in +2m
-.B papersize cust600x1200
-.in -2m
-.sp 1
-at the beginning of the
-.B DESC
-file.
.SH PAGE ORIENTATION
As with the page size, the orientation of the printed page
.RB ( portrait
@@ -247,7 +226,7 @@ file, insert a line with the following content:
.RB [ portrait | landscape ]
.in -2m
.sp 1
-As with paper sizes, only the first valid orientation command in the
+Only the first valid orientation command in the
.B DESC
file is used.
.PP
diff --git a/contrib/groff/src/devices/grolbp/lbp.cc b/contrib/groff/src/devices/grolbp/lbp.cc
index ec8c7b1..76db32a 100644
--- a/contrib/groff/src/devices/grolbp/lbp.cc
+++ b/contrib/groff/src/devices/grolbp/lbp.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1994, 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1994, 2000, 2001, 2002 Free Software Foundation, Inc.
Written by Francisco Andrés Verdú <pandres@dragonet.es> with many ideas
taken from the other groff drivers.
@@ -30,16 +30,22 @@ TODO
#include "driver.h"
#include "lbp.h"
#include "charset.h"
+#include "paper.h"
#include "nonposix.h"
extern "C" const char *Version_string;
-static short int papersize = -1, // papersize
- orientation = -1 , // orientation
- paperlength = 0, // Custom Paper size
- paperwidth = 0,
- ncopies = 1; // Number of copies
+static int user_papersize = -1; // papersize
+static int orientation = -1; // orientation
+static double user_paperlength = 0; // Custom Paper size
+static double user_paperwidth = 0;
+static int ncopies = 1; // Number of copies
+
+#define DEFAULT_LINEWIDTH_FACTOR 40 // 0.04em
+static int linewidth_factor = DEFAULT_LINEWIDTH_FACTOR;
+
+static int set_papersize(const char *paperformat);
class lbp_font : public font {
public:
@@ -55,7 +61,7 @@ private:
class lbp_printer : public printer {
public:
- lbp_printer();
+ lbp_printer(int, double, double);
~lbp_printer();
void set_char(int, font *, const environment *, int, const char *name);
void draw(int code, int *p, int np, const environment *env);
@@ -64,7 +70,7 @@ public:
font *make_font(const char *);
void end_of_line();
private:
- void set_line_thickness(int size, int dot = 0);
+ void set_line_thickness(int size,const environment *env);
void vdmstart();
void vdmflush(); // the name vdmend was already used in lbp.h
void setfillmode(int mode);
@@ -79,38 +85,27 @@ private:
int cur_size;
unsigned short cur_symbol_set;
int line_thickness;
+ int req_linethickness; // requested line thickness
+ int papersize;
+ int paperlength; // custom paper size
+ int paperwidth;
};
// Compatibility section.
//
-// Here we define some functions not present in some of the targets
+// Here we define some functions not present in some of the targets
// platforms
#ifndef HAVE_STRSEP
// Solaris 8 doesn't have the strsep function
static char *strsep(char **pcadena, const char *delim)
{
char *p;
-
- p = strtok(*pcadena,delim);
- *pcadena = strtok(NULL,delim);
- return p;
-
-};
+ p = strtok(*pcadena, delim);
+ *pcadena = strtok(NULL, delim);
+ return p;
+}
#endif
-#ifndef HAVE_STRDUP
-// Ditto with OS/390 and strdup
-static char *strdup(const char *s)
-{
- char *result;
-
- result = (char *)malloc(strlen(s)+1);
- if (result != NULL) strcpy(result,s);
- return result;
-
-}; // strdup
-
-#endif
lbp_font::lbp_font(const char *nm)
: font(nm)
{
@@ -124,12 +119,12 @@ lbp_font *lbp_font::load_lbp_font(const char *s)
{
lbp_font *f = new lbp_font(s);
f->lbpname = NULL;
- f->is_scalable = 1; // Default is that fonts are scalable
+ f->is_scalable = 1; // Default is that fonts are scalable
if (!f->load()) {
- delete f;
- return 0;
- }
- return f;
+ delete f;
+ return 0;
+ }
+ return f;
}
@@ -138,64 +133,75 @@ void lbp_font::handle_unknown_font_command(const char *command,
const char *filename, int lineno)
{
if (strcmp(command, "lbpname") == 0) {
- if (arg == 0)
- fatal_with_file_and_line(filename, lineno,
- "`%1' command requires an argument",
- command);
- this->lbpname = new char[strlen(arg)+1];
- strcpy(this->lbpname,arg);
- // We Recongnize bitmaped fonts by the first character of it's name
- if (arg[0] == 'N') this->is_scalable = 0;
- // fprintf(stderr,"Loading font \"%s\" \n",arg);
- }; // if (strcmp(command, "lbpname")
- // fprintf(stderr,"Loading font %s \"%s\" in %s at %d\n",command,arg,filename,lineno);
-};
+ if (arg == 0)
+ fatal_with_file_and_line(filename, lineno,
+ "`%1' command requires an argument",
+ command);
+ this->lbpname = new char[strlen(arg) + 1];
+ strcpy(this->lbpname, arg);
+ // we recognize bitmapped fonts by the first character of its name
+ if (arg[0] == 'N')
+ this->is_scalable = 0;
+ // fprintf(stderr, "Loading font \"%s\" \n", arg);
+ }
+ // fprintf(stderr, "Loading font %s \"%s\" in %s at %d\n",
+ // command, arg, filename, lineno);
+}
static void wp54charset()
{
unsigned int i;
-
lbpputs("\033[714;100;29;0;32;120.}");
- for (i = 0; i < sizeof(symset) ; i++) lbpputc(symset[i]);
+ for (i = 0; i < sizeof(symset); i++)
+ lbpputc(symset[i]);
lbpputs("\033[100;0 D");
- return ;
-};
+ return;
+}
-lbp_printer::lbp_printer()
+lbp_printer::lbp_printer(int ps, double pw, double pl)
: fill_pattern(1),
fill_mode(0),
cur_hpos(-1),
cur_font(0),
cur_size(0),
cur_symbol_set(0),
- line_thickness(-1)
+ req_linethickness(-1)
{
#ifdef SET_BINARY
- SET_BINARY(fileno(stdout));
+ SET_BINARY(fileno(stdout));
#endif
- lbpinit(stdout);
- lbpputs("\033c\033;\033[2&z\033[7 I\033[?32h\033[?33h\033[11h");
- wp54charset(); // Define the new symbol set
- lbpputs("\033[7 I\033[?32h\033[?33h\033[11h");
- // Paper size handling
- if (orientation < 0) orientation = 0;// Default orientation is portrait
- if (papersize < 0) papersize = 14; // Default paper size is A4
- if (papersize < 80) // standard paper
- lbpprintf("\033[%dp",(papersize | orientation));
- else // Custom paper
- lbpprintf("\033[%d;%d;%dp",(papersize | orientation),\
- paperlength,paperwidth);
-
- // Number of copies
- lbpprintf("\033[%dv\n",ncopies);
-
- lbpputs("\033[0u\033[1u\033P1y Grolbp\033\\");
- lbpmoveabs(0,0);
- lbpputs("\033[0t\033[2t");
- lbpputs("\033('$2\033)' 1"); // Primary symbol set IBML
- // Secondary symbol set IBMR1
- cur_symbol_set = 0;
-};
+ lbpinit(stdout);
+ lbpputs("\033c\033;\033[2&z\033[7 I\033[?32h\033[?33h\033[11h");
+ wp54charset(); // Define the new symbol set
+ lbpputs("\033[7 I\033[?32h\033[?33h\033[11h");
+ // Paper size handling
+ if (orientation < 0)
+ orientation = 0; // Default orientation is portrait
+ papersize = 14; // Default paper size is A4
+ if (font::papersize) {
+ papersize = set_papersize(font::papersize);
+ paperlength = font::paperlength;
+ paperwidth = font::paperwidth;
+ }
+ if (ps >= 0) {
+ papersize = ps;
+ paperlength = int(pl * font::res + 0.5);
+ paperwidth = int(pw * font::res + 0.5);
+ }
+ if (papersize < 80) // standard paper
+ lbpprintf("\033[%dp", (papersize | orientation));
+ else // Custom paper
+ lbpprintf("\033[%d;%d;%dp", (papersize | orientation),
+ paperlength, paperwidth);
+ // Number of copies
+ lbpprintf("\033[%dv\n", ncopies);
+ lbpputs("\033[0u\033[1u\033P1y Grolbp\033\\");
+ lbpmoveabs(0, 0);
+ lbpputs("\033[0t\033[2t");
+ lbpputs("\033('$2\033)' 1"); // Primary symbol set IBML
+ // Secondary symbol set IBMR1
+ cur_symbol_set = 0;
+}
lbp_printer::~lbp_printer()
{
@@ -209,460 +215,415 @@ void lbp_printer::begin_page(int)
void lbp_printer::end_page(int)
{
- if (vdminited()) vdmflush();
+ if (vdminited())
+ vdmflush();
lbpputc('\f');
cur_hpos = -1;
}
void lbp_printer::end_of_line()
{
- cur_hpos = -1; // force absolute motion
+ cur_hpos = -1; // force absolute motion
}
char *lbp_printer::font_name(const lbp_font *f, const int siz)
{
- static char bfont_name[255] ; // The resulting font name
- char type, // Italic, Roman, Bold
- ori, // Normal or Rotated
- *nam; // The font name without other data.
-// nam[strlen(f->lbpname)-2]; // The font name without other data.
- int cpi; // The font size in characters per inch
- // (Bitmaped fonts are monospaced).
-
-
- /* Bitmap font selection is ugly in this printer, so don't expect
- this function to be elegant. */
-
+ static char bfont_name[255]; // The resulting font name
+ char type, // Italic, Roman, Bold
+ ori, // Normal or Rotated
+ *nam; // The font name without other data.
+ int cpi; // The font size in characters per inch
+ // (bitmapped fonts are monospaced).
+ /* Bitmap font selection is ugly in this printer, so don't expect
+ this function to be elegant. */
bfont_name[0] = 0x00;
- if (orientation) // Landscape
- ori = 'R';
- else // Portrait
- ori = 'N';
- type = f->lbpname[strlen(f->lbpname)-1];
- nam = new char[strlen(f->lbpname)-2];
- strncpy(nam,&(f->lbpname[1]),strlen(f->lbpname)-2);
- nam[strlen(f->lbpname)-2] = 0x00;
- // fprintf(stderr,"Bitmap font '%s' %d %c %c \n",nam,siz,type,ori);
- /* Since these fonts are avaiable only at certain sizes,
- 10 and 17 cpi for courier, 12 and 17 cpi for elite,
- we adjust the resulting size. */
- cpi = 17;
- // Fortunately there were only two bitmaped fonts shiped with the printer.
- if (!strcasecmp(nam,"courier"))
- { // Courier font
- if (siz >= 12) cpi = 10;
- else cpi = 17;
- };
- if (!strcasecmp(nam,"elite"))
- { // Elite font
- if (siz >= 10) cpi = 12;
- else cpi = 17;
- };
-
+ if (orientation) // Landscape
+ ori = 'R';
+ else // Portrait
+ ori = 'N';
+ type = f->lbpname[strlen(f->lbpname) - 1];
+ nam = new char[strlen(f->lbpname) - 2];
+ strncpy(nam, &(f->lbpname[1]), strlen(f->lbpname) - 2);
+ nam[strlen(f->lbpname) - 2] = 0x00;
+ // fprintf(stderr, "Bitmap font '%s' %d %c %c \n", nam, siz, type, ori);
+ /* Since these fonts are available only at certain sizes,
+ 10 and 17 cpi for courier, 12 and 17 cpi for elite,
+ we adjust the resulting size. */
+ cpi = 17;
+ // Fortunately there are only two bitmapped fonts shipped with the printer.
+ if (!strcasecmp(nam, "courier")) {
+ // Courier font
+ if (siz >= 12)
+ cpi = 10;
+ else cpi = 17;
+ }
+ if (!strcasecmp(nam, "elite")) {
+ if (siz >= 10)
+ cpi = 12;
+ else cpi = 17;
+ }
// Now that we have all the data, let's generate the font name.
if ((type != 'B') && (type != 'I')) // Roman font
- sprintf(bfont_name,"%c%s%d",ori,nam,cpi);
+ sprintf(bfont_name, "%c%s%d", ori, nam, cpi);
else
- sprintf(bfont_name,"%c%s%d%c",ori,nam,cpi,type);
-
+ sprintf(bfont_name, "%c%s%d%c", ori, nam, cpi, type);
return bfont_name;
-
-}; // lbp_printer::font_name
+}
-void lbp_printer::set_char(int index, font *f, const environment *env, int w, const char *name)
+void lbp_printer::set_char(int index, font *f, const environment *env,
+ int w, const char *name)
{
int code = f->get_code(index);
-
unsigned char ch = code & 0xff;
unsigned short symbol_set = code >> 8;
if (f != cur_font) {
lbp_font *psf = (lbp_font *)f;
- // fprintf(stderr,"Loading font %s \"%d\" \n",psf->lbpname,env->size);
- if (psf->is_scalable)
- { // Scalable font selection is different from bitmaped
- lbpprintf("\033Pz%s.IBML\033\\\033[%d C",psf->lbpname,\
- (int)((env->size*300)/72));
- } else
- { // Bitmaped font
- lbpprintf("\033Pz%s.IBML\033\\\n",font_name(psf,env->size));
- };
- lbpputs("\033)' 1"); // Select IBML and IBMR1 symbol set
- cur_size = env->size;
+ // fprintf(stderr, "Loading font %s \"%d\" \n", psf->lbpname, env->size);
+ if (psf->is_scalable) {
+ // Scalable font selection is different from bitmaped
+ lbpprintf("\033Pz%s.IBML\033\\\033[%d C", psf->lbpname,
+ (int)((env->size * font::res) / 72));
+ }
+ else
+ // bitmapped font
+ lbpprintf("\033Pz%s.IBML\033\\\n", font_name(psf, env->size));
+ lbpputs("\033)' 1"); // Select IBML and IBMR1 symbol set
cur_font = psf;
cur_symbol_set = 0;
+ // Update the line thickness if needed
+ if ((req_linethickness < 0 ) && (env->size != cur_size))
+ set_line_thickness(req_linethickness,env);
+ cur_size = env->size;
}
if (symbol_set != cur_symbol_set) {
- if ( cur_symbol_set == 3 ) {
- // if current symbol set is Symbol we must restore the font
- lbpprintf("\033Pz%s.IBML\033\\\033[%d C",cur_font->lbpname,\
- (int)((env->size*300)/72));
- }; // if ( cur_symbol_set == 3 )
+ if (cur_symbol_set == 3)
+ // if current symbol set is Symbol we must restore the font
+ lbpprintf("\033Pz%s.IBML\033\\\033[%d C", cur_font->lbpname,
+ (int)((env->size * font::res) / 72));
switch (symbol_set) {
- case 0: lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets
- break;
- case 1: lbpputs("\033(d\033)' 1"); // Select wp54 symbol set
- break;
- case 2: lbpputs("\033('$2\033)'!0"); // Select IBMP symbol set
- break;
- case 3: lbpprintf("\033PzSymbol.SYML\033\\\033[%d C",\
- (int)((env->size*300)/72));
- lbpputs("\033(\"!!0\033)\"!!1"); // Select symbol font
- break;
- case 4: lbpputs("\033)\"! 1\033(\"!$2"); // Select PS symbol set
- break;
- }; // switch (symbol_set)
-
-// if (symbol_set == 1) lbpputs("\033(d"); // Select wp54 symbol set
-// else lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets
+ case 0:
+ lbpputs("\033('$2\033)' 1"); // Select IBML and IBMR1 symbol sets
+ break;
+ case 1:
+ lbpputs("\033(d\033)' 1"); // Select wp54 symbol set
+ break;
+ case 2:
+ lbpputs("\033('$2\033)'!0"); // Select IBMP symbol set
+ break;
+ case 3:
+ lbpprintf("\033PzSymbol.SYML\033\\\033[%d C",
+ (int)((env->size * font::res) / 72));
+ lbpputs("\033(\"!!0\033)\"!!1"); // Select symbol font
+ break;
+ case 4:
+ lbpputs("\033)\"! 1\033(\"!$2"); // Select PS symbol set
+ break;
+ }
cur_symbol_set = symbol_set;
}
if (env->size != cur_size) {
-
if (!cur_font->is_scalable)
- lbpprintf("\033Pz%s.IBML\033\\\n",font_name(cur_font,env->size));
+ lbpprintf("\033Pz%s.IBML\033\\\n", font_name(cur_font, env->size));
else
- lbpprintf("\033[%d C",(int)((env->size*300)/72));
+ lbpprintf("\033[%d C", (int)((env->size * font::res) / 72));
cur_size = env->size;
+ // Update the line thickness if needed
+ if (req_linethickness < 0 )
+ set_line_thickness(req_linethickness,env);
}
- if ((env->hpos != cur_hpos) || (env->vpos != cur_vpos))
- {
- // lbpmoveabs(env->hpos - ((5*300)/16),env->vpos );
- lbpmoveabs(env->hpos - 64,env->vpos - 64 );
- cur_vpos = env->vpos;
- cur_hpos = env->hpos;
- };
- if ((ch & 0x7F) < 32) lbpputs("\033[1.v");
+ if ((env->hpos != cur_hpos) || (env->vpos != cur_vpos)) {
+ // lbpmoveabs(env->hpos - ((5 * 300) / 16), env->vpos);
+ lbpmoveabs(env->hpos - 64, env->vpos - 64);
+ cur_vpos = env->vpos;
+ cur_hpos = env->hpos;
+ }
+ if ((ch & 0x7F) < 32)
+ lbpputs("\033[1.v");
lbpputc(ch);
cur_hpos += w;
-};
+}
-void
-lbp_printer::vdmstart()
+void lbp_printer::vdmstart()
{
FILE *f;
static int changed_origin = 0;
-
- errno = 0;
- f = tmpfile();
- // f = fopen("/tmp/gtmp","w+");
- if (f == NULL) perror("Openinig temp file");
- vdminit(f);
- if (!changed_origin) { // we should change the origin only one time
- changed_origin = 1;
- vdmorigin(-63,0);
- };
- vdmlinewidth(line_thickness);
-
-};
+ errno = 0;
+ f = tmpfile();
+ // f = fopen("/tmp/gtmp","w+");
+ if (f == NULL)
+ perror("Opening temporary file");
+ vdminit(f);
+ if (!changed_origin) { // we should change the origin only one time
+ changed_origin = 1;
+ vdmorigin(-63, 0);
+ }
+ vdmlinewidth(line_thickness);
+}
void
lbp_printer::vdmflush()
{
char buffer[1024];
int bytes_read = 1;
-
vdmend();
fflush(lbpoutput);
- /* lets copy the vdm code to the output */
+ /* let's copy the vdm code to the output */
rewind(vdmoutput);
- do
- {
- bytes_read = fread(buffer,1,sizeof(buffer),vdmoutput);
- bytes_read = fwrite(buffer,1,bytes_read,lbpoutput);
- } while ( bytes_read == sizeof(buffer));
-
- fclose(vdmoutput); // This will also delete the file,
- // since it is created by tmpfile()
- vdmoutput = NULL;
-
-}; // lbp_printer::vdmflush
-
-inline void
-lbp_printer::setfillmode(int mode)
+ do {
+ bytes_read = fread(buffer, 1, sizeof(buffer), vdmoutput);
+ bytes_read = fwrite(buffer, 1, bytes_read, lbpoutput);
+ } while (bytes_read == sizeof(buffer));
+ fclose(vdmoutput); // This will also delete the file,
+ // since it is created by tmpfile()
+ vdmoutput = NULL;
+}
+
+inline void lbp_printer::setfillmode(int mode)
{
if (mode != fill_mode) {
- if (mode != 1) vdmsetfillmode(mode,1,0);
- else vdmsetfillmode(mode,1,1); // To get black we must use white
- // inverted
- fill_mode = mode;
- };
-}; // setfillmode
+ if (mode != 1)
+ vdmsetfillmode(mode, 1, 0);
+ else
+ vdmsetfillmode(mode, 1, 1); // To get black we must use white
+ // inverted
+ fill_mode = mode;
+ }
+}
-inline void
-lbp_printer::polygon( int hpos,int vpos,int np,int *p)
+inline void lbp_printer::polygon(int hpos, int vpos, int np, int *p)
{
- //int points[np+2],i;
- int *points,i;
-
- points = new int[np+2];
- points[0] = hpos;
- points[1] = vpos;
-/* fprintf(stderr,"Poligon (%d,%d) ", points[0],points[1]);*/
- for (i = 0; i < np; i++) points[i+2] = p[i];
-/* for (i = 0; i < np; i++) fprintf(stderr," %d ",p[i]);
- fprintf(stderr,"\n"); */
- vdmpolygon((np /2) + 1,points);
-};
+ int *points, i;
+ points = new int[np + 2];
+ points[0] = hpos;
+ points[1] = vpos;
+ // fprintf(stderr, "Poligon (%d,%d) ", points[0], points[1]);
+ for (i = 0; i < np; i++)
+ points[i + 2] = p[i];
+ // for (i = 0; i < np; i++) fprintf(stderr, " %d ", p[i]);
+ // fprintf(stderr, "\n");
+ vdmpolygon((np /2) + 1, points);
+}
+
+inline void lbp_printer::set_line_thickness(int size,const environment *env)
+{
+ if (size == 0)
+ line_thickness = 1;
+ else {
+ if (size < 0)
+ // line_thickness =
+ // (env->size * (font::res/72)) * (linewidth_factor/1000)
+ // we ought to check for overflow
+ line_thickness =
+ env->size * linewidth_factor * font::res / 72000;
+ else // size > 0
+ line_thickness = size;
+ } // else from if (size == 0)
+ if (line_thickness < 1)
+ line_thickness = 1;
+ if (vdminited())
+ vdmlinewidth(line_thickness);
+ req_linethickness = size; // an size requested
+ /* fprintf(stderr, "thickness: %d == %d, size %d, %d \n",
+ size, line_thickness, env->size,req_linethickness); */
+ return;
+}; // lbp_printer::set_line_thickness
void lbp_printer::draw(int code, int *p, int np, const environment *env)
{
- switch (code) {
- case 't':
- if (np == 0) line_thickness = 1;
- else { // troff gratuitously adds an extra 0
- if (np != 1 && np != 2) {
- error("0 or 1 argument required for thickness");
- break;
- } // if (np != ...
- if (p[0] == 0) line_thickness = 1;
- if (p[0] < 0) // Default = 1 point
- line_thickness = (int)(env->size*30/72);
- line_thickness = (int)((abs(p[0])*env->size)/10);
- if ((line_thickness > 16 ) && (!vdminited()))
- { /* for greater thickness we must use VDM */
- vdmstart();
- /* vdmlinewidth(line_thickness); already done in
- * vdmstart() */
- };
- if (vdminited()) vdmlinewidth(line_thickness);
- // fprintf(stderr,"\nthickness: %d == %d, size %d\n",
- // p[0],line_thickness,env->size );
- } // else
- break;
-
- case 'l': // Line
- if (np != 2) {
- error("2 arguments required for line");
- break;
- };
- if (!vdminited()) vdmstart();
- vdmline(env->hpos,env->vpos,p[0],p[1]);
- /*fprintf(stderr,"\nline: %d,%d - %d,%d thickness %d == %d\n",\
- env->hpos - 64,env->vpos -64, env->hpos - 64 + p[0],\
- env->vpos -64 + p[1],env->size, line_thickness);*/
- break;
- case 'R': // Rule
- if (np != 2) {
- error("2 arguments required for Rule");
- break;
- }
- if (vdminited()) {
- setfillmode(fill_pattern); // Solid Rule
- vdmrectangle(env->hpos,env->vpos,p[0],p[1]);
- }
- else {
- lbpruleabs(env->hpos - 64,env->vpos -64 , p[0], p[1]);
- cur_vpos = p[1];
- cur_hpos = p[0];
- };
- fprintf(stderr,"\nrule: thickness %d == %d\n", env->size, line_thickness);
- break;
- case 'P': // Filled Polygon
- if (!vdminited()) vdmstart();
- setfillmode(fill_pattern);
- polygon(env->hpos,env->vpos,np,p);
- break;
- case 'p': // Empty Polygon
- if (!vdminited()) vdmstart();
- setfillmode(0);
- polygon(env->hpos,env->vpos,np,p);
- break;
- case 'C': // Filled Circle
- if (!vdminited()) vdmstart();
- // fprintf(stderr,"Circle (%d,%d) Fill %d\n",env->hpos,env->vpos,fill_pattern);
- setfillmode(fill_pattern);
- vdmcircle(env->hpos + (p[0]/2),env->vpos,p[0]/2);
- break;
- case 'c': // Empty Circle
- if (!vdminited()) vdmstart();
- setfillmode(0);
- vdmcircle(env->hpos + (p[0]/2),env->vpos,p[0]/2);
- break;
- case 'E': // Filled Ellipse
- if (!vdminited()) vdmstart();
- setfillmode(fill_pattern);
- vdmellipse(env->hpos + (p[0]/2),env->vpos,p[0]/2,p[1]/2,0);
- break;
- case 'e': // Empty Ellipse
- if (!vdminited()) vdmstart();
- setfillmode(0);
- vdmellipse(env->hpos + (p[0]/2),env->vpos,p[0]/2,p[1]/2,0);
- break;
- case 'a': // Arc
- if (!vdminited()) vdmstart();
- setfillmode(0);
- // VDM draws arcs clockwise and pic counterclockwise
- // We must compensate for that, exchanging the starting and
- // ending points
- vdmvarc(env->hpos + p[0],env->vpos+p[1],\
- int(sqrt( double((p[0]*p[0])+(p[1]*p[1])))),\
- p[2],p[3],\
- (-p[0]),(-p[1]),1,2);
- break;
- case '~': // Spline
- if (!vdminited()) vdmstart();
- setfillmode(0);
- vdmspline(np/2,env->hpos,env->vpos,p);
- break;
- case 'f':
- if (np != 1 && np != 2) {
- error("1 argument required for fill");
- break;
- };
- // fprintf(stderr,"Fill %d\n",p[0]);
- if ((p[0] == 1) || (p[0] >= 1000)) { // Black
- fill_pattern = 1;
- break;
- }; // if (p[0] == 1)
- if (p[0] == 0) { // White
- fill_pattern = 0;
- break;
- };
- if ((p[0] > 1) && (p[0] < 1000))
- {
- if (p[0] >= 990) fill_pattern = -23;
- else if (p[0] >= 700) fill_pattern = -28;
- else if (p[0] >= 500) fill_pattern = -27;
- else if (p[0] >= 400) fill_pattern = -26;
- else if (p[0] >= 300) fill_pattern = -25;
- else if (p[0] >= 200) fill_pattern = -22;
- else if (p[0] >= 100) fill_pattern = -24;
- else fill_pattern = -21;
- }; // if (p[0] >= 0 && p[0] <= 1000)
- break;
- default:
- error("unrecognised drawing command `%1'", char(code));
- break;
- }; // switch (code)
- return ;
-};
+ if ((req_linethickness < 0 ) && (env->size != cur_size))
+ set_line_thickness(req_linethickness,env);
+
+ switch (code) {
+ case 't':
+ if (np == 0)
+ line_thickness = 1;
+ else { // troff gratuitously adds an extra 0
+ if (np != 1 && np != 2) {
+ error("0 or 1 argument required for thickness");
+ break;
+ };
+ set_line_thickness(p[0],env);
+ };
+ break;
+ case 'l': // Line
+ if (np != 2) {
+ error("2 arguments required for line");
+ break;
+ }
+ if (!vdminited())
+ vdmstart();
+ vdmline(env->hpos, env->vpos, p[0], p[1]);
+/* fprintf(stderr, "\nline: %d,%d - %d,%d thickness %d == %d\n",
+ env->hpos - 64,env->vpos -64, env->hpos - 64 + p[0],
+ env->vpos -64 + p[1], env->size, line_thickness);*/
+ break;
+ case 'R': // Rule
+ if (np != 2) {
+ error("2 arguments required for Rule");
+ break;
+ }
+ if (vdminited()) {
+ setfillmode(fill_pattern); // Solid Rule
+ vdmrectangle(env->hpos, env->vpos, p[0], p[1]);
+ }
+ else {
+ lbpruleabs(env->hpos - 64, env->vpos -64, p[0], p[1]);
+ cur_vpos = p[1];
+ cur_hpos = p[0];
+ }
+ // fprintf(stderr, "\nrule: thickness %d == %d\n",
+ // env->size, line_thickness);
+ break;
+ case 'P': // Filled Polygon
+ if (!vdminited())
+ vdmstart();
+ setfillmode(fill_pattern);
+ polygon(env->hpos, env->vpos, np, p);
+ break;
+ case 'p': // Empty Polygon
+ if (!vdminited())
+ vdmstart();
+ setfillmode(0);
+ polygon(env->hpos, env->vpos, np, p);
+ break;
+ case 'C': // Filled Circle
+ if (!vdminited())
+ vdmstart();
+ // fprintf(stderr, "Circle (%d,%d) Fill %d\n",
+ // env->hpos, env->vpos, fill_pattern);
+ setfillmode(fill_pattern);
+ vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2);
+ break;
+ case 'c': // Empty Circle
+ if (!vdminited())
+ vdmstart();
+ setfillmode(0);
+ vdmcircle(env->hpos + (p[0]/2), env->vpos, p[0]/2);
+ break;
+ case 'E': // Filled Ellipse
+ if (!vdminited())
+ vdmstart();
+ setfillmode(fill_pattern);
+ vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0);
+ break;
+ case 'e': // Empty Ellipse
+ if (!vdminited())
+ vdmstart();
+ setfillmode(0);
+ vdmellipse(env->hpos + (p[0]/2), env->vpos, p[0]/2, p[1]/2, 0);
+ break;
+ case 'a': // Arc
+ if (!vdminited())
+ vdmstart();
+ setfillmode(0);
+ // VDM draws arcs clockwise and pic counterclockwise
+ // We must compensate for that, exchanging the starting and
+ // ending points
+ vdmvarc(env->hpos + p[0], env->vpos+p[1],
+ int(sqrt(double((p[0]*p[0]) + (p[1]*p[1])))),
+ p[2], p[3],
+ (-p[0]), (-p[1]), 1, 2);
+ break;
+ case '~': // Spline
+ if (!vdminited())
+ vdmstart();
+ setfillmode(0);
+ vdmspline(np/2, env->hpos, env->vpos, p);
+ break;
+ case 'f':
+ if (np != 1 && np != 2) {
+ error("1 argument required for fill");
+ break;
+ }
+ // fprintf(stderr, "Fill %d\n", p[0]);
+ if ((p[0] == 1) || (p[0] >= 1000)) { // Black
+ fill_pattern = 1;
+ break;
+ }
+ if (p[0] == 0) { // White
+ fill_pattern = 0;
+ break;
+ }
+ if ((p[0] > 1) && (p[0] < 1000))
+ {
+ if (p[0] >= 990) fill_pattern = -23;
+ else if (p[0] >= 700) fill_pattern = -28;
+ else if (p[0] >= 500) fill_pattern = -27;
+ else if (p[0] >= 400) fill_pattern = -26;
+ else if (p[0] >= 300) fill_pattern = -25;
+ else if (p[0] >= 200) fill_pattern = -22;
+ else if (p[0] >= 100) fill_pattern = -24;
+ else fill_pattern = -21;
+ }
+ break;
+ case 'F':
+ // not implemented yet
+ break;
+ default:
+ error("unrecognised drawing command `%1'", char(code));
+ break;
+ }
+ return;
+}
font *lbp_printer::make_font(const char *nm)
{
return lbp_font::load_lbp_font(nm);
}
-
-
printer *make_printer()
{
- return new lbp_printer;
+ return new lbp_printer(user_papersize, user_paperwidth, user_paperlength);
}
-static struct
-{
- const char *name;
- int code;
-} papersizes[] =
-{{ "A4", 14 },
-{ "letter", 30 },
-{ "legal", 32 },
-{ "executive", 40 },
-};
-
+static struct {
+ const char *name;
+ int code;
+} lbp_papersizes[] =
+ {{ "A4", 14 },
+ { "letter", 30 },
+ { "legal", 32 },
+ { "executive", 40 },
+ };
-static int set_papersize(const char *papersize)
+static int set_papersize(const char *paperformat)
{
unsigned int i;
-
// First test for a standard (i.e. supported directly by the printer)
- // papersize
- for (i = 0 ; i < sizeof(papersizes)/sizeof(papersizes[0]); i++)
+ // paper size
+ for (i = 0 ; i < sizeof(lbp_papersizes) / sizeof(lbp_papersizes[0]); i++)
{
- if (strcasecmp(papersizes[i].name,papersize) == 0)
- return papersizes[i].code;
- };
-
- // Now test for a custom papersize
- if (strncasecmp("cust",papersize,4) == 0)
- {
- char *p ,
- *p1,
- *papsize;
-
- p = papsize = strdup(&papersize[4]);
- if (papsize == NULL) return -1;
- p1 = strsep(&p,"x");
- if (p == NULL)
- { // let's test for an uppercase x
- p = papsize ;
- p1 = strsep(&p,"X");
- if (p == NULL) { free(papsize); return -1;};
- }; // if (p1 == NULL)
- paperlength = atoi(p1);
- if (paperlength == 0) { free(papsize); return -1;};
- paperwidth = atoi(p);
- if (paperwidth == 0) { free(papsize); return -1;};
- free(papsize);
- return 82;
- }; // if (strcnasecmp("cust",papersize,4) == 0)
-
- return -1;
-};
-
-static int handle_papersize_command(const char *arg)
-{
- int n = set_papersize(arg);
-
- if (n < 0)
- { // If is not a standard nor custom paper size
- // let's see if it's a file (i.e /etc/papersize )
- FILE *f = fopen(arg,"r");
- if (f != NULL)
- { // the file exists and is readable
- char psize[255],*p;
- fgets(psize,254,f);
- fclose(f);
- // set_papersize doesn't like the trailing \n
- p = psize; while (*p) p++;
- if (*(--p) == '\n') *p = 0x00;
-
- n = set_papersize(psize);
- }; // if (f != NULL)
- }; // if (n < 0)
-
- return n;
-}; // handle_papersize_command
-
+ if (strcasecmp(lbp_papersizes[i].name,paperformat) == 0)
+ return lbp_papersizes[i].code;
+ }
+ // Otherwise, we assume a custom paper size
+ return 82;
+}
static void handle_unknown_desc_command(const char *command, const char *arg,
const char *filename, int lineno)
{
- // papersize command
- if (strcasecmp(command, "papersize") == 0) {
- // We give priority to command line options
- if (papersize > 0) return;
- if (arg == 0)
- error_with_file_and_line(filename, lineno,
- "`papersize' command requires an argument");
- else
- {
- int n = handle_papersize_command(arg);
- if (n < 0)
- error_with_file_and_line(filename, lineno,
- "unknown paper size `%1'", arg);
- else
- papersize = n;
-
- }; // if (arg == 0) ... else ...
- }; // if (strcasecmp(command, "papersize")
-
- // orientation command
+ // orientation command
if (strcasecmp(command, "orientation") == 0) {
// We give priority to command line options
- if (orientation > 0) return;
+ if (orientation > 0)
+ return;
if (arg == 0)
error_with_file_and_line(filename, lineno,
- "`papersize' command requires an argument");
+ "`orientation' command requires an argument");
else {
- if (strcasecmp(arg,"portrait") == 0) orientation = 0;
- else { if (strcasecmp(arg,"landscape") == 0) orientation = 1;
- else error_with_file_and_line(filename, lineno,
- "`orientation' command requires an argument");
- };
- }; // if (arg == 0) ... else ...
- }; // if (strcasecmp(command, "orientation") == 0)
-};
+ if (strcasecmp(arg, "portrait") == 0)
+ orientation = 0;
+ else {
+ if (strcasecmp(arg, "landscape") == 0)
+ orientation = 1;
+ else
+ error_with_file_and_line(filename, lineno,
+ "invalid argument to `orientation' command");
+ }
+ }
+ }
+}
static struct option long_options[] = {
{ "orientation", required_argument, NULL, 'o' },
@@ -670,97 +631,110 @@ static struct option long_options[] = {
{ "copies", required_argument, NULL, 'c' },
{ "landscape", no_argument, NULL, 'l' },
{ "papersize", required_argument, NULL, 'p' },
+ { "linewidth", required_argument, NULL, 'w' },
{ "fontdir", required_argument, NULL, 'F' },
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, 0, 0 }
- };
+};
static void usage(FILE *stream)
{
fprintf(stream,
- "usage: %s [-lvh] [-c n] [-p paper_size] [-F dir] [-o or] "\
- " [files ...]\n"\
- " -o --orientation=[portrait|landscape]\n"\
- " -v --version\n"\
- " -c --copies=numcopies\n"\
- " -l --landscape\n"\
- " -p --papersize=paper_size\n"\
- " -F --fontdir=dir\n"\
- " -h --help\n",
+ "usage: %s [-lvh] [-c n] [-p paper_size] [-F dir] [-o or]\n"
+ " [-w width] [files ...]\n"
+ "\n"
+ " -o --orientation=[portrait|landscape]\n"
+ " -v --version\n"
+ " -c --copies=numcopies\n"
+ " -l --landscape\n"
+ " -p --papersize=paper_size\n"
+ " -w --linewidth=width\n"
+ " -F --fontdir=dir\n"
+ " -h --help\n",
program_name);
-}; // usage
+}
int main(int argc, char **argv)
{
- if (program_name == NULL) program_name = strdup(argv[0]);
-
- font::set_unknown_desc_command_handler(handle_unknown_desc_command);
- // command line parsing
- int c = 0;
- int option_index = 0;
-
- while (c >= 0 )
- {
- c = getopt_long (argc, argv, "F:p:lvo:c:h",\
- long_options, &option_index);
- switch (c) {
- case 'F' : font::command_line_font_dir(optarg);
- break;
- case 'p' : {
- int n = handle_papersize_command(optarg);
- if (n < 0)
- error("unknown paper size `%1'", optarg);
- else
- papersize = n;
- break;
- };
- case 'l' : orientation = 1;
- break;
- case 'v' : {
- printf("GNU grolbp (groff) version %s\n",
- Version_string);
- exit(0);
- break;
- };
- case 'o' : {
- if (strcasecmp(optarg,"portrait") == 0)
- orientation = 0;
- else {
- if (strcasecmp(optarg,"landscape") == 0)
- orientation = 1;
- else
- error("unknown orientation '%1'", optarg);
- };
- break;
- };
- case 'c' : {
- char *ptr;
- long n = strtol(optarg, &ptr, 10);
- if ((n <= 0) && (ptr == optarg))
- error("argument for -c must be a positive integer");
- else if (n <= 0 || n > 32767)
- error("out of range argument for -c");
- else
- ncopies = unsigned(n);
- break;
- }
- case 'h' : usage(stdout);
- exit(0);
- break;
- case '?' : usage(stderr);
- exit(1);
- break;
-
- }; // switch (c)
- }; // while (c > 0 )
-
- if (optind >= argc)
- do_file("-");
-
- while (optind < argc) {
- do_file(argv[optind++]);
- };
-
- lbpputs("\033c\033<");
- return 0;
-};
+ if (program_name == NULL)
+ program_name = strsave(argv[0]);
+ font::set_unknown_desc_command_handler(handle_unknown_desc_command);
+ // command line parsing
+ int c = 0;
+ int option_index = 0;
+ while (c >= 0) {
+ c = getopt_long (argc, argv, "F:p:lvo:c:hw:",
+ long_options, &option_index);
+ switch (c) {
+ case 'F':
+ font::command_line_font_dir(optarg);
+ break;
+ case 'p':
+ {
+ const char *s;
+ if (!font::scan_papersize(optarg, &s,
+ &user_paperlength, &user_paperwidth))
+ error("invalid paper size `%1' ignored", optarg);
+ else
+ user_papersize = set_papersize(s);
+ break;
+ }
+ case 'l':
+ orientation = 1;
+ break;
+ case 'v':
+ printf("GNU grolbp (groff) version %s\n", Version_string);
+ exit(0);
+ break;
+ case 'o':
+ if (strcasecmp(optarg, "portrait") == 0)
+ orientation = 0;
+ else {
+ if (strcasecmp(optarg, "landscape") == 0)
+ orientation = 1;
+ else
+ error("unknown orientation '%1'", optarg);
+ };
+ break;
+ case 'c':
+ {
+ char *ptr;
+ long n = strtol(optarg, &ptr, 10);
+ if ((n <= 0) && (ptr == optarg))
+ error("argument for -c must be a positive integer");
+ else if (n <= 0 || n > 32767)
+ error("out of range argument for -c");
+ else
+ ncopies = unsigned(n);
+ break;
+ }
+ case 'w':
+ {
+ char *ptr;
+ long n = strtol(optarg, &ptr, 10);
+ if (n == 0 && ptr == optarg)
+ error("argument for -w must be a non-negative integer");
+ else if (n < 0 || n > INT_MAX)
+ error("out of range argument for -w");
+ else
+ linewidth_factor = int(n);
+ break;
+ }
+ case 'h':
+ usage(stdout);
+ exit(0);
+ break;
+ case '?':
+ usage(stderr);
+ exit(1);
+ break;
+ }
+ }
+ if (optind >= argc)
+ do_file("-");
+ while (optind < argc)
+ do_file(argv[optind++]);
+ lbpputs("\033c\033<");
+ delete pr;
+ return 0;
+}
diff --git a/contrib/groff/src/devices/grolbp/lbp.h b/contrib/groff/src/devices/grolbp/lbp.h
index cacf3ea..3b8a941 100644
--- a/contrib/groff/src/devices/grolbp/lbp.h
+++ b/contrib/groff/src/devices/grolbp/lbp.h
@@ -1,5 +1,5 @@
// -*- C -*-
-/* Copyright (C) 1994, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1994, 2000, 2001 Free Software Foundation, Inc.
Written by Francisco Andrés Verdú <pandres@dragonet.es>
groff is free software; you can redistribute it and/or modify it under
diff --git a/contrib/groff/src/devices/grolj4/Makefile.sub b/contrib/groff/src/devices/grolj4/Makefile.sub
index bbb0cff..21c3780 100644
--- a/contrib/groff/src/devices/grolj4/Makefile.sub
+++ b/contrib/groff/src/devices/grolj4/Makefile.sub
@@ -1,6 +1,6 @@
-PROG=grolj4
+PROG=grolj4$(EXEEXT)
MAN1=grolj4.n
XLIBS=$(LIBDRIVER) $(LIBGROFF)
MLIB=$(LIBM)
-OBJS=lj4.o
+OBJS=lj4.$(OBJEXT)
CCSRCS=$(srcdir)/lj4.cc
diff --git a/contrib/groff/src/devices/grolj4/grolj4.man b/contrib/groff/src/devices/grolj4/grolj4.man
index 414ad78..267c621 100644
--- a/contrib/groff/src/devices/grolj4/grolj4.man
+++ b/contrib/groff/src/devices/grolj4/grolj4.man
@@ -1,5 +1,5 @@
.ig
-Copyright (C) 1994-2000, 2001 Free Software Foundation, Inc.
+Copyright (C) 1994-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
@@ -59,7 +59,7 @@ There is an additional drawing command available:
.BI \eD'R\ dh\ dv '
Draw a rule (solid black rectangle), with one corner
at the current position, and the diagonally opposite corner
-at the current position
+at the current position
.RI +( dh , dv ).
Afterwards the current position will be at the opposite corner. This
generates a PCL fill rectangle command, and so will work on
@@ -77,7 +77,7 @@ copies of each page.
Print the document with a landscape orientation.
.TP
.BI "\-d [" n ]
-Use duplex mode
+Use duplex mode
.IR n :
1\ is long-side binding; 2\ is short-side binding;
default is\ 1.
@@ -94,17 +94,20 @@ Print the version number.
.BI \-w n
Set the default line thickness to
.I n
-thousandths of an em.
+thousandths of an em.
+If this option isn't specified, the line thickness defaults to 0.04\~em.
.TP
.BI \-F dir
Prepend directory
-.IB dir /devlj4
-to the search path for font and device description files.
+.IB dir /dev name
+to the search path for font and device description files;
+.I name
+is the name of the device, usually
+.BR lj4 .
.LP
The following four commands are available additionally in the
-.B DESC
-file:
-.TP
+font description files:
+.TP
.BI pclweight \ N
The integer value
.I N
diff --git a/contrib/groff/src/devices/grolj4/lj4.cc b/contrib/groff/src/devices/grolj4/lj4.cc
index 6829acb..0c3150d 100644
--- a/contrib/groff/src/devices/grolj4/lj4.cc
+++ b/contrib/groff/src/devices/grolj4/lj4.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1994, 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1994, 2000, 2001, 2002 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -55,7 +55,7 @@ static struct {
{ "dl", 90, 71, 59 },
};
-static int paper_size = -1;
+static int user_paper_size = -1;
static int landscape_flag = 0;
static int duplex_flag = 0;
@@ -76,6 +76,8 @@ const int DEFAULT_HPGL_UNITS = 1016;
int line_width_factor = DEFAULT_LINE_WIDTH_FACTOR;
unsigned ncopies = 0; // 0 means don't send ncopies command
+static int lookup_paper_size(const char *);
+
class lj4_font : public font {
public:
~lj4_font();
@@ -158,7 +160,7 @@ void lj4_font::handle_unknown_font_command(const char *command,
class lj4_printer : public printer {
public:
- lj4_printer();
+ lj4_printer(int);
~lj4_printer();
void set_char(int, font *, const environment *, int, const char *name);
void draw(int code, int *p, int np, const environment *env);
@@ -184,6 +186,7 @@ private:
double pen_width;
double hpgl_scale;
int hpgl_inited;
+ int paper_size;
};
inline
@@ -207,7 +210,7 @@ void lj4_printer::hpgl_end()
fputs(";\033%0A", stdout);
}
-lj4_printer::lj4_printer()
+lj4_printer::lj4_printer(int ps)
: cur_hpos(-1),
cur_font(0),
cur_size(0),
@@ -221,11 +224,19 @@ lj4_printer::lj4_printer()
font::res);
fputs("\033E", stdout); // reset
if (font::res != 300)
- printf("\033&u%dD", font::res); // unit of measure
+ printf("\033&u%dD", font::res); // unit of measure
if (ncopies > 0)
printf("\033&l%uX", ncopies);
- if (paper_size < 0)
- paper_size = 0; // default to letter
+ paper_size = 0; // default to letter
+ if (font::papersize) {
+ int n = lookup_paper_size(font::papersize);
+ if (n < 0)
+ error("unknown paper size `%1'", font::papersize);
+ else
+ paper_size = n;
+ }
+ if (ps >= 0)
+ paper_size = ps;
printf("\033&l%dA" // paper size
"\033&l%dO" // orientation
"\033&l0E", // no top margin
@@ -266,7 +277,8 @@ int is_unprintable(unsigned char c)
return c < 32 && (c == 0 || (7 <= c && c <= 15) || c == 27);
}
-void lj4_printer::set_char(int index, font *f, const environment *env, int w, const char *name)
+void lj4_printer::set_char(int index, font *f, const environment *env,
+ int w, const char *name)
{
int code = f->get_code(index);
@@ -502,6 +514,9 @@ void lj4_printer::draw(int code, int *p, int np, const environment *env)
printf("FT10,%d", p[0]/10);
hpgl_end();
break;
+ case 'F':
+ // not implemented yet
+ break;
case 't':
{
if (np == 0) {
@@ -531,8 +546,8 @@ void lj4_printer::hpgl_init()
hpgl_scale = double(DEFAULT_HPGL_UNITS)/font::res;
printf("\033&f0S" // push position
"\033*p0x0Y" // move to 0,0
- "\033*c%dx%dy0T" // establish picture frame
- "\033%%1B" // switch to HPGL
+ "\033*c%dx%dy0T" // establish picture frame
+ "\033%%1B" // switch to HPGL
"SP1SC0,%.4f,0,-%.4f,2IR0,100,0,100" // set up scaling
"LA1,4,2,4" // round line ends and joins
"PR" // relative plotting
@@ -565,7 +580,7 @@ font *lj4_printer::make_font(const char *nm)
printer *make_printer()
{
- return new lj4_printer;
+ return new lj4_printer(user_paper_size);
}
static
@@ -580,25 +595,6 @@ int lookup_paper_size(const char *s)
return -1;
}
-static
-void handle_unknown_desc_command(const char *command, const char *arg,
- const char *filename, int lineno)
-{
- if (strcmp(command, "papersize") == 0) {
- if (arg == 0)
- error_with_file_and_line(filename, lineno,
- "`papersize' command requires an argument");
- else if (paper_size < 0) {
- int n = lookup_paper_size(arg);
- if (n < 0)
- error_with_file_and_line(filename, lineno,
- "unknown paper size `%1'", arg);
- else
- paper_size = n;
- }
- }
-}
-
static void usage(FILE *stream);
extern "C" int optopt, optind;
@@ -608,7 +604,6 @@ int main(int argc, char **argv)
program_name = argv[0];
static char stderr_buf[BUFSIZ];
setbuf(stderr, stderr_buf);
- font::set_unknown_desc_command_handler(handle_unknown_desc_command);
int c;
static const struct option long_options[] = {
{ "help", no_argument, 0, CHAR_MAX + 1 },
@@ -644,7 +639,7 @@ int main(int argc, char **argv)
if (n < 0)
error("unknown paper size `%1'", optarg);
else
- paper_size = n;
+ user_paper_size = n;
break;
}
case 'v':
diff --git a/contrib/groff/src/devices/grops/Makefile.sub b/contrib/groff/src/devices/grops/Makefile.sub
index 4182527..ee2e6d1 100644
--- a/contrib/groff/src/devices/grops/Makefile.sub
+++ b/contrib/groff/src/devices/grops/Makefile.sub
@@ -1,10 +1,10 @@
-PROG=grops
+PROG=grops$(EXEEXT)
MAN1=grops.n
XLIBS=$(LIBDRIVER) $(LIBGROFF)
MLIB=$(LIBM)
OBJS=\
- ps.o \
- psrm.o
+ ps.$(OBJEXT) \
+ psrm.$(OBJEXT)
CCSRCS=\
$(srcdir)/ps.cc \
$(srcdir)/psrm.cc
diff --git a/contrib/groff/src/devices/grops/TODO b/contrib/groff/src/devices/grops/TODO
index da67973..7ab3b69 100644
--- a/contrib/groff/src/devices/grops/TODO
+++ b/contrib/groff/src/devices/grops/TODO
@@ -6,9 +6,6 @@ Generate %%For comment.
Generate %%Title comment.
-For efficiency it might be better to have the printer interface have
-support for the t and u commands.
-
Angles in arc command: don't generate more digits after the decimal
point than are necessary.
diff --git a/contrib/groff/src/devices/grops/grops.man b/contrib/groff/src/devices/grops/grops.man
index e9c6be4..e7d2305 100644
--- a/contrib/groff/src/devices/grops/grops.man
+++ b/contrib/groff/src/devices/grops/grops.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
@@ -16,15 +16,25 @@ versions, except that this permission notice may be included in
translations approved by the Free Software Foundation instead of in
the original English.
..
+.
+.mso www.tmac
+.
+.
.\" Like TP, but if specified indent is more than half
.\" the current line-length - indent, use the default indent.
.de Tp
.ie \\n(.$=0:((0\\$1)*2u>(\\n(.lu-\\n(.iu)) .TP
.el .TP "\\$1"
..
+.
+.
.TH GROPS @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@"
+.
+.
.SH NAME
grops \- PostScript driver for groff
+.
+.
.SH SYNOPSIS
.nr a \n(.j
.ad l
@@ -32,43 +42,55 @@ grops \- PostScript driver for groff
.in +\w'\fBgrops 'u
.ti \niu
.B grops
+.
.de OP
-.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]"
+.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\%\\$2" "\ ]"
.el .RB "[\ " "\\$1" "\ ]"
..
+.
.OP \-glmv
.OP \-b n
.OP \-c n
-.OP \-w n
.OP \-F dir
+.OP \-p papersize
.OP \-P prologue
+.OP \-w n
.RI "[\ " files\|.\|.\|. "\ ]"
.br
.ad \na
+.
.PP
It is possible to have whitespace between a command line option and its
parameter.
+.
+.
.SH DESCRIPTION
.B grops
translates the output of GNU
.B troff
to PostScript.
+.
Normally
.B grops
should be invoked by using the groff command
with a
.B \-Tps
option.
+.
.if '@DEVICE@'ps' (Actually, this is the default for groff.)
+.
If no files are given,
.B grops
will read the standard input.
+.
A filename of
.B \-
will also cause
.B grops
to read the standard input.
+.
PostScript output is written to the standard output.
+.
When
.B grops
is run by
@@ -79,22 +101,29 @@ using the
.B groff
.B \-P
option.
+.
+.
.SH OPTIONS
.TP
.BI \-b n
Workaround broken spoolers and previewers.
+.
Normally
.B grops
produces output that conforms
the Document Structuring Conventions version 3.0.
+.
Unfortunately some spoolers and previewers can't handle such output.
-The value of
+.
+The value of\~\c
.I n
controls what
.B grops
does to its output acceptable to such programs.
-A value of 0 will cause grops not to employ any workarounds.
-Add 1 if no
+.
+A value of\~0 will cause grops not to employ any workarounds.
+.
+Add\~1 if no
.B %%BeginDocumentSetup
and
.B %%EndDocumentSetup
@@ -105,10 +134,12 @@ anything between the
comment and the first
.B %%Page
comment.
-Add 2 if lines in included files beginning with
+.
+Add\~2 if lines in included files beginning with
.B %!
should be stripped out; this is needed for Sun's pageview previewer.
-Add 4 if
+.
+Add\~4 if
.BR %%Page ,
.BR %%Trailer
and
@@ -120,63 +151,97 @@ don't understand the
and
.B %%EndDocument
comments.
-Add 8 if the first line of the PostScript output should be
+.
+Add\~8 if the first line of the PostScript output should be
.B %!PS-Adobe-2.0
rather than
.BR %!PS-Adobe-3.0 ;
this is needed when using Sun's Newsprint with a printer that requires
page reversal.
+.
The default value can be specified by a
+.
.RS
.IP
.BI broken\ n
+.
.LP
command in the DESC file.
-Otherwise the default value is 0.
+.
+Otherwise the default value is\~0.
.RE
+.
.TP
.BI \-c n
Print
.I n
copies of each page.
+.
+.TP
+.BI \-F dir
+Prepend directory
+.IB dir /dev name
+to the search path for prologue, font, and device description files;
+.I name
+is the name of the device, usually
+.BR ps .
+.
.TP
.BI \-g
Guess the page length.
+.
This generates PostScript code that guesses the page length.
+.
The guess will be correct only if the imageable area is vertically
centered on the page.
+.
This option allows you to generate documents that can be printed
both on letter (8.5\(mu11) paper and on A4 paper without change.
+.
.TP
.B \-l
Print the document in landscape format.
+.
.TP
.B \-m
Turn manual feed on for the document.
+.
.TP
-.BI \-F dir
-Prepend directory
-.IB dir /dev name
-to the search path for prologue, font, and device description files;
-.I name
-is the name of the device, usually
-.BR ps .
+.BI \-p paper-size
+Set physical dimension of output medium.
+.
+This overrides the
+.B papersize
+and
+.B paperlength
+commands in the
+.B DESC
+file; it accepts the same arguments as the
+.B papersize
+command.
+.
.TP
.BI \-P prologue-file
Use the file
.I prologue-file
(in the font path) as the prologue instead of the default prologue file
.BR prologue .
+.
This option overrides the environment variable
.SM GROPS_PROLOGUE.
+.
.TP
.BI \-w n
Lines should be drawn using a thickness of
-.I n
+.IR n \~\c
thousandths of an em.
+If this option is not given, the line thickness defaults to 0.04\~em.
+.
.TP
.B \-v
Print the version number.
+.
+.
.SH USAGE
There are styles called
.BR R ,
@@ -184,7 +249,8 @@ There are styles called
.BR B ,
and
.B BI
-mounted at font positions 1 to 4.
+mounted at font positions 1 to\~4.
+.
The fonts are grouped into families
.BR A ,
.BR BM ,
@@ -193,245 +259,313 @@ The fonts are grouped into families
.BR HN ,
.BR N ,
.B P
-and
+and\~\c
.B T
having members in each of these styles:
+.
.de FT
.if '\\*(.T'ps' .ft \\$1
..
+.
+.RS
.TP
.B AR
.FT AR
AvantGarde-Book
.FT
+.
.TP
.B AI
.FT AI
AvantGarde-BookOblique
.FT
+.
.TP
.B AB
.FT AB
AvantGarde-Demi
.FT
+.
.TP
.B ABI
.FT ABI
AvantGarde-DemiOblique
.FT
+.
.TP
.B BMR
.FT BMR
Bookman-Light
.FT
+.
.TP
.B BMI
.FT BMI
Bookman-LightItalic
.FT
+.
.TP
.B BMB
.FT BMB
Bookman-Demi
.FT
+.
.TP
.B BMBI
.FT BMBI
Bookman-DemiItalic
.FT
+.
.TP
.B CR
.FT CR
Courier
.FT
+.
.TP
.B CI
.FT CI
Courier-Oblique
.FT
+.
.TP
.B CB
.FT CB
Courier-Bold
.FT
+.
.TP
.B CBI
.FT CBI
Courier-BoldOblique
.FT
+.
.TP
.B HR
.FT HR
Helvetica
.FT
+.
.TP
.B HI
.FT HI
Helvetica-Oblique
.FT
+.
.TP
.B HB
.FT HB
Helvetica-Bold
.FT
+.
.TP
.B HBI
.FT HBI
Helvetica-BoldOblique
.FT
+.
.TP
.B HNR
.FT HNR
Helvetica-Narrow
.FT
+.
.TP
.B HNI
.FT HNI
Helvetica-Narrow-Oblique
.FT
+.
.TP
.B HNB
.FT HNB
Helvetica-Narrow-Bold
.FT
+.
.TP
.B HNBI
.FT HNBI
Helvetica-Narrow-BoldOblique
.FT
+.
.TP
.B NR
.FT NR
NewCenturySchlbk-Roman
.FT
+.
.TP
.B NI
.FT NI
NewCenturySchlbk-Italic
.FT
+.
.TP
.B NB
.FT NB
NewCenturySchlbk-Bold
.FT
+.
.TP
.B NBI
.FT NBI
NewCenturySchlbk-BoldItalic
.FT
+.
.TP
.B PR
.FT PR
Palatino-Roman
.FT
+.
.TP
.B PI
.FT PI
Palatino-Italic
.FT
+.
.TP
.B PB
.FT PB
Palatino-Bold
.FT
+.
.TP
.B PBI
.FT PBI
Palatino-BoldItalic
.FT
+.
.TP
.B TR
.FT TR
Times-Roman
.FT
+.
.TP
.B TI
.FT TI
Times-Italic
.FT
+.
.TP
.B TB
.FT TB
Times-Bold
.FT
+.
.TP
.B TBI
.FT TBI
Times-BoldItalic
.FT
+.RE
+.
.LP
There is also the following font which is not a member of a family:
+.
+.RS
.TP
.B ZCMI
.FT ZCMI
ZapfChancery-MediumItalic
.FT
+.RE
+.
.LP
There are also some special fonts called
.B SS
-and
+and\~\c
.BR S .
+.
Zapf Dingbats is available as
.BR ZD
and a reversed version of ZapfDingbats (with symbols pointing in the opposite
direction) is available as
.BR ZDR ;
most characters in these fonts are unnamed and must be accessed using
-.BR \eN .
+.BR \[rs]N .
+.
+.LP
+The default color for
+.B \[rs]m
+and
+.B \[rs]M
+is black; for colors defined in the `rgb' color space,
+.B setrgbcolor
+is used, for `cmy' and `cmyk'
+.BR setcmykcolor ,
+and for `gray'
+.BR setgray .
+.
.LP
.B grops
-understands various X commands produced using the
-.B \eX
+understands various X\~commands produced using the
+.B \[rs]X
escape sequence;
.B grops
will only interpret commands that begin with a
.B ps:
tag.
+.
.TP
-.BI \eX'ps:\ exec\ code '
+.BI \[rs]X'ps:\ exec\ code '
This executes the arbitrary PostScript commands in
.IR code .
+.
The PostScript currentpoint will be set to the position of the
-.B \eX
+.B \[rs]X
command before executing
.IR code .
+.
The origin will be at the top left corner of the page,
-and y coordinates will increase down the page.
-A procedure
+and y\~coordinates will increase down the page.
+.
+A procedure\~\c
.B u
will be defined that converts groff units
to the coordinate system in effect.
+.
For example,
+.
.RS
.IP
.B
\&.nr x 1i
.br
.B
-\eX'ps: exec \enx u 0 rlineto stroke'
+\[rs]X'ps: exec \[rs]nx u 0 rlineto stroke'
.br
.RE
+.
.IP
will draw a horizontal line one inch long.
+.
.I code
may make changes to the graphics state,
but any changes will persist only to the
end of the page.
+.
A dictionary containing the definitions specified by the
.B def
and
.B mdef
will be on top of the dictionary stack.
+.
If your code adds definitions to this dictionary,
you should allocate space for them using
-.BI \eX'ps\ mdef \ n '\fR.
+.BI \[rs]X'ps\ mdef \ n '\fR.
+.
Any definitions will persist only until the end of the page.
+.
If you use the
-.B \eY
+.B \[rs]Y
escape sequence with an argument that names a macro,
.I code
can extend over multiple lines.
+.
For example,
+.
.RS
.IP
.nf
@@ -439,63 +573,74 @@ For example,
\&.nr x 1i
\&.de y
\&ps: exec
-\&\enx u 0 rlineto
+\&\[rs]nx u 0 rlineto
\&stroke
\&..
-\&\eYy
+\&\[rs]Yy
.fi
.ft R
+.
.LP
is another way to draw a horizontal line one inch long.
.RE
+.
.TP
-.BI \eX'ps:\ file\ name '
+.BI \[rs]X'ps:\ file\ name '
This is the same as the
.B exec
command except that the PostScript code is read from file
.IR name .
+.
.TP
-.BI \eX'ps:\ def\ code '
+.BI \[rs]X'ps:\ def\ code '
Place a PostScript definition contained in
.I code
in the prologue.
+.
There should be at most one definition per
-.B \eX
+.B \[rs]X
command.
+.
Long definitions can be split over several
-.B \eX
+.B \[rs]X
commands;
all the
.I code
arguments are simply joined together separated by newlines.
+.
The definitions are placed in a dictionary which is automatically
pushed on the dictionary stack when an
.B exec
command is executed.
+.
If you use the
-.B \eY
+.B \[rs]Y
escape sequence with an argument that names a macro,
.I code
can extend over multiple lines.
+.
.TP
-.BI \eX'ps:\ mdef\ n\ code '
+.BI \[rs]X'ps:\ mdef\ n\ code '
Like
.BR def ,
except that
.I code
may contain up to
-.I n
+.IR n \~\c
definitions.
+.
.B grops
needs to know how many definitions
.I code
contains
so that it can create an appropriately sized PostScript dictionary
to contain them.
+.
.TP
-.BI \eX'ps:\ import\ file\ llx\ lly\ urx\ ury\ width\ \fR[\fP\ height\ \fR]\fP '
+.BI \[rs]X'ps:\ import\ file\ llx\ lly\ urx\ ury\ width\ \fR[\fP\ height\ \fR]\fP '
Import a PostScript graphic from
.IR file .
+.
The arguments
.IR llx ,
.IR lly ,
@@ -507,26 +652,29 @@ coordinate system; they should all be integers;
.I llx
and
.I lly
-are the x and y coordinates of the lower left
+are the x and y\~coordinates of the lower left
corner of the graphic;
.I urx
and
.I ury
-are the x and y coordinates of the upper right corner of the graphic;
+are the x and y\~coordinates of the upper right corner of the graphic;
.I width
and
.I height
are integers that give the desired width and height in groff
units of the graphic.
+.
The graphic will be scaled so that it has this width and height
and translated so that the lower left corner of the graphic is
located at the position associated with
-.B \eX
+.B \[rs]X
command.
+.
If the height argument is omitted it will be scaled uniformly in the
-x and y directions so that it has the specified width.
+x and y\~directions so that it has the specified width.
+.
Note that the contents of the
-.B \eX
+.B \[rs]X
command are not interpreted by
.BR troff ;
so vertical space for the graphic is not automatically added,
@@ -535,6 +683,7 @@ and the
and
.I height
arguments are not allowed to have attached scaling indicators.
+.
If the PostScript file complies with the Adobe Document Structuring
Conventions and contains a
.B %%BoundingBox
@@ -542,6 +691,7 @@ comment, then the bounding box can be automatically
extracted from within groff by using the
.B psbb
request.
+.
.RS
.LP
The
@@ -551,10 +701,11 @@ macros (which are automatically loaded when
is run by the groff command) include a
.B PSPIC
macro which allows a picture to be easily imported.
+.
This has the format
.IP
-\&\fB.PSPIC\fP [ \fB\-L\fP | \fB-R\fP | \fB\-I\fP \fIn\fP ]\ \"
-\fI\|file\fP [ \fIwidth\fP [ \fIheight\fP ]]
+\&\fB.PSPIC\fP [\fB\-L\fP|\fB-R\fP|\fB\-I\fP \fIn\fP]\ \fI\|file\fP [\fIwidth\fP [\fIheight\fP]]
+.
.LP
.I file
is the name of the file containing the illustration;
@@ -562,42 +713,49 @@ is the name of the file containing the illustration;
and
.I height
give the desired width and height of the graphic.
+.
The
.I width
and
.I height
arguments may have scaling indicators attached;
-the default scaling indicator is
+the default scaling indicator is\~\c
.BR i .
+.
This macro will scale the graphic uniformly
-in the x and y directions so that it is no more than
+in the x and y\~directions so that it is no more than
.I width
wide
and
.I height
high.
+.
By default, the graphic will be horizontally centered.
+.
The
.BI \-L
and
.BI \-R
cause the graphic to be left-aligned and right-aligned
respectively.
+.
The
.B \-I
-option causes the graphic to be indented by
+option causes the graphic to be indented by\~\c
.IR n .
.RE
+.
.TP
-.B \eX'ps:\ invis'
+.B \[rs]X'ps:\ invis'
.br
.ns
.TP
-.B \eX'ps:\ endinvis'
+.B \[rs]X'ps:\ endinvis'
No output will be generated for text and drawing commands
that are bracketed with these
-.B \eX
+.B \[rs]X
commands.
+.
These commands are intended for use when output from
.B troff
will be previewed before being processed with
@@ -605,71 +763,94 @@ will be previewed before being processed with
if the previewer is unable to display certain characters
or other constructs, then other substitute characters or constructs
can be used for previewing by bracketing them with these
-.B \eX
+.B \[rs]X
commands.
+.
.RS
.LP
For example,
.B gxditview
is not able to display a proper
-.B \e(em
+.B \[rs](em
character because the standard X11 fonts do not provide it;
this problem can be overcome by executing the following
request
+.
.IP
.ft B
.nf
-\&.char \e(em \eX'ps: invis'\e
-\eZ'\ev'-.25m'\eh'.05m'\eD'l .9m 0'\eh'.05m''\e
-\eX'ps: endinvis'\e(em
+\&.char \[rs](em \[rs]X'ps: invis'\[rs]
+\[rs]Z'\[rs]v'-.25m'\[rs]h'.05m'\[rs]D'l .9m 0'\[rs]h'.05m''\[rs]
+\[rs]X'ps: endinvis'\[rs](em
.ft
.fi
+.
.LP
In this case,
.B gxditview
will be unable to display the
-.B \e(em
+.B \[rs](em
character and will draw the line,
whereas
.B grops
will print the
-.B \e(em
+.B \[rs](em
character
and ignore the line.
.RE
+.
.LP
The input to
.B grops
must be in the format output by
.BR @g@troff (@MAN1EXT@).
+.
This is described in
.BR groff_out (@MAN5EXT@).
+.
In addition the device and font description files for the device used
must meet certain requirements.
+.
The device and font description files supplied for
.B ps
device meet all these requirements.
+.
.BR afmtodit (@MAN1EXT@)
can be used to create font files from AFM files.
-The resolution must be an integer multiple of 72 times the
+.
+The resolution must be an integer multiple of\~72 times the
.BR sizescale .
+.
The
.B ps
device uses a resolution of 72000 and a sizescale of 1000.
+.
The device description file should contain a command
.IP
.BI paperlength\ n
.LP
which says that output should be generated which is suitable for
printing on a page whose length is
-.I n
+.IR n \~\c
machine units.
+.
+Common values are 792000 for letter paper and 841890 for paper in A4 format.
+.
+Alternatively, it can contain
+.IP
+.BI papersize\ string
+.LP
+to specify a paper size; see
+.BR groff_font (@MAN5EXT@)
+for more information.
+.
Each font description file must contain a command
.IP
.BI internalname\ psname
.LP
which says that the PostScript name of the font is
.IR psname .
+.
It may also contain a command
.IP
.BI encoding\ enc_file
@@ -688,36 +869,48 @@ is the PostScript name of the character,
and
.I code
is its position in the encoding expressed as a decimal integer.
+.
+Lines starting with
+.B #
+and blank lines are ignored.
+.
The code for each character given in the font file must correspond
to the code for the character in encoding file, or to the code in the default
encoding for the font if the PostScript font is not to be reencoded.
+.
This code can be used with the
-.B \eN
+.B \[rs]N
escape sequence in
.B troff
to select the character,
even if the character does not have a groff name.
+.
Every character in the font file must exist in the PostScript font, and
the widths given in the font file must match the widths used
in the PostScript font.
+.
.B grops
will assume that a character with a groff name of
.B space
is blank (makes no marks on the page);
it can make use of such a character to generate more efficient and
compact PostScript output.
+.
.LP
.B grops
can automatically include the downloadable fonts necessary
to print the document.
+.
Any downloadable fonts which should, when required, be included by
.B grops
must be listed in the file
.BR @FONTDIR@/devps/download ;
this should consist of lines of the form
+.
.IP
.I
-font filename
+font filename
+.
.LP
where
.I font
@@ -732,9 +925,12 @@ fields may be separated by tabs or spaces;
.I filename
will be searched for using the same mechanism that is used
for groff font metric files.
+.
The
.B download
-file itself will also be searched for using this mechanism.
+file itself will also be searched for using this mechanism;
+currently, only the first found file in the font path is used.
+.
.LP
If the file containing a downloadable font or imported document
conforms to the Adobe Document Structuring Conventions,
@@ -742,11 +938,14 @@ then
.B grops
will interpret any comments in the files sufficiently to ensure that its
own output is conforming.
+.
It will also supply any needed font resources that are listed in the
.B download
file
as well as any needed file resources.
+.
It is also able to handle inter-resource dependencies.
+.
For example, suppose that you have a downloadable font called Garamond,
and also a downloadable font called Garamond-Outline
which depends on Garamond
@@ -754,12 +953,14 @@ which depends on Garamond
and change the PaintType),
then it is necessary for Garamond to be appear before Garamond-Outline
in the PostScript document.
+.
.B grops
will handle this automatically
provided that the downloadable font file for Garamond-Outline
indicates its dependence on Garamond by means of
the Document Structuring Conventions,
for example by beginning with the following lines
+.
.IP
.B
%!PS-Adobe-3.0 Resource-Font
@@ -772,19 +973,23 @@ for example by beginning with the following lines
.br
.B
%%IncludeResource: font Garamond
+.
.LP
In this case both Garamond and Garamond-Outline would need to be listed
in the
.B download
file.
+.
A downloadable font should not include its own name in a
.B %%DocumentSuppliedResources
comment.
+.
.LP
.B grops
will not interpret
.B %%DocumentFonts
comments.
+.
The
.BR %%DocumentNeededResources ,
.BR %%DocumentSuppliedResources ,
@@ -802,6 +1007,38 @@ and
.BR %%EndFont
comments)
should be used.
+.
+.
+.SS TrueType fonts
+TrueType fonts can be used with
+.B grops
+if converted first to
+.B "Type 42"
+format, an especial PostScript wrapper equivalent to the
+PFA format mentioned in
+.BR pfbtops (@MAN1EXT@).
+There are several different methods to generate a type42
+wrapper and most of them involve the use of a PostScript
+interpreter such as Ghostscript \(em see
+.BR gs (1).
+Yet, the easiest method involves the use of the application
+.BR ttftot42 .
+This program uses
+.BR freetype (3)
+(version 1.3.1) to generate type42
+font wrappers and well-formed AFM files that can be fed to
+the
+.BR afmtodit (@MAN1EXT@)
+script to create appropriate metric files.
+The resulting font wrappers should be added to the
+.B download
+file.
+.B ttftot42
+source code can be downloaded from
+.URL ftp://\:www.giga.or.at/\:pub/\:nih/\:ttftot42/ \
+ ftp://\:www.giga.or.at/\:pub/\:nih/\:ttftot42/ .
+.
+.
.SH ENVIRONMENT
.TP
.SM
@@ -814,29 +1051,37 @@ will use the file
.I foo
(in the font path) instead of the default prologue file
.BR prologue .
+.
The option
.B \-P
overrides this environment variable.
+.
+.
.SH FILES
.Tp \w'\fB@FONTDIR@/devps/download'u+2n
.B @FONTDIR@/devps/DESC
Device description file.
+.
.TP
.BI @FONTDIR@/devps/ F
Font description file for font
.IR F .
+.
.TP
.B @FONTDIR@/devps/download
List of downloadable fonts.
+.
.TP
.B @FONTDIR@/devps/text.enc
Encoding used for text fonts.
+.
.TP
.B @MACRODIR@/ps.tmac
Macros for use with
.BR grops ;
automatically loaded by
.BR troffrc
+.
.TP
.B @MACRODIR@/pspic.tmac
Definition of
@@ -844,13 +1089,17 @@ Definition of
macro,
automatically loaded by
.BR ps.tmac .
+.
.TP
.B @MACRODIR@/psold.tmac
Macros to disable use of characters not present in older
PostScript printers (e.g. `eth' or `thorn').
+.
.TP
.BI /tmp/grops XXXXXX
Temporary file.
+.
+.
.SH "SEE ALSO"
.BR afmtodit (@MAN1EXT@),
.BR groff (@MAN1EXT@),
diff --git a/contrib/groff/src/devices/grops/ps.cc b/contrib/groff/src/devices/grops/ps.cc
index a467f04..47d1f65 100644
--- a/contrib/groff/src/devices/grops/ps.cc
+++ b/contrib/groff/src/devices/grops/ps.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)
@@ -23,6 +23,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "stringclass.h"
#include "cset.h"
#include "nonposix.h"
+#include "paper.h"
#include "ps.h"
#include <time.h>
@@ -42,6 +43,7 @@ static int linewidth = -1;
// Non-zero means generate PostScript code that guesses the paper
// length using the imageable area.
static int guess_flag = 0;
+static double user_paper_length = 0;
// Non-zero if -b was specified on the command line.
static int bflag = 0;
@@ -319,7 +321,7 @@ ps_output &ps_output::put_fix_number(int i)
ps_output &ps_output::put_float(double d)
{
char buf[128];
- sprintf(buf, "%.4f", d);
+ sprintf(buf, "%.3g", d);
int len = strlen(buf);
if (col > 0 && col + len + need_space > max_line_length) {
putc('\n', fp);
@@ -354,6 +356,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,13 +498,13 @@ class ps_printer : public printer {
int sbuf_space_code;
int sbuf_kern;
style sbuf_style;
+ 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;
- int fill;
unsigned char output_space_code;
enum { MAX_DEFINED_STYLES = 50 };
style defined_styles[MAX_DEFINED_STYLES];
@@ -504,13 +526,15 @@ 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 fill = 0);
+
public:
- ps_printer();
+ ps_printer(double);
~ps_printer();
void set_char(int i, font *f, const environment *env, int w, const char *name);
void draw(int code, int *p, int np, const environment *env);
@@ -521,14 +545,14 @@ public:
void end_of_line();
};
-ps_printer::ps_printer()
+// `pl' is in inches
+ps_printer::ps_printer(double pl)
: out(0, MAX_LINE_LENGTH),
pages_output(0),
sbuf_len(0),
output_hpos(-1),
output_vpos(-1),
line_thickness(-1),
- fill(FILL_MAX + 1),
ndefined_styles(0),
next_encoding_index(0),
ndefs(0),
@@ -553,9 +577,12 @@ ps_printer::ps_printer()
res = r;
out.set_fixed_point(point);
space_char_index = font::name_to_index("space");
- paper_length = font::paperlength;
+ if (pl == 0)
+ paper_length = font::paperlength;
+ else
+ paper_length = int(pl * font::res + 0.5);
if (paper_length == 0)
- paper_length = 11*font::res;
+ paper_length = 11 * font::res;
equalise_spaces = font::res >= 72000;
}
@@ -590,7 +617,8 @@ void ps_printer::set_char(int i, font *f, const environment *env, int w, const c
if (sbuf_len > 0) {
if (sbuf_len < SBUF_SIZE
&& sty == sbuf_style
- && sbuf_vpos == env->vpos) {
+ && sbuf_vpos == env->vpos
+ && sbuf_color == *env->col) {
if (sbuf_end_hpos == env->hpos) {
sbuf[sbuf_len++] = code;
sbuf_end_hpos += w + sbuf_kern;
@@ -645,6 +673,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;
+ if (sbuf_color != *env->col)
+ set_color(env->col);
}
static char *make_encoding_name(int encoding_index)
@@ -693,7 +723,8 @@ void ps_printer::define_encoding(const char *encoding, int encoding_index)
a_delete vec[i];
}
}
- out.put_delimiter(']').put_symbol("def");
+ out.put_delimiter(']')
+ .put_symbol("def");
}
void ps_printer::reencode_font(ps_font *f)
@@ -759,18 +790,60 @@ void ps_printer::set_style(const style &sty)
int h = sty.height == 0 ? sty.point_size : sty.height;
h *= font::res/(72*font::sizescale);
int c = int(h*tan(radians(sty.slant)) + .5);
- out.put_fix_number(c).put_fix_number(h).put_literal_symbol(psname)
+ out.put_fix_number(c)
+ .put_fix_number(h)
+ .put_literal_symbol(psname)
.put_symbol("MF");
}
else {
- out.put_literal_symbol(psname).put_symbol("SF");
+ out.put_literal_symbol(psname)
+ .put_symbol("SF");
}
defined_styles[ndefined_styles++] = sty;
}
+void ps_printer::set_color(color *col, int fill)
+{
+ 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)
{
- out.put_literal_symbol("SC").put_number(c).put_symbol("def");
+ out.put_literal_symbol("SC")
+ .put_number(c)
+ .put_symbol("def");
}
void ps_printer::end_of_line()
@@ -863,39 +936,43 @@ 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) {
// we ought to check for overflow here
int lw = ((font::res/(72*font::sizescale))*linewidth*env->size)/1000;
- out.put_fix_number(lw).put_symbol("LW");
+ out.put_fix_number(lw)
+ .put_symbol("LW");
output_draw_point_size = env->size;
output_line_thickness = -1;
}
}
else {
if (output_line_thickness != line_thickness) {
- out.put_fix_number(line_thickness).put_symbol("LW");
+ out.put_fix_number(line_thickness)
+ .put_symbol("LW");
output_line_thickness = line_thickness;
output_draw_point_size = -1;
}
}
+ if (sbuf_color != *env->col)
+ set_color(env->col);
}
-void ps_printer::fill_path()
+void ps_printer::fill_path(const environment *env)
{
- if (fill > FILL_MAX)
- out.put_symbol("BL");
+ if (sbuf_color == *env->fill)
+ out.put_symbol("FL");
else
- out.put_float(transform_fill(fill)).put_symbol("FL");
+ 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':
@@ -911,11 +988,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;
@@ -924,7 +1000,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)
@@ -944,11 +1020,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;
@@ -973,11 +1048,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;
@@ -1015,7 +1089,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;
@@ -1025,7 +1099,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]))
@@ -1043,60 +1117,47 @@ void ps_printer::draw(int code, int *p, int np, const environment *env)
}
break;
case 't':
- {
- if (np == 0) {
- line_thickness = -1;
- }
- else {
- // troff gratuitously adds an extra 0
- if (np != 1 && np != 2) {
- error("0 or 1 argument required for thickness");
- break;
- }
- line_thickness = p[0];
- }
- break;
- }
- case 'f':
- {
+ if (np == 0)
+ line_thickness = -1;
+ else {
+ // troff gratuitously adds an extra 0
if (np != 1 && np != 2) {
- error("1 argument required for fill");
+ error("0 or 1 argument required for thickness");
break;
}
- fill = p[0];
- if (fill < 0 || fill > FILL_MAX) {
- // This means fill with the current color.
- fill = FILL_MAX + 1;
- }
- break;
- }
+ line_thickness = p[0];
+ }
+ break;
default:
error("unrecognised drawing command `%1'", char(code));
break;
}
-
output_hpos = output_vpos = -1;
}
-
void ps_printer::begin_page(int n)
{
- out.begin_comment("Page:").comment_arg(i_to_a(n));
- out.comment_arg(i_to_a(++pages_output)).end_comment();
+ out.begin_comment("Page:")
+ .comment_arg(i_to_a(n));
+ out.comment_arg(i_to_a(++pages_output))
+ .end_comment();
output_style.f = 0;
output_space_code = 32;
output_draw_point_size = -1;
output_line_thickness = -1;
output_hpos = output_vpos = -1;
ndefined_styles = 0;
- out.simple_comment("BeginPageSetup");
- out.put_symbol("BP");
- out.simple_comment("EndPageSetup");
+ out.simple_comment("BeginPageSetup")
+ .put_symbol("BP")
+ .simple_comment("EndPageSetup");
+ if (sbuf_color != default_color)
+ set_color(&sbuf_color);
}
void ps_printer::end_page(int)
{
flush_sbuf();
+ set_color(&default_color);
out.put_symbol("EP");
if (invis_count != 0) {
error("missing `endinvis' command");
@@ -1111,9 +1172,9 @@ font *ps_printer::make_font(const char *nm)
ps_printer::~ps_printer()
{
- out.simple_comment("Trailer");
- out.put_symbol("end");
- out.simple_comment("EOF");
+ out.simple_comment("Trailer")
+ .put_symbol("end")
+ .simple_comment("EOF");
if (fseek(tempfp, 0L, 0) < 0)
fatal("fseek on temporary file failed");
fputs("%!PS-Adobe-", stdout);
@@ -1142,8 +1203,12 @@ ps_printer::~ps_printer()
rm.need_font(psf->get_internal_name());
}
rm.print_header_comments(out);
- out.begin_comment("Pages:").comment_arg(i_to_a(pages_output)).end_comment();
- out.begin_comment("PageOrder:").comment_arg("Ascend").end_comment();
+ out.begin_comment("Pages:")
+ .comment_arg(i_to_a(pages_output))
+ .end_comment();
+ out.begin_comment("PageOrder:")
+ .comment_arg("Ascend")
+ .end_comment();
#if 0
fprintf(out.get_file(), "%%%%DocumentMedia: () %g %g 0 () ()\n",
font::paperwidth*72.0/font::res,
@@ -1164,7 +1229,8 @@ ps_printer::~ps_printer()
out.simple_comment("BeginSetup");
}
rm.document_setup(out);
- out.put_symbol(dict_name).put_symbol("begin");
+ out.put_symbol(dict_name)
+ .put_symbol("begin");
if (ndefs > 0)
ndefs += DEFS_DICT_SPARE;
out.put_literal_symbol(defs_dict_name)
@@ -1184,8 +1250,12 @@ ps_printer::~ps_printer()
out.special(defs.contents());
out.put_symbol("end");
if (ncopies != 1)
- out.put_literal_symbol("#copies").put_number(ncopies).put_symbol("def");
- out.put_literal_symbol("RES").put_number(res).put_symbol("def");
+ out.put_literal_symbol("#copies")
+ .put_number(ncopies)
+ .put_symbol("def");
+ out.put_literal_symbol("RES")
+ .put_number(res)
+ .put_symbol("def");
out.put_literal_symbol("PL");
if (guess_flag)
out.put_symbol("PLG");
@@ -1246,7 +1316,7 @@ void ps_printer::special(char *arg, const environment *env, char type)
for (; *p != '\0' && *p != ' ' && *p != '\n'; p++)
;
if (*command == '\0') {
- error("X command without `ps:' tag ignored");
+ error("empty X command ignored");
return;
}
for (unsigned int i = 0; i < sizeof(proc_table)/sizeof(proc_table[0]); i++)
@@ -1474,7 +1544,7 @@ void ps_printer::do_endinvis(char *, const environment *)
printer *make_printer()
{
- return new ps_printer;
+ return new ps_printer(user_paper_length);
}
static void usage(FILE *stream);
@@ -1491,21 +1561,23 @@ int main(int argc, char **argv)
{ "version", no_argument, 0, 'v' },
{ NULL, 0, 0, 0 }
};
- while ((c = getopt_long(argc, argv, "F:P:glmc:w:vb:", long_options, NULL))
+ while ((c = getopt_long(argc, argv, "b:c:F:glmp:P:vw:", long_options, NULL))
!= EOF)
switch(c) {
- case 'v':
- {
- printf("GNU grops (groff) version %s\n", Version_string);
- exit(0);
- break;
- }
+ case 'b':
+ // XXX check this
+ broken_flags = atoi(optarg);
+ bflag = 1;
+ break;
case 'c':
if (sscanf(optarg, "%d", &ncopies) != 1 || ncopies <= 0) {
error("bad number of copies `%s'", optarg);
ncopies = 1;
}
break;
+ case 'F':
+ font::command_line_font_dir(optarg);
+ break;
case 'g':
guess_flag = 1;
break;
@@ -1515,8 +1587,9 @@ int main(int argc, char **argv)
case 'm':
manual_feed_flag = 1;
break;
- case 'F':
- font::command_line_font_dir(optarg);
+ case 'p':
+ if (!font::scan_papersize(optarg, 0, &user_paper_length, 0))
+ error("invalid custom paper size `%1' ignored", optarg);
break;
case 'P':
env = "GROPS_PROLOGUE";
@@ -1526,17 +1599,16 @@ int main(int argc, char **argv)
if (putenv(strsave(env.contents())))
fatal("putenv failed");
break;
+ case 'v':
+ printf("GNU grops (groff) version %s\n", Version_string);
+ exit(0);
+ break;
case 'w':
if (sscanf(optarg, "%d", &linewidth) != 1 || linewidth < 0) {
error("bad linewidth `%1'", optarg);
linewidth = -1;
}
break;
- case 'b':
- // XXX check this
- broken_flags = atoi(optarg);
- bflag = 1;
- break;
case CHAR_MAX + 1: // --help
usage(stdout);
exit(0);
diff --git a/contrib/groff/src/devices/grops/ps.h b/contrib/groff/src/devices/grops/ps.h
index 6e78597..0e149fc 100644
--- a/contrib/groff/src/devices/grops/ps.h
+++ b/contrib/groff/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/contrib/groff/src/devices/grops/psrm.cc b/contrib/groff/src/devices/grops/psrm.cc
index 5f232c0..f2177da 100644
--- a/contrib/groff/src/devices/grops/psrm.cc
+++ b/contrib/groff/src/devices/grops/psrm.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)
@@ -389,7 +389,7 @@ static int ps_get_line(char *buf, FILE *fp)
int err = 0;
while (c != '\r' && c != '\n' && c != EOF) {
if ((c < 0x1b && !white_space(c)) || c == 0x7f)
- error("illegal input character code %1", int(c));
+ error("invalid input character code %1", int(c));
else if (i < PS_LINE_MAX)
buf[i++] = c;
else if (!err) {
@@ -724,6 +724,32 @@ int read_one_of(const char **ptr, const char **s, int n)
return -1;
}
+void skip_possible_newline(const char *ptr, FILE *fp, FILE *outfp)
+{
+ int c = getc(fp);
+ if (c == '\r') {
+ current_lineno++;
+ if (outfp)
+ putc(c, outfp);
+ int cc = getc(fp);
+ if (cc != '\n') {
+ if (cc != EOF)
+ ungetc(cc, fp);
+ }
+ else {
+ if (outfp)
+ putc(cc, outfp);
+ }
+ }
+ else if (c == '\n') {
+ current_lineno++;
+ if (outfp)
+ putc(c, outfp);
+ }
+ else if (c != EOF)
+ ungetc(c, fp);
+}
+
int resource_manager::do_begin_data(const char *ptr, int, FILE *fp,
FILE *outfp)
{
@@ -790,6 +816,7 @@ int resource_manager::do_begin_data(const char *ptr, int, FILE *fp,
}
} while ((unit == Bytes ? bytecount : linecount) < numberof);
}
+ skip_possible_newline(ptr, fp, outfp);
char buf[PS_LINE_MAX + 2];
if (!ps_get_line(buf, fp)) {
error("missing %%%%EndData line");
@@ -826,11 +853,12 @@ int resource_manager::do_begin_binary(const char *ptr, int, FILE *fp,
if (cc != '\n')
current_lineno++;
if (cc != EOF)
- ungetc(c, fp);
+ ungetc(cc, fp);
}
else if (c == '\n')
current_lineno++;
}
+ skip_possible_newline(ptr, fp, outfp);
char buf[PS_LINE_MAX + 2];
if (!ps_get_line(buf, fp)) {
error("missing %%%%EndBinary line");
diff --git a/contrib/groff/src/devices/grotty/Makefile.sub b/contrib/groff/src/devices/grotty/Makefile.sub
index 91d3908..8802674 100644
--- a/contrib/groff/src/devices/grotty/Makefile.sub
+++ b/contrib/groff/src/devices/grotty/Makefile.sub
@@ -1,6 +1,6 @@
-PROG=grotty
+PROG=grotty$(EXEEXT)
MAN1=grotty.n
XLIBS=$(LIBDRIVER) $(LIBGROFF)
MLIB=$(LIBM)
-OBJS=tty.o
+OBJS=tty.$(OBJEXT)
CCSRCS=$(srcdir)/tty.cc
diff --git a/contrib/groff/src/devices/grotty/tty.cc b/contrib/groff/src/devices/grotty/tty.cc
index d13adbf..81183b8 100644
--- a/contrib/groff/src/devices/grotty/tty.cc
+++ b/contrib/groff/src/devices/grotty/tty.cc
@@ -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.
@@ -23,6 +23,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
extern "C" const char *Version_string;
+#define putstring(s) fputs(s, stdout)
+
#ifndef SHRT_MIN
#define SHRT_MIN (-32768)
#endif
@@ -39,18 +41,42 @@ static int bold_flag = 1;
static int underline_flag = 1;
static int overstrike_flag = 1;
static int draw_flag = 1;
+static int italic_flag = 0;
+static int old_drawing_scheme = 0;
enum {
UNDERLINE_MODE = 0x01,
BOLD_MODE = 0x02,
VDRAW_MODE = 0x04,
HDRAW_MODE = 0x08,
- CU_MODE = 0x10
+ CU_MODE = 0x10,
+ COLOR_CHANGE = 0x20
};
// Mode to use for bold-underlining.
static unsigned char bold_underline_mode = BOLD_MODE|UNDERLINE_MODE;
+#ifndef IS_EBCDIC_HOST
+#define CSI "\033["
+#else
+#define CSI "\047["
+#endif
+
+// SGR handling (ISO 6429)
+#define SGR_BOLD CSI "1m"
+#define SGR_NO_BOLD CSI "22m"
+#define SGR_ITALIC CSI "3m"
+#define SGR_NO_ITALIC CSI "23m"
+#define SGR_UNDERLINE CSI "4m"
+#define SGR_NO_UNDERLINE CSI "24m"
+// many terminals can't handle `CSI 39 m' and `CSI 49 m' to reset
+// the foreground and bachground color, respectively; thus we use
+// `CSI 0 m' exclusively
+#define SGR_DEFAULT CSI "0m"
+
+#define TTY_MAX_COLORS 8
+#define DEFAULT_COLOR_IDX TTY_MAX_COLORS
+
class tty_font : public font {
tty_font(const char *);
unsigned char mode;
@@ -109,10 +135,13 @@ public:
short hpos;
unsigned int code;
unsigned char mode;
+ unsigned char back_color_idx;
+ unsigned char fore_color_idx;
void *operator new(size_t);
void operator delete(void *);
inline int draw_mode() { return mode & (VDRAW_MODE|HDRAW_MODE); }
- inline int order() { return mode & (VDRAW_MODE|HDRAW_MODE|CU_MODE); }
+ inline int order() {
+ return mode & (VDRAW_MODE|HDRAW_MODE|CU_MODE|COLOR_CHANGE); }
};
glyph *glyph::free_list = 0;
@@ -146,14 +175,26 @@ class tty_printer : public printer {
int nlines;
int cached_v;
int cached_vpos;
- void add_char(unsigned int, int, int, unsigned char);
+ unsigned char curr_fore_idx;
+ unsigned char curr_back_idx;
+ int is_underline;
+ int is_bold;
+ int cu_flag;
+ color tty_colors[TTY_MAX_COLORS];
+ void make_underline();
+ void make_bold(unsigned int);
+ unsigned char color_to_idx(color *col);
+ void add_char(unsigned int, int, int, color *, color *, unsigned char);
public:
tty_printer(const char *device);
~tty_printer();
void set_char(int, font *, const environment *, int, const char *name);
void draw(int code, int *p, int np, const environment *env);
void special(char *arg, const environment *env, char type);
+ void change_color(const environment *env);
+ void change_fill_color(const environment *env);
void put_char(unsigned int);
+ void put_color(unsigned char, int);
void begin_page(int) { }
void end_page(int page_length);
font *make_font(const char *);
@@ -162,10 +203,35 @@ public:
tty_printer::tty_printer(const char *device) : cached_v(0)
{
is_utf8 = !strcmp(device, "utf8");
+ tty_colors[0].set_rgb(0, // black
+ 0,
+ 0);
+ tty_colors[1].set_rgb(color::MAX_COLOR_VAL, // red
+ 0,
+ 0);
+ tty_colors[2].set_rgb(0, // green
+ color::MAX_COLOR_VAL,
+ 0);
+ tty_colors[3].set_rgb(color::MAX_COLOR_VAL, // yellow
+ color::MAX_COLOR_VAL,
+ 0);
+ tty_colors[4].set_rgb(0, // blue
+ 0,
+ color::MAX_COLOR_VAL);
+ tty_colors[5].set_rgb(color::MAX_COLOR_VAL, // magenta
+ 0,
+ color::MAX_COLOR_VAL);
+ tty_colors[6].set_rgb(0, // cyan
+ color::MAX_COLOR_VAL,
+ color::MAX_COLOR_VAL);
+ tty_colors[7].set_rgb(color::MAX_COLOR_VAL, // white
+ color::MAX_COLOR_VAL,
+ color::MAX_COLOR_VAL);
nlines = 66;
lines = new glyph *[nlines];
for (int i = 0; i < nlines; i++)
lines[i] = 0;
+ cu_flag = 0;
}
tty_printer::~tty_printer()
@@ -173,15 +239,64 @@ tty_printer::~tty_printer()
a_delete lines;
}
+void tty_printer::make_underline()
+{
+ if (old_drawing_scheme) {
+ putchar('_');
+ putchar('\b');
+ }
+ else {
+ if (!is_underline) {
+ if (italic_flag)
+ putstring(SGR_ITALIC);
+ else
+ putstring(SGR_UNDERLINE);
+ }
+ is_underline = 1;
+ }
+}
+
+void tty_printer::make_bold(unsigned int c)
+{
+ if (old_drawing_scheme) {
+ put_char(c);
+ putchar('\b');
+ }
+ else {
+ if (!is_bold)
+ putstring(SGR_BOLD);
+ is_bold = 1;
+ }
+}
+
+unsigned char tty_printer::color_to_idx(color *col)
+{
+ if (col->is_default())
+ return DEFAULT_COLOR_IDX;
+ for (int i = 0; i < TTY_MAX_COLORS; i++)
+ if (*col == tty_colors[i])
+ return (unsigned char)i;
+ unsigned r, g, b;
+ col->get_rgb(&r, &g, &b);
+ error("Unknown color (%1, %2, %3) mapped to default", r, g, b);
+ return DEFAULT_COLOR_IDX;
+}
+
void tty_printer::set_char(int i, font *f, const environment *env,
int w, const char *name)
{
if (w != font::hor)
fatal("width of character not equal to horizontal resolution");
- add_char(f->get_code(i), env->hpos, env->vpos, ((tty_font *)f)->get_mode());
+ add_char(f->get_code(i),
+ env->hpos, env->vpos,
+ env->col, env->fill,
+ ((tty_font *)f)->get_mode());
}
-void tty_printer::add_char(unsigned int c, int h, int v, unsigned char mode)
+void tty_printer::add_char(unsigned int c,
+ int h, int v,
+ color *fore, color *back,
+ unsigned char mode)
{
#if 0
// This is too expensive.
@@ -221,12 +336,14 @@ void tty_printer::add_char(unsigned int c, int h, int v, unsigned char mode)
glyph *g = new glyph;
g->hpos = hpos;
g->code = c;
+ g->fore_color_idx = color_to_idx(fore);
+ g->back_color_idx = color_to_idx(back);
g->mode = mode;
// The list will be reversed later. After reversal, it must be in
- // increasing order of hpos, with CU specials before HDRAW characters
- // before VDRAW characters before normal characters at each hpos, and
- // otherwise in order of occurrence.
+ // increasing order of hpos, with COLOR_CHANGE and CU specials before
+ // HDRAW characters before VDRAW characters before normal characters
+ // at each hpos, and otherwise in order of occurrence.
glyph **pp;
for (pp = lines + (vpos - 1); *pp; pp = &(*pp)->next)
@@ -239,8 +356,51 @@ void tty_printer::add_char(unsigned int c, int h, int v, unsigned char mode)
void tty_printer::special(char *arg, const environment *env, char type)
{
- if (type == 'u')
- add_char(*arg - '0', env->hpos, env->vpos, CU_MODE);
+ if (type == 'u') {
+ add_char(*arg - '0', env->hpos, env->vpos, env->col, env->fill, CU_MODE);
+ return;
+ }
+ if (type != 'p')
+ return;
+ char *p;
+ for (p = arg; *p == ' ' || *p == '\n'; p++)
+ ;
+ char *tag = p;
+ for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++)
+ ;
+ if (*p == '\0' || strncmp(tag, "tty", p - tag) != 0) {
+ error("X command without `tty:' tag ignored");
+ return;
+ }
+ p++;
+ for (; *p == ' ' || *p == '\n'; p++)
+ ;
+ char *command = p;
+ for (; *p != '\0' && *p != ' ' && *p != '\n'; p++)
+ ;
+ if (*command == '\0') {
+ error("empty X command ignored");
+ return;
+ }
+ if (strncmp(command, "sgr", p - command) == 0) {
+ for (; *p == ' ' || *p == '\n'; p++)
+ ;
+ int n;
+ if (*p != '\0' && sscanf(p, "%d", &n) == 1 && n == 0)
+ old_drawing_scheme = 1;
+ else
+ old_drawing_scheme = 0;
+ }
+}
+
+void tty_printer::change_color(const environment *env)
+{
+ add_char(0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE);
+}
+
+void tty_printer::change_fill_color(const environment *env)
+{
+ add_char(0, env->hpos, env->vpos, env->col, env->fill, COLOR_CHANGE);
}
void tty_printer::draw(int code, int *p, int np, const environment *env)
@@ -260,7 +420,7 @@ void tty_printer::draw(int code, int *p, int np, const environment *env)
len = -len;
}
while (len >= 0) {
- add_char('|', env->hpos, v, VDRAW_MODE);
+ add_char('|', env->hpos, v, env->col, env->fill, VDRAW_MODE);
len -= font::vert;
v += font::vert;
}
@@ -274,7 +434,7 @@ void tty_printer::draw(int code, int *p, int np, const environment *env)
len = -len;
}
while (len >= 0) {
- add_char('-', h, env->vpos, HDRAW_MODE);
+ add_char('-', h, env->vpos, env->col, env->fill, HDRAW_MODE);
len -= font::hor;
h += font::hor;
}
@@ -302,14 +462,37 @@ void tty_printer::put_char(unsigned int wc)
do *++p = (unsigned char)(((wc >> (6 * --count)) & 0x3f) | 0x80);
while (count > 0);
*++p = '\0';
- fputs(buf, stdout);
+ putstring(buf);
}
- else {
+ else
putchar(wc);
- }
}
-int cu_flag = 0;
+void tty_printer::put_color(unsigned char color_index, int back)
+{
+ if (color_index == DEFAULT_COLOR_IDX) {
+ putstring(SGR_DEFAULT);
+ // set bold and underline again
+ if (is_bold)
+ putstring(SGR_BOLD);
+ if (is_underline) {
+ if (italic_flag)
+ putstring(SGR_ITALIC);
+ else
+ putstring(SGR_UNDERLINE);
+ }
+ // set other color again
+ back = !back;
+ color_index = back ? curr_back_idx : curr_fore_idx;
+ }
+ putstring(CSI);
+ if (back)
+ putchar('4');
+ else
+ putchar('3');
+ putchar(color_index + '0');
+ putchar('m');
+}
void tty_printer::end_page(int page_length)
{
@@ -345,6 +528,10 @@ void tty_printer::end_page(int page_length)
}
int hpos = 0;
glyph *nextp;
+ curr_fore_idx = DEFAULT_COLOR_IDX;
+ curr_back_idx = DEFAULT_COLOR_IDX;
+ is_underline = 0;
+ is_bold = 0;
for (p = g; p; delete p, p = nextp) {
nextp = p->next;
if (p->mode & CU_MODE) {
@@ -376,34 +563,79 @@ void tty_printer::end_page(int page_length)
int next_tab_pos = ((hpos + TAB_WIDTH) / TAB_WIDTH) * TAB_WIDTH;
if (next_tab_pos > p->hpos)
break;
- if (cu_flag) {
- putchar('_');
- putchar('\b');
+ if (cu_flag)
+ make_underline();
+ else if (!old_drawing_scheme && is_underline) {
+ if (italic_flag)
+ putstring(SGR_NO_ITALIC);
+ else
+ putstring(SGR_NO_UNDERLINE);
+ is_underline = 0;
}
putchar('\t');
hpos = next_tab_pos;
}
}
for (; hpos < p->hpos; hpos++) {
- if (cu_flag) {
- putchar('_');
- putchar('\b');
+ if (cu_flag)
+ make_underline();
+ else if (!old_drawing_scheme && is_underline) {
+ if (italic_flag)
+ putstring(SGR_NO_ITALIC);
+ else
+ putstring(SGR_NO_UNDERLINE);
+ is_underline = 0;
}
putchar(' ');
}
}
assert(hpos == p->hpos);
- if (p->mode & UNDERLINE_MODE) {
- putchar('_');
- putchar('\b');
+ if (p->mode & COLOR_CHANGE) {
+ if (!old_drawing_scheme) {
+ if (p->fore_color_idx != curr_fore_idx) {
+ put_color(p->fore_color_idx, 0);
+ curr_fore_idx = p->fore_color_idx;
+ }
+ if (p->back_color_idx != curr_back_idx) {
+ put_color(p->back_color_idx, 1);
+ curr_back_idx = p->back_color_idx;
+ }
+ }
+ continue;
+ }
+ if (p->mode & UNDERLINE_MODE)
+ make_underline();
+ else if (!old_drawing_scheme && is_underline) {
+ if (italic_flag)
+ putstring(SGR_NO_ITALIC);
+ else
+ putstring(SGR_NO_UNDERLINE);
+ is_underline = 0;
}
- if (p->mode & BOLD_MODE) {
- put_char(p->code);
- putchar('\b');
+ if (p->mode & BOLD_MODE)
+ make_bold(p->code);
+ else if (!old_drawing_scheme && is_bold) {
+ putstring(SGR_NO_BOLD);
+ is_bold = 0;
+ }
+ if (!old_drawing_scheme) {
+ if (p->fore_color_idx != curr_fore_idx) {
+ put_color(p->fore_color_idx, 0);
+ curr_fore_idx = p->fore_color_idx;
+ }
+ if (p->back_color_idx != curr_back_idx) {
+ put_color(p->back_color_idx, 1);
+ curr_back_idx = p->back_color_idx;
+ }
}
put_char(p->code);
hpos++;
}
+ if (!old_drawing_scheme
+ && (is_bold || is_underline
+ || curr_fore_idx != DEFAULT_COLOR_IDX
+ || curr_back_idx != DEFAULT_COLOR_IDX))
+ putstring(SGR_DEFAULT);
putchar('\n');
}
if (form_feed_flag) {
@@ -432,6 +664,8 @@ int main(int argc, char **argv)
{
program_name = argv[0];
static char stderr_buf[BUFSIZ];
+ if (getenv("GROFF_NO_SGR"))
+ old_drawing_scheme = 1;
setbuf(stderr, stderr_buf);
int c;
static const struct option long_options[] = {
@@ -439,19 +673,25 @@ int main(int argc, char **argv)
{ "version", no_argument, 0, 'v' },
{ NULL, 0, 0, 0 }
};
- while ((c = getopt_long(argc, argv, "F:vhfbuoBUd", long_options, NULL))
+ while ((c = getopt_long(argc, argv, "F:vhfbciuoBUd", long_options, NULL))
!= EOF)
switch(c) {
case 'v':
- {
- printf("GNU grotty (groff) version %s\n", Version_string);
- exit(0);
- break;
- }
+ printf("GNU grotty (groff) version %s\n", Version_string);
+ exit(0);
+ break;
+ case 'i':
+ // Use italic font instead of underlining.
+ italic_flag = 1;
+ break;
case 'b':
// Do not embolden by overstriking.
bold_flag = 0;
break;
+ case 'c':
+ // Use old scheme for emboldening and underline.
+ old_drawing_scheme = 1;
+ break;
case 'u':
// Do not underline.
underline_flag = 0;
@@ -493,6 +733,13 @@ int main(int argc, char **argv)
default:
assert(0);
}
+ if (old_drawing_scheme)
+ italic_flag = 0;
+ else {
+ bold_underline_mode = BOLD_MODE|UNDERLINE_MODE;
+ bold_flag = 1;
+ underline_flag = 1;
+ }
if (optind >= argc)
do_file("-");
else {
@@ -505,6 +752,6 @@ int main(int argc, char **argv)
static void usage(FILE *stream)
{
- fprintf(stream, "usage: %s [-hfvbuodBU] [-F dir] [files ...]\n",
+ fprintf(stream, "usage: %s [-hfvbciuodBU] [-F dir] [files ...]\n",
program_name);
}
OpenPOWER on IntegriCloud