summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog123
-rw-r--r--Makefile.in6
-rwxr-xr-xdoc/Makefile4
-rw-r--r--doc/groff.texinfo60
-rwxr-xr-xdoc/homepage.ms12
-rwxr-xr-xfont/devhtml2/DESC.proto12
-rwxr-xr-xfont/devhtml2/Makefile.sub33
-rwxr-xr-xfont/devhtml2/R.proto308
-rw-r--r--man/groff_font.man4
-rwxr-xr-xsrc/devices/grohtml/ChangeLog263
-rw-r--r--src/devices/grohtml/Makefile.sub12
-rwxr-xr-xsrc/devices/grohtml/TODO294
-rwxr-xr-xsrc/devices/grohtml/design.ms129
-rw-r--r--src/devices/grohtml/grohtml.man97
-rwxr-xr-xsrc/devices/grohtml/html-chars.h (renamed from src/devices/grohtml/html_chars.h)4
-rw-r--r--src/devices/grohtml/html-text.cc649
-rw-r--r--src/devices/grohtml/html-text.h97
-rwxr-xr-xsrc/devices/grohtml/html.cc6607
-rw-r--r--src/devices/grohtml/html.h15
-rwxr-xr-xsrc/devices/grohtml/ordered_list.h193
-rw-r--r--src/devices/grohtml/output.cc146
-rw-r--r--src/devices/grohtml/post-html.cc2667
-rwxr-xr-xsrc/devices/grohtml2/Makefile.in9
-rwxr-xr-xsrc/devices/grohtml2/Makefile.sub9
-rwxr-xr-xsrc/devices/grohtml2/post-html.cc93
-rw-r--r--[-rwxr-xr-x]src/include/html-strings.h (renamed from src/preproc/html2/pre-html.h)23
-rwxr-xr-xsrc/include/htmlindicate.h30
-rw-r--r--src/include/printer.h3
-rw-r--r--src/libs/libdriver/printer.cc10
-rwxr-xr-xsrc/libs/libgroff/htmlindicate.cc69
-rw-r--r--src/preproc/eqn/main.cc14
-rwxr-xr-xsrc/preproc/html2/Makefile.sub7
-rwxr-xr-xsrc/preproc/html2/image.cc448
-rwxr-xr-xsrc/preproc/html2/pre-html.cc773
-rwxr-xr-xsrc/preproc/html2/pushbackbuffer.cc308
-rwxr-xr-xsrc/preproc/html2/pushbackbuffer.h53
-rw-r--r--src/preproc/pic/troff.cc7
-rw-r--r--src/preproc/tbl/main.cc13
-rw-r--r--src/roff/groff/groff.cc18
-rw-r--r--src/roff/troff/div.cc2
-rw-r--r--src/roff/troff/env.cc139
-rw-r--r--src/roff/troff/env.h7
-rw-r--r--src/roff/troff/input.cc199
-rw-r--r--src/roff/troff/node.cc434
-rw-r--r--src/roff/troff/node.h56
-rw-r--r--src/roff/troff/reg.h5
-rw-r--r--src/roff/troff/request.h8
-rw-r--r--src/roff/troff/troff.h5
-rw-r--r--tmac/Makefile.sub4
-rw-r--r--tmac/an-old.tmac32
-rwxr-xr-xtmac/arkup.tmac162
-rw-r--r--tmac/eqnrc14
-rw-r--r--tmac/groff_man.man2
-rwxr-xr-xtmac/groff_mwww.man (renamed from tmac/groff_markup.man)119
-rwxr-xr-xtmac/groff_tmac.man2
-rwxr-xr-xtmac/html-old.tmac (renamed from tmac/html2.tmac)8
-rwxr-xr-xtmac/html-tags.tmac49
-rw-r--r--tmac/html.tmac42
-rwxr-xr-xtmac/mwww.tmac (renamed from tmac/markup.tmac)0
-rw-r--r--tmac/pspic.tmac26
-rw-r--r--tmac/s.tmac68
-rw-r--r--tmac/troffrc5
-rw-r--r--tmac/troffrc-end17
-rw-r--r--tmac/www.tmac213
64 files changed, 5023 insertions, 10217 deletions
diff --git a/ChangeLog b/ChangeLog
index e17ee97a..f61fc9f0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,126 @@
+2000-01-15 Gaius Mulley <gaius@glam.ac.uk>
+
+ First cut of the new html device driver. Changes to pre-html and
+ the new grohtml are too numerous to be documented here.
+
+ Stuff related to `html' has been renamed to `html-old' and `html2'
+ stuff has been renamed to `html' (including directories). The new
+ html device driver is therefore invoked as `-Thtml'.
+
+ Added new `\O' escape to suppress output (needed by html driver).
+
+ Added functions and code to pass info about input-level commands
+ (`.in', `.fl', etc.) to html driver.
+
+ Three new functions (.html-begin, .html-end, and .html-image) for
+ better html handling: `html-begin' will execute the remaining line
+ if at the outermost nesting level, increasing an internal counter.
+ `html-end' does the same but decreases the internal counter.
+ `html_image' puts its arguments into a special node (suppress_node)
+ to define an image region.
+
+ The `output' request has been removed.
+
+ * tmac/html-tags.tmac: Removed.
+ * tmac/arkup.tmac: Updated and renamed to ...
+ * tmac/www.tmac: New file.
+ * tmac/markup.tmac Updated and renamed to ...
+ * tmac/mwww.tmac: New file.
+ * tmac/Makefile.sub: Updated.
+ * tmac/an-old.tmac: Updated.
+ * tmac/eqnrc: Updated.
+ * tmac/groff_man.man
+ * tmac/groff_markup.man: Updated and renamed to ...
+ * tmac/groff_mwww.man: New file.
+ * tmac/groff_tmac.man: Updated.
+ * tmac/html-old.tmac: Updated and Renamed from html.tmac.
+ * tmac/html.tmac: Updated and renamed from html2.tmac.
+ * tmac/pspic.tmac: Updated html support.
+ * tmac/s.tmac: Added html output support.
+ * tmac/troffrc, tmac/troffrc-end: Updated.
+
+ * Makefile.in, doc/Makefile: Updated.
+ * doc/groff.texinfo: Added info about new `\O' escape.
+ * doc/homepage.ms: Use `MAILTO' macro.
+
+ * font/devhtml/DESC.proto: Add `C' font.
+ * font/devhtml/Makefile.sub: Updated.
+ * font/devhtml/R.proto: Minor fixes.
+ * font/devhtml-old/Makefile.sub: Updated.
+
+ * src/devices/grohtml-old/Makefile.sub: Updated.
+
+ * src/libs/libdriver/printer.cc (printer::get_font_from_index): New
+ method.
+ * src/libs/libgroff/htmlindicate.cc (html_begin_suppress,
+ graphic_start): Add `inline' parameter. Update.
+ (html_end_suppress, graphic_end): Update.
+
+ * src/include/html-strings.h: New file.
+ * src/include/htmlindicate.h: Comments updated.
+ * src/include/printer.h: Updated.
+
+ * src/preproc/eqn/main.cc (do_file, main): Updated.
+ * src/preproc/pic/troff.cc (troff_output::start_picture,
+ troff_output::finish_picture): Updated.
+ * src/preproc/tbl/main.cc (process_input_file): Updated.
+
+ * src/roff/groff/groff.cc (main): Updated.
+ Pass device arguments to predrivers also.
+ Use `ps' device for `eqn' preprocessor if `-Thtml' is given.
+ * src/roff/troff/env.h (environment): Updated.
+ New elements `need_eol' and `ignore_next_eol' (for html output).
+ * src/roff/troff/env.cc (environment::environment): Add initializers
+ for `need_eol' and `ignore_next_eol'.
+ (environment::add_html_tag_eol, environment::add_html_tag_tabs): New
+ functions.
+ (point_size, fill, no_fill, center, right_justify, line_length,
+ indent, temporary_indent, break_request, handle_tab): Use
+ `add_html_tag()'.
+ (set_tabs): Use `add_html_tag_tabs()'.
+ (environment::add_html_tag): Updated.
+ (environment::do_break): Updated.
+ * src/roff/troff/div.cc (space_request, flush_output): Use
+ `environment::add_html_tag()'.
+ * src/roff/troff/input.cc: Updated.
+ New variable `html_level' to indicate nested `html-begin' requests.
+ (file_iterator::fill): Use `environment::add_html_tag_eol()'.
+ (non_interpreted_char_node, token_node, non_interpreted_node): Add
+ `force_tprint()' method.
+ (token::next): Handle `\O'.
+ (do_suppress): Implement it.
+ (html_begin, html_end, html_image): New functions.
+ (init_output_requests): Renamed to ...
+ (init_html_requests): this.
+ (main): Use it.
+ (macro::append_str, macro::append_unsigned, macro::append_int): New
+ methods.
+ New variable `output_low_mark_miny' to limit minimal value of y.
+ (reset_output_registers): Use it.
+ (output_request): Removed.
+ (get_output_registers): New function.
+ * src/roff/troff/node.h (node): Make `force_tprint()' virtual.
+ (*_node): Added `force_tprint()' if necessary.
+ (special_node): New elements `tf' and `get_tfont()'.
+ (suppress_node): New class.
+ * src/roff/troff/node.cc:
+ New global variables `image_no' and `suppress_start_page'.
+ (real_output_file): New method `is_on()'.
+ (troff_output_file): New method `start_special(tfont)'.
+ (troff_output_file::really_print_line): Use `tprint' conditionally.
+ (real_output_file::print_line): Updated.
+ (real_output_file::on): Updated.
+ (*_node): Added `force_tprint()'.
+ (special_node::special_node): Initializer updated.
+ (special_node::same, special_node::copy, special_node::tprint_start):
+ Updated.
+ (get_reg_int, get_reg_str): New functions.
+ (suppress_node::*): New methods.
+ New global variables last_position, last_image_filename;
+ (min): New inline function.
+ * src/roff/troff/reg.h, src/roff/troff/request.h,
+ src/roff/troff/troff.h: Updated.
+
2001-01-13 Werner LEMBERG <wl@gnu.org>
* NEWS, src/roff/troff/troff.man, doc/groff.texinfo: Fix
diff --git a/Makefile.in b/Makefile.in
index 4d8870e7..602a812e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -341,13 +341,13 @@ CCPROGDIRS=\
src/preproc/grn \
src/preproc/refer \
src/preproc/soelim \
- src/preproc/html2 \
+ src/preproc/html \
src/devices/grops \
src/devices/grotty \
src/devices/grodvi \
src/devices/grolj4 \
src/devices/grohtml \
- src/devices/grohtml2 \
+ src/devices/grohtml-old \
src/devices/grolbp \
src/utils/tfmtodit \
src/utils/hpftodit \
@@ -366,7 +366,7 @@ DEVDIRS=\
font/devX100-12 \
font/devlj4 \
font/devhtml \
- font/devhtml2 \
+ font/devhtml-old \
font/devlbp
ALLTTYDEVDIRS=\
font/devascii \
diff --git a/doc/Makefile b/doc/Makefile
index 57abf327..408e6e12 100755
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -54,13 +54,13 @@ all: $(DOCS)
GROFF_TMAC_PATH=../tmac; \
export GROFF_TMAC_PATH; \
sed -e "s;@VERSION@;$(version)$(revision);" $< \
- | $(GROFF) -Tascii $(FFLAG) -U -ms -markup >$@
+ | $(GROFF) -Tascii $(FFLAG) -U -ms -mwww >$@
.ms.ps:
GROFF_TMAC_PATH=../tmac; \
export GROFF_TMAC_PATH; \
sed -e "s;@VERSION@;$(version)$(revision);" $< \
- | $(GROFF) -Tps $(FFLAG) -U -ms -markup >$@
+ | $(GROFF) -Tps $(FFLAG) -U -ms -mwww >$@
.texinfo.dvi:
texi2dvi -e $<
diff --git a/doc/groff.texinfo b/doc/groff.texinfo
index 58fd6da6..b35b7c92 100644
--- a/doc/groff.texinfo
+++ b/doc/groff.texinfo
@@ -1081,7 +1081,7 @@ accessible via @code{groff}. This option prevents the loading of the
Make programs run by @code{groff} print out their version number.
@item -V
-Print the pipeline on stdout instead of executing it.
+Print the pipeline on @code{stdout} instead of executing it.
@item -z
Suppress output from @code{gtroff}. Only error messages will be
@@ -1352,7 +1352,7 @@ groff file
@noindent
This command processes @file{file} without a macro package or a
preprocessor. The output device is the default, @samp{ps}, and the
-output is sent to stdout.
+output is sent to @code{stdout}.
@example
groff -t -mandoc -Tascii file | less
@@ -2174,7 +2174,7 @@ in italic.
@cindex @file{man}, default indentation
@cindex default indentation, @file{man}
The default indentation is 7.2@dmn{n} for all output devices except for
-@code{grohtml} which uses 1.2@dmn{i} instead.
+@code{grohtml} which ignores indentation.
@maindex DT
@maindex TH
@@ -2329,6 +2329,7 @@ Users of macro packages may skip it if not interested in details.
* Traps::
* Diversions::
* Environments::
+* Suppressing output::
* I/O::
* Postprocessor Access::
* Miscellaneous::
@@ -6362,7 +6363,7 @@ name.
This would be called as
@example
-.vl $Id: groff.texinfo,v 1.62 2001/01/13 21:49:18 wlemb Exp $
+.vl $Id: groff.texinfo,v 1.63 2001/01/17 14:17:18 wlemb Exp $
@end example
@xref{Request Arguments}.
@@ -7063,7 +7064,7 @@ hacks; for example, the following will set register @code{n} to@w{ }1.
@c =====================================================================
-@node Environments, I/O, Diversions, Programming Tutorial
+@node Environments, Suppressing output, Diversions, Programming Tutorial
@section Environments
@cindex environments
@@ -7150,7 +7151,46 @@ which takes the name of the environment to copy from as an argument.
@c =====================================================================
-@node I/O, Postprocessor Access, Environments, Programming Tutorial
+@node Suppressing output, I/O, Environments, Programming Tutorial
+@section Suppressing output
+@cindex suppressing output
+
+@findex \O
+@code{gtroff} allows the programmer to disable resp.@: enable output
+through the use of the @code{\O} escape:
+
+@table @samp
+@item \O0
+Disable any ditroff glyphs from being emitted to the device driver.
+
+@item \O1
+Enable output of glyphs.
+@end table
+
+The previous commands also reset the four registers @samp{opminx},
+@samp{opminy}, @samp{opmaxx}, and @samp{opmaxy} to -1. @xref{Register
+Index}. These four registers mark the top left and bottom right hand
+corners of a box which encompasses all written glyphs.
+
+The following two parameter of @code{\O} are @code{grohtml} device
+specific.
+
+@table @samp
+@item \O2
+Disable any ditroff glyphs from being emitted to the device driver. Also
+write out to @code{stderr} the page number and four registers encompassing
+the glyphs previously written since the last call to @code{\O}.
+
+@item \O3
+Enable output of glyphs (the default). Also write out to @code{stderr}
+the page number and four registers encompassing the glyphs previously
+written since the last call to @code{\O}.
+@end table
+
+
+@c =====================================================================
+
+@node I/O, Postprocessor Access, Suppressing output, Programming Tutorial
@section I/O
@cindex i/o
@cindex input and output requests
@@ -7501,16 +7541,16 @@ The @code{pm} request will dump out the entire symbol table.
@cindex dumping number registers
@cindex number registers, dumping
The @code{pnr} request will print the names and contents of all
-currently defined number registers on stderr.
+currently defined number registers on @code{stderr}.
@item
@findex ptr
@cindex dumping traps
@cindex traps, dumping
The @code{ptr} request will print the names and positions of all traps
-(not including input line traps and diversion traps) on stderr. Empty
-slots in the page trap list are printed as well, because they can affect
-the priority of subsequently planted traps.
+(not including input line traps and diversion traps) on @code{stderr}.
+Empty slots in the page trap list are printed as well, because they can
+affect the priority of subsequently planted traps.
@item
@findex fl
diff --git a/doc/homepage.ms b/doc/homepage.ms
index ccf81319..00da216f 100755
--- a/doc/homepage.ms
+++ b/doc/homepage.ms
@@ -139,16 +139,18 @@ bug-groff@gnu.org for reporting bugs
groff@gnu.org for general discussion of groff
groff-commit@ffii.org a read-only list showing logs of
commitments to the CVS repository
-\fR
+\fP
.fi
.RE
.sp
.LP
-Note that groff@gnu.org is an alias for groff@ffii.org; you must be
-subscribed to the `groff' and `groff-commit' lists to send mails.
+Note that groff@gnu.org is an alias for
+.MAILTO groff@ffii.org groff@ffii.org ;
+you must be subscribed to the `groff' and `groff-commit' lists to send mails.
.LP
To subscribe, send e-mail to [list]-request@[domain] (example:
-groff-request@ffii.org) with the word `subscribe' in either the
+.MAILTO groff-request@ffii.org groff-request@ffii.org )
+with the word `subscribe' in either the
subject or body of the e-mail (don't include the quotes).
.LP
GNU groff was written by
@@ -157,6 +159,6 @@ It is now maintained by
.MAILTO Ted.Harding@nessie.mcc.ac.uk "Ted Harding"
and
.MAILTO wl@gnu.org "Werner Lemberg" .
-.LINE
+.br
.
.\" EOF
diff --git a/font/devhtml2/DESC.proto b/font/devhtml2/DESC.proto
deleted file mode 100755
index ba27fba0..00000000
--- a/font/devhtml2/DESC.proto
+++ /dev/null
@@ -1,12 +0,0 @@
-res 240
-hor 24
-vert 40
-unitwidth 10
-sizes 10 0
-fonts 5 R I B BI S
-tcommand
-html
-postpro post-grohtml
-prepro pre-grohtml
-use_charnames_in_special
-pass_filenames
diff --git a/font/devhtml2/Makefile.sub b/font/devhtml2/Makefile.sub
deleted file mode 100755
index f973e9d2..00000000
--- a/font/devhtml2/Makefile.sub
+++ /dev/null
@@ -1,33 +0,0 @@
-DEV=html2
-PROTOFONTS=R I B BI
-FONTS=$(PROTOFONTS) S
-DEVFILES=$(FONTS) DESC
-CLEANADD=$(FONTS) DESC
-
-RES=240
-CPI=10
-LPI=6
-
-$(FONTS): R.proto
- @echo Making $@
- @-rm -f $@
- @(charwidth=`expr $(RES) / $(CPI)` ; \
- sed -e "s/^name [A-Z]*$$/name $@/" \
- -e "s/^\\([^ ]*\\) [0-9]+ /\\1 $$charwidth /" \
- -e "s/^spacewidth [0-9]+$$/spacewidth $$charwidth/" \
- -e "s/^internalname .*$$/internalname $@/" \
- -e "/^internalname/s/BI/3/" \
- -e "/^internalname/s/B/2/" \
- -e "/^internalname/s/I/1/" \
- -e "/^internalname .*[^ 0-9]/d" \
- $(srcdir)/R.proto >$@)
-
-DESC: DESC.proto
- @echo Making $@
- @-rm -f $@
- @sed -e "s/^res .*$$/res $(RES)/" \
- -e "s/^hor .*$$/hor `expr $(RES) / $(CPI)`/" \
- -e "s/^vert .*$$/vert `expr $(RES) / $(LPI)`/" \
- -e "s/^fonts .*$$/fonts `set $(FONTS); echo $$#` $(FONTS)/" \
- $(srcdir)/DESC.proto >$@
-
diff --git a/font/devhtml2/R.proto b/font/devhtml2/R.proto
deleted file mode 100755
index cb0e0799..00000000
--- a/font/devhtml2/R.proto
+++ /dev/null
@@ -1,308 +0,0 @@
-name R
-internalname 0
-spacewidth 24
-charset
-! 24 0 0x0021
-" 24 0 0x0022 &quot;
-dq "
-# 24 0 0x0023
-sh "
-$ 24 0 0x0024
-Do "
-% 24 0 0x0025
-& 24 0 0x0026 &amp;
-aq 24 0 0x0027
-( 24 0 0x0028
-) 24 0 0x0029
-* 24 0 0x002A
-+ 24 0 0x002B
-pl "
-, 24 0 0x002C
-\- 24 0 00002D
-hy "
-- "
-. 24 0 0x002E
-/ 24 0 0x002F
-sl "
-0 24 0 0x0030
-1 24 0 0x0031
-2 24 0 0x0032
-3 24 0 0x0033
-4 24 0 0x0034
-5 24 0 0x0035
-6 24 0 0x0036
-7 24 0 0x0037
-8 24 0 0x0038
-9 24 0 0x0039
-: 24 0 0x003A
-; 24 0 0x003B
-< 24 0 0x003C &lt;
-= 24 0 0x003D
-eq "
-> 24 0 0x003E &gt;
-? 24 0 0x003F
-@ 24 0 0x0040
-at "
-A 24 0 0x0041
-B 24 0 0x0042
-C 24 0 0x0043
-D 24 0 0x0044
-E 24 0 0x0045
-F 24 0 0x0046
-G 24 0 0x0047
-H 24 0 0x0048
-I 24 0 0x0049
-J 24 0 0x004A
-K 24 0 0x004B
-L 24 0 0x004C
-M 24 0 0x004D
-N 24 0 0x004E
-O 24 0 0x004F
-P 24 0 0x0050
-Q 24 0 0x0051
-R 24 0 0x0052
-S 24 0 0x0053
-T 24 0 0x0054
-U 24 0 0x0055
-V 24 0 0x0056
-W 24 0 0x0057
-X 24 0 0x0058
-Y 24 0 0x0059
-Z 24 0 0x005A
-[ 24 0 0x005B
-lB "
-\ 24 0 0x005C
-rs "
-] 24 0 0x005D
-rB "
-a^ 24 0 0x005E
-^ "
-ha "
-_ 24 0 0x005F
-ru "
-ul "
-\` 24 0 0x0060
-ga "
-a 24 0 0x0061
-b 24 0 0x0062
-c 24 0 0x0063
-d 24 0 0x0064
-e 24 0 0x0065
-f 24 0 0x0066
-g 24 0 0x0067
-h 24 0 0x0068
-i 24 0 0x0069
-j 24 0 0x006A
-k 24 0 0x006B
-l 24 0 0x006C
-m 24 0 0x006D
-n 24 0 0x006E
-o 24 0 0x006F
-p 24 0 0x0070
-q 24 0 0x0071
-r 24 0 0x0072
-s 24 0 0x0073
-t 24 0 0x0074
-u 24 0 0x0075
-v 24 0 0x0076
-w 24 0 0x0077
-x 24 0 0x0078
-y 24 0 0x0079
-z 24 0 0x007A
-lC 24 0 0x007B
-{ "
-ba 24 0 0x007C
-or "
-| "
-rC 24 0 0x007D
-} "
-a~ 24 0 0x007E
-~ "
-ti "
-r! 24 0 0x00A1 &iexcl;
-char161 "
-ct 24 0 0x00A2 &cent;
-char162 "
-Po 24 0 0x00A3 &pound;
-char163 "
-Cs 24 0 0x00A4 &curren;
-char164 "
-Ye 24 0 0x00A5 &yen;
-char165 "
-bb 24 0 0x00A6 &brvbar;
-char166 "
-sc 24 0 0x00A7 &sect;
-char167 "
-ad 24 0 0x00A8 &uml;
-char168 "
-co 24 0 0x00A9 &copy;
-char169 "
-Of 24 0 0x00AA &ordf;
-char170 "
-Fo 24 0 0x00AB &laquo;
-char171 "
-no 24 0 0x00AC &not;
-char172 "
-rg 24 0 0x00AE &reg;
-char174 "
-a- 24 0 0x00AF &macr;
-char175 "
-de 24 0 0x00B0 &deg;
-char176 "
-+- 24 0 0x00B1 &plusmn;
-char177 "
-S2 24 0 0x00B2 &sup2;
-char178 "
-S3 24 0 0x00B3 &sup3;
-char179 "
-aa 24 0 0x00B4 &acute;
-char180 "
-char181 24 0 0x00B5 &micro;
-ps 24 0 0x00B6 &para;
-char182 "
-pc 24 0 0x00B7 &middot;
-char183 "
-ac 24 0 0x00B8 &cedil;
-char184 "
-S1 24 0 0x00B9 &sup1;
-char185 "
-Om 24 0 0x00BA &ordm;
-char186 "
-Fc 24 0 0x00BB &raquo;
-char187 "
-14 24 0 0x00BC &frac14;
-char188 "
-12 24 0 0x00BD &frac12;
-char189 "
-34 24 0 0x00BE &frac34;
-char190 "
-r? 24 0 0x00BF &iquest;
-char191 "
-`A 24 0 0x00C0 &Agrave;
-char192 "
-'A 24 0 0x00C1 &Aacute;
-char193 "
-^A 24 0 0x00C2 &Acirc;
-char194 "
-~A 24 0 0x00C3 &Atilde;
-char195 "
-:A 24 0 0x00C4 &Auml;
-char196 "
-oA 24 0 0x00C5 &Aring;
-char197 "
-AE 24 0 0x00C6 &AElig;
-char198 "
-,C 24 0 0x00C7 &Ccedil;
-char199 "
-`E 24 0 0x00C8 &Egrave;
-char200 "
-'E 24 0 0x00C9 &Eacute;
-char201 "
-^E 24 0 0x00CA &Ecirc;
-char202 "
-:E 24 0 0x00CB &Euml;
-char203 "
-`I 24 0 0x00CC &Igrave;
-char204 "
-'I 24 0 0x00CD &Iacute;
-char205 "
-^I 24 0 0x00CE &Icirc;
-char206 "
-:I 24 0 0x00CF &Iuml;
-char207 "
--D 24 0 0x00D0 &ETH;
-char208 "
-~N 24 0 0x00D1 &Ntilde;
-char209 "
-`O 24 0 0x00D2 &Ograve;
-char210 "
-'O 24 0 0x00D3 &Oacute;
-char211 "
-^O 24 0 0x00D4 &Ocirc;
-char212 "
-~O 24 0 0x00D5 &Otilde;
-char213 "
-:O 24 0 0x00D6 &Ouml;
-char214 "
-mu 24 0 0x00D7 &times;
-char215 "
-/O 24 0 0x00D8 &Oslash;
-char216 "
-`U 24 0 0x00D9 &Ugrave;
-char217 "
-'U 24 0 0x00DA &Uacute;
-char218 "
-^U 24 0 0x00DB &Ucirc;
-char219 "
-:U 24 0 0x00DC &Uuml;
-char220 "
-'Y 24 0 0x00DD &Yacute;
-char221 "
-TP 24 0 0x00DE &THORN;
-char222 "
-ss 24 0 0x00DF &szlig;
-char223 "
-`a 24 0 0x00E0 &agrave;
-char224 "
-'a 24 0 0x00E1 &aacute;
-char225 "
-^a 24 0 0x00E2 &acirc;
-char226 "
-~a 24 0 0x00E3 &atilde;
-char227 "
-:a 24 0 0x00E4 &auml;
-char228 "
-oa 24 0 0x00E5 &aring;
-char229 "
-ae 24 0 0x00E6 &aelig;
-char230 "
-,c 24 0 0x00E7 &ccedil;
-char231 "
-`e 24 0 0x00E8 &egrave;
-char232 "
-'e 24 0 0x00E9 &eacute;
-char233 "
-^e 24 0 0x00EA &ecirc;
-char234 "
-:e 24 0 0x00EB &euml;
-char235 "
-`i 24 0 0x00EC &igrave;
-char236 "
-'i 24 0 0x00ED &iacute;
-char237 "
-^i 24 0 0x00EE &icirc;
-char238 "
-:i 24 0 0x00EF &iuml;
-char239 "
-Sd 24 0 0x00F0 &eth;
-char240 "
-~n 24 0 0x00F1 &ntilde;
-char241 "
-`o 24 0 0x00F2 &ograve;
-char242 "
-'o 24 0 0x00F3 &oacute;
-char243 "
-^o 24 0 0x00F4 &ocirc;
-char244 "
-~o 24 0 0x00F5 &otilde;
-char245 "
-:o 24 0 0x00F6 &ouml;
-char246 "
-di 24 0 0x00F7 &divide;
-char247 "
-/o 24 0 0x00F8 &oslash;
-char248 "
-`u 24 0 0x00F9 &ugrave;
-char249 "
-'u 24 0 0x00FA &uacute;
-char250 "
-^u 24 0 0x00FB &ucirc;
-char251 "
-:u 24 0 0x00FC &uuml;
-char252 "
-'y 24 0 0x00FD &yacute;
-char253 "
-Tp 24 0 0x00FE &thorn;
-char254 "
-:y 24 0 0x00FF &yuml;
-char255 "
diff --git a/man/groff_font.man b/man/groff_font.man
index 8b9e3b40..c2f7461e 100644
--- a/man/groff_font.man
+++ b/man/groff_font.man
@@ -1,5 +1,5 @@
.ig \"-*- nroff -*-
-Copyright (C) 1989-1995 Free Software Foundation, Inc.
+Copyright (C) 1989-1995, 2001 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
@@ -250,7 +250,7 @@ otherwise it corresponds to the groff input character
(if it is exactly two characters
.I xx
it can be entered as
-.BI \e( xx\fR.)
+.BI \e( xx\fR).
Groff supports eight bit characters; however some utilities
has difficulties with eight bit characters.
For this reason, there is a convention that the name
diff --git a/src/devices/grohtml/ChangeLog b/src/devices/grohtml/ChangeLog
deleted file mode 100755
index 4b574384..00000000
--- a/src/devices/grohtml/ChangeLog
+++ /dev/null
@@ -1,263 +0,0 @@
-2000-11-16 Werner LEMBERG <wl@gnu.org>
-
- * html.cc (main): Use stdout for -v.
-
- Fixing copyright dates.
-
-2000-11-15 Werner LEMBERG <wl@gnu.org>
-
- * html.cc (main): Make -v exit immediately to be compliant with
- the GNU standard.
-
-2000-08-23 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc (char_translate_to_html): New function.
- (str_translate_to_html): Use it.
-
-2000-06-17 Eli Zaretskii <eliz@is.elta.co.il>
-
- * html.cc [!_POSIX_VERSION]: Include limits.h and dirent.h or
- sys/dir.h. Define NAME_MAX using MAXNAMLEN. Include nonposix.h.
- (file_name_max): New function.
- (html_printer::make_new_image_name): If the filesystem doesn't
- support file names longer than 14 characters, use a shorter
- image_name string.
- (html_printer::convert_to_image): Enlarge the size of buffer[] to
- accomodate 2 temp file names plus some slack. Don't put \n at the
- end of commands passed to system(). Redirect stderr to the null
- device programmatically, not via the shell. Use NULL_DEV, not
- literal "/dev/null". Print diagnostics if any calls to system()
- failed.
-
-2000-05-31 Keith Thompson <kst@SDSC.EDU>
-
- * html.cc: Added declaration of mktemp() as needed for SunOS 4.1.3.
-
-2000-05-11 Werner LEMBERG <wl@gnu.org>
-
- * output.cc (simple_output::simple_output): Reordering of
- initializers to remove compiler warning.
-
-2000-04-28 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc (calculate_margin): Calculate the left and right margin
- irrespective of the boolean `margin_on'. Fixes a divide by zero bug
- and a column bug as reported by Steve Blinkhorn <steve@prd.co.uk>.
- Improved the behaviour of the -m (margin on) option.
-
- * html.cc (make_html_indent): More checking.
-
- * html.cc (right_indentation): Fixed substitution slip-up.
-
-2000-03-30 Werner LEMBERG <wl@gnu.org>
-
- * grohtml.man: Document use of whitespace between command line
- arguments and its parameters.
-
-2000-03-17 Werner LEMBERG <wl@gnu.org>
-
- * grohtml.man: Some formatting.
-
-2000-03-11 Werner LEMBERG <wl@gnu.org>
-
- * ordered_list.h (list_element): Added `<T>' twice to satisfy picky
- compilers.
-
-2000-03-01 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc (handle_unknown_font_command): Removed dead code as
- spotted by Werner.
-
-2000-02-11 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc (create_tmp_file, create_temp_name): Removed. It has been
- replaced with calls to xtmpfile() and xtmptemplate().
-
-2000-02-07 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc (html_printer::make_new_image_name): Tidied up file and
- fixed name of image if the source file is in a different directory.
-
- * html.cc (create_file): Renamed to create_tmp_file.
-
-2000-02-07 Colin Phipps <crp22@cam.ac.uk>
-
- * html.cc (create_file): Identified & fixed security bug when
- creating files in /tmp.
-
-2000-02-06 Werner LEMBERG <wl@gnu.org>
-
- * Makefile.sub: Adapted to new directory structure.
-
-2000-01-28 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc: Minor fixes.
-
-2000-01-27 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc: Added support for the new tcommand `F'.
- * TODO: Updated.
-
-2000-01-24 Gaius Mulley <gaius@glam.ac.uk>
-
- * design.ms: Revised. Removed TODO stuff.
-
- * TODO: New file.
-
-2000-01-21 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc: Add support for char names in special requests (to
- support e.g. accented characters in HTML specials).
-
-2000-01-14 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc, html.h: Many fixes to table code.
-
- Fixes to manual page handling, font changes, spaces, and
- diacritical characters. All *standard* html character encodings
- are handled.
-
- Added -T option which turns off all image generation for tables.
- One day grohtml should be able to determine this for itself.
-
- Altered image name to: <groff_input_file>-<index>.png as per
- Werners suggestion.
-
- * grohtml.man: Document -T option.
-
- * html_chars.h: New file, providing diacritical table support.
-
- * output.cc: New file, providing basic output routines for grohtml.
-
- * Makefile.sub: Added output.cc.
-
- * Makefile.dep: Updated.
-
-2000-01-13 Bruno Haible <haible@clisp.cons.org>
-
- * html.cc: Avoid most "g++ -Wall -Wno-sign-compare" warnings.
-
-2000-01-10 Werner Lemberg <wl@gnu.org>
-
- * html.cc: Use Version_string instead of version_string.
-
-1999-12-30 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc (is_appropriate_to_start_table): Added a missing
- declaration.
-
-1999-12-28 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc: Revisited the table handling code with a vengeance,
- aiming to make manual pages generate sensible html.
- Superscripting/subscripting revisited. Fixed wierd table lengths.
- Table widths are now specified in percentages. Fixed the man.n
- test example which Werner reported.
-
-Version 1.15 released
-=====================
-
-1999-12-21 Werner LEMBERG <wl@gnu.org>
-
- * grohtml.man: Fixed copyright year.
-
-1999-12-15 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc: Some other fixes.
-
-1999-12-13 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc (main): Added new option `-x' to help debugging tables.
-
-1999-12-11 Gaius Mulley <gaius@glam.ac.uk>
-
- * html.cc: Fixed image position bugs. However, three major bugs
- remain: Firstly, grohtml sometimes miscalculates the end of an
- html table resulting in text which appears twice. Secondly,
- equation numbers are not handled correctly. Thirdly, equation
- macros and pic macros can confuse grohtml; this can be seen by
- nested `graphic-start's -- I believe the best method to solve this
- is to detect .EQ, .EN, .TS, .TE, .PS, .PE sequences in troff and
- add the graphic-start special character at this point.
-
- * grohtml.man: Minor fixes.
-
-1999-11-29 Gaius Mulley <gaius@glam.ac.uk>
-
- * design.ms: More updates; added some basic introductional
- information.
-
- * html.cc: Fixed more bugs mainly in the table handling code.
- Making the code terminate a table at the correct position.
- Indented .IPs appear to work now. Region ends also correctly
- terminate tables.
-
-1999-11-16 Gaius Mulley <gaius@glam.ac.uk>
-
- * design.ms, grohtml.man: Updated.
-
- * html.cc, ordered_list.h: Fixed many bugs in the table handling
- code. Reverted the -t switch so that table handling code is used
- by default and users must turn it off with -t.
-
- Manual page generation using `groff -Thtml -man' is much better
- due in large part to the table code and minor alterations in
- tmac.an.
-
-1999-10-30 Gaius Mulley <gaius@glam.ac.uk>
-
- * implemented auto formatting and introduced html table
- code. Fixed several text handling bugs and grohtml will
- detect centered lines - an offshoot of the html table code.
-
- * reverted meaning of grohtml's `-a' switch: using -a means that
- output will be preformatted.
-
-1999-10-05 Gaius Mulley <gaius@glam.ac.uk>
-
- * Introduced command line options -r to determine the resolution
- of generated images, -I to determine the format of images
- generated.
-
- * Fixed many bugs to do with superscripts, subscripts,
- indentation, font changes, and extraneous spaces.
-
- * Fixed bug in determining the range of polygons and splines.
-
- * Updated the manual page to reflect the new options.
-
- * The default image type is png format, however this will only
- work if you have a gs with a png output device. If you don't have
- a gs with this ability you can either reconfigure html to generate
- gif images by default (alter a #define in html.cc). Or
- alternatively you can use the -Igif option.
-
-1999-09-27 Werner LEMBERG <wl@gnu.org>
-
- * html.cc (move_horizontal): Fonts have changed one character too
- late.
-
-1999-09-26 Werner LEMBERG <wl@gnu.org>
-
- * grohtml.man: Minor cosmetic fixes.
-
-1999-09-25 Gaius Mulley <gaius@glam.ac.uk>
-
- * grohtml.man, html.cc: Rewrite of the html text component. Basic
- font faces supported together with font types. Superscript and
- subscript have also been implemented. Temporarily removed the
- -P-a switch on grohtml as it is not working (never worked). This
- is the next `to do'. Added a simple macro tmac.arkup which
- contains simple html features. This macro needs further work.
- Arc, spline, polygon fill have all been added and arc max/min xy
- limits are calculated, the same needs to be done for spline. Many
- bugs have been fixed regarding basic html text.
-
- * design.ms: New file describing how html.cc works.
-
-Aug 1999
-
- Initial release, very basic html text generated, quite ugly text
- is generated according to many reports :-) Equations, tables,
- pictures generate gif files via gs and ppmquant, ppmtogif, grops.
-
diff --git a/src/devices/grohtml/Makefile.sub b/src/devices/grohtml/Makefile.sub
index a1e301f0..2c3a55a5 100644
--- a/src/devices/grohtml/Makefile.sub
+++ b/src/devices/grohtml/Makefile.sub
@@ -1,10 +1,16 @@
-PROG=grohtml
+PROG=post-grohtml
MAN1=grohtml.n
XLIBS=$(LIBDRIVER) $(LIBGROFF)
MLIB=$(LIBM)
OBJS=\
- html.o \
+ post-html.o \
+ html-text.o \
output.o
CCSRCS=\
- $(srcdir)/html.cc \
+ $(srcdir)/post-html.cc \
+ $(srcdir)/html-text.cc \
$(srcdir)/output.cc
+HDRS=\
+ $(srcdir)/html.h \
+ $(srcdir)/html-chars.h \
+ $(srcdir)/html-text.h
diff --git a/src/devices/grohtml/TODO b/src/devices/grohtml/TODO
deleted file mode 100755
index 4924bd1c..00000000
--- a/src/devices/grohtml/TODO
+++ /dev/null
@@ -1,294 +0,0 @@
-
-------------------------------------------------------------------
- T O D O L I S T
-------------------------------------------------------------------
-finish working out the max and min x, y, extents for splines.
-------------------------------------------------------------------
-check and test thoroughly all the character descriptions in devhtml
-(originally taken from devX100)
-------------------------------------------------------------------
-improve tmac.arkup
-------------------------------------------------------------------
-also improve documentation.
-------------------------------------------------------------------
-fix the bugs which are exposed by Eric Raymonds pic guide,
-"Making Pictures With GNU PIC". It appears that grohtml becomes confused
-about which sections of the document are text and which sections need
-to be rendered as an image.
-------------------------------------------------------------------
-it would be nice to modularise the source. A natural division might be
-to extract the table handling code from html.cc into table.cc.
-The table.cc could be expanded to recognise output from tbl and try
-and generate html tables with lines/rules/boxes. The code as it stands
-should cope with very simple plain text tables. But of course at present
-it does not get a chance to do this because the output of gtbl is
-bracketed by \fCgraphic-start\fR and \fCgraphic-end\fR.
-------------------------------------------------------------------
-introduce anti aliasing for the images as mentioned by Werner.
-------------------------------------------------------------------
-improve generation of html. Perhaps by using a stack of current
-html commands and using a kind of peephole optimizer on the stack?
-Certainly the html should be buffered and optimized.
-------------------------------------------------------------------
-
-
-Informal to do bug list and done list
-=====================================
-
-This very informal and I've included some comments. Mainly consists
-of a emailed bugs and wish lists. All very useful and welcome.
-
-------------------------------------------------------------------
-Dean writes: (provinsd@enf403-2.ensu.ucalgary.ca)
-
-I noticed also that the TOC appears immediately after the title, splitting
-it from the author and abstract. Any chance it can be moved down?
-
-gaius> this should be straight forward. (Not done yet though)
-------------------------------------------------------------------
-
-.) The command `\(->', translates to the `registered' sign (or rather
- the character `0xAE') instead of a right arrow.
-
---nearly fixed-- 4/01/2000
-
-gaius> if we know the standard html character encoding for farrow which
-gaius> will work on *all* browsers then this can be fixed inside devhtml/TR
-gaius> etc. Otherwise I guess we could translate this character into ->
-gaius> in tmac.html ?
-
-------------------------------------------------------------------
-
-Werner writes:
-
-Nevertheless, still some bugs in it. As usual, I'm refering to man.1
-of the mandb package; my command to create man.html was
-
- groff -U -t -man -Thtml -P-r -P200 man.1 > man.html
-
-.) The `-w , --where, --location' node at the beginning of man.html
- shouldn't be there at all.
-
-> .) Some paragraphs still contain hyphenated words (e.g. first
-> paragraph of the `DESCRIPTION' section).
-
-Oops! Please ignore this. I forgot to include `-mhtml' :-)
-
-.) Is it possible to have anti-aliased PNG images?
-
-.) The item `man --help' in the `EXAMPLES' section doesn't start a new
- paragraph.
-
-.) In the description of the -r switch (in the `OPTIONS' section),
- there is a new paragraph in the middle of a sentence.
-
-.) What about centering the images? Or does it depend on the table
- itself?
-
-gaius> yes, grohtml places images at their relative position on the page.
-
-.) In the `OPTIONS' section, `-c, --catman' and `-d, --debug' are
- glued together which shouldn't happen.
---fixed--
-
-.) Sometimes, an empty line is missing between items, e.g. between the
- description of the -e and the -f options.
-
-.) After the `-w, --where, --location' line, there is a superfluous
- empty line.
-
-.) The indentation in the `FILES' section is inconsistent. The same
- is true for `-V, --version' a few lines above.
-
-.) The formatting of the paragraph after the first table is completely
- wrong. It appears that the first few words are set in two columns;
- additionally, the indentation is incorrect.
-
-.) Similarly, the description of `-l' in the OPTIONS section is
- idented incorrectly. Wrong indentations happen still quite
- frequently.
-
-.) In the description of the `-D' option, there is a blank line in the
- middle of a paragraph.
-
-
- Werner
-
-------------------------------------------------------------------
-Werner writes:
-
-Gaius,
-
-checking a weird man page written by myself in German (using German
-hyphenation patterns also :-), I found some more bugs:
-
-.) Look at the following:
-
-[\c
-...\^\c
-]
-[\c
-.BI -P \ \%Plattform-ID\^\c
-]
-
- This translates to
-
-[<font size=3><B>-E</B> <font size=3><I>Kodierungs-ID</I> <font size=3>]
- ^
- (groff breaks the line after the final `]'.)
-
- There are two errors in it: First of all, the `\ ' command should
- be translated to `&nbsp;'. Secondly, a blank has crept in (marked
- with `^'. Apparently, this is related to whether it is the last
- item of a line or not.
-
---fixed-- 4 01 2000
-------------------------------------------------------------------
-
-from Steve Blinkhorn <steve@prd.co.uk>
-
-One thought that came immediately to mind after our first trials.
-If grohtml depends on grops, should there not be an easy interface to
-allow PostScript code to be interpreted into the output? For
-instance, we generate our letterhead, including a logo, on the fly in
-groff. The logo is pure PostScript. We use PostScript for colour
-manipulation, and recently for generating a lot of graphics for
-printing.
-
-gaius> should be interesting - if we can generate PS then GS it
-gaius> we should be in business
-
-------------------------------------------------------------------
- D O N E L I S T
-------------------------------------------------------------------
-the logical place and name for a file describing tmac.arkup is
-groff_markup.man placed into the `tmac' subdirectory, and your html.ms
-looks like being this kind of file.
-
-So I won't check it in currently -- may I ask you to convert this file
-to a man page?
-
--- fixed --
-
-Another related problem: I can imagine that a lot of people start to
-write man pages with HTML output in mind also. Nevertheless, it
-should be still possible to display such pages correctly with a plain
-text man pager. As a consequence, such man pages should contain at
-the beginning something like
-
- .do mso tmac.arkup
-
-What do you think?
-
- Werner
-
--- fixed --
-gaius> fixed by using troffrc-end I believe
---------------------------------------------------------------------
-Gaius,
-
-in troffrc, it appears to me that tmac.html is loaded if the output
-device is HTML. So why must I load it again (using -mhtml) to
-suppress hyphenation for HTML output? Can you provide a fix for this?
-
- Werner
-
-gaius> fixed as above
---------------------------------------------------------------------
-
-from (daeschler@shuttle.de) Rainer Daeschler
-
-I recognized s problem limiting the usage for
-"none-english aliens". The generation of PNG of GIF,
-skips all special characters like
-
- äöü ÄÖÜ ß
-
-French, Spanish, and Scandinavian national letters, too.
-
---fixed-- 14/01/2000
-
-An option which forces tables into HTML-code instead of building
-an image would be most valuable. Of course it would not preserve
-the original layout in many cases, but ease modifications of
-the HTML-output to the users demand afterwards.
-
---fixed-- 14/01/2000
-
-gaius> use the new -T option to grohtml (-P-T to groff)
-
------------------------------------------------------------------
-from Werner
-
- but `pre-defined' appears as `pre&shy; line' (note the space
- character after the soft hyphen). Something in the code makes
- problems here...
-
- (IIRC, I've sent you this man.1 file a few weeks ago).
-
-gaius> Werner fixed this by adding .cflags 0 -\(hy\(em\(en to tmac.html
-
------------------------------------------------------------------
-from Werner and Eddie
-> > > .LP
-> > > .URL Germany "ftp://groff.ffii.org/pub/groff/"
-> > > |
-> > > .URL USA "ftp://ftp.gnu.org/gnu/groff/"
-> >
-> > Problem: the first "|" of each line is missing a leading white space
-> > space.
-> >
-> > How to ensure the spaces get put there?
->
-> This is a feature grohtml (unfortunately -- AFAIK, Gaius hasn't found
-> a good workaround yet). HTML stuff gets written as specials which
-> don't consume space for troff, causing some miscalculation if placed
-> at the beginning of a paragraph. A workaround is to write
->
-> .LP
-> \&
-> .URL ...
-> |
-> .URL ...
-
-gaius> fixed by adding \& to HTML as per Werner's suggestion
-
-
-Werner writes:
-
-PNGs created by grohtml have apparently a white background -- isn't it
-possible to make the background transparent optionally?
-
-Another suggestion: What do you think about calling the PNG files
-<groff_input_file>-<index>.png or something like this? I can't see an
-advantage in the current naming scheme except for debugging purposes
-where it may be necessary to stay with the old files.
-
---fixed-- 04 01 2000
-
-gaius> however I've had to retain a default grohtml-pid-index.png for all
-gaius> stdin as we don't know the filename.. sadly looks like everything..
-gaius> Nearly done by including a new tcommand 'F filename'
-
---fixed-- 26 01 2000
-------------------------------------------------------------------
-
-.) The following code produces ugly results -- is it possible to make
- the HTML result similar to the ascii output?
-
-.in +4m
-.ta 3iC
-.I "Plattform Plattform-ID (pid)"
-\&.sp
-.ta 3iR
-Apple Unicode 0
-.br
-Macintosh 1
-.br
-ISO 2
-.br
-Microsoft 3
-.PP
-
---fixed-- 14/01/2000
-------------------------------------------------------------------
diff --git a/src/devices/grohtml/design.ms b/src/devices/grohtml/design.ms
deleted file mode 100755
index 6216d4eb..00000000
--- a/src/devices/grohtml/design.ms
+++ /dev/null
@@ -1,129 +0,0 @@
-.nr PS 12
-.nr VS 14
-.LP
-.TL
-Design of grohtml
-.sp 1i
-.SH
-What is grohtml
-.LP
-Grohtml is a back end for groff which generates html.
-The aim of grohtml is to produce respectible html given
-fairly typical groff input.
-.SH
-Limitations of grohtml
-.LP
-Although basic text can be translated
-in a straightforward fashion there are some areas where grohtml
-has to try and guess text relationship. In particular whenever
-grohtml encounters text tables and indented paragraphs or
-two column mode it will try and utilize the html table construct
-to preserve columns. Grohtml also attempts to work out which
-lines should be automatically formatted by the browser.
-Ultimately in trying to make reasonable guesses most of the time
-it will make mistakes occasionally.
-.PP
-Tbl, pic, eqn's are also generated using images which may be
-considered a limitation.
-.SH
-Overview of html.cc
-.LP
-This file briefly provides an overview of how html.cc operates.
-The html device driver works as follows:
-.IP (i) .5i
-firstly it creates a linked list of all words on a page.
-.IP (ii) .5i
-it runs through the page and finds the left most margin. Later
-on when generating the page it removes the margin.
-.IP (iii) .5i
-scans a page and builds two kinds of regions ascii text and graphical.
-The graphical regions consist of tbl's, eqn's, pic's
-(basically anything that cannot be textually displayed).
-It will scan through a page to find lines (such as footer etc)
-and places these into tiny graphical regions. Certain fonts
-also are treated as a graphical region - as html has no easy
-equivalent. For example Greek math symbols.
-.LP
-Finally all graphical regions are translated into png files and
-all text regions into html text.
-.PP
-To give grohtml a sporting chance of accuratly deciding which
-is a graphical region and which is text, the front end programs
-tbl, eqn, pic have all been tweeked to encapsulate pictures, tables
-and equations with the following lines:
-.sp
-.nf
-\f[CR]\&.if '\\*(.T'html' \\X(graphic-start(\c
-
-\&.if '\\*(.T'html' \\X(graphic-end(\c
-\fP
-.fi
-.sp
-these appear to grohtml as:
-.sp
-.nf
-\f[CR]\&x X graphic-start
-
-\&...
-
-\&x X graphic-end\fP
-.fi
-.sp
-.LP
-In addition to graphic-start and graphic-end there are two
-other "special characters" which are used.
-.sp
-\f[CR]\&x X index:N\fP
-.sp
-where N is a number. The purpose of this sequence is to stop
-devhtml from automatically producing links to headings which
-have a header level >N.
-The line:
-.sp
-\f[CR]\&x X html:STRING\fR
-.sp
-.LP
-allows a STRING to be passed through to the output file with
-no processing whatsoever. Ie it allows users to include html
-commands, via macro, such as:
-.sp
-\f[CR]\&.URL "Latest Emacs" "ftp://somewonderful.gnu.software"\fP
-.sp
-.LP
-Where the URL macro bundles the info into STRING above.
-For more info consult: \f[CR]tmac/tmac.arkup\fP.
-.PP
-While scanning through a page the html device copies headings and titles
-into a list of links which are later written to the beginning
-of the html document.
-.SH
-Table handling code
-.LP
-Provided that the -t option is not present when grohtml is run the grohtml
-driver will attempt to find textual tables and generate html tables.
-This allows .RS and .RE commands to operate with auto formatting. It also
-should grohtml to process .2C correctly. However, the table handling code
-has to examine the troff output and \fIguess\fR when a table starts and
-finishes. It is well to know the limitations of this approach as it
-sometimes makes the wrong decision.
-.LP
-Here are some of the rules that grohtml uses for terminating a html table:
-.LP
-.IP "(i)" .5i
-A table will be terminated when grohtml finds line which is all in bold
-font (it believes that this is a header which is outside of a table).
-This might be considered incorrect behaviour especially if you use .2C
-which generates a heading on the left column when the corresponding
-right row is blank.
-.IP "(ii)" .5i
-A table is terminated when grohtml sees that the complete line is
-has been spanned by words. Ie no gaps exist.
-.IP "(nb)" .5i
-the documentation about these rules is particularly incomplete and needs finishing
-when time prevails.
-.SH
-Dependencies
-.LP
-Grohtml is dependent upon grops, gs which are invoked to
-generate all png files. Png files are generated whenever a table, picture,
-equation or line is encountered.
diff --git a/src/devices/grohtml/grohtml.man b/src/devices/grohtml/grohtml.man
index 95488f0e..1e93e006 100644
--- a/src/devices/grohtml/grohtml.man
+++ b/src/devices/grohtml/grohtml.man
@@ -36,24 +36,21 @@ grohtml \- html driver for groff
.ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]"
.el .RB "[\ " "\\$1" "\ ]"
..
-.OP \-atTvdgm?
+.OP \-v?lrn
.OP \-F dir
-.OP \-I imagetype
-.OP \-r resolution
+.OP \-i resolution
+.OP \-o image vertical offset
.RI "[\ " files\|.\|.\|. "\ ]"
.br
.ad \na
-.PP
-It is possible to have whitespace between a command line option and its
-parameter.
.SH DESCRIPTION
.B grohtml
translates the output of GNU
.B troff
to html.
-Normally
+Users should always invoke
.B grohtml
-should be invoked by using the groff command with a
+via the groff command with a
.B \-Thtml
option.
If no files are given,
@@ -77,49 +74,22 @@ using the
option.
.SH OPTIONS
.TP
-.B \-a
-force
-.B grohtml
-to generate html line breaks in the same position as troff dictates.
-Without this option
-.B grohtml
-generates text in paragraphs which is formatted by the html browser.
+.B \-v
+Displays the version.
.TP
-.B \-d
-turn on internal debugging.
+.B \-?
+Emits a usage synopsis.
.TP
-.B \-g
-tell
-.B grohtml
-not to try and guess titles and headings.
-By using this flag together with the -m and -a flag
-.B grohtml
-will treat the html browser as a printer, not as a formatter.
+.B -l
+Turns off the production of automatic section links at the top of the document.
.TP
-.B \-m
-leave margins alone.
-.B grohtml
-will not remove left margins.
+.B -r
+Turns off the automatic header and footer line (html rule).
.TP
-.B \-t
-forbids
-.B grohtml
-from generating html tables when implementing indentation and tabular text.
-.B grohtml
-can implement .IP by tables or html indents.
-However if .2C is used it can only be sensibly converted to html using a
-table structure.
-As a few known bugs still exist with the html table code this option is
-present to supress execution of this development code.
-The default in
-.B grohtml
-is that html tables are generated when appropriate.
-.TP
-.B \-T
-forbids
-.B grohtml
-from generating images when processing output from tbl.
-This is useful when simple textual tables are being produced.
+.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 (netscape).
.TP
.BI \-F dir
Prepend directory
@@ -129,17 +99,10 @@ to the search path for font and device description files;
is the name of the device, usually
.BR html .
.TP
-.BI \-I imagetype
-select the type of image generated when grohtml encounters an equation,
-table, or picture.
-By default this is png256.
-Legal image types are: gif and any of the png formats which are supported by
-ghostscript gs(1).
-.TP
-.BI \-r resolution
+.BI \-i resolution
select the resolution for all images.
By default this is 80 pixels per inch.
-Example: -r100 indicates 100 pixels per inch.
+Example: -i100 indicates 100 pixels per inch.
.TP
.B \-v
Print the version number.
@@ -154,29 +117,15 @@ There are styles called
and
.B BI
mounted at font positions 1 to 4.
-It is advisable to invoke groff with the -mhtml macro set, which turns off
-headers, footers, and hyphenation; additionally, it will right justify text.
.SH DEPENDENCIES
.B grohtml
-is dependent upon grops and gs.
-If
-.B grohtml
-has been configured to generate gif files then it is further dependent upon,
-ppmtogif, and ppmquant.
-However if it has been configured to generate png files (the default) then
-it is dependent upon gs having a png output device.
+is dependent upon the png utilities and gs.
Images are generated whenever a table, picture, equation or line is
encountered.
.SH BUGS
-This is still very alpha.
-At least three major bugs remain:
-Firstly,
-.B grohtml
-sometimes miscalculates the end of an html table resulting in text which
-appears twice.
-Secondly equation numbers are not handled correctly.
-Thirdly equation macros and pic macros can confuse
-.BR grohtml .
+.B Grohtml
+has been completely redesigned and rewriten.
+It is still alpha code.
.SH "SEE ALSO"
.BR afmtodit (@MAN1EXT@),
.BR groff (@MAN1EXT@),
diff --git a/src/devices/grohtml/html_chars.h b/src/devices/grohtml/html-chars.h
index 76f094c8..f58f8dcc 100755
--- a/src/devices/grohtml/html_chars.h
+++ b/src/devices/grohtml/html-chars.h
@@ -1,11 +1,11 @@
// -*- C++ -*-
-/* Copyright (C) 2000 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
*
* Gaius Mulley (gaius@glam.ac.uk) wrote output.cc
* but it owes a huge amount of ideas and raw code from
* James Clark (jjc@jclark.com) grops/ps.cc.
*
- * html_chars.h
+ * html-chars.h
*
* provides a diacritical character combination table for html
*/
diff --git a/src/devices/grohtml/html-text.cc b/src/devices/grohtml/html-text.cc
new file mode 100644
index 00000000..1621085b
--- /dev/null
+++ b/src/devices/grohtml/html-text.cc
@@ -0,0 +1,649 @@
+// -*- C++ -*-
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ *
+ * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cc
+ *
+ * html-text.cc
+ *
+ * provide a troff like state machine interface which
+ * generates html text.
+ */
+
+/*
+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"
+
+#if !defined(TRUE)
+# define TRUE (1==1)
+#endif
+#if !defined(FALSE)
+# define FALSE (1==0)
+#endif
+
+
+#include "html-text.h"
+
+
+html_text::html_text (simple_output *op) :
+ stackptr(NULL), lastptr(NULL), out(op), space_emitted(TRUE)
+{
+}
+
+html_text::~html_text ()
+{
+ flush_text();
+}
+
+/*
+ * end_tag - shuts down the tag.
+ */
+
+void html_text::end_tag (tag_definition *t)
+{
+ switch (t->type) {
+
+ case I_TAG: out->put_string("</i>"); break;
+ case B_TAG: out->put_string("</b>"); break;
+ case P_TAG: out->put_string("</p>"); out->write_newline(); out->enable_newlines(FALSE); 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>\n"); out->enable_newlines(TRUE); break;
+ case SMALL_TAG: out->put_string("</small>"); break;
+ case BIG_TAG: out->put_string("</big>"); break;
+
+ default:
+ error("unrecognised tag");
+ }
+}
+
+/*
+ * issue_tag - writes out an html tag with argument.
+ */
+
+void html_text::issue_tag (char *tagname, char *arg)
+{
+ if ((arg == 0) || (strlen(arg) == 0)) {
+ out->put_string(tagname);
+ out->put_string(">");
+ } else {
+ out->put_string(tagname);
+ out->put_string(" ");
+ out->put_string(arg);
+ out->put_string(">");
+ }
+}
+
+/*
+ * start_tag - starts a tag.
+ */
+
+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); 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: issue_tag("\n<pre", 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 BREAK_TAG: break;
+
+ default:
+ error("unrecognised tag");
+ }
+}
+
+/*
+ * flush_text - flushes html tags which are outstanding on the html stack.
+ */
+
+void html_text::flush_text (void)
+{
+ int notext=TRUE;
+ tag_definition *p=stackptr;
+
+ while (stackptr != 0) {
+ notext = (notext && (! stackptr->text_emitted));
+ if (! notext) {
+ end_tag(stackptr);
+ }
+ p = stackptr;
+ stackptr = stackptr->next;
+ free(p);
+ }
+ lastptr = NULL;
+}
+
+/*
+ * is_present - returns TRUE if tag is already present on the stack.
+ */
+
+int html_text::is_present (HTML_TAG t)
+{
+ tag_definition *p=stackptr;
+
+ while (p != NULL) {
+ if (t == p->type) {
+ return( TRUE );
+ }
+ p = p->next;
+ }
+ return( FALSE );
+}
+
+/*
+ * push_para - adds a new entry onto the html paragraph stack.
+ */
+
+void html_text::push_para (HTML_TAG t, char *arg)
+{
+ tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition));
+
+ p->type = t;
+ p->arg1 = arg;
+ p->text_emitted = FALSE;
+
+ /*
+ * 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)) && (lastptr != NULL)) {
+ lastptr->next = p;
+ lastptr = p;
+ p->next = NULL;
+ } else {
+ p->next = stackptr;
+ if (stackptr == NULL)
+ lastptr = p;
+ stackptr = p;
+ }
+}
+
+/*
+ * do_italic - changes to italic
+ */
+
+void html_text::do_italic (void)
+{
+ done_bold();
+ done_tt();
+ if (! is_present(I_TAG)) {
+ push_para(I_TAG, "");
+ }
+}
+
+/*
+ * do_bold - changes to bold.
+ */
+
+void html_text::do_bold (void)
+{
+ done_italic();
+ done_tt();
+ if (! is_present(B_TAG)) {
+ push_para(B_TAG, "");
+ }
+}
+
+/*
+ * do_tt - changes to teletype.
+ */
+
+void html_text::do_tt (void)
+{
+ done_bold();
+ done_italic();
+ if (! is_present(TT_TAG)) {
+ push_para(TT_TAG, "");
+ }
+}
+
+/*
+ * do_pre - changes to preformated text.
+ */
+
+void html_text::do_pre (void)
+{
+ done_bold();
+ done_italic();
+ done_tt();
+ char *type = done_para();
+ if (! is_present(PRE_TAG)) {
+ push_para(PRE_TAG, "");
+ }
+}
+
+/*
+ * is_in_pre - returns TRUE if we are currently within a preformatted
+ * <pre> block.
+ */
+
+int html_text::is_in_pre (void)
+{
+ return( is_present(PRE_TAG) );
+}
+
+/*
+ * shutdown - shuts down an html tag.
+ */
+
+char *html_text::shutdown (HTML_TAG t)
+{
+ char *arg=NULL;
+
+ if (is_present(t)) {
+ tag_definition *p =stackptr;
+ tag_definition *temp =NULL;
+ int notext =TRUE;
+
+ while ((stackptr != NULL) && (stackptr->type != t)) {
+ notext = (notext && (! stackptr->text_emitted));
+ if (! notext) {
+ end_tag(stackptr);
+ }
+
+ /*
+ * pop tag
+ */
+ p = stackptr;
+ stackptr = stackptr->next;
+ if (stackptr == NULL)
+ lastptr = NULL;
+
+ /*
+ * push tag onto temp stack
+ */
+ p->next = temp;
+ temp = p;
+ }
+
+ /*
+ * and examine stackptr
+ */
+ if ((stackptr != NULL) && (stackptr->type == t)) {
+ if (stackptr->text_emitted) {
+ end_tag(stackptr);
+ }
+ if (t == P_TAG) {
+ arg = stackptr->arg1;
+ }
+ p = stackptr;
+ stackptr = stackptr->next;
+ if (stackptr == NULL)
+ lastptr = NULL;
+ free(p);
+ }
+
+ /*
+ * and restore unaffected tags
+ */
+ while (temp != NULL) {
+ push_para(temp->type, temp->arg1);
+ p = temp;
+ temp = temp->next;
+ free(p);
+ }
+ }
+ return( arg );
+}
+
+/*
+ * done_bold - shuts downs a bold tag.
+ */
+
+void html_text::done_bold (void)
+{
+ shutdown(B_TAG);
+}
+
+/*
+ * done_italic - shuts downs an italic tag.
+ */
+
+void html_text::done_italic (void)
+{
+ shutdown(I_TAG);
+}
+
+/*
+ * done_sup - shuts downs a sup tag.
+ */
+
+void html_text::done_sup (void)
+{
+ shutdown(SUP_TAG);
+}
+
+/*
+ * done_sub - shuts downs a sub tag.
+ */
+
+void html_text::done_sub (void)
+{
+ shutdown(SUB_TAG);
+}
+
+/*
+ * done_tt - shuts downs a tt tag.
+ */
+
+void html_text::done_tt (void)
+{
+ shutdown(TT_TAG);
+}
+
+/*
+ * done_pre - shuts downs a pre tag.
+ */
+
+void html_text::done_pre (void)
+{
+ shutdown(PRE_TAG);
+}
+
+/*
+ * done_small - shuts downs a small tag.
+ */
+
+void html_text::done_small (void)
+{
+ shutdown(SMALL_TAG);
+}
+
+/*
+ * done_big - shuts downs a big tag.
+ */
+
+void html_text::done_big (void)
+{
+ shutdown(BIG_TAG);
+}
+
+/*
+ * check_emit_text - ensures that all previous tags have been emitted (in order)
+ * before the text is written.
+ */
+
+void html_text::check_emit_text (tag_definition *t)
+{
+ if ((t != NULL) && (! t->text_emitted)) {
+ check_emit_text(t->next);
+ t->text_emitted = TRUE;
+ start_tag(t);
+ }
+}
+
+/*
+ * do_emittext - tells the class that text was written during the current tag.
+ */
+
+void html_text::do_emittext (char *s, int length)
+{
+ if ((! is_present(P_TAG)) && (! is_present(PRE_TAG)))
+ do_para("");
+
+ if (is_present(BREAK_TAG)) {
+ int text = remove_break();
+ check_emit_text(stackptr);
+ if (text) {
+ if (is_present(PRE_TAG)) {
+ out->put_string("\n");
+ } else {
+ out->put_string("<br>\n");
+ }
+ }
+ } else {
+ check_emit_text(stackptr);
+ }
+ out->put_string(s, length);
+ space_emitted = FALSE;
+}
+
+/*
+ * do_para- starts a new paragraph
+ */
+
+void html_text::do_para (char *arg)
+{
+ done_pre();
+ if (! is_present(P_TAG)) {
+ remove_sub_sup();
+ push_para(P_TAG, arg);
+ space_emitted = TRUE;
+ }
+}
+
+/*
+ * done_para - shuts down a paragraph tag.
+ */
+
+char *html_text::done_para (void)
+{
+ space_emitted = TRUE;
+ return( shutdown(P_TAG) );
+}
+
+/*
+ * do_space - issues an end of paragraph
+ */
+
+void html_text::do_space (void)
+{
+ do_para(done_para());
+ space_emitted = TRUE;
+}
+
+/*
+ * do_break - issue a break tag.
+ */
+
+void html_text::do_break (void)
+{
+ if (! is_present(PRE_TAG)) {
+ if (emitted_text()) {
+ if (! is_present(BREAK_TAG)) {
+ push_para(BREAK_TAG, "");
+ }
+ }
+ }
+ space_emitted = TRUE;
+}
+
+/*
+ * do_newline - issue a newline providing that we are inside a <pre> tag.
+ */
+
+void html_text::do_newline (void)
+{
+ if (is_present(PRE_TAG)) {
+ do_emittext("\n", 1);
+ space_emitted = TRUE;
+ }
+}
+
+/*
+ * emitted_text - returns FALSE if white space has just been written.
+ */
+
+int html_text::emitted_text (void)
+{
+ return( ! space_emitted);
+}
+
+/*
+ * emit_space - writes a space providing that text was written beforehand.
+ */
+
+int html_text::emit_space (void)
+{
+ if (space_emitted) {
+ if (is_present(PRE_TAG)) {
+ do_emittext(" ", 1);
+ }
+ } else {
+ out->space_or_newline();
+ space_emitted = TRUE;
+ }
+}
+
+/*
+ * remove_tag - removes a tag from the stack.
+ */
+
+void html_text::remove_tag (HTML_TAG tag)
+{
+ tag_definition *p = stackptr;
+ tag_definition *l = 0;
+ tag_definition *q = 0;
+
+ while ((p != 0) && (p->type != tag)) {
+ l = p;
+ p = p->next;
+ }
+ if ((p != 0) && (p->type == tag)) {
+ if (p == stackptr) {
+ stackptr = stackptr->next;
+ if (stackptr == NULL)
+ lastptr = NULL;
+ q = stackptr;
+ } else if (l == 0) {
+ error("stack list pointers are wrong");
+ } else {
+ l->next = p->next;
+ q = p->next;
+ if (l->next == NULL)
+ lastptr = l;
+ }
+ free(p);
+ }
+}
+
+/*
+ * remove_sub_sup - removes a sub or sup tag, should either exist on the stack.
+ */
+
+void html_text::remove_sub_sup (void)
+{
+ if (is_present(SUB_TAG)) {
+ remove_tag(SUB_TAG);
+ }
+ if (is_present(SUP_TAG)) {
+ remove_tag(SUP_TAG);
+ }
+ if (is_present(PRE_TAG)) {
+ remove_tag(PRE_TAG);
+ }
+}
+
+/*
+ * remove_break - break tags are not balanced thus remove it once it has been emitted.
+ * It returns TRUE if text was emitted before the <br> was issued.
+ */
+
+int html_text::remove_break (void)
+{
+ tag_definition *p = stackptr;
+ tag_definition *l = 0;
+ tag_definition *q = 0;
+
+ while ((p != 0) && (p->type != BREAK_TAG)) {
+ l = p;
+ p = p->next;
+ }
+ if ((p != 0) && (p->type == BREAK_TAG)) {
+ if (p == stackptr) {
+ stackptr = stackptr->next;
+ if (stackptr == NULL)
+ lastptr = NULL;
+ q = stackptr;
+ } else if (l == 0) {
+ error("stack list pointers are wrong");
+ } else {
+ l->next = p->next;
+ q = p->next;
+ if (l->next == NULL)
+ lastptr = l;
+ }
+ free(p);
+ }
+ /*
+ * now determine whether text was issued before <br>
+ */
+ while (q != 0) {
+ if (q->text_emitted) {
+ return( TRUE );
+ } else {
+ q = q->next;
+ }
+ }
+ return( FALSE );
+}
+
+/*
+ * do_small - potentially inserts a <small> tag into the html stream.
+ * However we check for a <big> tag, if present then we terminate it.
+ * Otherwise a <small> tag is inserted.
+ */
+
+void html_text::do_small (void)
+{
+ if (is_present(BIG_TAG)) {
+ done_big();
+ } else {
+ push_para(SMALL_TAG, "");
+ }
+}
+
+/*
+ * do_big - is the mirror image of do_small.
+ */
+
+void html_text::do_big (void)
+{
+ if (is_present(SMALL_TAG)) {
+ done_small();
+ } else {
+ push_para(BIG_TAG, "");
+ }
+}
+
+/*
+ * do_sup - save a superscript tag on the stack of tags.
+ */
+
+void html_text::do_sup (void)
+{
+ push_para(SUP_TAG, "");
+}
+
+/*
+ * do_sub - save a subscript tag on the stack of tags.
+ */
+
+void html_text::do_sub (void)
+{
+ push_para(SUB_TAG, "");
+}
+
diff --git a/src/devices/grohtml/html-text.h b/src/devices/grohtml/html-text.h
new file mode 100644
index 00000000..b9164e6e
--- /dev/null
+++ b/src/devices/grohtml/html-text.h
@@ -0,0 +1,97 @@
+// -*- C++ -*-
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+ *
+ * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cc
+ *
+ * html-text.h
+ *
+ * provides a state machine interface which generates html text.
+ */
+
+/*
+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"
+
+/*
+ * html tags
+ */
+
+typedef enum {I_TAG, B_TAG, P_TAG, SUB_TAG, SUP_TAG, TT_TAG, PRE_TAG, SMALL_TAG, BIG_TAG, BREAK_TAG} HTML_TAG;
+
+typedef struct tag_definition {
+ HTML_TAG type;
+ char *arg1;
+ int text_emitted;
+ tag_definition *next;
+} tag_definition ;
+
+/*
+ * the state of the current paragraph.
+ * It allows post-html.cc to request font changes, paragraph start/end
+ * and emits balanced tags with a small amount of peephole optimization.
+ */
+
+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 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);
+ int emitted_text (void);
+ int emit_space (void);
+ int is_in_pre (void);
+ void remove_tag (HTML_TAG tag);
+ void remove_sub_sup (void);
+
+private:
+ tag_definition *stackptr; /* the current paragraph state */
+ tag_definition *lastptr; /* the end of the stack */
+ simple_output *out;
+ int space_emitted;
+
+ 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);
+};
diff --git a/src/devices/grohtml/html.cc b/src/devices/grohtml/html.cc
deleted file mode 100755
index b7acb6b7..00000000
--- a/src/devices/grohtml/html.cc
+++ /dev/null
@@ -1,6607 +0,0 @@
-// -*- C++ -*-
-/* Copyright (C) 1999 Free Software Foundation, Inc.
- *
- * Gaius Mulley (gaius@glam.ac.uk) wrote grohtml
- * but it owes a huge amount of ideas and raw code from
- * James Clark (jjc@jclark.com) grops/ps.cc.
- */
-
-/*
-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.h"
-#include "html_chars.h"
-#include <time.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-extern "C" {
- // SunOS 4.1.3 fails to declare this in stdlib.h
- char *mktemp(char *);
-}
-
-#include <stdio.h>
-#include <fcntl.h>
-
-#ifndef _POSIX_VERSION
-
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif /* HAVE_LIMITS_H */
-
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#else /* not HAVE_DIRENT_H */
-#ifdef HAVE_SYS_DIR_H
-#include <sys/dir.h>
-#endif /* HAVE_SYS_DIR_H */
-#endif /* not HAVE_DIRENT_H */
-
-#ifndef NAME_MAX
-#ifdef MAXNAMLEN
-#define NAME_MAX MAXNAMLEN
-#else /* !MAXNAMLEN */
-#ifdef MAXNAMELEN
-#define NAME_MAX MAXNAMELEN
-#else /* !MAXNAMELEN */
-#define NAME_MAX 14
-#endif /* !MAXNAMELEN */
-#endif /* !MAXNAMLEN */
-#endif /* !NAME_MAX */
-
-#endif /* not _POSIX_VERSION */
-
-#include "nonposix.h"
-
-#include "ordered_list.h"
-
-#if !defined(TRUE)
-# define TRUE (1==1)
-#endif
-#if !defined(FALSE)
-# define FALSE (1==0)
-#endif
-
-#define MAX_TEMP_NAME 1024
-#define MAX_STRING_LENGTH 4096
-#define MAX_CHAR_SIZE 50 // maximum length of character name
-
-#define Y_FUDGE_MARGIN +0.83
-#define A4_PAGE_LENGTH (11.6944-Y_FUDGE_MARGIN)
-#define DEFAULT_IMAGE_RES 80
-#define IMAGE_BOARDER_PIXELS 10
-#define MAX_WORDS_PER_LINE 1000 // only used for table indentation
-#define GAP_SPACES 3 // how many spaces needed to guess a gap?
-#define GAP_WIDTH_ONE_LINE 2 // 1/GAP_WIDTH_ONE_LINE inches required for one line table
-#define CENTER_TOLERANCE 2 // how many pixels off center will we think a line or region is centered
-#define MIN_COLUMN 7 // minimum column size pixels for multiple lines
-#define MIN_COLUMN_FOR_TWO_LINES 20 // minimum column size pixels for a 2 line table
-#define MIN_TEXT_PERCENT 5 // try and round to this percentage value for used columns
-#define PERCENT_THRESHOLD 20 // don't bother trying to increase and width greater than this
-
-
-/*
- * Only uncomment one of the following to determine default image type.
- */
-
-#define IMAGE_DEFAULT_PNG
-/* #define IMAGE_DEFAULT_GIF */
-
-
-#if defined(IMAGE_DEFAULT_GIF)
-static enum { gif, png } image_type = gif;
-static char *image_device = "gif";
-#elif defined(IMAGE_DEFAULT_PNG)
-static enum { gif, png } image_type = png;
-static char *image_device = "png256";
-#else
-# error "you must define either IMAGE_DEFAULT_GIF or IMAGE_DEFAULT_PNG"
-#endif
-
-static int debug_on = FALSE;
-static int guess_on = TRUE;
-static int margin_on = FALSE;
-static int auto_on = TRUE;
-static int table_on = TRUE;
-static int image_res = DEFAULT_IMAGE_RES;
-static int debug_table_on = FALSE;
-static int table_image_on = TRUE; // default is to create images for tbl
-
-static int linewidth = -1;
-
-#define DEFAULT_LINEWIDTH 40 /* in ems/1000 */
-#define MAX_LINE_LENGTH 72
-#define FILL_MAX 1000
-
-void stop () {}
-
-
-/*
- * start with a few favorites
- */
-
-static int min (int a, int b)
-{
- if (a < b) {
- return( a );
- } else {
- return( b );
- }
-}
-
-static int max (int a, int b)
-{
- if (a > b) {
- return( a );
- } else {
- return( b );
- }
-}
-
-/*
- * is_subsection - returns TRUE if a1..a2 is within b1..b2
- */
-
-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)) );
-}
-
-/*
- * 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
- return( ! ((a1 > b2) || (a2 < b1)) );
-}
-
-/*
- * is_digit - returns TRUE if character, ch, is a digit.
- */
-
-static int is_digit (char ch)
-{
- return( (ch >= '0') && (ch <= '9') );
-}
-
-/*
- * more_than_line_break - returns TRUE should v1 and v2 differ by more than
- * a simple line break.
- */
-
-static int more_than_line_break (int v1, int v2, int size)
-{
- return( abs(v1-v2)>size );
-}
-
-/*
- * the class and methods for styles
- */
-
-struct style {
- font *f;
- int point_size;
- int font_no;
- int height;
- int slant;
- style ();
- style (font *, int, int, int, int);
- int operator == (const style &) const;
- int operator != (const style &) const;
-};
-
-style::style()
- : f(0)
-{
-}
-
-style::style(font *p, int sz, int h, int sl, int no)
- : f(p), point_size(sz), font_no(no), height(h), slant(sl)
-{
-}
-
-int style::operator==(const style &s) const
-{
- return (f == s.f && point_size == s.point_size
- && height == s.height && slant == s.slant);
-}
-
-int style::operator!=(const style &s) const
-{
- return !(*this == s);
-}
-
-
-/*
- * the class and methods for retaining ascii text
- */
-
-struct char_block {
- enum { SIZE = 256 };
- char buffer[SIZE];
- int used;
- char_block *next;
-
- char_block();
-};
-
-char_block::char_block()
-: used(0), next(0)
-{
-}
-
-class char_buffer {
-public:
- char_buffer();
- ~char_buffer();
- char *add_string(char *, unsigned int);
-private:
- char_block *head;
- char_block *tail;
-};
-
-char_buffer::char_buffer()
-: head(0), tail(0)
-{
-}
-
-char_buffer::~char_buffer()
-{
- while (head != 0) {
- char_block *temp = head;
- head = head->next;
- delete temp;
- }
-}
-
-char *char_buffer::add_string (char *s, unsigned int length)
-{
- int i=0;
- unsigned int old_used;
-
- if (tail == 0) {
- tail = new char_block;
- head = tail;
- } else {
- if (tail->used + length+1 > char_block::SIZE) {
- tail->next = new char_block;
- 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 {
- tail->buffer[tail->used] = s[i];
- tail->used++;
- i++;
- length--;
- } while (length>0);
-
- // add terminating nul character
-
- tail->buffer[tail->used] = '\0';
- tail->used++;
-
- // and return start of new string
-
- return( &tail->buffer[old_used] );
-}
-
-/*
- * the classes and methods for maintaining pages and text positions and graphic regions
- */
-
-class text_glob {
-public:
- int is_less (text_glob *a, text_glob *b);
- text_glob (style *s, char *string, unsigned int length,
- int min_vertical, int min_horizontal,
- int max_vertical, int max_horizontal, int is_command, int is_html);
- text_glob (void);
- ~text_glob (void);
-
- style text_style;
- char *text_string;
- unsigned int text_length;
- int minv, maxv, minh, maxh;
- int is_raw_command; // should the text be sent directly to the device?
- int is_html_command; // is the raw command definitely for the html device ie not an eqn?
-};
-
-text_glob::text_glob (style *s, char *string, unsigned int length,
- int min_vertical, int min_horizontal,
- int max_vertical, int max_horizontal, int is_command, int is_html)
- : text_style(*s), text_string(string), text_length(length),
- minv(min_vertical), maxv(max_vertical), minh(min_horizontal), maxh(max_horizontal),
- is_raw_command(is_command), is_html_command(is_html)
-{
-}
-
-text_glob::text_glob ()
- : text_string(0), text_length(0), minv(-1), maxv(-1), minh(-1), maxh(-1),
- is_raw_command(FALSE), is_html_command(FALSE)
-{
-}
-
-text_glob::~text_glob ()
-{
-}
-
-int text_glob::is_less (text_glob *a, text_glob *b)
-{
- if (is_intersection(a->minv+1, a->maxv-1, b->minv+1, b->maxv-1)) {
- return( a->minh < b->minh );
- } else {
- return( a->maxv < b->maxv );
- }
-}
-
-struct xycoord {
- int x;
- int y;
-};
-
-class graphic_glob {
-public:
- int is_less (graphic_glob *a, graphic_glob *b);
- graphic_glob (int troff_code);
- graphic_glob (void);
- ~graphic_glob (void);
-
- int minv, maxv, minh, maxh;
- int xc, yc;
- int nopoints; // number of points allocated in array below
- struct xycoord *point;
- int size;
- int fill;
- int code;
-};
-
-graphic_glob::graphic_glob ()
- : minv(-1), maxv(-1), minh(-1), maxh(-1), nopoints(0), point(0), size(0), code(0)
-{
-}
-
-graphic_glob::~graphic_glob ()
-{
- if (point != 0) {
- free(point);
- }
-}
-
-graphic_glob::graphic_glob (int troff_code)
- : minv(-1), maxv(-1), minh(-1), maxh(-1), nopoints(0), point(0), size(0), code(troff_code)
-{
-}
-
-int graphic_glob::is_less (graphic_glob *a, graphic_glob *b)
-{
- return( (a->minv < b->minv) || ((a->minv == b->minv) && (a->minh < b->minh)) );
-}
-
-class region_glob {
-public:
- region_glob (void);
- ~region_glob (void);
- int is_less (region_glob *a, region_glob *b);
-
- int minv, maxv, minh, maxh;
-};
-
-int region_glob::is_less (region_glob *a, region_glob *b)
-{
- return( (a->minv < b->minv) || ((a->minv == b->minv) && (a->minh < b->minh)) );
-}
-
-region_glob::region_glob (void)
- : minv(-1), maxv(-1), minh(-1), maxh(-1)
-{
-}
-
-region_glob::~region_glob (void)
-{
-}
-
-class page {
-public:
- page (void);
- void add (style *s, char *string, unsigned int length,
- int min_vertical, int min_horizontal,
- int max_vertical, int max_horizontal);
- void add_html_command (style *s, char *string, unsigned int length,
- int min_vertical, int min_horizontal,
- int max_vertical, int max_horizontal);
- void add_special_char (style *s, char *string, unsigned int length,
- int min_vertical, int min_horizontal,
- int max_vertical, int max_horizontal);
- void add_line (int code, int x1, int y1, int x2, int y2, int size, int fill);
- void add_arc (int code, int xc, int yc, int *p, double *c, int size, int fill);
- void add_polygon (int code, int np, int *p, int oh, int ov, int size, int fill);
- void add_spline (int code, int xc, int yc, int np, int *p, int size, int fill);
- void calculate_region (void);
- int is_in_region (graphic_glob *g);
- int can_grow_region (graphic_glob *g);
- void make_new_region (graphic_glob *g);
- int has_line (region_glob *r);
- int has_word (region_glob *r);
- int no_raw_commands (int minv, int maxv);
-
- // and the data
-
- ordered_list <region_glob> regions; // squares of bitmapped pics,eqn,tbl's
- ordered_list <text_glob> words; // position of words on page
- ordered_list <graphic_glob> lines; // position of lines on page
- char_buffer buffer; // all characters for this page
- int is_in_graphic; // should graphics and words go below or above
- ordered_list <text_glob> region_words; // temporary accumulation of words in a region
- ordered_list <graphic_glob> region_lines; // (as above) and used so that we can determine
- // the regions vertical limits
-};
-
-page::page()
- : is_in_graphic(FALSE)
-{
-}
-
-void page::add (style *s, char *string, unsigned int length,
- 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, FALSE);
- if (is_in_graphic) {
- region_words.add(g);
- } else {
- words.add(g);
- }
- }
-}
-
-/*
- * add_html_command - it only makes sense to add html commands when we are not inside
- * a graphical entity.
- */
-
-void page::add_html_command (style *s, char *string, unsigned int length,
- int min_vertical, int min_horizontal,
- int max_vertical, int max_horizontal)
-{
- if ((length > 0) && (! is_in_graphic)) {
- text_glob *g=new text_glob(s, buffer.add_string(string, length), length,
- min_vertical, min_horizontal, max_vertical, max_horizontal, TRUE, TRUE);
- words.add(g);
- }
-}
-
-/*
- * add_special_char - it only makes sense to add special characters when we are inside
- * a graphical entity.
- */
-
-void page::add_special_char (style *s, char *string, unsigned int length,
- int min_vertical, int min_horizontal,
- int max_vertical, int max_horizontal)
-{
- if ((length > 0) && (is_in_graphic)) {
- text_glob *g=new text_glob(s, buffer.add_string(string, length), length,
- min_vertical, min_horizontal, max_vertical, max_horizontal, TRUE, FALSE);
- region_words.add(g);
- }
-}
-
-void page::add_line (int code, int x1, int y1, int x2, int y2, int size, int fill)
-{
- graphic_glob *g = new graphic_glob(code);
-
- g->minh = min(x1, x2);
- g->maxh = max(x1, x2);
- g->minv = min(y1, y2);
- g->maxv = max(y1, y2);
- g->point = (struct xycoord *)malloc(sizeof(xycoord)*2);
- g->nopoints = 2;
- g->point[0].x = x1 ;
- g->point[0].y = y1 ;
- g->point[1].x = x2 ;
- g->point[1].y = y2 ;
- g->xc = 0;
- g->yc = 0;
- g->size = size;
- g->fill = fill;
-
- if (is_in_graphic) {
- region_lines.add(g);
- } else {
- lines.add(g);
- }
-}
-
-/*
- * assign_min_max_for_arc - works out the smallest box that will encompass an
- * arc defined by: origin: g->xc, g->xc
- * and vector (p[0], p[1]) and (p[2], p[3])
- */
-
-void assign_min_max_for_arc (graphic_glob *g, int *p, double *c)
-{
- int radius = (int) sqrt(c[0]*c[0]+c[1]*c[1]);
- int xv1 = p[0];
- int yv1 = p[1];
- int xv2 = p[2];
- int yv2 = p[3];
- int x1 = g->xc+xv1;
- int y1 = g->yc+yv1;
- int x2 = g->xc+xv1+xv2;
- int y2 = g->yc+yv1+yv2;
-
- // firstly lets use the 'circle' limitation
- g->minh = x1-radius;
- g->maxh = x1+radius;
- g->minv = y1-radius;
- g->maxv = y1+radius;
-
- // incidentally I'm sure there is a better way to do this, but I don't know it
- // please can someone let me know or "improve" this function
-
- // now see which min/max can be reduced and increased for the limits of the arc
- //
- //
- // Q2 | Q1
- // -----+-----
- // Q3 | Q4
- //
-
-
- if ((xv1>=0) && (yv1>=0)) {
- // first vector in Q3
- if ((xv2>=0) && (yv2>=0)) {
- // second in Q1
- g->maxh = x2;
- g->minv = y1;
- } else if ((xv2<0) && (yv2>=0)) {
- // second in Q2
- g->maxh = x2;
- g->minv = y1;
- } else if ((xv2>=0) && (yv2<0)) {
- // second in Q4
- g->minv = min(y1, y2);
- } else if ((xv2<0) && (yv2<0)) {
- // second in Q3
- if (x1>=x2) {
- g->minh = x2;
- g->maxh = x1;
- g->minv = min(y1, y2);
- g->maxv = max(y1, y2);
- } else {
- // xv2, yv2 could all be zero?
- }
- }
- } else if ((xv1>=0) && (yv1<0)) {
- // first vector in Q2
- if ((xv2>=0) && (yv2>=0)) {
- // second in Q1
- g->maxh = max(x1, x2);
- g->minh = min(x1, x2);
- g->minv = y1;
- } else if ((xv2<0) && (yv2>=0)) {
- // second in Q2
- if (x1<x2) {
- g->maxh = x2;
- g->minh = x1;
- g->minv = min(y1, y2);
- g->maxv = max(y1, y2);
- } else {
- // otherwise almost full circle anyway
- }
- } else if ((xv2>=0) && (yv2<0)) {
- // second in Q4
- g->minv = y2;
- g->minh = x1;
- } else if ((xv2<0) && (yv2<0)) {
- // second in Q3
- g->minh = min(x1, x2);
- }
- } else if ((xv1<0) && (yv1<0)) {
- // first vector in Q1
- if ((xv2>=0) && (yv2>=0)) {
- // second in Q1
- if (x1<x2) {
- g->minh = x1;
- g->maxh = x2;
- g->minv = min(y1, y2);
- g->maxv = max(y1, y2);
- } else {
- // nearly full circle
- }
- } else if ((xv2<0) && (yv2>=0)) {
- // second in Q2
- g->maxv = max(y1, y2);
- } else if ((xv2>=0) && (yv2<0)) {
- // second in Q4
- g->minv = min(y1, y2);
- g->maxv = max(y1, y2);
- g->minh = min(x1, x2);
- } else if ((xv2<0) && (yv2<0)) {
- // second in Q3
- g->minh = x2;
- g->maxv = y1;
- }
- } else if ((xv1<0) && (yv1>=0)) {
- // first vector in Q4
- if ((xv2>=0) && (yv2>=0)) {
- // second in Q1
- g->maxh = max(x1, x2);
- } else if ((xv2<0) && (yv2>=0)) {
- // second in Q2
- g->maxv = max(y1, y2);
- g->maxh = max(x1, x2);
- } else if ((xv2>=0) && (yv2<0)) {
- // second in Q4
- if (x1>=x2) {
- g->minv = min(y1, y2);
- g->maxv = max(y1, y2);
- g->minh = min(x1, x2);
- g->maxh = max(x2, x2);
- } else {
- // nearly full circle
- }
- } else if ((xv2<0) && (yv2<0)) {
- // second in Q3
- g->maxv = max(y1, y2);
- g->minh = min(x1, x2);
- g->maxh = max(x1, x2);
- }
- }
- // this should *never* happen but if it does it means a case above is wrong..
-
- // this code is only present for safety sake
- if (g->maxh < g->minh) {
- if (debug_on) {
- fprintf(stderr, "assert failed minh > maxh\n"); fflush(stderr);
- // stop();
- }
- g->maxh = g->minh;
- }
- if (g->maxv < g->minv) {
- if (debug_on) {
- fprintf(stderr, "assert failed minv > maxv\n"); fflush(stderr);
- // stop();
- }
- g->maxv = g->minv;
- }
-}
-
-void page::add_arc (int code, int xc, int yc, int *p, double *c, int size, int fill)
-{
- graphic_glob *g = new graphic_glob(code);
-
- g->point = (struct xycoord *)malloc(sizeof(xycoord)*2);
- g->nopoints = 2;
- g->point[0].x = p[0] ;
- g->point[0].y = p[1] ;
- g->point[1].x = p[2] ;
- g->point[1].y = p[3] ;
- g->xc = xc;
- g->yc = yc;
- g->size = size;
- g->fill = fill;
-
- assign_min_max_for_arc(g, p, c);
-
- if (is_in_graphic) {
- region_lines.add(g);
- } else {
- lines.add(g);
- }
-}
-
-
-void page::add_polygon (int code, int np, int *p, int oh, int ov, int size, int fill)
-{
- graphic_glob *g = new graphic_glob(code);
- int j = 0;
- int i;
-
- g->point = (struct xycoord *)malloc(sizeof(xycoord)*np/2);
- g->nopoints = np/2;
-
- for (i=0; i<g->nopoints; i++) {
- g->point[i].x = p[j];
- j++;
- g->point[i].y = p[j];
- j++;
- }
- // now calculate min/max
- g->minh = g->point[0].x;
- g->minv = g->point[0].y;
- g->maxh = g->point[0].x;
- g->maxv = g->point[0].y;
- for (i=1; i<g->nopoints; i++) {
- g->minh = min(g->minh, g->point[i].x);
- g->minv = min(g->minv, g->point[i].y);
- g->maxh = max(g->maxh, g->point[i].x);
- g->maxv = max(g->maxv, g->point[i].y);
- }
- g->size = size;
- g->xc = oh;
- g->yc = ov;
- g->fill = fill;
-
- if (is_in_graphic) {
- region_lines.add(g);
- } else {
- lines.add(g);
- }
-}
-
-void page::add_spline (int code, int xc, int yc, int np, int *p, int size, int fill)
-{
- graphic_glob *g = new graphic_glob(code);
- int j = 0;
- int i;
-
- g->point = (struct xycoord *)malloc(sizeof(xycoord)*np/2);
- g->nopoints = np/2;
-
- for (i=0; i<g->nopoints; i++) {
- g->point[i].x = p[j];
- j++;
- g->point[i].y = p[j];
- j++;
- }
- // now calculate min/max
- g->minh = min(g->point[0].x, g->point[0].x/2);
- g->minv = min(g->point[0].y, g->point[0].y/2);
- g->maxh = max(g->point[0].x, g->point[0].x/2);
- g->maxv = max(g->point[0].y, g->point[0].y/2);
-
- /* tnum/tden should be between 0 and 1; the closer it is to 1
- the tighter the curve will be to the guiding lines; 2/3
- is the standard value */
- const int tnum = 2;
- const int tden = 3;
-
- for (i=1; i<g->nopoints-1; i++) {
- g->minh = min(g->minh, g->point[i].x*tnum/(2*tden));
- g->minv = min(g->minv, g->point[i].y*tnum/(2*tden));
- g->maxh = max(g->maxh, g->point[i].x*tnum/(2*tden));
- g->maxv = max(g->maxv, g->point[i].y*tnum/(2*tden));
-
- g->minh = min(g->minh, g->point[i].x/2+(g->point[i+1].x*(tden-tden))/(2*tden));
- g->minv = min(g->minv, g->point[i].y/2+(g->point[i+1].y*(tden-tden))/(2*tden));
- g->maxh = max(g->maxh, g->point[i].x/2+(g->point[i+1].x*(tden-tden))/(2*tden));
- g->maxv = max(g->maxv, g->point[i].y/2+(g->point[i+1].y*(tden-tden))/(2*tden));
-
- g->minh = min(g->minh, (g->point[i].x-g->point[i].x/2) + g->point[i+1].x/2);
- g->minv = min(g->minv, (g->point[i].y-g->point[i].y/2) + g->point[i+1].y/2);
- g->maxh = max(g->maxh, (g->point[i].x-g->point[i].x/2) + g->point[i+1].x/2);
- g->maxv = max(g->maxv, (g->point[i].y-g->point[i].y/2) + g->point[i+1].y/2);
- }
- i = g->nopoints-1;
-
- g->minh = min(g->minh, (g->point[i].x-g->point[i].x/2)) + xc;
- g->minv = min(g->minv, (g->point[i].y-g->point[i].y/2)) + yc;
- g->maxh = max(g->maxh, (g->point[i].x-g->point[i].x/2)) + xc;
- g->maxv = max(g->maxv, (g->point[i].y-g->point[i].y/2)) + yc;
-
- g->size = size;
- g->xc = xc;
- g->yc = yc;
- g->fill = fill;
-
- if (is_in_graphic) {
- region_lines.add(g);
- } else {
- lines.add(g);
- }
-}
-
-class html_font : public font {
- html_font(const char *);
-public:
- int encoding_index;
- char *encoding;
- char *reencoded_name;
- ~html_font();
- static html_font *load_html_font(const char *);
-};
-
-html_font *html_font::load_html_font(const char *s)
-{
- html_font *f = new html_font(s);
- if (!f->load()) {
- delete f;
- return 0;
- }
- return f;
-}
-
-html_font::html_font(const char *nm)
-: font(nm)
-{
-}
-
-html_font::~html_font()
-{
-}
-
-/*
- * a simple class to contain the header to this document
- */
-
-class title_desc {
-public:
- title_desc ();
- ~title_desc ();
-
- int has_been_written;
- int has_been_found;
- char text[MAX_STRING_LENGTH];
-};
-
-
-title_desc::title_desc ()
- : has_been_written(FALSE), has_been_found(FALSE)
-{
-}
-
-title_desc::~title_desc ()
-{
-}
-
-class header_desc {
-public:
- header_desc ();
- ~header_desc ();
-
- int no_of_headings; // how many headings have we found?
- char_buffer headings; // all the headings used in the document
- ordered_list <text_glob> headers;
- int header_level; // current header level
- int written_header; // have we written the header yet?
- char header_buffer[MAX_STRING_LENGTH]; // current header text
-
- void write_headings (FILE *f);
-};
-
-header_desc::header_desc ()
- : no_of_headings(0), header_level(2), written_header(0)
-{
-}
-
-header_desc::~header_desc ()
-{
-}
-
-/*
- * paragraph_type - alignment for a new paragraph
- */
-
-typedef enum { left_alignment, center_alignment } paragraph_type;
-
-/*
- * text_defn - defines the limit of text, initially these are stored in the
- * column array as words. Later we examine the white space between
- * the words in successive lines to find out whether we can detect
- * distinct columns. The columns are generated via html tables.
- */
-
-struct text_defn {
- int left; // the start of a word or text
- int right; // the end of the text and beginning of white space
- int is_used; // will this this column be used for words or space
- int right_hits; // count of the number of words touching right position
- int percent; // what percentage width should we use for this cell?
-};
-
-/*
- * introduce a paragraph class so that we can nest paragraphs
- * from plain html text and html tables.
- */
-
-class html_paragraph {
-public:
- html_paragraph (int in, int need, paragraph_type type, html_paragraph *prev);
- ~html_paragraph ();
-
- int in_paragraph;
- int need_paragraph;
- paragraph_type para_type;
- html_paragraph *previous;
-};
-
-/*
- * html_paragraph - constructor, fill in the public fields.
- */
-
-html_paragraph::html_paragraph (int in, int need, paragraph_type type, html_paragraph *prev)
- : in_paragraph(in), need_paragraph(need),
- para_type(type), previous(prev)
-{
-}
-
-/*
- * html_paragraph - deconstructor
- */
-
-html_paragraph::~html_paragraph ()
-{
-}
-
-/*
- * note that html_tables are currently only used to provide a better
- * indentation mechanism for html text (in particular it allows grohtml
- * to render .IP and .2C together with autoformatting).
- */
-
-class html_table {
-public:
- html_table ();
- ~html_table ();
-
- int no_of_columns; // how many columns are we using?
- struct text_defn *columns; // left and right margins for each column
- int vertical_limit; // the limit of the table
- int wrap_margin; // is the current rightmost margin able to wrap words?
-};
-
-html_table::html_table ()
- : no_of_columns(0), columns(0), vertical_limit(0), wrap_margin(0)
-{
-}
-
-html_table::~html_table ()
-{
-}
-
-class html_printer : public printer {
- FILE *tempfp;
- simple_output html;
- simple_output troff;
- int res;
- int postscript_res;
- int space_char_index;
- int no_of_printed_pages;
- int paper_length;
- enum { SBUF_SIZE = 8192 };
- char sbuf[SBUF_SIZE];
- int sbuf_len;
- int sbuf_start_hpos;
- int sbuf_vpos;
- int sbuf_end_hpos;
- int sbuf_kern;
- style sbuf_style;
- int sbuf_dmark_hpos;
- 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;
- string defs;
- char *inside_font_style;
- int page_number;
- title_desc title;
- header_desc header;
- int header_indent;
- page *page_contents;
- html_table indentation;
- int left_margin_indent;
- int right_margin_indent;
- int need_one_newline;
- int issued_newline;
- html_paragraph *current_paragraph;
- char image_name[MAX_STRING_LENGTH];
- int image_number;
- int graphic_level;
- int supress_sub_sup;
-
- int start_region_vpos;
- int start_region_hpos;
- int end_region_vpos;
- int end_region_hpos;
- int cutoff_heading;
-
- struct graphic_glob *start_graphic;
- struct text_glob *start_text;
-
- void flush_sbuf ();
- void set_style (const style &);
- void set_space_code (unsigned char c);
- void do_exec (char *, const environment *);
- void do_import (char *, const environment *);
- void do_def (char *, const environment *);
- void do_mdef (char *, const environment *);
- void do_file (char *, const environment *);
- void set_line_thickness (const environment *);
- void change_font (text_glob *g, int is_to_html);
- void terminate_current_font (void);
- void flush_font (void);
- void flush_page (void);
- void add_char_to_sbuf (unsigned char code);
- void add_to_sbuf (char code, const char *name);
- void display_word (text_glob *g, int is_to_html);
- void html_display_word (text_glob *g);
- void troff_display_word (text_glob *g);
- void display_line (graphic_glob *g, int is_to_html);
- void display_fill (graphic_glob *g);
- void calculate_margin (void);
- void traverse_page_regions (void);
- void dump_page (void);
- int is_within_region (graphic_glob *g);
- int is_within_region (text_glob *t);
- int is_less (graphic_glob *g, text_glob *t);
- void display_globs (int is_to_html);
- void move_horizontal (text_glob *g, int left_margin);
- void move_vertical (text_glob *g, paragraph_type p);
- void write_html_font_face (const char *fontname, const char *left, const char *right);
- void write_html_font_type (const char *fontname, const char *left, const char *right);
- void html_change_font (text_glob *g, const char *fontname, int size);
- char *html_position_text (text_glob *g, int left_margin, int right_margin);
- int html_position_region (void);
- void troff_change_font (const char *fontname, int size, int font_no);
- void troff_position_text (text_glob *g);
- int pretend_is_on_same_line (text_glob *g, int left_margin, int right_margin);
- int is_on_same_line (text_glob *g, int vpos);
- int looks_like_subscript (text_glob *g);
- int looks_like_superscript (text_glob *g);
- int looks_like_smaller_font (text_glob *g);
- int looks_like_larger_font (text_glob *g);
- void begin_paragraph (paragraph_type p);
- void begin_paragraph_no_height (paragraph_type p);
- void force_begin_paragraph (void);
- void end_paragraph (void);
- void save_paragraph (void);
- void restore_paragraph (void);
- void html_newline (void);
- void convert_to_image (char *troff_src, char *image_name);
- void write_title (int in_head);
- void find_title (void);
- int is_bold (text_glob *g);
- void write_header (text_glob *g);
- void determine_header_level (void);
- void build_header (text_glob *g);
- void make_html_indent (int indent);
- int is_whole_line_bold (text_glob *g);
- int is_a_header (text_glob *g);
- int processed_header (text_glob *g);
- void make_new_image_name (void);
- void calculate_region_margins (region_glob *r);
- void remove_redundant_regions (void);
- void remove_duplicate_regions (void);
- void move_region_to_page (void);
- void calculate_region_range (graphic_glob *r);
- void flush_graphic (void);
- void write_string (graphic_glob *g, int is_to_html);
- void prologue (void);
- int gs_x (int x);
- int gs_y (int y);
- void display_regions (void);
- int check_able_to_use_table (text_glob *g);
- int using_table_for_indent (void);
- int collect_columns (struct text_defn *next_words, struct text_defn *next_cols,
- struct text_defn *last_words, struct text_defn *last_cols,
- int max_words);
- void include_into_list (struct text_defn *line, struct text_defn *item);
- int is_in_column (struct text_defn *line, struct text_defn *item, int max_words);
- int is_column_match (struct text_defn *match, struct text_defn *line1,
- struct text_defn *line2, int max_words);
- int count_columns (struct text_defn *line);
- void rewind_text_to (text_glob *g);
- int found_use_for_table (text_glob *start);
- void column_display_word (int cell, int vert, int left, int right, int next);
- void start_table (void);
- void end_table (void);
- void foreach_column_include_text (text_glob *start);
- void define_cell (int i);
- int column_calculate_left_margin (int left, int right);
- int column_calculate_right_margin (int left, int right);
- void display_columns (const char *word, const char *name, text_defn *line);
- void calculate_right (struct text_defn *line, int max_words);
- void determine_right_most_column (struct text_defn *line, int max_words);
- int remove_white_using_words (struct text_defn *next_guess, struct text_defn *last_guess, struct text_defn *next_line);
- void copy_line (struct text_defn *dest, struct text_defn *src);
- void combine_line (struct text_defn *dest, struct text_defn *src);
- int conflict_with_words (struct text_defn *column_guess, struct text_defn *words);
- void remove_entry_in_line (struct text_defn *line, int j);
- void remove_redundant_columns (struct text_defn *line);
- void add_column_gaps (struct text_defn *line);
- int continue_searching_column (text_defn *next_col, text_defn *last_col, text_defn *all_words);
- void add_right_full_width (struct text_defn *line, int mingap);
- int is_continueous_column (text_defn *last_col, text_defn *next_line);
- int is_exact_left (text_defn *last_col, text_defn *next_line);
- int find_column_index_in_line (text_glob *t, text_defn *line);
- void emit_space (text_glob *g, int force_space);
- int is_in_middle (int left, int right);
- int check_able_to_use_center (text_glob *g);
- void write_centered_line (text_glob *g);
- int single_centered_line (text_defn *first, text_defn *second, text_glob *g);
- int determine_row_limit (text_glob *start, int v);
- void assign_used_columns (text_glob *start);
- int find_column_index (text_glob *t);
- int large_enough_gap (text_defn *last_col);
- int is_worth_column (int left, int right);
- int is_subset_of_columns (text_defn *a, text_defn *b);
- void count_hits (text_defn *col, int no_of_columns, int limit);
- void count_right_hits (text_defn *col, int no_of_columns);
- int calculate_min_gap (text_glob *g);
- int right_indentation (struct text_defn *last_guess);
- void calculate_percentage_width (text_glob *start);
- int able_to_steal_width (void);
- int need_to_steal_width (void);
- int can_distribute_fairly (void);
- void utilize_round_off (void);
- int will_wrap_text (int i, text_glob *start);
- int next_line_on_left_column (int i, text_glob *start);
- void remove_table_column (int i);
- void remove_unnecessary_unused (text_glob *start);
- int is_small_table (int lines, struct text_defn *last_guess,
- struct text_defn *words_1, struct text_defn *cols_1,
- struct text_defn *words_2, struct text_defn *cols_2,
- int *limit, int *limit_1);
- int is_column_subset (struct text_defn *cols_1, struct text_defn *cols_2);
- int is_appropriate_to_start_table (struct text_defn *cols_1, struct text_defn *cols_2,
- struct text_defn *last_guess);
- int is_a_full_width_column (void);
- int right_most_column (struct text_defn *col);
- int large_enough_gap_for_two (struct text_defn *col);
- void remove_zero_percentage_column (void);
- void translate_to_html (text_glob *g);
- int html_knows_about (char *troff);
- 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 ();
- const char *check_diacritical_combination (unsigned char code, const char *name);
- int seen_backwards_escape (char *s, int l);
- int should_defer_table (int lines, struct text_glob *start, struct text_defn *cols_1);
- int is_new_exact_right (struct text_defn *last_guess, struct text_defn *last_cols, struct text_defn *next_cols);
- void issue_left_paragraph (void);
- void adjust_margin_percentages (void);
- int total_percentages (void);
- int get_left (void);
- void can_loose_column (text_glob *start, struct text_defn *last_guess, int limit);
- int check_lack_of_hits (struct text_defn *next_guess, struct text_defn *last_guess, text_glob *start, int limit);
- int is_in_table (void);
-
- // 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);
- font *make_font(const char *);
- void end_of_line();
-};
-
-html_printer::html_printer()
-: html(0, MAX_LINE_LENGTH),
- troff(0, MAX_LINE_LENGTH),
- no_of_printed_pages(0),
- sbuf_len(0),
- sbuf_dmark_hpos(-1),
- output_hpos(-1),
- output_vpos(-1),
- line_thickness(-1),
- fill(FILL_MAX + 1),
- inside_font_style(0),
- page_number(0),
- header_indent(-1),
- left_margin_indent(0),
- right_margin_indent(0),
- need_one_newline(0),
- issued_newline(0),
- image_number(0),
- graphic_level(0),
- supress_sub_sup(TRUE),
- start_region_vpos(0),
- start_region_hpos(0),
- end_region_vpos(0),
- end_region_hpos(0),
- cutoff_heading(100)
-{
- tempfp = xtmpfile();
- html.set_file(tempfp);
- if (linewidth < 0)
- linewidth = DEFAULT_LINEWIDTH;
- if (font::hor != 1)
- fatal("horizontal resolution must be 1");
- if (font::vert != 1)
- fatal("vertical resolution must be 1");
-#if 0
- // should be sorted html..
- if (font::res % (font::sizescale*72) != 0)
- fatal("res must be a multiple of 72*sizescale");
-#endif
- int r = font::res;
- int point = 0;
- while (r % 10 == 0) {
- r /= 10;
- point++;
- }
- res = r;
- html.set_fixed_point(point);
- space_char_index = font::name_to_index("space");
- paper_length = font::paperlength;
- if (paper_length == 0)
- paper_length = 11*font::res;
- page_contents = new page;
-
- postscript_res = 72000;
- current_paragraph = new html_paragraph(FALSE, FALSE, left_alignment, 0);
-}
-
-/*
- * 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.
- * It escapes \ with \\
- * We need to preserve the name of characters if they exist
- * because we may need to send this character to two different
- * devices: html and postscript.
- */
-
-void html_printer::add_to_sbuf (char code, const char *name)
-{
- if (name == 0) {
- if (code == '\\') {
- add_char_to_sbuf('\\');
- }
- add_char_to_sbuf(code);
- } else {
- int l=strlen(name);
- int i=0;
-
- add_char_to_sbuf('\\');
- add_char_to_sbuf('(');
- while (i<l) {
- if (name[i] == '\\') {
- add_char_to_sbuf('\\');
- }
- add_char_to_sbuf(name[i]);
- i++;
- }
- add_char_to_sbuf('\\');
- add_char_to_sbuf(')');
- }
-}
-
-int html_printer::sbuf_continuation (unsigned char code, const char *name,
- const environment *env, int w)
-{
- if ((sbuf_end_hpos == env->hpos) || (sbuf_dmark_hpos == env->hpos)) {
- name = check_diacritical_combination(code, name);
- add_to_sbuf(code, name);
- determine_diacritical_mark(name, env);
- sbuf_end_hpos += w + sbuf_kern;
- return( TRUE );
- } else {
- if ((sbuf_len < SBUF_SIZE-1) && (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) {
- name = check_diacritical_combination(code, name);
- add_to_sbuf(code, name);
- determine_diacritical_mark(name, env);
- sbuf_end_hpos = env->hpos + w;
- return( TRUE );
- }
- } else if ((sbuf_len > 0) && (sbuf_dmark_hpos)) {
- /*
- * check whether the diacritical mark is on the same character
- */
- int space_width = sbuf_style.f->get_space_width(sbuf_style.point_size);
-
- if (abs(sbuf_dmark_hpos-env->hpos) < space_width) {
- name = check_diacritical_combination(code, name);
- add_to_sbuf(code, name);
- determine_diacritical_mark(name, env);
- sbuf_end_hpos = env->hpos + w;
- 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 );
- }
-}
-
-/*
- * check_diacriticial_combination - checks to see whether the character code
- * if combined with the previous diacriticial mark
- * forms a new character.
- */
-
-const char *html_printer::check_diacritical_combination (unsigned char code, const char *name)
-{
- static char troff_char[2];
-
- if ((name == 0) && (sbuf_dmark_hpos >= 0)) {
- // last character was a diacritical mark
- char *last = remove_last_char_from_sbuf();
-
- int i=0;
- int j;
-
- while (diacritical_table[i].mark != NULL) {
- if (strcmp(diacritical_table[i].mark, last) == 0) {
- j=0;
- while ((diacritical_table[i].second_troff_char[j] != (char)0) &&
- (diacritical_table[i].second_troff_char[j] != code)) {
- j++;
- }
- if (diacritical_table[i].second_troff_char[j] == code) {
- troff_char[0] = diacritical_table[i].translation;
- troff_char[1] = code;
- troff_char[2] = (char)0;
- return( troff_char );
- }
- }
- i++;
- }
- add_to_sbuf(last[0], last);
- }
- return( name );
-}
-
-/*
- * determine_diacritical_mark - if name is a diacriticial mark the record the position.
- * --fixme-- is there a better way of doing this
- * this must be done in troff somewhere.
- */
-
-void html_printer::determine_diacritical_mark (const char *name, const environment *env)
-{
- if (name != 0) {
- int i=0;
-
- while (diacritical_table[i].mark != NULL) {
- if (strcmp(name, diacritical_table[i].mark) == 0) {
- sbuf_dmark_hpos = env->hpos;
- return;
- }
- i++;
- }
- }
- sbuf_dmark_hpos = -1;
-}
-
-/*
- * set_char - adds a character into the sbuf if it is a continuation with the previous
- * word otherwise flush the current sbuf and add character anew.
- */
-
-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);
- if (sty.slant != 0) {
- if (sty.slant > 80 || sty.slant < -80) {
- error("silly slant `%1' degrees", sty.slant);
- sty.slant = 0;
- }
- }
- if ((name != 0) && (page_contents->is_in_graphic)) {
- flush_sbuf();
- int r=font::res; // resolution of the device
- page_contents->add_special_char(&sty, (char *)name, strlen(name),
- env->vpos-sty.point_size*r/72, env->hpos,
- env->vpos , env->hpos+w);
- sbuf_end_hpos = env->hpos + w;
- sbuf_start_hpos = env->hpos;
- sbuf_vpos = env->vpos;
- sbuf_style = sty;
- sbuf_kern = 0;
- } else {
- if ((sbuf_len > 0) && (sbuf_len < SBUF_SIZE) && (sty == sbuf_style) &&
- (sbuf_vpos == env->vpos) && (sbuf_continuation(code, name, env, w))) {
- return;
- } else {
- flush_sbuf();
- sbuf_len = 0;
- add_to_sbuf(code, name);
- determine_diacritical_mark(name, env);
- sbuf_end_hpos = env->hpos + w;
- sbuf_start_hpos = env->hpos;
- sbuf_vpos = env->vpos;
- sbuf_style = sty;
- sbuf_kern = 0;
- }
- }
-}
-
-/*
- * file_name_max - return the maximum file-name length permitted
- * by the underlying filesystem.
- *
- * (Code shamelessly stolen from indxbib/dirnamemax.c.)
- */
-
-static size_t
-file_name_max (const char *fname)
-{
-#ifdef _POSIX_VERSION
- return pathconf (fname, _PC_NAME_MAX);
-#else
- return NAME_MAX;
-#endif
-}
-
-
-/*
- * make_new_image_name - creates a new file name ready for a image file.
- */
-
-void html_printer::make_new_image_name (void)
-{
- image_number++;
-
- if ((current_filename == 0) ||
- (strcmp(current_filename, "<standard input>") == 0) ||
- (strcmp(current_filename, "-") == 0) ||
- (strcspn(current_filename, DIR_SEPS) < strlen(current_filename))) {
- if (file_name_max(".") > 14)
- sprintf(image_name, "groff-html-%d-%ld", image_number, (long)getpid());
- else
- // The "-gh" part might be truncated on MS-DOS, but there's enough
- // space for the PID and up to 99 image numbers. That's why "-gh"
- // comes last.
- sprintf(image_name, "%d-%ld-gh", image_number, (long)getpid());
- } else if (file_name_max(".") > 14) {
- sprintf(image_name, "%s-%d-%ld", current_filename, image_number, (long)getpid());
- } else { // see the commentary above
- sprintf(image_name, "%d-%ld-%s",
- image_number, (long)getpid(), current_filename);
- // Make sure image_name does not have a dot in its trunk, since
- // convert_to_image will append .gif or .png to it, and DOS doesn't
- // allow more than a single dot in a file name.
- int i = strlen(image_name);
- for ( ; i > 0; i--) {
- if (strchr(DIR_SEPS, image_name[i - 1]))
- break;
- if (image_name[i - 1] == '.') {
- image_name[i - 1] = '\0';
- break;
- }
- }
- }
-}
-
-/*
- * write_title - writes the title to this document
- */
-
-void html_printer::write_title (int in_head)
-{
- if (title.has_been_found) {
- if (in_head) {
- html.put_string("<title>");
- html.put_string(title.text);
- html.put_string("</title>\n");
- } else {
- title.has_been_written = TRUE;
- html.put_string("<h1 align=center>");
- html.put_string(title.text);
- html.put_string("</h1>\n");
- }
- }
-}
-
-/*
- * get_html_translation - given the position of the character and its name
- * return the device encoding for such character.
- */
-
-char *get_html_translation (font *f, char *name)
-{
- int index;
-
- if ((f == 0) || (name == 0) || (strcmp(name, "") == 0)) {
- return( NULL );
- } else {
- index = f->name_to_index(name);
- if (index == 0) {
- error("character `%s' not found", name);
- return( NULL );
- } else {
- return( (char *)f->get_special_device_encoding(index) );
- }
- }
-}
-
-/*
- * char_translate_to_html - convert a single non escaped character
- * into the appropriate html character.
- */
-
-int char_translate_to_html (font *f, char *buf, int buflen, char ch, int b, int and_single)
-{
- 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) {
- 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 {
- /*
- * do not attempt to encode single characters
- */
- 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 (index != 0) {
- buf[b] = f->get_code(index);
- b++;
- }
- }
- }
- } else {
- b = char_translate_to_html(f, buf, buflen, str[i], b, and_single);
- i++;
- }
- } else {
- b = char_translate_to_html(f, buf, buflen, str[i], b, and_single);
- i++;
- }
- }
- buf[min(b, buflen)] = (char)0;
-}
-
-/*
- * find_title - finds a title to this document, if it exists.
- */
-
-void html_printer::find_title (void)
-{
- text_glob *t;
- int r=font::res;
- int removed_from_head;
- char buf[MAX_STRING_LENGTH];
-
- if ((page_number == 1) && (guess_on)) {
- if (! page_contents->words.is_empty()) {
-
- int end_title_hpos = 0;
- int start_title_vpos = 0;
- int found_title_start = FALSE;
- int height = 0;
- int start_region =-1;
-
- if (! page_contents->regions.is_empty()) {
- region_glob *r;
-
- page_contents->regions.start_from_head();
- r = page_contents->regions.get_data();
- if (r->minv > 0) {
- start_region = r->minv;
- }
- }
-
- page_contents->words.start_from_head();
- do {
- t = page_contents->words.get_data();
- removed_from_head = FALSE;
- if ((found_title_start) && (start_region != -1) && (t->maxv >= start_region)) {
- /*
- * we have just encountered the first graphic region so
- * we stop looking for a title.
- */
- title.has_been_found = TRUE;
- return;
- } else if (t->is_raw_command) {
- // skip raw commands
- page_contents->words.move_right(); // move onto next word
- } else if ((!found_title_start) && (t->minh > left_margin_indent) &&
- ((start_region == -1) || (t->maxv < start_region))) {
- start_title_vpos = t->minv;
- end_title_hpos = t->minh;
- str_translate_to_html(t->text_style.f, buf, MAX_STRING_LENGTH, t->text_string, t->text_length, TRUE);
- strcpy((char *)title.text, buf);
- height = t->text_style.point_size*r/72;
- found_title_start = TRUE;
- page_contents->words.sub_move_right();
- removed_from_head = ((!page_contents->words.is_empty()) &&
- (page_contents->words.is_equal_to_head()));
- } else if (found_title_start) {
- if ((t->minv == start_title_vpos) ||
- ((!more_than_line_break(start_title_vpos, t->minv, (height*3)/2)) &&
- (t->minh > left_margin_indent)) ||
- (is_bold(t) && (t->minh > left_margin_indent))) {
- start_title_vpos = min(t->minv, start_title_vpos);
- end_title_hpos = max(t->maxh, end_title_hpos);
- 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->words.sub_move_right();
- removed_from_head = ((!page_contents->words.is_empty()) &&
- (page_contents->words.is_equal_to_head()));
- } else {
- // end of title
- title.has_been_found = TRUE;
- return;
- }
- } else if (t->minh <= left_margin_indent) {
- // no margin exists
- return;
- } else {
- // move onto next word
- page_contents->words.move_right();
- }
- } while ((! page_contents->words.is_equal_to_head()) || (removed_from_head));
- }
- }
-}
-
-/*
- * html_newline - generates a newline <br>
- */
-
-void html_printer::html_newline (void)
-{
- int r = font::res;
- int height = output_style.point_size*r/72;
-
- if (current_paragraph->in_paragraph) {
- // safe to generate a pretty newline
- html.put_string("<br>\n");
- } else {
- html.put_string("<br>");
- }
- output_vpos += height;
- issued_newline = TRUE;
-}
-
-/*
- * issue_left_paragraph - emits a left paragraph together with appropriate
- * margin if header_indent is < left_margin_indent.
- */
-
-void html_printer::issue_left_paragraph (void)
-{
- if ((header_indent < left_margin_indent) && (! using_table_for_indent())) {
- html.put_string("<p style=\"margin-left: ");
- html.put_number(((left_margin_indent-header_indent)*100)/(right_margin_indent-header_indent));
- html.put_string("%\">");
- } else {
- html.put_string("<p>");
- }
-}
-
-/*
- * force_begin_paragraph - force the begin_paragraph to be emitted.
- */
-
-void html_printer::force_begin_paragraph (void)
-{
- if (current_paragraph->in_paragraph && current_paragraph->need_paragraph) {
- switch (current_paragraph->para_type) {
-
- case left_alignment: issue_left_paragraph();
- break;
- case center_alignment: html.put_string("<p align=center>");
- break;
- default: fatal("unknown paragraph alignment type");
- }
- current_paragraph->need_paragraph = FALSE;
- }
-}
-
-/*
- * begin_paragraph - starts a new paragraph. It does nothing if a paragraph
- * has already been started.
- */
-
-void html_printer::begin_paragraph (paragraph_type p)
-{
- if (! current_paragraph->in_paragraph) {
- int r = font::res;
- int height = output_style.point_size*r/72;
-
- if (output_vpos >=0) {
- // we leave it alone if it is set to the top of page
- output_vpos += height;
- }
- current_paragraph->need_paragraph = TRUE; // delay the <p> just in case we don't actually emit text
- current_paragraph->in_paragraph = TRUE;
- current_paragraph->para_type = p;
- issued_newline = TRUE;
- }
-}
-
-
-/*
- * begin_paragraph_no_height - starts a new paragraph. It does nothing if a paragraph
- * has already been started. Note it does not alter output_vpos.
- */
-
-void html_printer::begin_paragraph_no_height (paragraph_type p)
-{
- if (! current_paragraph->in_paragraph) {
- current_paragraph->need_paragraph = TRUE; // delay the <p> just in case we don't actually emit text
- current_paragraph->in_paragraph = TRUE;
- current_paragraph->para_type = p;
- issued_newline = TRUE;
- }
-}
-
-/*
- * end_paragraph - end the current paragraph. It does nothing if a paragraph
- * has not been started.
- */
-
-void html_printer::end_paragraph (void)
-{
- if (current_paragraph->in_paragraph) {
- // check whether we have generated any text inbetween the potential paragraph begin end
- if (! current_paragraph->need_paragraph) {
- int r = font::res;
- int height = output_style.point_size*r/72;
-
- output_vpos += height;
- terminate_current_font();
- html.put_string("</p>\n");
- } else {
- terminate_current_font();
- }
- current_paragraph->para_type = left_alignment;
- current_paragraph->in_paragraph = FALSE;
- }
-}
-
-/*
- * save_paragraph - saves the current paragraph state and
- * creates new paragraph state.
- */
-
-void html_printer::save_paragraph (void)
-{
- if (current_paragraph == 0) {
- fatal("current_paragraph is NULL");
- }
- current_paragraph = new html_paragraph(current_paragraph->in_paragraph,
- current_paragraph->need_paragraph,
- current_paragraph->para_type,
- current_paragraph);
- terminate_current_font();
-}
-
-/*
- * restore_paragraph - restores the previous paragraph state.
- */
-
-void html_printer::restore_paragraph (void)
-{
- html_paragraph *old = current_paragraph;
-
- current_paragraph = current_paragraph->previous;
- free(old);
-}
-
-/*
- * calculate_margin - runs through the words and graphics globs
- * and finds the start of the left most margin.
- */
-
-void html_printer::calculate_margin (void)
-{
- text_glob *w;
- graphic_glob *g;
-
- // remove margin
-
- right_margin_indent = 0;
-
- if (! page_contents->words.is_empty()) {
-
- // firstly check the words to determine the right margin
-
- page_contents->words.start_from_head();
- do {
- w = page_contents->words.get_data();
- if ((w->maxh >= 0) && (w->maxh > right_margin_indent)) {
- right_margin_indent = w->maxh;
-#if 0
- if (right_margin_indent == 758) stop();
-#endif
- }
- page_contents->words.move_right();
- } while (! page_contents->words.is_equal_to_head());
-
- /*
- * only examine graphics if no words present
- */
- if (! page_contents->lines.is_empty()) {
- // now check for diagrams for right margin
- page_contents->lines.start_from_head();
- do {
- g = page_contents->lines.get_data();
- if ((g->maxh >= 0) && (g->maxh > right_margin_indent)) {
- right_margin_indent = g->maxh;
-#if 0
- if (right_margin_indent == 950) stop();
-#endif
- }
- page_contents->lines.move_right();
- } while (! page_contents->lines.is_equal_to_head());
- }
-
-
- /*
- * now we know the right margin lets do the same to find left margin
- */
-
- if (header_indent == -1) {
- header_indent = right_margin_indent;
- }
- left_margin_indent = right_margin_indent;
-
- if (! page_contents->words.is_empty()) {
- do {
- w = page_contents->words.get_data();
- if ((w->minh >= 0) && (w->minh < left_margin_indent)) {
- if (! is_a_header(w) && (! w->is_raw_command)) {
- left_margin_indent = w->minh;
- }
- }
- page_contents->words.move_right();
- } while (! page_contents->words.is_equal_to_head());
- }
-
- /*
- * only examine graphic for margins if text yields nothing
- */
-
- if (! page_contents->lines.is_empty()) {
- // now check for diagrams
- page_contents->lines.start_from_head();
- do {
- g = page_contents->lines.get_data();
- if ((g->minh >= 0) && (g->minh < left_margin_indent)) {
- left_margin_indent = g->minh;
- }
- page_contents->lines.move_right();
- } while (! page_contents->lines.is_equal_to_head());
- }
- }
-}
-
-/*
- * calculate_region - runs through the graphics globs and text globs
- * and ensures that all graphic routines
- * are defined by the region lists.
- * This then allows us to easily
- * determine the range of vertical and
- * horizontal boundaries for pictures,
- * tbl's and eqn's.
- *
- */
-
-void page::calculate_region (void)
-{
- graphic_glob *g;
-
- if (! lines.is_empty()) {
- lines.start_from_head();
- do {
- g = lines.get_data();
- if (! is_in_region(g)) {
- if (! can_grow_region(g)) {
- make_new_region(g);
- }
- }
- lines.move_right();
- } while (! lines.is_equal_to_head());
- }
-}
-
-/*
- * remove_redundant_regions - runs through the regions and ensures that
- * all are needed. This is required as
- * a picture may be empty, or EQ EN pair
- * maybe empty.
- */
-
-void html_printer::remove_redundant_regions (void)
-{
- region_glob *r;
-
- // firstly run through the region making sure that all are needed
- // ie all contain a line or word
- if (! page_contents->regions.is_empty()) {
- page_contents->regions.start_from_tail();
- do {
- r = page_contents->regions.get_data();
- calculate_region_margins(r);
- if (page_contents->has_line(r) || page_contents->has_word(r)) {
- page_contents->regions.move_right();
- } else {
- page_contents->regions.sub_move_right();
- }
- } while ((! page_contents->regions.is_empty()) &&
- (! page_contents->regions.is_equal_to_tail()));
- }
-}
-
-void html_printer::display_regions (void)
-{
- if (debug_table_on) {
- region_glob *r;
-
- fprintf(stderr, "==========s t a r t===========\n");
- if (! page_contents->regions.is_empty()) {
- page_contents->regions.start_from_head();
- do {
- r = page_contents->regions.get_data();
- fprintf(stderr, "region minv %d maxv %d\n", r->minv, r->maxv);
- page_contents->regions.move_right();
- } while (! page_contents->regions.is_equal_to_head());
- }
- fprintf(stderr, "============e n d=============\n");
- fflush(stderr);
- }
-}
-
-/*
- * remove_duplicate_regions - runs through the regions and ensures that
- * no duplicates exist.
- */
-
-void html_printer::remove_duplicate_regions (void)
-{
- region_glob *r;
- region_glob *l=0;
-
- if (! page_contents->regions.is_empty()) {
- page_contents->regions.start_from_head();
- l = page_contents->regions.get_data();
- page_contents->regions.move_right();
- r = page_contents->regions.get_data();
- if (l != r) {
- do {
- r = page_contents->regions.get_data();
- // we have a legit region so we check for an intersection
- if (is_intersection(r->minv, r->minv, l->minv, l->maxv) &&
- is_intersection(r->minh, r->maxh, l->minh, l->maxh)) {
- l->minv = min(r->minv, l->minv);
- l->maxv = max(r->maxv, l->maxv);
- l->minh = min(r->minh, l->minh);
- l->maxh = max(r->maxh, l->maxh);
- calculate_region_margins(l);
- page_contents->regions.sub_move_right();
- } else {
- l = r;
- page_contents->regions.move_right();
- }
- } while ((! page_contents->regions.is_empty()) &&
- (! page_contents->regions.is_equal_to_head()));
- }
- }
-}
-
-int page::has_line (region_glob *r)
-{
- graphic_glob *g;
-
- if (! lines.is_empty()) {
- lines.start_from_head();
- do {
- g = lines.get_data();
- if (is_subsection(g->minv, g->maxv, r->minv, r->maxv) &&
- is_subsection(g->minh, g->maxh, r->minh, r->maxh)) {
- return( TRUE );
- }
- lines.move_right();
- } while (! lines.is_equal_to_head());
- }
- return( FALSE );
-}
-
-
-int page::has_word (region_glob *r)
-{
- text_glob *g;
-
- if (! words.is_empty()) {
- words.start_from_head();
- do {
- g = words.get_data();
- if (is_subsection(g->minv, g->maxv, r->minv, r->maxv) &&
- is_subsection(g->minh, g->maxh, r->minh, r->maxh)) {
- return( TRUE );
- }
- words.move_right();
- } while (! words.is_equal_to_head());
- }
- return( FALSE );
-}
-
-
-void html_printer::calculate_region_margins (region_glob *r)
-{
- text_glob *w;
- graphic_glob *g;
-
- r->minh = right_margin_indent;
- r->maxh = left_margin_indent;
-
- if (! page_contents->lines.is_empty()) {
- page_contents->lines.start_from_head();
- do {
- g = page_contents->lines.get_data();
- if (is_subsection(g->minv, g->maxv, r->minv, r->maxv)) {
- r->minh = min(r->minh, g->minh);
- r->maxh = max(r->maxh, g->maxh);
- }
- page_contents->lines.move_right();
- } while (! page_contents->lines.is_equal_to_head());
- }
- if (! page_contents->words.is_empty()) {
- page_contents->words.start_from_head();
- do {
- w = page_contents->words.get_data();
- if (is_subsection(w->minv, w->maxv, r->minv, r->maxv)) {
- r->minh = min(r->minh, w->minh);
- r->maxh = max(r->maxh, w->maxh);
- }
- page_contents->words.move_right();
- } while (! page_contents->words.is_equal_to_head());
- }
-}
-
-
-int page::is_in_region (graphic_glob *g)
-{
- region_glob *r;
-
- if (! regions.is_empty()) {
- regions.start_from_head();
- do {
- r = regions.get_data();
- if (is_subsection(g->minv, g->maxv, r->minv, r->maxv) &&
- is_subsection(g->minh, g->maxh, r->minh, r->maxh)) {
- return( TRUE );
- }
- regions.move_right();
- } while (! regions.is_equal_to_head());
- }
- return( FALSE );
-}
-
-
-/*
- * no_raw_commands - returns TRUE if no html raw commands exist between
- * minv and maxv.
- */
-
-int page::no_raw_commands (int minv, int maxv)
-{
- text_glob *g;
-
- if (! words.is_empty()) {
- words.start_from_head();
- do {
- g = words.get_data();
- if ((g->is_raw_command) && (g->is_html_command) &&
- (is_intersection(g->minv, g->maxv, minv, maxv))) {
- return( FALSE );
- }
- words.move_right();
- } while (! words.is_equal_to_head());
- }
- return( TRUE );
-}
-
-/*
- * can_grow_region - returns TRUE if a region exists which can be extended
- * to include graphic_glob *g. The region is extended.
- */
-
-int page::can_grow_region (graphic_glob *g)
-{
- region_glob *r;
- int quarter_inch=font::res/4;
-
- if (! regions.is_empty()) {
- regions.start_from_head();
- do {
- r = regions.get_data();
- // must prevent grohtml from growing a region through a html raw command
- if (is_intersection(g->minv, g->maxv, r->minv, r->maxv+quarter_inch) &&
- (no_raw_commands(r->minv, r->maxv+quarter_inch))) {
-#if defined(DEBUGGING)
- stop();
- printf("r minh=%d minv=%d maxh=%d maxv=%d\n",
- r->minh, r->minv, r->maxh, r->maxv);
- printf("g minh=%d minv=%d maxh=%d maxv=%d\n",
- g->minh, g->minv, g->maxh, g->maxv);
-#endif
- r->minv = min(r->minv, g->minv);
- r->maxv = max(r->maxv, g->maxv);
- r->minh = min(r->minh, g->minh);
- r->maxh = max(r->maxh, g->maxh);
-#if defined(DEBUGGING)
- printf(" r minh=%d minv=%d maxh=%d maxv=%d\n",
- r->minh, r->minv, r->maxh, r->maxv);
-#endif
- return( TRUE );
- }
- regions.move_right();
- } while (! regions.is_equal_to_head());
- }
- return( FALSE );
-}
-
-
-/*
- * make_new_region - creates a new region to contain, g.
- */
-
-void page::make_new_region (graphic_glob *g)
-{
- region_glob *r=new region_glob;
-
- r->minv = g->minv;
- r->maxv = g->maxv;
- r->minh = g->minh;
- r->maxv = g->maxv;
- regions.add(r);
-}
-
-
-void html_printer::dump_page(void)
-{
- text_glob *g;
-
- printf("\n\ndebugging start\n");
- page_contents->words.start_from_head();
- do {
- g = page_contents->words.get_data();
- printf("%s ", g->text_string);
- page_contents->words.move_right();
- } while (! page_contents->words.is_equal_to_head());
- printf("\ndebugging end\n\n");
-}
-
-
-/*
- * traverse_page_regions - runs through the regions in current_page
- * and generate html for text, and troff output
- * for all graphics.
- */
-
-void html_printer::traverse_page_regions (void)
-{
- region_glob *r;
-
- start_region_vpos = 0;
- start_region_hpos = 0;
- end_region_vpos = -1;
- end_region_hpos = -1;
-
- if (! page_contents->regions.is_empty()) {
- page_contents->regions.start_from_head();
- do {
- r = page_contents->regions.get_data();
- if (r->minv > 0) {
- end_region_vpos = r->minv-1;
- } else {
- end_region_vpos = 0;
- }
- end_region_hpos = -1;
- display_globs(TRUE);
- calculate_region_margins(r);
- start_region_vpos = end_region_vpos;
- end_region_vpos = r->maxv;
- start_region_hpos = r->minh;
- end_region_hpos = r->maxh;
- display_globs(FALSE);
- start_region_vpos = end_region_vpos+1;
- start_region_hpos = 0;
- page_contents->regions.move_right();
- } while (! page_contents->regions.is_equal_to_head());
- start_region_vpos = end_region_vpos+1;
- start_region_hpos = 0;
- end_region_vpos = -1;
- end_region_hpos = -1;
- }
- display_globs(TRUE);
-}
-
-int html_printer::is_within_region (text_glob *t)
-{
- int he, ve, hs;
-
- if (start_region_hpos == -1) {
- hs = t->minh;
- } else {
- hs = start_region_hpos;
- }
- if (end_region_vpos == -1) {
- ve = t->maxv;
- } else {
- ve = end_region_vpos;
- }
- if (end_region_hpos == -1) {
- he = t->maxh;
- } else {
- he = end_region_hpos;
- }
- return( is_subsection(t->minv, t->maxv, start_region_vpos, ve) &&
- is_subsection(t->minh, t->maxh, hs, he) );
-}
-
-int html_printer::is_within_region (graphic_glob *g)
-{
- int he, ve, hs;
-
- if (start_region_hpos == -1) {
- hs = g->minh;
- } else {
- hs = start_region_hpos;
- }
- if (end_region_vpos == -1) {
- ve = g->maxv;
- } else {
- ve = end_region_vpos;
- }
- if (end_region_hpos == -1) {
- he = g->maxh;
- } else {
- he = end_region_hpos;
- }
- return( is_subsection(g->minv, g->maxv, start_region_vpos, ve) &&
- is_subsection(g->minh, g->maxh, hs, he) );
-}
-
-int html_printer::is_less (graphic_glob *g, text_glob *t)
-{
- return( (g->minv < t->minv) || ((g->minv == t->minv) && (g->minh < t->minh)) );
-}
-
-void html_printer::convert_to_image (char *troff_src, char *image_name)
-{
- char buffer[MAX_STRING_LENGTH*2 + 200];
- char *ps_src = mktemp(xtmptemplate("-ps-"));
-
- sprintf(buffer, "grops%s %s > %s", EXE_EXT, troff_src, ps_src);
- if (debug_on) {
- fprintf(stderr, "%s\n", buffer);
- }
- int status = system(buffer);
- if (status == -1) {
- fprintf(stderr, "\"%s\" failed (no grops on PATH?)\n", buffer);
- return;
- }
- else if (status) {
- fprintf(stderr, "\"%s\" returned status %d\n", buffer, status);
- }
-
- if (image_type == gif) {
- sprintf(buffer,
- "echo showpage | gs%s -q -dSAFER -sDEVICE=ppmraw -r%d -g%dx%d -sOutputFile=- %s - | ppmquant%s 256 | ppmtogif%s > %s.gif",
- EXE_EXT, image_res,
- (end_region_hpos-start_region_hpos)*image_res/font::res+IMAGE_BOARDER_PIXELS,
- (end_region_vpos-start_region_vpos)*image_res/font::res+IMAGE_BOARDER_PIXELS,
- ps_src, EXE_EXT, EXE_EXT, image_name);
- } else {
- sprintf(buffer,
- "echo showpage | gs%s -q -dSAFER -sDEVICE=%s -r%d -g%dx%d -sOutputFile=- %s - > %s.png",
- EXE_EXT, image_device,
- image_res,
- (end_region_hpos-start_region_hpos)*image_res/font::res+IMAGE_BOARDER_PIXELS,
- (end_region_vpos-start_region_vpos)*image_res/font::res+IMAGE_BOARDER_PIXELS,
- ps_src, image_name);
-#if 0
- sprintf(buffer,
- "echo showpage | gs -q -dSAFER -sDEVICE=ppmraw -r%d -g%dx%d -sOutputFile=- %s.ps - > %s.pnm ; pnmtopng -transparent white %s.pnm > %s.png \n",
- /* image_device, */
- image_res,
- (end_region_hpos-start_region_hpos)*image_res/font::res+IMAGE_BOARDER_PIXELS,
- (end_region_vpos-start_region_vpos)*image_res/font::res+IMAGE_BOARDER_PIXELS,
- name, name, name, image_name);
-#endif
- }
- if (debug_on) {
- fprintf(stderr, "%s\n", buffer);
- }
- // Redirect standard error to the null device. This is more
- // portable than using "2> /dev/null" inside the commands above,
- // since it doesn't require a Unixy shell.
- int save_stderr = dup(2);
- if (save_stderr > 2) {
- int fdnull = open(NULL_DEV, O_WRONLY|O_BINARY, 0666);
- if (fdnull > 2)
- dup2(fdnull, 2);
- if (fdnull >= 0)
- close(fdnull);
- }
- status = system(buffer);
- dup2(save_stderr, 2);
- if (status == -1) {
- fprintf(stderr,
- "Conversion to image failed (no gs/ppmquant/ppmtogif on PATH?)\n");
- }
- else if (status) {
- fprintf(stderr,
- "Conversion to image returned status %d\n", status);
- }
- unlink(ps_src);
- unlink(troff_src);
-}
-
-void html_printer::prologue (void)
-{
- troff.put_string("x T ps\nx res ");
- troff.put_number(postscript_res);
- troff.put_string(" 1 1\nx init\np1\n");
-}
-
-void html_printer::display_globs (int is_to_html)
-{
- text_glob *t=0;
- graphic_glob *g=0;
- FILE *f=0;
- char *troff_src;
- int something=FALSE;
- int is_center=FALSE;
-
- end_paragraph();
-
- if (! is_to_html) {
- is_center = html_position_region();
- make_new_image_name();
- f = xtmpfile(&troff_src, "-troff-", FALSE);
- troff.set_file(f);
- prologue();
- output_style.f = 0;
- }
- if (! page_contents->words.is_empty()) {
- page_contents->words.start_from_head();
- t = page_contents->words.get_data();
- }
-
- if (! page_contents->lines.is_empty()) {
- page_contents->lines.start_from_head();
- g = page_contents->lines.get_data();
- }
-
- do {
-#if 0
- if ((t != 0) && (strcmp(t->text_string, "(1.a)") == 0)) {
- stop();
- }
-#endif
- if ((t == 0) && (g != 0)) {
- if (is_within_region(g)) {
- something = TRUE;
- display_line(g, is_to_html);
- }
- if (page_contents->lines.is_empty() || page_contents->lines.is_equal_to_tail()) {
- g = 0;
- } else {
- g = page_contents->lines.move_right_get_data();
- }
- } else if ((g == 0) && (t != 0)) {
- if (is_within_region(t)) {
- display_word(t, is_to_html);
- something = TRUE;
- }
- if (page_contents->words.is_empty() || page_contents->words.is_equal_to_tail()) {
- t = 0;
- } else {
- t = page_contents->words.move_right_get_data();
- }
- } else {
- if ((g == 0) || (t == 0)) {
- // hmm nothing to print out...
- } else if (is_less(g, t)) {
- if (is_within_region(g)) {
- display_line(g, is_to_html);
- something = TRUE;
- }
- if (page_contents->lines.is_empty() || page_contents->lines.is_equal_to_tail()) {
- g = 0;
- } else {
- g = page_contents->lines.move_right_get_data();
- }
- } else {
- if (is_within_region(t)) {
- display_word(t, is_to_html);
- something = TRUE;
- }
- if (page_contents->words.is_empty() || page_contents->words.is_equal_to_tail()) {
- t = 0;
- } else {
- t = page_contents->words.move_right_get_data();
- }
- }
- }
- } while ((t != 0) || (g != 0));
-
- if ((! is_to_html) && (f != 0)) {
- fclose(troff.get_file());
- if (something) {
- convert_to_image(troff_src, image_name);
-
- if (is_center) {
- end_paragraph();
- begin_paragraph(center_alignment);
- force_begin_paragraph();
- }
- html.put_string("<img src=\"");
- html.put_string(image_name);
- if (image_type == gif) {
- html.put_string(".gif\"");
- } else {
- html.put_string(".png\"");
- }
- html.put_string(">\n");
- html_newline();
- if (is_center) {
- end_paragraph();
- }
-
- output_vpos = end_region_vpos;
- output_hpos = 0;
- need_one_newline = FALSE;
- output_style.f = 0;
- end_paragraph();
- }
- }
-}
-
-void html_printer::flush_page (void)
-{
- calculate_margin();
- output_vpos = -1;
- output_hpos = get_left();
- supress_sub_sup = TRUE;
-#if 0
- dump_page();
-#endif
- html.begin_comment("left margin: ").comment_arg(i_to_a(left_margin_indent)).end_comment();;
- html.begin_comment("right margin: ").comment_arg(i_to_a(right_margin_indent)).end_comment();;
- remove_redundant_regions();
- page_contents->calculate_region();
- remove_duplicate_regions();
- find_title();
- supress_sub_sup = TRUE;
- traverse_page_regions();
- terminate_current_font();
- if (need_one_newline) {
- html_newline();
- }
- end_paragraph();
-
- // move onto a new page
- delete page_contents;
- page_contents = new page;
-}
-
-static int convertSizeToHTML (int size)
-{
- if (size < 6) {
- return( 0 );
- } else if (size < 8) {
- return( 1 );
- } else if (size < 10) {
- return( 2 );
- } else if (size < 12) {
- return( 3 );
- } else if (size < 14) {
- return( 4 );
- } else if (size < 16) {
- return( 5 );
- } else if (size < 18) {
- return( 6 );
- } else {
- return( 7 );
- }
-}
-
-
-void html_printer::write_html_font_face (const char *fontname, const char *left, const char *right)
-{
- switch (fontname[0]) {
-
- case 'C': html.put_string(left) ; html.put_string("tt"); html.put_string(right);
- break;
- case 'H': break;
- case 'T': break;
- default: break;
- }
-}
-
-
-void html_printer::write_html_font_type (const char *fontname, const char *left, const char *right)
-{
- if (strcmp(&fontname[1], "B") == 0) {
- html.put_string(left) ; html.put_string("B"); html.put_string(right);
- } else if (strcmp(&fontname[1], "I") == 0) {
- html.put_string(left) ; html.put_string("I"); html.put_string(right);
- } else if (strcmp(&fontname[1], "BI") == 0) {
- html.put_string(left) ; html.put_string("EM"); html.put_string(right);
- }
-}
-
-
-void html_printer::html_change_font (text_glob *g, const char *fontname, int size)
-{
- char buffer[1024];
-
- if (output_style.f != 0) {
- const char *oldfontname = output_style.f->get_name();
-
- // firstly terminate the current font face and type
- if ((oldfontname != 0) && (oldfontname != fontname)) {
- write_html_font_face(oldfontname, "</", ">");
- write_html_font_type(oldfontname, "</", ">");
- }
- }
-
- if ((output_style.point_size != size) && (output_style.point_size != 0)) {
- // shutdown the previous font size
- html.put_string("</font>");
- }
-
- if ((output_style.point_size != size) && (size != 0)) {
- // now emit the size if it has changed
- sprintf(buffer, "<font size=%d>", convertSizeToHTML(size));
- html.put_string(buffer);
- output_style.point_size = size; // and remember the size
- }
- output_style.f = 0; // no style at present
- output_style.point_size = size; // remember current font size
-
- if (fontname != 0) {
- if (! g->is_raw_command) {
- // now emit the new font
- write_html_font_face(fontname, "<", ">");
-
- // now emit the new font type
- write_html_font_type(fontname, "<", ">");
-
- output_style = g->text_style; // remember style for next time
- }
- }
-}
-
-
-void html_printer::change_font (text_glob *g, int is_to_html)
-{
- if (is_to_html) {
- if (output_style != g->text_style) {
- const char *fontname=0;
- int size=0;
-
- if (g->text_style.f != 0) {
- fontname = g->text_style.f->get_name();
- size = (font::res/(72*font::sizescale))*g->text_style.point_size;
- }
- html_change_font(g, fontname, size);
- }
- } else {
- // is to troff
- if (output_style != g->text_style) {
- if (g->text_style.f != 0) {
- const char *fontname = g->text_style.f->get_name();
- int size = (font::res/(72*font::sizescale))*g->text_style.point_size;
-
- if (fontname == 0) {
- fatal("no internalname specified for font");
- }
-
- troff_change_font(fontname, size, g->text_style.font_no);
- output_style = g->text_style; // remember style for next time
- }
- }
- }
-}
-
-/*
- * is_bold - returns TRUE if the text inside, g, is using a bold face.
- * It returns FALSE is g contains a raw html command, even if this uses
- * a bold font.
- */
-
-int html_printer::is_bold (text_glob *g)
-{
- if (g->text_style.f == 0) {
- // unknown font
- return( FALSE );
- } else if (g->is_raw_command) {
- return( FALSE );
- } else {
- const char *fontname = g->text_style.f->get_name();
-
- if (strlen(fontname) >= 2) {
- return( fontname[1] == 'B' );
- } else {
- return( FALSE );
- }
- }
-}
-
-void html_printer::terminate_current_font (void)
-{
- text_glob g;
-
- // we create a dummy glob just so we can tell html_change_font not to start up
- // a new font
- g.is_raw_command = TRUE;
- html_change_font(&g, 0, 0);
-}
-
-void html_printer::write_header (text_glob *g)
-{
- if (strlen(header.header_buffer) > 0) {
- if (header.header_level > 7) {
- header.header_level = 7;
- }
-
- if (cutoff_heading+2 > header.header_level) {
- // firstly we must terminate any font and type faces
- terminate_current_font();
- end_paragraph();
-
- // secondly we generate a tag
- html.put_string("<a name=\"");
- html.put_string(header.header_buffer);
- html.put_string("\"></a>");
- // now we save the header so we can issue a list of link
- style st;
-
- header.no_of_headings++;
-
- 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);
- header.headers.add(h); // and add this header to the header list
- } else {
- terminate_current_font();
- end_paragraph();
- }
-
- // we adjust the margin if necessary
-
- if (g->minh < left_margin_indent) {
- header_indent = g->minh;
- }
-
- // 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(">");
-
- need_one_newline = FALSE;
- begin_paragraph(left_alignment);
- header.written_header = TRUE;
- }
-}
-
-/*
- * translate_str_to_html - translates a string, str, into html representation.
- * len indicates the string length.
- */
-
-void translate_str_to_html (font *f, char *str, int len)
-{
- char buf[MAX_STRING_LENGTH];
-
- str_translate_to_html(f, buf, MAX_STRING_LENGTH, str, len, TRUE);
- strncpy(str, buf, max(len, strlen(buf)+1));
-}
-
-/*
- * write_headings - emits a list of links for the headings in this document
- */
-
-void header_desc::write_headings (FILE *f)
-{
- text_glob *g;
-
- if (! headers.is_empty()) {
- headers.start_from_head();
- do {
- g = headers.get_data();
- fprintf(f, "<a href=\"#%s\">%s</a><br>\n", g->text_string, g->text_string);
- headers.move_right();
- } while (! headers.is_equal_to_head());
- }
-}
-
-void html_printer::determine_header_level (void)
-{
- int i;
- int l=strlen(header.header_buffer);
- int stops=0;
-
- for (i=0; ((i<l) && ((header.header_buffer[i] == '.') || is_digit(header.header_buffer[i]))) ; i++) {
- if (header.header_buffer[i] == '.') {
- stops++;
- }
- }
- if (stops > 0) {
- header.header_level = stops;
- }
-}
-
-
-void html_printer::build_header (text_glob *g)
-{
- text_glob *l;
- int current_vpos;
- char buf[MAX_STRING_LENGTH];
-
- strcpy(header.header_buffer, "");
- do {
- l = g;
- current_vpos = g->minv;
- 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);
- page_contents->words.move_right();
- g = page_contents->words.get_data();
- if (g->minv == current_vpos) {
- strcat(header.header_buffer, " ");
- }
- } while ((! page_contents->words.is_equal_to_head()) &&
- ((g->minv == current_vpos) || (l->maxh == right_margin_indent)));
-
- determine_header_level();
- // finally set the output to neutral for after the header
-
- g = page_contents->words.get_data();
- output_vpos = g->minv; // set output_vpos to the next line since
- output_hpos = left_margin_indent; // html header forces a newline anyway
- page_contents->words.move_left(); // so that next time we use old g
-
- need_one_newline = FALSE;
-}
-
-
-/*
- * is_whole_line_bold - returns TRUE if the whole line is bold.
- */
-
-int html_printer::is_whole_line_bold (text_glob *g)
-{
- text_glob *n=g;
- int current_vpos=g->minv;
-
- do {
- if (is_bold(n)) {
- page_contents->words.move_right();
- n = page_contents->words.get_data();
- } else {
- while (page_contents->words.get_data() != g) {
- page_contents->words.move_left();
- }
- return( FALSE );
- }
- } while ((! page_contents->words.is_equal_to_head()) && (is_on_same_line(n, current_vpos)));
- // was (n->minv == current_vpos)
- while (page_contents->words.get_data() != g) {
- page_contents->words.move_left();
- }
- return( TRUE );
-}
-
-
-/*
- * is_a_header - returns TRUE if the whole sequence of contineous lines are bold.
- * It checks to see whether a line is likely to be contineous and
- * then checks that all words are bold.
- */
-
-int html_printer::is_a_header (text_glob *g)
-{
- text_glob *l;
- text_glob *n=g;
- int current_vpos;
-
- do {
- l = n;
- current_vpos = n->minv;
- if (is_bold(n)) {
- page_contents->words.move_right();
- n = page_contents->words.get_data();
- } else {
- while (page_contents->words.get_data() != g) {
- page_contents->words.move_left();
- }
- return( FALSE );
- }
- } while ((! page_contents->words.is_equal_to_head()) &&
- ((n->minv == current_vpos) || (l->maxh == right_margin_indent)));
- while (page_contents->words.get_data() != g) {
- page_contents->words.move_left();
- }
- return( TRUE );
-}
-
-
-int html_printer::processed_header (text_glob *g)
-{
- if ((guess_on) && (g->minh <= left_margin_indent) && (! using_table_for_indent()) &&
- (is_a_header(g))) {
- build_header(g);
- write_header(g);
- return( TRUE );
- } else {
- return( FALSE );
- }
-}
-
-int is_punctuation (char *s, int length)
-{
- return( (length == 1) &&
- ((s[0] == '(') || (s[0] == ')') || (s[0] == '!') || (s[0] == '.') || (s[0] == '[') ||
- (s[0] == ']') || (s[0] == '?') || (s[0] == ',') || (s[0] == ';') || (s[0] == ':') ||
- (s[0] == '@') || (s[0] == '#') || (s[0] == '$') || (s[0] == '%') || (s[0] == '^') ||
- (s[0] == '&') || (s[0] == '*') || (s[0] == '+') || (s[0] == '-') || (s[0] == '=') ||
- (s[0] == '{') || (s[0] == '}') || (s[0] == '|') || (s[0] == '\"') || (s[0] == '\''))
- );
-}
-
-/*
- * move_horizontal - moves right into the position, g->minh.
- */
-
-void html_printer::move_horizontal (text_glob *g, int left_margin)
-{
- if (g->text_style.f != 0) {
- int w = g->text_style.f->get_space_width(g->text_style.point_size);
-
- if (w == 0) {
- fatal("space width is zero");
- }
- if ((output_hpos == left_margin) && (g->minh > output_hpos)) {
- make_html_indent(g->minh-output_hpos);
- } else {
- emit_space(g, FALSE);
- }
- output_hpos = g->maxh;
- output_vpos = g->minv;
-
- change_font(g, TRUE);
- }
-}
-
-/*
- * looks_like_subscript - returns TRUE if, g, looks like a subscript.
- */
-
-int html_printer::looks_like_subscript (text_glob *g)
-{
- int r = font::res;
- int height = output_style.point_size*r/72;
-
- /* was return( ((output_vpos < g->minv) && (output_style.point_size != 0) &&
- * (output_style.point_size > g->text_style.point_size)) );
- */
-
- return( (output_style.point_size != 0) && (! supress_sub_sup) && (output_vpos+height < g->maxv) );
-}
-
-/*
- * looks_like_superscript - returns TRUE if, g, looks like a superscript.
- */
-
-int html_printer::looks_like_superscript (text_glob *g)
-{
- int r = font::res;
- int height = output_style.point_size*r/72;
-
-/* was
- * return(((output_vpos > g->minv) && (output_style.point_size != 0) &&
- * (output_style.point_size > g->text_style.point_size)));
- */
-
- return( (output_style.point_size != 0) && (! supress_sub_sup) && (output_vpos+height > g->maxv) );
-}
-
-/*
- * looks_like_larger_font - returns TRUE if, g, can be treated as a larger font.
- * g needs to be on the same line
- */
-
-int html_printer::looks_like_larger_font (text_glob *g)
-{
- int r = font::res;
- int height = output_style.point_size*r/72;
-
- return( (output_vpos+height == g->maxv) && (output_style.point_size != 0) &&
- (convertSizeToHTML(g->text_style.point_size)+1 == convertSizeToHTML(output_style.point_size)) );
-}
-
-/*
- * looks_like_smaller_font - returns TRUE if, g, can be treated as a smaller font.
- * g needs to be on the same line
- */
-
-int html_printer::looks_like_smaller_font (text_glob *g)
-{
- int r = font::res;
- int height = output_style.point_size*r/72;
-
- return( (output_vpos+height == g->maxv) && (output_style.point_size != 0) &&
- (convertSizeToHTML(g->text_style.point_size) == convertSizeToHTML(output_style.point_size)+1) );
-}
-
-/*
- * pretend_is_on_same_line - returns TRUE if we think, g, is on the same line as the previous glob.
- * Note that it believes a single word spanning the left..right as being
- * on a different line.
- */
-
-int html_printer::pretend_is_on_same_line (text_glob *g, int left_margin, int right_margin)
-{
- return( auto_on && (right_margin == output_hpos) && (left_margin == g->minh) &&
- (right_margin != g->maxh) && ((! is_whole_line_bold(g)) || (g->text_style.f == output_style.f)) &&
- (! (using_table_for_indent()) || (indentation.wrap_margin)) );
-}
-
-int html_printer::is_on_same_line (text_glob *g, int vpos)
-{
-#if 0
- if (g->is_html_command) {
- stop();
- }
-#endif
- return(
- (vpos >= 0) &&
- (is_intersection(vpos, vpos+g->text_style.point_size*font::res/72-1, g->minv, g->maxv))
- );
-}
-
-
-/*
- * make_html_indent - creates a relative indentation.
- */
-
-void html_printer::make_html_indent (int indent)
-{
- if ((indent > 0) && ((right_margin_indent-get_left()) > 0) &&
- ((indent*100)/(right_margin_indent-get_left()))) {
- html.put_string("<span style=\" text-indent: ");
- html.put_number((indent*100)/(right_margin_indent-get_left()));
- html.put_string("%;\"></span>");
- }
-}
-
-/*
- * using_table_for_indent - returns TRUE if we currently using a table for indentation
- * purposes.
- */
-
-int html_printer::using_table_for_indent (void)
-{
- return( indentation.no_of_columns != 0 );
-}
-
-/*
- * calculate_min_gap - returns the minimum gap by which we deduce columns.
- * This is a rough heuristic.
- */
-
-int html_printer::calculate_min_gap (text_glob *g)
-{
- text_glob *t = g;
-
- while ((t->is_raw_command) && (! page_contents->words.is_equal_to_tail()) &&
- ((t->minv < end_region_vpos) || (end_region_vpos < 0))) {
- page_contents->words.move_right();
- t=page_contents->words.get_data();
- }
- rewind_text_to(g);
- if (t->is_raw_command) {
- return( font::res * 10 ); // impossibly large gap width
- } else {
- return( t->text_style.f->get_space_width(t->text_style.point_size)*GAP_SPACES );
- }
-}
-
-/*
- * collect_columns - place html text in a column and return the vertical limit reached.
- */
-
-int html_printer::collect_columns (struct text_defn *next_words,
- struct text_defn *next_cols,
- struct text_defn *last_words,
- struct text_defn *last_cols,
- int max_words)
-{
- text_glob *start = page_contents->words.get_data();
- text_glob *t = start;
- int upper_limit = 0;
-
- /*
- * initialize cols and words
- */
- next_words[0].left = 0;
- next_words[0].right = 0;
- next_cols [0].left = 0;
- next_cols [0].right = 0;
-
- /*
- * if we have not reached the end collect the words on the current line
- */
- if (start != 0) {
- int graphic_limit = end_region_vpos;
-
- if (is_whole_line_bold(t) && (t->minh <= left_margin_indent) && (guess_on)) {
- /*
- * found header therefore terminate indentation table.
- * Return a negative number so we know a header has
- * stopped the column
- */
- upper_limit = -t->minv;
- } else {
- int i =0; // is the index into next_cols
- int j =0; // is the column index for last_cols
- int k =0; // is the index into next_words
- int l =0; // is the index into next_words
- int prevh =0;
- int mingap =calculate_min_gap(start);
-
- /*
- * while words on the same line record them and any significant gaps
- */
- while ((t != 0) && (is_on_same_line(t, start->minv) && (i<max_words)) &&
- ((graphic_limit == -1) || (graphic_limit > t->minv))) {
-
- /*
- * now find column index from the last line which corresponds to, t.
- */
- j = find_column_index_in_line(t, last_cols);
-
- /*
- * now find word index from the last line which corresponds to, t.
- */
- l = find_column_index_in_line(t, last_words);
-
- /*
- * Note t->minh might equal t->maxh when we are passing a special device character via \X
- * we currently ignore this when considering tables
- *
- * if we have found a significant gap then record it
- */
- if (((t->minh - prevh >= mingap) ||
- ((last_cols != 0) && (last_cols [j].right != 0) && (t->minh == last_cols [j].left))) &&
- (t->minh != t->maxh)) {
- next_cols[i].left = t->minh;
- next_cols[i].right = t->maxh;
- i++;
- /*
- * terminate the array
- */
- if (i<max_words) {
- next_cols[i].left = 0;
- next_cols[i].right = 0;
- }
- } else if (i>0) {
- /*
- * move previous right hand column to align with, t.
- */
-
- if (t->minh > next_cols[i-1].left) {
- /*
- * a simple precaution in case we get globs which are technically on the same line
- * (sadly this does occur sometimes - maybe we should be stricter with is_on_same_line)
- * --fixme--
- */
- next_cols[i-1].right = max(next_cols[i-1].right, t->maxh);
- }
- }
- /*
- * remember to record the individual words
- */
- next_words[k].left = t->minh;
- next_words[k].right = t->maxh;
- k++;
-
- /*
- * and record the vertical upper limit
- */
- upper_limit = max(t->minv, upper_limit);
-
- /*
- * and update prevh - used to detect a when a different line is seen
- */
- prevh = t->maxh;
-
- /*
- * get next word into, t, which equals 0, if no word is found
- */
- page_contents->words.move_right();
- t = page_contents->words.get_data();
- if (page_contents->words.is_equal_to_head()) {
- t = 0;
- }
- }
-
- /*
- * and terminate the next_words array
- */
-
- if (k<max_words) {
- next_words[k].left = 0;
- next_words[k].right = 0;
- }
-
- /*
- * consistency check, next_cols, after removing redundant colums.
- */
-
- remove_redundant_columns(next_cols);
-
-#if 0
- for (k=0; k<count_columns(next_cols); k++) {
- if (next_cols[k].left > next_cols[k].right) {
- fprintf(stderr, "left > right\n"); fflush(stderr);
- stop();
- fatal("next_cols has messed up columns");
- }
- if ((k>0) && (k+1<count_columns(next_cols)) && (next_cols[k].right > next_cols[k+1].left)) {
- fprintf(stderr, "next_cols[k].right > next_cols[k+1].left\n"); fflush(stderr);
- stop();
- fatal("next_cols has messed up columns");
- }
- }
-#endif
- }
- }
- return( upper_limit );
-}
-
-/*
- * conflict_with_words - returns TRUE if a word sequence crosses a column.
- */
-
-int html_printer::conflict_with_words (struct text_defn *column_guess, struct text_defn *words)
-{
- int i=0;
- int j;
-
- while ((column_guess[i].right != 0) && (i<MAX_WORDS_PER_LINE)) {
- j=0;
- while ((words[j].right != 0) && (j<MAX_WORDS_PER_LINE)) {
- if ((words[j].left <= column_guess[i].right) && (i+1<MAX_WORDS_PER_LINE) &&
- (column_guess[i+1].right != 0) && (words[j].right >= column_guess[i+1].left)) {
- if (debug_table_on) {
- fprintf(stderr, "is a conflict with words\n");
- fflush(stderr);
- }
- return( TRUE );
- }
- j++;
- }
- i++;
- }
- if (debug_table_on) {
- fprintf(stderr, "is NOT a conflict with words\n");
- fflush(stderr);
- }
- return( FALSE );
-}
-
-/*
- * combine_line - combines dest and src.
- */
-
-void html_printer::combine_line (struct text_defn *dest, struct text_defn *src)
-{
- int i;
-
- for (i=0; (i<MAX_WORDS_PER_LINE) && (src[i].right != 0); i++) {
- include_into_list(dest, &src[i]);
- }
- remove_redundant_columns(dest);
-}
-
-/*
- * remove_entry_in_line - removes an entry, j, in, line.
- */
-
-void html_printer::remove_entry_in_line (struct text_defn *line, int j)
-{
- while (line[j].right != 0) {
- line[j].left = line[j+1].left;
- line[j].right = line[j+1].right;
- j++;
- }
-}
-
-/*
- * remove_redundant_columns - searches through the array columns and removes any redundant entries.
- */
-
-void html_printer::remove_redundant_columns (struct text_defn *line)
-{
- int i=0;
- int j=0;
-
- while (line[i].right != 0) {
- if ((i<MAX_WORDS_PER_LINE) && (line[i+1].right != 0)) {
- j = 0;
- while ((j<MAX_WORDS_PER_LINE) && (line[j].right != 0)) {
- if ((j != i) && (is_intersection(line[i].left, line[i].right, line[j].left, line[j].right))) {
- line[i].left = min(line[i].left , line[j].left);
- line[i].right = max(line[i].right, line[j].right);
- remove_entry_in_line(line, j);
- } else {
- j++;
- }
- }
- }
- i++;
- }
-}
-
-/*
- * include_into_list - performs an order set inclusion
- */
-
-void html_printer::include_into_list (struct text_defn *line, struct text_defn *item)
-{
- int i=0;
-
- while ((i<MAX_WORDS_PER_LINE) && (line[i].right != 0) && (line[i].left<item->left)) {
- i++;
- }
-
- if (line[i].right == 0) {
- // add to the end
- if (i<MAX_WORDS_PER_LINE) {
- if ((i>0) && (line[i-1].left > item->left)) {
- fatal("insertion error");
- }
- line[i].left = item->left;
- line[i].right = item->right;
- i++;
- line[i].left = 0;
- line[i].right = 0;
- }
- } else {
- if (line[i].left == item->left) {
- line[i].right = max(item->right, line[i].right);
- } else {
- // insert
- int left = item->left;
- int right = item->right;
- int l = line[i].left;
- int r = line[i].right;
-
- while ((i+1<MAX_WORDS_PER_LINE) && (line[i].right != 0)) {
- line[i].left = left;
- line[i].right = right;
- i++;
- left = l;
- right = r;
- l = line[i].left;
- r = line[i].right;
- }
- if (i+1<MAX_WORDS_PER_LINE) {
- line[i].left = left;
- line[i].right = right;
- line[i+1].left = 0;
- line[i+1].right = 0;
- }
- }
- }
-}
-
-/*
- * is_in_column - return TRUE if value is present in line.
- */
-
-int html_printer::is_in_column (struct text_defn *line, struct text_defn *item, int max_words)
-{
- int i=0;
-
- while ((i<max_words) && (line[i].right != 0)) {
- if (line[i].left == item->left) {
- return( TRUE );
- } else {
- i++;
- }
- }
- return( FALSE );
-}
-
-/*
- * calculate_right - calculate the right most margin for each column in line.
- */
-
-void html_printer::calculate_right (struct text_defn *line, int max_words)
-{
- int i=0;
-
- while ((i<max_words) && (line[i].right != 0)) {
- if (i>0) {
- line[i-1].right = line[i].left;
- }
- i++;
- }
-}
-
-/*
- * add_right_full_width - adds an extra column to the right to bring the table up to
- * full width.
- */
-
-void html_printer::add_right_full_width (struct text_defn *line, int mingap)
-{
- int i=0;
-
- while ((i<MAX_WORDS_PER_LINE) && (line[i].right != 0)) {
- i++;
- }
-
- if ((i>0) && (line[i-1].right != right_margin_indent) && (i+1<MAX_WORDS_PER_LINE)) {
- line[i].left = min(line[i-1].right+mingap, right_margin_indent);
- line[i].right = right_margin_indent;
- i++;
- if (i<MAX_WORDS_PER_LINE) {
- line[i].left = 0;
- line[i].right = 0;
- }
- }
-}
-
-/*
- * determine_right_most_column - works out the right most limit of the right most column.
- * Required as we might be performing a .2C and only
- * have enough text to fill the left column.
- */
-
-void html_printer::determine_right_most_column (struct text_defn *line, int max_words)
-{
- int i=0;
-
- while ((i<max_words) && (line[i].right != 0)) {
- i++;
- }
- if (i>0) {
- // remember right_margin_indent is the right most position for this page
- line[i-1].right = column_calculate_right_margin(line[i-1].left, right_margin_indent);
- }
-}
-
-/*
- * is_column_match - returns TRUE if a word is aligned in the same horizontal alignment
- * between two lines, line1 and line2. If so then this horizontal
- * position is saved in match.
- */
-
-int html_printer::is_column_match (struct text_defn *match,
- struct text_defn *line1, struct text_defn *line2, int max_words)
-{
- int i=0;
- int j=0;
- int found=FALSE;
- int first=(match[0].left==0);
-
- if (first) {
- struct text_defn t;
-
- t.left = left_margin_indent;
- t.right = 0;
-
- include_into_list(match, &t);
- }
- while ((line1[i].right != 0) && (line2[i].right != 0)) {
- if (line1[i].left == line2[j].left) {
- // same horizontal alignment found
- include_into_list(match, &line1[i]);
- i++;
- j++;
- found = TRUE;
- } else if (line1[i].left < line2[j].left) {
- i++;
- } else {
- j++;
- }
- }
- calculate_right(match, max_words);
- return( found );
-}
-
-/*
- * check_lack_of_hits - returns TRUE if a column has been moved to a position
- * of only one hit from a position of more than one hit.
- */
-
-int html_printer::check_lack_of_hits (struct text_defn *next_guess,
- struct text_defn *last_guess,
- text_glob *start, int limit)
-{
- text_glob *current=page_contents->words.get_data();
- int n=count_columns(last_guess);
- int m=count_columns(next_guess);
- int i, j;
-
- if (limit > 0) {
- rewind_text_to(start);
- count_hits(last_guess, n, limit);
- rewind_text_to(current);
- i=0;
- j=0;
- while ((i<n) && (j<m) &&
- (last_guess[i].right != 0) && (next_guess[j].right != 0)) {
- if ((is_intersection(last_guess[i].left, last_guess[i].right,
- next_guess[j].left, next_guess[j].right)) &&
- (next_guess[j].left < last_guess[i].left) &&
- (last_guess[i].is_used >= 2)) {
- /*
- * next_guess has to be = 1 as this position is new
- */
- return( TRUE );
- }
- if (last_guess[i].left < next_guess[j].left) {
- i++;
- } else {
- j++;
- }
- }
- }
- return( FALSE );
-}
-
-/*
- * remove_white_using_words - remove white space in, last_guess, by examining, next_line
- * placing results into next_guess.
- * It returns TRUE if the same columns exist in next_guess and last_guess
- * we do allow columns to shrink but if a column disappears then we return FALSE.
- */
-
-int html_printer::remove_white_using_words (struct text_defn *next_guess,
- struct text_defn *last_guess, struct text_defn *next_line)
-{
- int i=0;
- int j=0;
- int k=0;
- int removed=FALSE;
-
- while ((last_guess[j].right != 0) && (next_line[k].right != 0)) {
- if (last_guess[j].left == next_line[k].left) {
- // same horizontal alignment found
- next_guess[i].left = last_guess[j].left;
- next_guess[i].right = max(last_guess[j].right, next_line[k].right);
- i++;
- j++;
- k++;
- if ((next_guess[i-1].right > last_guess[j].left) && (last_guess[j].right != 0)) {
- removed = TRUE;
- }
- } else if (last_guess[j].right < next_line[k].left) {
- next_guess[i].left = last_guess[j].left;
- next_guess[i].right = last_guess[j].right;
- i++;
- j++;
- } else if (last_guess[j].left > next_line[k].right) {
- // insert a word sequence from next_line[k]
- next_guess[i].left = next_line[k].left;
- next_guess[i].right = next_line[k].right;
- i++;
- k++;
- } else if (is_intersection(last_guess[j].left, last_guess[j].right, next_line[k].left, next_line[k].right)) {
- // potential for a column disappearing
- next_guess[i].left = min(last_guess[j].left , next_line[k].left);
- next_guess[i].right = max(last_guess[j].right, next_line[k].right);
- i++;
- j++;
- k++;
- if ((next_guess[i-1].right > last_guess[j].left) && (last_guess[j].right != 0)) {
- removed = TRUE;
- }
- }
- }
- while (next_line[k].right != 0) {
- next_guess[i].left = next_line[k].left;
- next_guess[i].right = next_line[k].right;
- i++;
- k++;
- }
- if (i<MAX_WORDS_PER_LINE) {
- next_guess[i].left = 0;
- next_guess[i].right = 0;
- }
- if (debug_table_on) {
- if (removed) {
- fprintf(stderr, "have removed column\n");
- } else {
- fprintf(stderr, "have NOT removed column\n");
- }
- fflush(stderr);
- }
- remove_redundant_columns(next_guess);
- return( removed );
-}
-
-/*
- * count_columns - returns the number of elements inside, line.
- */
-
-int html_printer::count_columns (struct text_defn *line)
-{
- int i=0;
-
- while (line[i].right != 0) {
- i++;
- }
- return( i );
-}
-
-/*
- * rewind_text_to - moves backwards until page_contents is looking at, g.
- */
-
-void html_printer::rewind_text_to (text_glob *g)
-{
- while (page_contents->words.get_data() != g) {
- if (page_contents->words.is_equal_to_head()) {
- page_contents->words.start_from_tail();
- } else {
- page_contents->words.move_left();
- }
- }
-}
-
-/*
- * can_loose_column - checks to see whether we should combine two columns.
- * This is allowed if there are is only one hit on the
- * left hand edge and the previous column is very close.
- */
-
-void html_printer::can_loose_column (text_glob *start, struct text_defn *last_guess, int limit)
-{
- text_glob *current=page_contents->words.get_data();
- int n=count_columns(last_guess);
- int i;
-
- rewind_text_to(start);
- count_hits(last_guess, n, limit);
- i=0;
- while (i<n-1) {
- if ((last_guess[i+1].is_used == 1) &&
- (calculate_min_gap(start) > (last_guess[i+1].left-last_guess[i].right))) {
- last_guess[i].right = last_guess[i+1].right;
- remove_entry_in_line(last_guess, i+1);
- n = count_columns(last_guess);
- i = 0;
- } else {
- i++;
- }
- }
- rewind_text_to(current);
-}
-
-/*
- * display_columns - a long overdue debugging function, as this column code is causing me grief :-(
- */
-
-void html_printer::display_columns (const char *word, const char *name, text_defn *line)
-{
- int i=0;
-
- fprintf(stderr, "[%s:%s]", name, word);
- while (line[i].right != 0) {
- fprintf(stderr, " <left=%d right=%d %d%%> ", line[i].left, line[i].right, line[i].percent);
- i++;
- }
- fprintf(stderr, "\n");
- fflush(stderr);
-}
-
-/*
- * copy_line - dest = src
- */
-
-void html_printer::copy_line (struct text_defn *dest, struct text_defn *src)
-{
- int k;
-
- for (k=0; ((src[k].right != 0) && (k<MAX_WORDS_PER_LINE)); k++) {
- dest[k].left = src[k].left;
- dest[k].right = src[k].right;
- }
- if (k<MAX_WORDS_PER_LINE) {
- dest[k].left = 0;
- dest[k].right = 0;
- }
-}
-
-/*
- * add_column_gaps - adds empty columns between columns which don't exactly align
- */
-
-void html_printer::add_column_gaps (struct text_defn *line)
-{
- int i=0;
- struct text_defn t;
-
- // firstly lets see whether we need an initial column on the left hand side
- if ((line[0].left != get_left()) && (line[0].right != 0) &&
- (get_left() < line[0].left) && (is_worth_column(get_left(), line[0].left))) {
- t.left = get_left();
- t.right = line[0].left;
- include_into_list(line, &t);
- }
-
- while ((i<MAX_WORDS_PER_LINE) && (line[i].right != 0)) {
- if ((i+1<MAX_WORDS_PER_LINE) && (line[i+1].right != 0) && (line[i].right != line[i+1].left) &&
- (is_worth_column(line[i].right, line[i+1].left))) {
- t.left = line[i].right;
- t.right = line[i+1].left;
- include_into_list(line, &t);
- i=0;
- } else {
- i++;
- }
- }
- // now let us see whether we need a final column on the right hand side
- if ((i>0) && (line[i-1].right != right_margin_indent) &&
- (is_worth_column(line[i-1].right, right_margin_indent))) {
- t.left = line[i-1].right;
- t.right = right_margin_indent;
- include_into_list(line, &t);
- }
-}
-
-/*
- * is_continueous_column - returns TRUE if a line has a word on one
- * of the last_col right most boundaries.
- */
-
-int html_printer::is_continueous_column (text_defn *last_col, text_defn *next_line)
-{
- int w = count_columns(next_line);
- int c = count_columns(last_col);
- int i, j;
-
- for (i=0; i<c; i++) {
- for (j=0; j<w; j++) {
- if (last_col[i].right == next_line[j].right) {
- return( TRUE );
- }
- }
- }
- return( FALSE );
-}
-
-/*
- * is_exact_left - returns TRUE if a line has a word on one
- * of the last_col left most boundaries.
- */
-
-int html_printer::is_exact_left (text_defn *last_col, text_defn *next_line)
-{
- int w = count_columns(next_line);
- int c = count_columns(last_col);
- int i, j;
-
- for (i=0; i<c; i++) {
- for (j=0; j<w; j++) {
- if ((last_col[i].left == next_line[j].left) ||
- (last_col[i].left != left_margin_indent)) {
- return( TRUE );
- }
- }
- }
- return( FALSE );
-}
-
-/*
- * continue_searching_column - decides whether we should carry on searching text for a column.
- */
-
-int html_printer::continue_searching_column (text_defn *next_col,
- text_defn *last_col,
- text_defn *all_words)
-{
- int count = count_columns(next_col);
- int words = count_columns(all_words);
-
- if ((words == 0) || ((words == 1) &&
- (all_words[0].left == left_margin_indent) &&
- (all_words[0].right == right_margin_indent))) {
- // no point as we have now seen a full line of contineous text with no gap
- return( FALSE );
- }
- return( (count == count_columns(last_col)) &&
- (last_col[0].left != left_margin_indent) || (last_col[0].right != right_margin_indent) );
-}
-
-/*
- * is_worth_column - returns TRUE if the size of this column is worth defining.
- */
-
-int html_printer::is_worth_column (int left, int right)
-{
-#if 0
- return( abs(right-left) >= MIN_COLUMN );
-#endif
- return( TRUE );
-}
-
-/*
- * large_enough_gap - returns TRUE if a large enough gap for one line was seen.
- * We need to make sure that a single line definitely warrents
- * a table.
- * It also removes other smaller gaps.
- */
-
-int html_printer::large_enough_gap (text_defn *last_col)
-{
- int i=0;
- int found=FALSE;
- int r=font::res;
- int gap=r/GAP_WIDTH_ONE_LINE;
-
- if (abs(last_col[i].left - left_margin_indent) >= gap) {
- found = TRUE;
- }
- while ((last_col[i].right != 0) && (last_col[i+1].right != 0)) {
- if (abs(last_col[i+1].left-last_col[i].right) >= gap) {
- found = TRUE;
- i++;
- } else {
- // not good enough for a single line, remove it
- last_col[i].right = last_col[i+1].right;
- remove_entry_in_line(last_col, i+1);
- }
- }
- return( found );
-}
-
-/*
- * is_subset_of_columns - returns TRUE if line, a, is a subset of line, b.
- */
-
-int html_printer::is_subset_of_columns (text_defn *a, text_defn *b)
-{
- int i;
- int j;
-
- i=0;
- while ((i<MAX_WORDS_PER_LINE) && (a[i].right != 0)) {
- j=0;
- while ((j<MAX_WORDS_PER_LINE) && (b[j].right != 0) &&
- ((b[j].left != a[i].left) || (b[j].right != a[i].right))) {
- j++;
- }
- if ((j==MAX_WORDS_PER_LINE) || (b[j].right == 0)) {
- // found a different column - not a subset
- return( FALSE );
- }
- i++;
- }
- return( TRUE );
-}
-
-/*
- * count_hits - counts the number of hits per column. A left hit
- * is when the left hand position of a glob hits
- * the left hand column.
- */
-
-void html_printer::count_hits (text_defn *col, int no_of_columns, int limit)
-{
- int i;
- text_glob *start = page_contents->words.get_data();
- text_glob *g = start;
-
- // firstly reset the used field
- for (i=0; i<no_of_columns; i++) {
- col[i].is_used = 0;
- }
- // now calculate the left hand hits
- while ((g != 0) && (g->minv <= limit)) {
- i=0;
- while ((i<no_of_columns) && (col[i].right < g->minh)) {
- i++;
- }
- if ((col[i].left == g->minh) && (col[i].right != 0)) {
- col[i].is_used++;
- }
- page_contents->words.move_right();
- if (page_contents->words.is_equal_to_head()) {
- g = 0;
- page_contents->words.start_from_tail();
- } else {
- g=page_contents->words.get_data();
- }
- }
-}
-
-/*
- * count_right_hits - counts the number of right hits per column.
- * A right hit is when the left hand position
- * of a glob hits the right hand column.
- */
-
-void html_printer::count_right_hits (text_defn *col, int no_of_columns)
-{
- int i;
- text_glob *start = page_contents->words.get_data();
- text_glob *g = start;
-
- // firstly reset the used field
- for (i=0; i<no_of_columns; i++) {
- col[i].right_hits = 0;
- }
- // now calculate the left hand hits
- while ((g != 0) && (g->minv <= indentation.vertical_limit)) {
- i=0;
- while ((i<no_of_columns) && (col[i].right < g->minh)) {
- i++;
- }
- if ((i<no_of_columns) && (col[i].right == g->maxh)) {
- if (debug_table_on) {
- fprintf(stderr, "found right hit [%s] at %d in %d\n",
- g->text_string, g->maxh, i);
- fflush(stderr);
- }
- col[i].right_hits++;
- }
- page_contents->words.move_right();
- if (page_contents->words.is_equal_to_head()) {
- g = 0;
- page_contents->words.start_from_tail();
- } else {
- g=page_contents->words.get_data();
- }
- }
-}
-
-/*
- * right_indentation - returns TRUE if a single column has been found and
- * it resembles an indentation. Ie .RS/.RE or ABSTACT
- */
-
-int html_printer::right_indentation (struct text_defn *last_guess)
-{
- // it assumes that last_guess contains a single column
- return( (last_guess[0].left > left_margin_indent) );
-}
-
-/*
- * able_to_steal_width - returns TRUE if we have an unused column which we can steal from.
- * It must have more than MIN_TEXT_PERCENT to do this.
- */
-
-int html_printer::able_to_steal_width (void)
-{
- int i;
-
- for (i=0; i<indentation.no_of_columns; i++) {
- if ((! indentation.columns[i].is_used) &&
- (indentation.columns[i].percent > MIN_TEXT_PERCENT)) {
- return( TRUE );
- }
- }
- return( FALSE );
-}
-
-/*
- * is_divisible_by - returns TRUE if n is divisible by d leaving no remainder.
- */
-
-static int is_divisible_by (int n, int d)
-{
- return( (n % d) == 0 );
-}
-
-/*
- * need_to_steal_width - returns TRUE if a used column need to be
- * given a little extra width for safty sake.
- */
-
-int html_printer::need_to_steal_width (void)
-{
- int i;
-
- for (i=0; i<indentation.no_of_columns; i++) {
- if ((indentation.columns[i].is_used) &&
- (indentation.columns[i].percent == (((indentation.columns[i].right - indentation.columns[i].left) * 100) /
- (right_margin_indent-left_margin_indent))) &&
- (indentation.columns[i].percent < PERCENT_THRESHOLD)) {
- return( TRUE );
- }
- }
- return( FALSE );
-}
-
-/*
- * utilize_round_off - utilize the remaining percent width in text columns
- */
-
-void html_printer::utilize_round_off (void)
-{
- int total = total_percentages();
- int excess, i;
-
- // use up the spare excess
-
- excess = 100-total;
-
- for (i=0; (i<indentation.no_of_columns) && (excess>0); i++) {
- if ((indentation.columns[i].is_used) &&
- (indentation.columns[i].percent < PERCENT_THRESHOLD)) {
- indentation.columns[i].percent++;
- excess--;
- }
- }
- // we might as well try and keep any numbers simple if possible
- for (i=0; (i<indentation.no_of_columns) && (excess>0); i++) {
- if ((indentation.columns[i].is_used) &&
- (! is_divisible_by(indentation.columns[i].percent, MIN_TEXT_PERCENT))) {
- indentation.columns[i].percent++;
- excess--;
- }
- }
- // forget the niceties lets just use excess up now!
- for (i=0; (i<indentation.no_of_columns) && (excess>0); i++) {
- if (indentation.columns[i].is_used) {
- indentation.columns[i].percent++;
- excess--;
- }
- }
-}
-
-/*
- * can_distribute_fairly - returns TRUE if we can redistribute some of the unused width into
- * columns that are used.
- */
-
-int html_printer::can_distribute_fairly (void)
-{
- int i;
- int total=0;
- int used =0;
- int excess;
-
- // firstly total up all percentages - so we can use round offs
- for (i=0; i<indentation.no_of_columns; i++) {
- total += indentation.columns[i].percent;
- if ((indentation.columns[i].is_used) &&
- (indentation.columns[i].percent < PERCENT_THRESHOLD)) {
- used++;
- }
- }
- //
- excess = 100-total;
- if (excess < used) {
- for (i=0; i<indentation.no_of_columns; i++) {
- if (! indentation.columns[i].is_used) {
- if (indentation.columns[i].percent > MIN_TEXT_PERCENT) {
- indentation.columns[i].percent--;
- excess++;
- }
- }
- }
- }
- if (excess >= used) {
- for (i=0; i<indentation.no_of_columns; i++) {
- if ((indentation.columns[i].is_used) &&
- (indentation.columns[i].percent < PERCENT_THRESHOLD) &&
- (indentation.columns[i].percent == (((indentation.columns[i].right - indentation.columns[i].left) * 100) /
- (right_margin_indent-left_margin_indent)))) {
- indentation.columns[i].percent++;
- excess--;
- }
- }
- return( TRUE );
- }
- return( FALSE );
-}
-
-/*
- * remove_table_column - removes column, i, from the indentation.
- */
-
-void html_printer::remove_table_column (int i)
-{
- while (i<indentation.no_of_columns) {
- indentation.columns[i].left = indentation.columns[i+1].left;
- indentation.columns[i].right = indentation.columns[i+1].right;
- indentation.columns[i].is_used = indentation.columns[i+1].is_used;
- indentation.columns[i].percent = indentation.columns[i+1].percent;
- i++;
- }
- indentation.no_of_columns--;
-}
-
-/*
- * next_line_on_left_column - returns TRUE if the next line in
- * column, i, has a word on the left margin.
- */
-
-int html_printer::next_line_on_left_column (int i, text_glob *start)
-{
- int current_vpos=start->minv;
-
- while ((start != 0) && (start->minv < indentation.vertical_limit) &&
- (is_on_same_line(start, current_vpos))) {
- if (page_contents->words.is_equal_to_tail()) {
- start = 0;
- } else {
- page_contents->words.move_right();
- start = page_contents->words.get_data();
- }
- }
- if ((start != 0) && (start->minv < indentation.vertical_limit)) {
- // onto next line now
- current_vpos=start->minv;
- while ((start != 0) && (start->minv < indentation.vertical_limit) &&
- (is_on_same_line(start, current_vpos))) {
- if (start->minh == indentation.columns[i].left) {
- return( TRUE );
- }
- if (page_contents->words.is_equal_to_tail()) {
- start = 0;
- } else {
- page_contents->words.move_right();
- start = page_contents->words.get_data();
- }
- }
- }
- return( FALSE );
-}
-
-/*
- * will_wrap_text - returns TRUE if text is wrapped in column, i.
- */
-
-int html_printer::will_wrap_text (int i, text_glob *start)
-{
- text_glob *current=page_contents->words.get_data();
-
- if (auto_on) {
- rewind_text_to(start);
- while ((start != 0) && (start->minv < indentation.vertical_limit)) {
- if (indentation.columns[i].right == start->maxh) {
- // ok right word is on column boarder - check next line
- if (next_line_on_left_column(i, start)) {
- rewind_text_to(current);
- return( TRUE );
- }
- }
- if (page_contents->words.is_equal_to_tail()) {
- start = 0;
- } else {
- page_contents->words.move_right();
- start = page_contents->words.get_data();
- }
- }
- }
- rewind_text_to(current);
- return( FALSE );
-}
-
-/*
- * remove_unnecessary_unused - runs through a table and decides whether an unused
- * column can be removed. This is only true if the
- * column to the left does not wrap text.
- */
-
-void html_printer::remove_unnecessary_unused (text_glob *start)
-{
- int i=0;
- int left=get_left();
- int right;
-
- while (i<indentation.no_of_columns) {
- if ((indentation.columns[i].is_used) &&
- (i+1<indentation.no_of_columns) && (! indentation.columns[i+1].is_used)) {
- /*
- * so i+1 is unused and there is a used column to the left.
- * Now we check whether we can add the unused column to the column, i.
- * This can only be done if column, i, is not wrapping text.
- */
- if (! will_wrap_text(i, start)) {
-#if 1
- if (i+1 < indentation.no_of_columns) {
- right = indentation.columns[i+1].right;
- } else {
- right = right_margin_indent;
- }
- indentation.columns[i].percent = (((right - indentation.columns[i].left) * 100) /
- (right_margin_indent-left));
-#else
- indentation.columns[i].percent = (((indentation.columns[i+1].right - indentation.columns[i].left) * 100) /
- (right_margin_indent-left));
-#endif
- remove_table_column(i+1);
- i=-1;
- }
- }
- i++;
- }
-}
-
-/*
- * remove_zero_percentage_column - removes all zero percentage width columns
- */
-
-void html_printer::remove_zero_percentage_column (void)
-{
- int i=0;
-
- while (i<indentation.no_of_columns) {
- if (indentation.columns[i].percent == 0) {
- remove_table_column(i);
- i=0;
- } else {
- i++;
- }
- }
-}
-
-/*
- * get_left - returns the actual left most margin.
- */
-
-int html_printer::get_left (void)
-{
- if ((header_indent < left_margin_indent) && (header_indent != -1)) {
- return( header_indent );
- } else {
- if (margin_on) {
- return( 0 );
- } else {
- return( left_margin_indent );
- }
- }
-}
-
-/*
- * calculate_percentage_width - calculates the percentage widths,
- * this function will be generous to
- * columns which have words as some browsers
- * produce messy output if the percentage is exactly
- * that required for text..
- * We try and round up to MIN_TEXT_PERCENT
- * of course we can only do this if we can steal from
- * an unused column.
- */
-
-void html_printer::calculate_percentage_width (text_glob *start)
-{
- int i;
- int left=get_left();
- int right;
-
- // firstly calculate raw percentages
- for (i=0; i<indentation.no_of_columns; i++) {
-#if 0
- indentation.columns[i].percent = (((indentation.columns[i].right - indentation.columns[i].left) * 100) /
- (right_margin_indent-left));
-#else
- if (i+1 < indentation.no_of_columns) {
- right = indentation.columns[i+1].left;
- } else {
- right = right_margin_indent;
- }
- indentation.columns[i].percent = (((right - indentation.columns[i].left) * 100) /
- (right_margin_indent-left));
-#endif
- }
- if (debug_table_on) {
- display_columns(start->text_string, "[b4 steal] indentation.columns", indentation.columns);
- }
-
- // now steal from the unused columns..
- remove_unnecessary_unused(start);
-
- if (debug_table_on) {
- display_columns(start->text_string, "[after steal] indentation.columns", indentation.columns);
- }
-
-#if 0
- utilize_round_off();
-#endif
- remove_zero_percentage_column();
-}
-
-
-/*
- * is_column_subset - returns TRUE if the columns described by small can be contained in
- * the columns in large.
- */
-
-int html_printer::is_column_subset (struct text_defn *small, struct text_defn *large)
-{
- int ns=count_columns(small);
- int nl=count_columns(large);
- int found;
- int i=0;
- int j;
-
- while (i<ns) {
- j=0;
- found = FALSE;
- while (j<nl) {
- if (is_intersection(small[i].left, small[i].right, large[j].left, large[j].right)) {
- found = TRUE;
- if (! is_subsection(small[i].left, small[i].right, large[j].left, large[j].right)) {
- // found column which is not a subset
- return( FALSE );
- }
- }
- j++;
- }
- if (! found) {
- return( FALSE );
- }
- i++;
- }
- // small cannot be an empty set
- return( ns>0 );
-}
-
-/*
- * right_most_column - returns the right most column position.
- */
-
-int html_printer::right_most_column (struct text_defn *col)
-{
- int i = count_columns(col);
-
- if (i>0) {
- return( col[i-1].right );
- } else {
- return( 0 );
- }
-}
-
-/*
- * large_enough_gap_for_two - returns TRUE if there exists a large enough gap
- * for two lines.
- */
-
-int html_printer::large_enough_gap_for_two (struct text_defn *col)
-{
- int i=0;
- int found=FALSE;
- int gap=MIN_COLUMN_FOR_TWO_LINES;
-
- if (abs(col[i].left - left_margin_indent) >= gap) {
- found = TRUE;
- }
- while ((col[i].right != 0) && (col[i+1].right != 0)) {
- if (abs(col[i+1].left-col[i].right) >= gap) {
- found = TRUE;
- i++;
- } else {
- // not good enough for this table, remove it
- col[i].right = col[i+1].right;
- remove_entry_in_line(col, i+1);
- }
- }
- return( found );
-}
-
-/*
- * is_small_table - applies some rigorous rules to test whether we should start this
- * table at this point.
- */
-
-int html_printer::is_small_table (int lines, struct text_defn *last_guess,
- struct text_defn *words_1, struct text_defn *cols_1,
- struct text_defn *words_2, struct text_defn *cols_2,
- int *limit, int *limit_1)
-{
- /*
- * firstly we check for an indented paragraph
- */
-
- if ((lines >= 2) &&
- (count_columns(cols_1) == count_columns(cols_2)) && (count_columns(cols_1) == 1) &&
- right_indentation(cols_1) && (! right_indentation(cols_2)) &&
- (cols_1[0].right == right_margin_indent)) {
- return( FALSE );
- }
-
- if (lines == 2) {
- /*
- * as we only have two lines in our table we need to examine in detail whether
- * we should construct a table from these two lines.
- * For example if the text is the start of an indented paragraph and
- * line1 and line2 are contineous then they should form one row in our table but
- * if line1 and line2 are not contineous it is safer to treat them separately.
- *
- * We are prepared to reduce the table to one line
- */
- if (((count_columns(cols_1) != count_columns(cols_2)) && (cols_1[0].left > cols_2[0].left)) ||
- (! ((is_column_subset(cols_1, cols_2)) ||
- (is_column_subset(cols_2, cols_1))))) {
- /*
- * now we must check to see whether line1 and line2 join
- */
- if ((right_most_column(cols_1) == right_margin_indent) &&
- (cols_2[0].left == left_margin_indent)) {
- /*
- * looks like they join, we don't want a table at all.
- */
- return( FALSE );
- }
- /*
- * use single line table
- */
- lines--;
- *limit = *limit_1;
- copy_line(last_guess, cols_1);
- }
- }
-
- if ((count_columns(last_guess)==1) && (right_indentation(last_guess))) {
- if (lines == 1) {
- *limit = *limit_1;
- }
- return( TRUE );
- }
-
- /*
- * check for large gap with single line or if multiple lines with more than one column
- */
-
- if (lines == 1) {
- if (large_enough_gap(last_guess)) {
- *limit = *limit_1;
- return( TRUE );
- }
- } else if (count_columns(last_guess)>1) {
- if (lines == 2) {
- return( large_enough_gap_for_two(last_guess) );
- }
- return( TRUE );
- }
- return( FALSE );
-}
-
-
-/*
- * is_appropriate_to_start_table - returns TRUE if it is appropriate to start the table
- * at this point.
- */
-
-int html_printer::is_appropriate_to_start_table (struct text_defn *cols_1,
- struct text_defn *cols_2,
- struct text_defn *last_guess)
-{
- if (count_columns(last_guess) == 1) {
- if (debug_table_on) {
- display_columns("", "[is] cols_1" , cols_1);
- display_columns("", "[is] cols_2" , cols_2);
- display_columns("", "[is] last_guess", last_guess);
- }
-
- if (! ((is_column_subset(cols_1, cols_2)) ||
- (is_column_subset(cols_2, cols_1)))) {
- return( FALSE );
- }
- if ((count_columns(cols_1) == 1) &&
- (cols_1[0].left > left_margin_indent) && (cols_1[0].right < right_margin_indent) &&
- (cols_1[0].right != cols_2[0].right) &&
- (count_columns(last_guess) == 1)) {
- return( FALSE );
- }
- }
- return( TRUE );
-}
-
-/*
- * is_a_full_width_column - returns TRUE if there exists a full width column.
- */
-
-int html_printer::is_a_full_width_column (void)
-{
- int i=0;
-
- while (i<indentation.no_of_columns) {
- if (((indentation.columns[i].left == get_left()) ||
- (indentation.columns[i].left == left_margin_indent)) &&
- (indentation.columns[i].right == right_margin_indent)) {
- return( TRUE );
- }
- i++;
- }
- return( FALSE );
-}
-
-/*
- * should_defer_table - returns TRUE if we should defer this table.
- * This can occur if the first line seen indent
- * is < than future lines. In which case it
- * will cause future lines in this table
- * to be indented. The lesser of the evils
- * is to treat the first line by itself.
- */
-
-int html_printer::should_defer_table (int lines, struct text_glob *start, struct text_defn *cols_1)
-{
- if (lines > 2) {
- int i=0;
- int c=count_columns(cols_1);
-
- count_hits(cols_1, count_columns(cols_1), indentation.vertical_limit);
- rewind_text_to(start);
- count_right_hits(cols_1, count_columns(cols_1));
- rewind_text_to(start);
- while (i<c) {
- if ((cols_1[i].is_used > 1) || (cols_1[i].right_hits > 1)) {
- return( FALSE );
- }
- i++;
- }
- /*
- * first line (cols_1) is not aligned on any future column, we defer.
- */
- return( TRUE );
- }
- return( FALSE );
-}
-
-/*
- * is_new_exact_right - returns TRUE if the, next_cols, has a word sitting
- * on the right hand margin of last_guess. But only
- * if no exact right word was found in last_cols.
- */
-
-int html_printer::is_new_exact_right (struct text_defn *last_guess,
- struct text_defn *last_cols,
- struct text_defn *next_cols)
-{
- int n=count_columns(last_guess)-1;
- return( FALSE );
-
- if ((n>=0) && (last_guess[n].right != 0) && (last_cols[n].right != 0) && (next_cols[n].right != 0)) {
- if ((last_cols[n].right != last_guess[n].right) &&
- ((next_cols[n].right == last_guess[n].right) || (next_cols[n].right == right_margin_indent))) {
- return( TRUE );
- }
- }
- return( FALSE );
-}
-
-/*
- * found_use_for_table - checks whether the some words on one line directly match
- * the horizontal alignment of the line below.
- * This is rather complex as we need to detect text tables
- * such as .2C .IP Abstracts and indentations
- *
- * Algorithm is:
- *
- * read first line of text and calculate the significant
- * gaps between words
- * next next line of text and do the same
- * if a conflict between these lines exists and
- * first line is centered
- * then
- * return centered line
- * elsif start of a table is found
- * then
- * repeat
- * read next line of text and calculate significant gaps
- * until conflict between the gaps is found
- * record table
- * return table found
- * else
- * return no table found
- * fi
- */
-
-int html_printer::found_use_for_table (text_glob *start)
-{
- text_glob *t;
- struct text_defn all_words [MAX_WORDS_PER_LINE]; // logical OR of words on each line
- struct text_defn words_1 [MAX_WORDS_PER_LINE]; // actual words found on first line
- struct text_defn words_2 [MAX_WORDS_PER_LINE]; // actual words found on second line
- struct text_defn cols_1 [MAX_WORDS_PER_LINE]; // columns found on line 1
- struct text_defn cols_2 [MAX_WORDS_PER_LINE]; // columns found on line 2
- struct text_defn last_words [MAX_WORDS_PER_LINE]; // actual words found on last line
- struct text_defn last_cols [MAX_WORDS_PER_LINE]; // columns found so far
- struct text_defn next_words [MAX_WORDS_PER_LINE]; // actual words found on last line (new)
- struct text_defn next_cols [MAX_WORDS_PER_LINE]; // columns found on next line
- struct text_defn last_guess [MAX_WORDS_PER_LINE]; // columns found on last line
- // (logical AND of gaps (treat gaps = true))
- struct text_defn next_guess [MAX_WORDS_PER_LINE]; // columns found on next line
- // (logical AND of gaps (treat gaps = true))
- struct text_defn prev_guess [MAX_WORDS_PER_LINE]; // temporary copy of last_guess
- int i =0;
- int lines =1; // number of lines read
- int limit; // vertical limit reached in our table
- int limit_1; // vertical position after line 1
-
-#if 0
- if (strcmp(start->text_string, "<hr>") == 0) {
- stop();
- }
-#endif
-
- /*
- * get first set of potential columns into last_line, call this last_guess
- */
- limit = collect_columns(words_1, cols_1, 0, 0, MAX_WORDS_PER_LINE);
- limit_1 = limit;
- copy_line(last_guess, cols_1);
-
- /*
- * initialize the all_words columns - if this should ever equal a complete line
- * with no gaps then we terminate the table.
- */
- copy_line(all_words, cols_1);
-
- /*
- * and set the current limit found
- */
- indentation.vertical_limit = limit;
-
- /*
- * have we reached the end of page?
- */
- if (page_contents->words.is_equal_to_head() || (limit == 0)) {
- cols_2[0].left = 0;
- cols_2[0].right = 0;
- } else {
- /*
- * the answer to the previous question was no.
- * So we need to examine the next line
- */
- limit = collect_columns(words_2, cols_2, words_1, cols_1, MAX_WORDS_PER_LINE);
- if (limit >= 0) {
- lines++;
- }
- }
-
- /*
- * now check to see whether the first line looks like a single centered line
- */
- if (single_centered_line(cols_1, cols_2, start)) {
- rewind_text_to(start);
- write_centered_line(start);
- /*
- * indicate to caller than we have centered text, not found a table.
- */
- indentation.no_of_columns = 0;
- return( TRUE );
- } else if (! table_on) {
- /*
- * user does not allow us to find a table (we are allowed to find centered lines (above))
- */
- rewind_text_to(start);
- return( FALSE );
- }
-
- /*
- * remove any gaps from all_words
- */
- combine_line(all_words, cols_2);
- if (debug_table_on) {
- display_columns(start->text_string, "[1] all_words" , all_words);
- display_columns(start->text_string, "[1] cols_1" , cols_1);
- display_columns(start->text_string, "[1] words_1" , words_1);
- display_columns(start->text_string, "[1] cols_2" , cols_2);
- display_columns(start->text_string, "[1] words_2" , words_2);
- display_columns(start->text_string, "[1] last_guess", last_guess);
- }
-
- /*
- * next_guess = last_guess AND next_cols (where gap = true)
- */
-
- if (remove_white_using_words(prev_guess, last_guess, cols_2)) {
- }
- if (remove_white_using_words(next_guess, prev_guess, all_words)) {
- }
-
- if (debug_table_on) {
- display_columns(start->text_string, "[2] next_guess", next_guess);
- }
-
- copy_line(prev_guess, cols_1);
- combine_line(prev_guess, cols_2);
-
- /*
- * if no sequence of words crosses a column and
- * both the last column and all_words are not a full solid line of text
- */
- if ((! conflict_with_words(next_guess, all_words)) &&
- (continue_searching_column(next_guess, next_guess, all_words)) &&
- (is_appropriate_to_start_table(cols_1, cols_2, prev_guess)) &&
- (! page_contents->words.is_equal_to_head()) &&
- ((end_region_vpos < 0) || (limit < end_region_vpos)) &&
- (limit > 0)) {
-
- /*
- * subtract any columns which are bridged by a sequence of words
- */
-
- copy_line(next_cols , cols_2);
- copy_line(next_words, words_2);
-
- do {
- copy_line(prev_guess, next_guess); // copy next_guess away so we can compare it later
- combine_line(last_guess, next_guess);
-
- if (debug_table_on) {
- t = page_contents->words.get_data();
- display_columns(t->text_string, "[l] last_guess", last_guess);
- }
- indentation.vertical_limit = limit;
-
- copy_line(last_cols, next_cols);
- copy_line(last_words, next_words);
- if (page_contents->words.is_equal_to_head()) {
- /*
- * terminate the search
- */
- next_cols[0].left = 0;
- next_cols[0].right = 0;
- } else {
- limit = collect_columns(next_words, next_cols, last_words, last_cols, MAX_WORDS_PER_LINE);
- lines++;
- }
-
- combine_line(all_words, next_cols);
- if (debug_table_on) {
- display_columns(t->text_string, "[l] all_words" , all_words);
- display_columns(t->text_string, "[l] last_cols" , last_cols);
- display_columns(t->text_string, "[l] next_words", next_words);
- display_columns(t->text_string, "[l] next_cols" , next_cols);
- }
-
- if (limit >= 0) {
- /*
- * (if limit is < 0 then the table ends anyway.)
- * we check to see whether we should combine close columns.
- */
- can_loose_column(start, last_guess, limit);
- }
- t = page_contents->words.get_data();
-#if 0
- if (strcmp(t->text_string, "heT") == 0) {
- stop();
- }
-#endif
-
- } while ((! remove_white_using_words(next_guess, last_guess, next_cols)) &&
- (! conflict_with_words(next_guess, all_words)) &&
- (continue_searching_column(next_guess, last_guess, all_words)) &&
- ((is_continueous_column(prev_guess, last_cols)) || (is_exact_left(last_guess, next_cols))) &&
- (! is_new_exact_right(last_guess, last_cols, next_cols)) &&
- (! page_contents->words.is_equal_to_head()) &&
- (! check_lack_of_hits(next_guess, last_guess, start, limit)) &&
- ((end_region_vpos <= 0) || (t->minv < end_region_vpos)) &&
- (limit >= 0));
- lines--;
- }
-
- if (limit < 0) {
- indentation.vertical_limit = limit;
- }
-
- if (page_contents->words.is_equal_to_head()) {
- // end of page check whether we should include everything
- if ((! conflict_with_words(next_guess, all_words)) &&
- (continue_searching_column(next_guess, last_guess, all_words)) &&
- ((is_continueous_column(prev_guess, last_cols)) || (is_exact_left(last_guess, next_cols)))) {
- // end of page reached - therefore include everything
- page_contents->words.start_from_tail();
- t = page_contents->words.get_data();
- combine_line(last_guess, next_guess);
- indentation.vertical_limit = t->minv;
- }
- } else {
- t = page_contents->words.get_data();
- if (((! conflict_with_words(last_guess, all_words))) &&
- (t->minv > end_region_vpos) && (end_region_vpos > 0)) {
- indentation.vertical_limit = limit;
- }
- if ((end_region_vpos > 0) && (t->minv > end_region_vpos)) {
- indentation.vertical_limit = min(indentation.vertical_limit, end_region_vpos+1);
- } else if (indentation.vertical_limit < 0) {
- // -1 as we don't want to include section heading itself
- indentation.vertical_limit = -indentation.vertical_limit-1;
- }
- }
-
- if (debug_table_on) {
- display_columns(start->text_string, "[1] all_words" , all_words);
- display_columns(start->text_string, "[1] cols_1" , cols_1);
- display_columns(start->text_string, "[1] words_1" , words_1);
- display_columns(start->text_string, "[1] cols_2" , cols_2);
- display_columns(start->text_string, "[1] words_2" , words_2);
- display_columns(start->text_string, "[1] last_guess", last_guess);
- display_columns(start->text_string, "[1] next_guess", next_guess);
- }
- rewind_text_to(start);
-
- i = count_columns(last_guess);
- if ((i>1) || (right_indentation(last_guess))) {
-
- // was (continue_searching_column(last_guess, last_guess, all_words)))) {
- if (should_defer_table(lines, start, cols_1)) {
- /*
- * yes, but let us check for a single line table
- */
- lines = 1;
- copy_line(last_guess, cols_1);
- }
-
- if (is_small_table(lines, last_guess, words_1, cols_1, words_2, cols_2,
- &indentation.vertical_limit, &limit_1)) {
-
- // copy match into permenant html_table
-
- if (indentation.columns != 0) {
- free(indentation.columns);
- }
- if (debug_table_on) {
- display_columns(start->text_string, "[x] last_guess", last_guess);
- }
- add_column_gaps(last_guess);
- if (debug_table_on) {
- display_columns(start->text_string, "[g] last_guess", last_guess);
- }
-
- /*
- * +1 for the potential header_margin
- * +1 for null
- */
-
- indentation.no_of_columns = count_columns(last_guess);
- indentation.columns = (struct text_defn *)malloc((indentation.no_of_columns+2)*sizeof(struct text_defn));
-
- i=0;
- while (i<=indentation.no_of_columns) {
- indentation.columns[i].left = last_guess[i].left;
- indentation.columns[i].right = last_guess[i].right;
- i++;
- }
-
- if (indentation.no_of_columns>0) {
- assign_used_columns(start);
- rewind_text_to(start);
- calculate_percentage_width(start);
-
- if (debug_table_on) {
- display_columns(start->text_string, "[g] indentation.columns", indentation.columns);
- }
-
- /*
- * clearly a single column 100% is not worth using a table.
- * Also we check to see whether the first line is sensibly
- * part of this table.
- */
- if (is_a_full_width_column()) {
- indentation.no_of_columns = 0;
- free( indentation.columns );
- indentation.columns = 0;
- } else {
- return( TRUE );
- }
- }
- }
- }
- return( FALSE );
-}
-
-/*
- * define_cell - creates a table cell using the percentage width.
- */
-
-void html_printer::define_cell (int i)
-{
- html.put_string("<td valign=\"top\" align=\"left\" width=\"");
- html.put_number(indentation.columns[i].percent);
- html.put_string("%\">\n");
-}
-
-/*
- * column_display_word - given a left, right pair and the indentation.vertical_limit
- * write out html text within this region.
- */
-
-void html_printer::column_display_word (int cell, int vert, int left, int right, int next)
-{
- text_glob *g=page_contents->words.get_data();
-
- supress_sub_sup = TRUE;
- if (left != next) {
- define_cell(cell);
- begin_paragraph_no_height(left_alignment);
- while ((g != 0) && (g->minv <= vert)) {
- if ((left <= g->minh) && (g->minh<right)) {
- char *postword=html_position_text(g, left, right);
-
- if (header.written_header) {
- fatal("should never generate a header inside a table");
- } else {
- if (g->is_raw_command) {
- html.put_string((char *)g->text_string);
- } else {
- translate_to_html(g);
- }
- if (postword != 0) {
- html.put_string(postword);
- }
- issued_newline = FALSE;
- }
- }
- if (page_contents->words.is_equal_to_tail()) {
- g = 0;
- } else {
- page_contents->words.move_right();
- g=page_contents->words.get_data();
- }
- }
- end_paragraph();
- html.put_string("</td>\n");
- if (g != 0) {
- page_contents->words.move_left();
- // and correct output_vpos
- g=page_contents->words.get_data();
- output_vpos = g->minv;
- }
- }
-}
-
-/*
- * total_percentages - returns the total of all the percentages in the table.
- */
-
-int html_printer::total_percentages ()
-{
- int i;
- int sum=0;
-
- for (i=0; i<indentation.no_of_columns; i++) {
- sum += indentation.columns[i].percent;
- }
- return( sum );
-}
-
-/*
- * start_table - creates a table according with parameters contained within class html_table.
- */
-
-void html_printer::start_table (void)
-{
- save_paragraph();
- html.put_string("\n<table width=\"");
- html.put_number(total_percentages());
- html.put_string("%\" rules=\"none\" frame=\"none\" cols=\"");
- html.put_number(indentation.no_of_columns);
- html.put_string("\" cellspacing=\"0\" cellpadding=\"0\">\n");
-}
-
-/*
- * end_table - finishes off a table.
- */
-
-void html_printer::end_table (void)
-{
- html.put_string("</table>\n");
- indentation.no_of_columns = 0;
- restore_paragraph();
- supress_sub_sup = TRUE;
-}
-
-
-/*
- * is_in_table - returns TRUE if we are inside an html table.
- */
-
-int html_printer::is_in_table (void)
-{
- return( indentation.no_of_columns != 0 );
-}
-
-
-/*
- * column_calculate_right_margin - scan through the column and find the right most margin
- */
-
-int html_printer::column_calculate_right_margin (int left, int right)
-{
- if (left == right) {
- return( right );
- } else {
- int rightmost =-1;
- int count = 0;
- text_glob *start = page_contents->words.get_data();
- text_glob *g = start;
-
- while ((g != 0) && (g->minv <= indentation.vertical_limit)) {
- if ((left <= g->minh) && (g->minh<right)) {
- if (debug_on) {
- fprintf(stderr, "right word = %s %d\n", g->text_string, g->maxh); fflush(stderr);
- }
- if (g->maxh == rightmost) {
- count++;
- } else if (g->maxh > rightmost) {
- count = 1;
- rightmost = g->maxh;
- }
- if (g->maxh > right) {
- if (debug_on) {
- fprintf(stderr, "problem as right word = %s %d [%d..%d]\n",
- g->text_string, right, g->minh, g->maxh); fflush(stderr);
- // stop();
- }
- }
- }
- page_contents->words.move_right();
- if (page_contents->words.is_equal_to_head()) {
- g = 0;
- page_contents->words.start_from_tail();
- } else {
- g=page_contents->words.get_data();
- }
- }
- rewind_text_to(start);
- if (rightmost == -1) {
- return( right ); // no words in this column
- } else {
- return( rightmost );
- }
- }
-}
-
-/*
- * column_calculate_left_margin - scan through the column and find the left most margin
- */
-
-int html_printer::column_calculate_left_margin (int left, int right)
-{
- if (left == right) {
- return( left );
- } else {
- int leftmost=right;
- text_glob *start = page_contents->words.get_data();
- text_glob *g = start;
-
- while ((g != 0) && (g->minv <= indentation.vertical_limit)) {
- if ((left <= g->minh) && (g->minh<right)) {
- leftmost = min(g->minh, leftmost);
- }
- page_contents->words.move_right();
- if (page_contents->words.is_equal_to_head()) {
- g = 0;
- page_contents->words.start_from_tail();
- } else {
- g=page_contents->words.get_data();
- }
- }
- rewind_text_to(start);
- if (leftmost == right) {
- return( left ); // no words in this column
- } else {
- return( leftmost );
- }
- }
-}
-
-/*
- * find_column_index - returns the index to the column in which glob, t, exists.
- */
-
-int html_printer::find_column_index_in_line (text_glob *t, text_defn *line)
-{
- int i=0;
-
- while ((line != 0) && ((line[i].right != 0) || (line[i].right != 0)) &&
- (! ((line[i].left<=t->minh) && (line[i].right>t->minh)))) {
- i++;
- }
- return( i );
-}
-
-/*
- * find_column_index - returns the index to the column in which glob, t, exists.
- */
-
-int html_printer::find_column_index (text_glob *t)
-{
- int i=0;
-
- while ((i<indentation.no_of_columns) &&
- (! ((indentation.columns[i].left<=t->minh) &&
- (indentation.columns[i].right>t->minh)))) {
- i++;
- }
- return( i );
-}
-
-/*
- * determine_row_limit - checks each row to see if there is a gap in a cell.
- * We return the vertical position after the empty cell
- * at the start of the next line.
- */
-
-int html_printer::determine_row_limit (text_glob *start, int v)
-{
- text_glob *t;
- int i;
- int vpos, last, prev;
- text_glob *is_gap[MAX_WORDS_PER_LINE];
- text_glob zero(&start->text_style, 0, 0, 0, 0, 0, 0, 0, 0);
-
-#if 1
- if ((v == -1) && (strcmp(start->text_string, "CASE") == 0)) {
- stop();
- }
-#endif
-
- if (v >= indentation.vertical_limit) {
- return( v+1 );
- } else {
- /*
- * initially we start with all gaps in our table
- * after a gap we start a new row
- * here we set the gap array to the previous line
- */
-
- if (v>=0) {
- t = page_contents->words.get_data();
- if (t->minv < v) {
- do {
- page_contents->words.move_right();
- t = page_contents->words.get_data();
- } while ((! page_contents->words.is_equal_to_head()) &&
- (t->minv <= v));
- }
- }
- if (page_contents->words.is_equal_to_head()) {
- t = &zero;
- } else {
- page_contents->words.move_left();
- t = page_contents->words.get_data();
- }
-
- prev = t->minv;
- for (i=0; i<indentation.no_of_columns; i++) {
- is_gap[i] = t;
- }
-
- if (page_contents->words.is_equal_to_tail()) {
- rewind_text_to(start);
- return( indentation.vertical_limit );
- } else {
- page_contents->words.move_right();
- }
- t = page_contents->words.get_data();
- vpos = t->minv;
-
- // now check each row for a gap
- do {
- last = vpos;
- vpos = t->minv;
- if (vpos > indentation.vertical_limit) {
- // we have reached the end of the table, quit
- rewind_text_to(start);
- return( indentation.vertical_limit );
- }
-
- i = find_column_index(t);
- if (i>=indentation.no_of_columns) {
- error("find_column_index has failed");
- stop();
- } else {
- if (! is_on_same_line(t, last)) {
- prev = last;
- }
-
- if ((! is_on_same_line(is_gap[i], vpos)) && (! is_on_same_line(is_gap[i], prev)) &&
- (indentation.columns[i].is_used)) {
- // no word on previous line - must be a gap - force alignment of row
- rewind_text_to(start);
- return( prev );
- }
- is_gap[i] = t;
- }
- page_contents->words.move_right();
- t = page_contents->words.get_data();
- } while ((! page_contents->words.is_equal_to_head()) &&
- (vpos < indentation.vertical_limit) && (vpos >= last));
- page_contents->words.move_left();
- t = page_contents->words.get_data();
- rewind_text_to(start);
- return( indentation.vertical_limit );
- }
-}
-
-/*
- * assign_used_columns - sets the is_used field of the column array of records.
- */
-
-void html_printer::assign_used_columns (text_glob *start)
-{
- text_glob *t = start;
- int i;
-
- for (i=0; i<indentation.no_of_columns; i++) {
- indentation.columns[i].is_used = FALSE;
- }
-
- rewind_text_to(start);
- if (! page_contents->words.is_empty()) {
- do {
- i = find_column_index(t);
- if (indentation.columns[i].right != 0) {
- if (debug_table_on) {
- fprintf(stderr, "[%s] in column %d at %d..%d limit %d\n", t->text_string,
- i, t->minv, t->maxv, indentation.vertical_limit); fflush(stderr);
- }
- indentation.columns[i].is_used = TRUE;
- }
- page_contents->words.move_right();
- t = page_contents->words.get_data();
- } while ((t->minv<indentation.vertical_limit) &&
- (! page_contents->words.is_equal_to_head()));
- }
- if (debug_table_on) {
- for (i=0; i<indentation.no_of_columns; i++) {
- fprintf(stderr, " <left=%d right=%d is_used=%d> ",
- indentation.columns[i].left,
- indentation.columns[i].right,
- indentation.columns[i].is_used);
- }
- fprintf(stderr, "\n");
- fflush(stderr);
- }
-}
-
-/*
- * adjust_margin_percentages - so far we have ignored the header_indent
- * and just considered left_margin_indent..right_margin_indent.
- * (We do this since we can assume 100% is total width for main text).
- * However as header_indent can be < left_margin_indent we need to
- * recalculate the real percentages in the light of the extended width.
- */
-
-void html_printer::adjust_margin_percentages (void)
-{
- if ((header_indent < left_margin_indent) && (header_indent != -1)) {
- /*
- * recalculation necessary
- */
- int i=0;
-
- while (i<indentation.no_of_columns) {
- indentation.columns[i].percent = (indentation.columns[i].percent *
- (right_margin_indent - left_margin_indent)) /
- (right_margin_indent - header_indent);
- i++;
- }
- // remove_zero_percentage_column();
- }
-}
-
-/*
- * foreach_column_include_text - foreach column in a table place the
- * appropriate html text.
- */
-
-void html_printer::foreach_column_include_text (text_glob *start)
-{
- if (indentation.no_of_columns>0) {
- int i;
- int left, right;
- int limit=-1;
-
- start_table();
- rewind_text_to(start);
- count_right_hits(indentation.columns, indentation.no_of_columns);
- rewind_text_to(start);
-
- do {
- limit = determine_row_limit(start, limit); // find the bottom of the next row
- html.put_string("<tr valign=\"top\" align=\"left\">\n");
- i=0;
- start = page_contents->words.get_data();
- while (i<indentation.no_of_columns) {
- // reset the output position to the start of column
- rewind_text_to(start);
- output_vpos = start->minv;
- output_hpos = indentation.columns[i].left;
- // and display each column until limit
- right = column_calculate_right_margin(indentation.columns[i].left,
- indentation.columns[i].right);
- left = column_calculate_left_margin(indentation.columns[i].left,
- indentation.columns[i].right);
-
- if (right>indentation.columns[i].right) {
- if (debug_on) {
- fprintf(stderr, "assert calculated right column edge is greater than column\n"); fflush(stderr);
- // stop();
- }
- }
-
- if (left<indentation.columns[i].left) {
- if (debug_on) {
- fprintf(stderr, "assert calculated left column edge is less than column\n"); fflush(stderr);
- // stop();
- }
- }
-
- if ((indentation.columns[i].right_hits == 1) &&
- (indentation.columns[i].right != right_margin_indent)) {
- indentation.wrap_margin = FALSE;
- if (debug_on) {
- fprintf(stderr, "turning auto wrap off during column %d for start word %s\n",
- i, start->text_string);
- fflush(stderr);
- // stop();
- }
- } else {
- indentation.wrap_margin = TRUE;
- }
-
- column_display_word(i, limit, left, right, indentation.columns[i].right);
- i++;
- }
-
- if (page_contents->words.is_equal_to_tail()) {
- start = 0;
- } else {
- page_contents->words.sub_move_right();
- if (page_contents->words.is_empty()) {
- start = 0;
- } else {
- start = page_contents->words.get_data();
- }
- }
-
- html.put_string("</tr>\n");
- } while (((limit < indentation.vertical_limit) && (start != 0) &&
- (! page_contents->words.is_empty())) || (limit == -1));
- end_table();
-
- if (start == 0) {
- // finished page remove all words
- page_contents->words.start_from_head();
- while (! page_contents->words.is_empty()) {
- page_contents->words.sub_move_right();
- }
- } else if (! page_contents->words.is_empty()) {
- page_contents->words.move_left();
- }
- }
-}
-
-/*
- * write_centered_line - generates a line of centered text.
- */
-
-void html_printer::write_centered_line (text_glob *g)
-{
- int current_vpos=g->minv;
-
- move_vertical(g, center_alignment);
-
- header.written_header = FALSE;
- supress_sub_sup = TRUE;
- output_vpos = g->minv;
- output_hpos = g->minh;
- do {
- char *postword=html_position_text(g, left_margin_indent, right_margin_indent);
-
- if (! header.written_header) {
- if (g->is_raw_command) {
- html.put_string((char *)g->text_string);
- } else {
- translate_to_html(g);
- }
- if (postword != 0) {
- html.put_string(postword);
- }
- need_one_newline = TRUE;
- issued_newline = FALSE;
- }
- page_contents->words.move_right();
- g = page_contents->words.get_data();
- } while ((! page_contents->words.is_equal_to_head()) && (is_on_same_line(g, current_vpos)));
- page_contents->words.move_left(); // so when we move right we land on the word following this centered line
- need_one_newline = TRUE;
-}
-
-/*
- * is_in_middle - returns TRUE if the text defn, t, is in the middle of the page.
- */
-
-int html_printer::is_in_middle (int left, int right)
-{
- return( abs(abs(left-left_margin_indent) - abs(right_margin_indent-right)) <= CENTER_TOLERANCE );
-}
-
-/*
- * single_centered_line - returns TRUE if first is a centered line with a different
- * margin to second.
- */
-
-int html_printer::single_centered_line (text_defn *first, text_defn *second, text_glob *g)
-{
- return(
- ((count_columns(first) == 1) && (first[0].left != left_margin_indent) &&
- (first[0].left != second[0].left) && is_in_middle(first->left, first->right))
- );
-}
-
-/*
- * check_able_to_use_center - returns TRUE if we can see a centered line.
- */
-
-int html_printer::check_able_to_use_center (text_glob *g)
-{
- if (auto_on && table_on && ((! is_on_same_line(g, output_vpos)) || issued_newline) && (! using_table_for_indent())) {
- // we are allowed to check for centered line
- // first check to see whether we might be looking at a set of columns
- struct text_defn last_guess[MAX_WORDS_PER_LINE];
- struct text_defn last_words[MAX_WORDS_PER_LINE];
-
- collect_columns(last_words, last_guess, 0, 0, MAX_WORDS_PER_LINE);
-
- rewind_text_to(g);
- if ((count_columns(last_guess) == 1) && (is_in_middle(last_guess[0].left, last_guess[0].right))) {
- write_centered_line(g);
- return( TRUE );
- }
- }
- return( FALSE );
-}
-
-/*
- * check_able_to_use_table - examines forthcoming text to see whether we can
- * better format it by using an html transparent table.
- */
-
-int html_printer::check_able_to_use_table (text_glob *g)
-{
- if (auto_on && ((! is_on_same_line(g, output_vpos)) || issued_newline) && (! using_table_for_indent())) {
- // we are allowed to check for table
-
- if ((output_hpos != right_margin_indent) && (found_use_for_table(g))) {
- foreach_column_include_text(g);
- return( TRUE );
- }
- }
- return( FALSE );
-}
-
-/*
- * move_vertical - if we are using html auto formatting then decide whether to
- * break the line via a <br> or a </p><p> sequence.
- */
-
-void html_printer::move_vertical (text_glob *g, paragraph_type p)
-{
- int r = font::res;
- int height = (g->text_style.point_size+2)*r/72; // --fixme-- we always assume VS is PS+2 (could do better)
- int temp_vpos;
-
- if (auto_on) {
- if ((more_than_line_break(output_vpos, g->minv, height)) || (p != current_paragraph->para_type)) {
- end_paragraph();
- begin_paragraph(p);
- } else {
- html_newline();
- }
- } else {
- if (output_vpos == -1) {
- temp_vpos = g->minv;
- } else {
- temp_vpos = output_vpos;
- }
-
- force_begin_paragraph();
- if (need_one_newline) {
- html_newline();
- temp_vpos += height;
- } else {
- need_one_newline = TRUE;
- }
-
- while ((temp_vpos < g->minv) && (more_than_line_break(temp_vpos, g->minv, height))) {
- html_newline();
- temp_vpos += height;
- }
- }
-}
-
-/*
- * emit_space - emits a space within html, it checks for the font type and
- * will change font depending upon, g. Courier spaces are larger
- * than roman so we need consistancy when changing between them.
- */
-
-void html_printer::emit_space (text_glob *g, int force_space)
-{
- if (! current_paragraph->need_paragraph) {
- // only generate a space if we have written a word - as html will ignore it otherwise
- if ((output_style != g->text_style) && (g->text_style.f != 0)) {
- terminate_current_font();
- }
- if (force_space || (g->minh > output_hpos)) {
- html.put_string(" ");
- }
- change_font(g, TRUE);
- }
-}
-
-/*
- * html_position_text - determine whether the text is subscript/superscript/normal
- * or a header.
- */
-
-char *html_printer::html_position_text (text_glob *g, int left_margin, int right_margin)
-{
- char *postword=0;
-
- begin_paragraph(left_alignment);
-
- if ((! header.written_header) &&
- (is_on_same_line(g, output_vpos) ||
- pretend_is_on_same_line(g, left_margin, right_margin))) {
-
- /*
- * check whether we should supress superscripts and subscripts.
- * I guess we might be able to do better by examining text on this line
- * --fixme--
- */
-
- if ((! is_on_same_line(g, output_vpos)) && (pretend_is_on_same_line(g, left_margin, right_margin))) {
- supress_sub_sup = TRUE;
- }
- header.written_header = FALSE;
- force_begin_paragraph();
-
- // check whether we need to insert white space between words on 'same' line
- if (pretend_is_on_same_line(g, left_margin, right_margin)) {
- emit_space(g, TRUE);
- }
-
- // check whether the font was reset after generating an image
- if (output_style.f == 0) {
- change_font(g, TRUE);
- }
-
- if (looks_like_subscript(g)) {
-
- g->text_style.point_size = output_style.point_size;
- g->minv = output_vpos; // this ensures that output_vpos doesn't alter
- // which allows multiple subscripted words
- move_horizontal(g, left_margin);
- html.put_string("<sub>");
- postword = "</sub>";
- } else if (looks_like_superscript(g)) {
-
- g->text_style.point_size = output_style.point_size;
- g->minv = output_vpos;
-
- move_horizontal(g, left_margin);
- html.put_string("<sup>");
- postword = "</sup>";
- } else {
- move_horizontal(g, left_margin);
- }
- supress_sub_sup = FALSE;
- } else {
- // we have found a new line
- if (! header.written_header) {
- move_vertical(g, left_alignment);
- }
- header.written_header = FALSE;
-
- if (processed_header(g)) {
- // we must not alter output_vpos as we have peeped at the next word
- // and set vpos to this - to ensure we do not generate a <br> after
- // a heading. (The html heading automatically generates a line break)
- output_hpos = left_margin;
- return( postword );
- } else {
- force_begin_paragraph();
- if ((! is_in_table()) && (margin_on)) {
- make_html_indent(left_margin);
- }
- if (g->minh-left_margin != 0) {
- make_html_indent(g->minh-left_margin);
- }
- change_font(g, TRUE);
- supress_sub_sup = FALSE;
- }
- }
- output_vpos = g->minv;
- output_hpos = g->maxh;
- return( postword );
-}
-
-
-int html_printer::html_position_region (void)
-{
- int r = font::res;
- int height = output_style.point_size*r/72;
- int temp_vpos;
- int is_center = FALSE;
-
- if (output_style.point_size != 0) {
- if (output_vpos != start_region_vpos) {
-
- // graphic starts on a different line
- if (output_vpos == -1) {
- temp_vpos = start_region_vpos;
- } else {
- temp_vpos = output_vpos;
- }
- supress_sub_sup = TRUE;
- if (need_one_newline) {
- html_newline();
- temp_vpos += height;
- } else {
- need_one_newline = TRUE;
- }
-
- while ((temp_vpos < start_region_vpos) &&
- (more_than_line_break(temp_vpos, start_region_vpos, height))) {
- html_newline();
- temp_vpos += height;
- }
- }
- }
- if (auto_on && (is_in_middle(start_region_hpos, end_region_hpos))) {
- is_center = TRUE;
- } else {
- if (start_region_hpos > get_left()) {
- make_html_indent(start_region_hpos-get_left());
- }
- }
- output_vpos = start_region_vpos;
- output_hpos = start_region_hpos;
- return( is_center );
-}
-
-/*
- * gs_x - translate and scale the x axis
- */
-
-int html_printer::gs_x (int x)
-{
- x += IMAGE_BOARDER_PIXELS/2;
- return((x-start_region_hpos)*postscript_res/font::res);
-}
-
-
-/*
- * gs_y - translate and scale the y axis
- */
-
-int html_printer::gs_y (int y)
-{
- int yoffset=((int)(A4_PAGE_LENGTH*(double)font::res))-end_region_vpos;
-
- y += IMAGE_BOARDER_PIXELS/2;
- return( (y+yoffset)*postscript_res/font::res );
-}
-
-
-void html_printer::troff_position_text (text_glob *g)
-{
- change_font(g, FALSE);
-
- troff.put_string("V");
- troff.put_number(gs_y(g->maxv));
- troff.put_string("\n");
-
- troff.put_string("H");
- troff.put_number(gs_x(g->minh));
- troff.put_string("\n");
-}
-
-void html_printer::troff_change_font (const char *fontname, int size, int font_no)
-{
- troff.put_string("x font ");
- troff.put_number(font_no);
- troff.put_string(" ");
- troff.put_string(fontname);
- troff.put_string("\nf");
- troff.put_number(font_no);
- troff.put_string("\ns");
- troff.put_number(size*1000);
- troff.put_string("\n");
-}
-
-
-void html_printer::set_style(const style &sty)
-{
-#if 0
- const char *fontname = sty.f->get_name();
- if (fontname == 0)
- fatal("no internalname specified for font");
-
- change_font(fontname, (font::res/(72*font::sizescale))*sty.point_size);
-#endif
-}
-
-void html_printer::end_of_line()
-{
- flush_sbuf();
- output_hpos = -1;
-}
-
-void html_printer::html_display_word (text_glob *g)
-{
-#if 0
- if (strcmp(g->text_string, "ot") == 0) {
- stop();
- }
-#endif
- if (! check_able_to_use_table(g)) {
- char *postword=html_position_text(g, left_margin_indent, right_margin_indent);
-
- if (! header.written_header) {
- if (g->is_raw_command) {
- html.put_string((char *)g->text_string);
- } else {
- translate_to_html(g);
- }
- if (postword != 0) {
- html.put_string(postword);
- }
- need_one_newline = TRUE;
- issued_newline = FALSE;
- }
- }
-}
-
-void html_printer::troff_display_word (text_glob *g)
-{
- troff_position_text(g);
- if (g->is_raw_command) {
- int l=strlen((char *)g->text_string);
- if (l == 1) {
- troff.put_string("c");
- troff.put_string((char *)g->text_string);
- troff.put_string("\n");
- } else if (l > 1) {
- troff.put_string("C");
- troff.put_troffps_char((char *)g->text_string);
- troff.put_string("\n");
- }
- } else {
- troff_position_text(g);
- troff.put_string("t");
- troff.put_translated_string((const char *)g->text_string);
- troff.put_string("\n");
- }
-}
-
-void html_printer::display_word (text_glob *g, int is_to_html)
-{
- if (is_to_html) {
- html_display_word(g);
- } else if ((g->is_raw_command) && (g->is_html_command)) {
- // found a raw html command inside a graphic glob.
- // We should emit the command to the html device, but of course we
- // cannot place it correctly as we are dealing with troff words.
- // Remember output_vpos will refer to troff and not html.
- html.put_string((char *)g->text_string);
- } else {
- troff_display_word(g);
- }
-}
-
-/*
- * translate_to_html - translates a textual string into html text
- */
-
-void html_printer::translate_to_html (text_glob *g)
-{
- char buf[MAX_STRING_LENGTH];
-
- str_translate_to_html(g->text_style.f, buf, MAX_STRING_LENGTH,
- g->text_string, g->text_length, TRUE);
- html.put_string(buf);
-}
-
-/*
- * html_knows_about - given a character name, troff, return TRUE
- * if we know how to display this character using
- * html unicode.
- */
-
-int html_printer::html_knows_about (char *troff)
-{
- // --fixme-- needs to have similar code as above
- return( FALSE );
-}
-
-/*
- * display_fill - generates a troff format fill command
- */
-
-void html_printer::display_fill (graphic_glob *g)
-{
- troff.put_string("Df ") ;
- troff.put_number(g->fill);
- troff.put_string(" 0\n");
-}
-
-/*
- * display_line - displays a line using troff format
- */
-
-void html_printer::display_line (graphic_glob *g, int is_to_html)
-{
- if (is_to_html) {
- fatal("cannot emit lines in html");
- }
- if (g->code == 'l') {
- // straight line
-
- troff.put_string("V");
- troff.put_number(gs_y(g->point[0].y));
- troff.put_string("\n");
-
- troff.put_string("H");
- troff.put_number(gs_x(g->point[0].x));
- troff.put_string("\n");
-
- display_fill(g);
-
- troff.put_string("Dl ");
- troff.put_number((g->point[1].x-g->point[0].x)*postscript_res/font::res);
- troff.put_string(" ");
- troff.put_number((g->point[1].y-g->point[0].y)*postscript_res/font::res);
- troff.put_string("\n");
- // printf("line %c %d %d %d %d size %d\n", (char)g->code, g->point[0].x, g->point[0].y,
- // g->point[1].x, g->point[1].y, g->size);
- } else if ((g->code == 'c') || (g->code == 'C')) {
- // circle
-
- int xradius = (g->maxh - g->minh) / 2;
- int yradius = (g->maxv - g->minv) / 2;
- // center of circle or elipse
-
- troff.put_string("V");
- troff.put_number(gs_y(g->minv+yradius));
- troff.put_string("\n");
-
- troff.put_string("H");
- troff.put_number(gs_x(g->minh));
- troff.put_string("\n");
-
- display_fill(g);
-
- if (g->code == 'c') {
- troff.put_string("Dc ");
- } else {
- troff.put_string("DC ");
- }
-
- troff.put_number(xradius*2*postscript_res/font::res);
- troff.put_string("\n");
-
- } else if ((g->code == 'e') || (g->code == 'E')) {
- // ellipse
-
- int xradius = (g->maxh - g->minh) / 2;
- int yradius = (g->maxv - g->minv) / 2;
- // center of elipse - this is untested
-
- troff.put_string("V");
- troff.put_number(gs_y(g->minv+yradius));
- troff.put_string("\n");
-
- troff.put_string("H");
- troff.put_number(gs_x(g->minh));
- troff.put_string("\n");
-
- display_fill(g);
-
- if (g->code == 'e') {
- troff.put_string("De ");
- } else {
- troff.put_string("DE ");
- }
-
- troff.put_number(xradius*2*postscript_res/font::res);
- troff.put_string(" ");
- troff.put_number(yradius*2*postscript_res/font::res);
- troff.put_string("\n");
- } else if ((g->code == 'p') || (g->code == 'P')) {
- // polygon
- troff.put_string("V");
- troff.put_number(gs_y(g->yc));
- troff.put_string("\n");
-
- troff.put_string("H");
- troff.put_number(gs_x(g->xc));
- troff.put_string("\n");
-
- display_fill(g);
-
- if (g->code == 'p') {
- troff.put_string("Dp");
- } else {
- troff.put_string("DP");
- }
-
- int i;
- int xc=g->xc;
- int yc=g->yc;
- for (i=0; i<g->nopoints; i++) {
- troff.put_string(" ");
- troff.put_number((g->point[i].x-xc)*postscript_res/font::res);
- troff.put_string(" ");
- troff.put_number((g->point[i].y-yc)*postscript_res/font::res);
- xc = g->point[i].x;
- yc = g->point[i].y;
- }
- troff.put_string("\n");
- } else if (g->code == 'a') {
- // arc
- troff.put_string("V");
- troff.put_number(gs_y(g->yc));
- troff.put_string("\n");
-
- troff.put_string("H");
- troff.put_number(gs_x(g->xc));
- troff.put_string("\n");
-
- display_fill(g);
-
- troff.put_string("Da");
-
- int i;
-
- for (i=0; i<g->nopoints; i++) {
- troff.put_string(" ");
- troff.put_number(g->point[i].x*postscript_res/font::res);
- troff.put_string(" ");
- troff.put_number(g->point[i].y*postscript_res/font::res);
- }
- troff.put_string("\n");
- } else if (g->code == '~') {
- // spline
- troff.put_string("V");
- troff.put_number(gs_y(g->yc));
- troff.put_string("\n");
-
- troff.put_string("H");
- troff.put_number(gs_x(g->xc));
- troff.put_string("\n");
-
- display_fill(g);
-
- troff.put_string("D~");
-
- int i;
- int xc=g->xc;
- int yc=g->yc;
- for (i=0; i<g->nopoints; i++) {
- troff.put_string(" ");
- troff.put_number((g->point[i].x-xc)*postscript_res/font::res);
- troff.put_string(" ");
- troff.put_number((g->point[i].y-yc)*postscript_res/font::res);
- xc = g->point[i].x;
- yc = g->point[i].y;
- }
- troff.put_string("\n");
- }
-}
-
-
-/*
- * flush_sbuf - flushes the current sbuf into the list of glyphs.
- */
-
-void html_printer::flush_sbuf()
-{
- if (sbuf_len > 0) {
- int r=font::res; // resolution of the device
- set_style(sbuf_style);
-
- page_contents->add(&sbuf_style, sbuf, sbuf_len,
- 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;
- sbuf_dmark_hpos = -1;
- }
-}
-
-
-void html_printer::set_line_thickness(const environment *env)
-{
- line_thickness = env->size;
- printf("line thickness = %d\n", line_thickness);
-}
-
-void html_printer::draw(int code, int *p, int np, const environment *env)
-{
- switch (code) {
-
- case 'l':
- if (np == 2) {
- page_contents->add_line(code,
- env->hpos, env->vpos, env->hpos+p[0], env->vpos+p[1],
- env->size, fill);
- } else {
- error("2 arguments required for line");
- }
- 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 'P':
- // fall through
- case 'p':
- {
- 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);
- }
- break;
- case 'E':
- // fall through
- case 'e':
- 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);
-
- break;
- case 'C':
- // fill circle
-
- case 'c':
- {
- // 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);
- }
- break;
- case 'a':
- {
- 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");
- }
- }
- break;
- case '~':
- {
- 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);
- }
- break;
- case 'f':
- {
- 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;
- }
- break;
- }
-
- default:
- error("unrecognised drawing command `%1'", char(code));
- break;
- }
-}
-
-
-void html_printer::begin_page(int n)
-{
- page_number = n;
- html.begin_comment("Page: ").comment_arg(i_to_a(page_number)).end_comment();;
- no_of_printed_pages++;
-
- output_style.f = 0;
- output_space_code = 32;
- output_draw_point_size = -1;
- output_line_thickness = -1;
- output_hpos = -1;
- output_vpos = -1;
-}
-
-void testing (text_glob *g) {}
-
-void html_printer::flush_graphic (void)
-{
- graphic_glob g;
-
- graphic_level = 0;
- page_contents->is_in_graphic = FALSE;
-
- g.minv = -1;
- g.maxv = -1;
- calculate_region_range(&g);
- if (g.minv != -1) {
- page_contents->make_new_region(&g);
- }
- move_region_to_page();
-}
-
-void html_printer::end_page(int)
-{
- flush_sbuf();
- flush_graphic();
- flush_page();
-}
-
-font *html_printer::make_font(const char *nm)
-{
- return html_font::load_html_font(nm);
-}
-
-html_printer::~html_printer()
-{
- if (fseek(tempfp, 0L, 0) < 0)
- fatal("fseek on temporary file failed");
- html.set_file(stdout);
- fputs("<html>\n", stdout);
- fputs("<head>\n", stdout);
- fputs("<meta name=\"Content-Style\" content=\"text/css\">\n", stdout);
- write_title(TRUE);
- fputs("</head>\n", stdout);
- fputs("<body>\n", stdout);
- write_title(FALSE);
- header.write_headings(stdout);
- {
- extern const char *Version_string;
- html.begin_comment("Creator : ")
- .comment_arg("groff ")
- .comment_arg("version ")
- .comment_arg(Version_string)
- .end_comment();
- }
- {
-#ifdef LONG_FOR_TIME_T
- long
-#else
- time_t
-#endif
- t = time(0);
- html.begin_comment("CreationDate: ")
- .comment_arg(ctime(&t))
- .end_comment();
- }
- html.begin_comment("Total number of pages: ").comment_arg(i_to_a(no_of_printed_pages)).end_comment();
- html.end_line();
- html.copy_file(tempfp);
- fputs("</body>\n", stdout);
- fputs("</html>\n", stdout);
- fclose(tempfp);
-}
-
-
-/*
- * calculate_region_range - calculates the vertical range for words and lines
- * within the region lists.
- */
-
-void html_printer::calculate_region_range (graphic_glob *r)
-{
- text_glob *w;
- graphic_glob *g;
-
- if (! page_contents->region_lines.is_empty()) {
- page_contents->region_lines.start_from_head();
- do {
- g = page_contents->region_lines.get_data();
- if ((r->minv == -1) || (g->minv < r->minv)) {
- r->minv = g->minv;
- }
- if ((r->maxv == -1) || (g->maxv > r->maxv)) {
- r->maxv = g->maxv;
- }
- page_contents->region_lines.move_right();
- } while (! page_contents->region_lines.is_equal_to_head());
- }
- if (! page_contents->region_words.is_empty()) {
- page_contents->region_words.start_from_head();
- do {
- w = page_contents->region_words.get_data();
-
- if ((r->minv == -1) || (w->minv < r->minv)) {
- r->minv = w->minv;
- }
- if ((r->maxv == -1) || (w->maxv > r->maxv)) {
- r->maxv = w->maxv;
- }
- page_contents->region_words.move_right();
- } while (! page_contents->region_words.is_equal_to_head());
- }
-}
-
-
-/*
- * move_region_to_page - moves lines and words held in the temporary region
- * list to the page list.
- */
-
-void html_printer::move_region_to_page (void)
-{
- text_glob *w;
- graphic_glob *g;
-
- page_contents->region_lines.start_from_head();
- while (! page_contents->region_lines.is_empty()) {
- g = page_contents->region_lines.get_data(); // remove from our temporary region list
- page_contents->lines.add(g); // and add to the page list
- page_contents->region_lines.sub_move_right();
- }
- page_contents->region_words.start_from_head();
- while (! page_contents->region_words.is_empty()) {
- w = page_contents->region_words.get_data(); // remove from our temporary region list
- page_contents->words.add(w); // and add to the page list
- page_contents->region_words.sub_move_right();
- }
-}
-
-/*
- * is_graphic_start - returns TRUE if the start of table, pic, eqn was seen.
- */
-
-int is_graphic_start (char *s)
-{
- return( (strcmp(s, "graphic-start") == 0) ||
- ((strcmp(s, "table-start") == 0) && (table_image_on)) );
-}
-
-/*
- * is_graphic_end - return TRUE if the end of a table, pic, eqn was seen.
- */
-
-int is_graphic_end (char *s)
-{
- return( (strcmp(s, "graphic-end") == 0) ||
- ((strcmp(s, "table-end") == 0) && (table_image_on)) );
-}
-
-/*
- * special - handle all x X requests from troff. For grohtml they allow users
- * to pass raw html commands, turn auto linked headings off/on and
- * also allow tbl, eqn & pic say what commands they have generated.
- */
-
-void html_printer::special(char *s, const environment *env)
-{
- if (s != 0) {
- if (is_graphic_start(s)) {
- graphic_level++;
- if (graphic_level == 1) {
- page_contents->is_in_graphic = TRUE; // add words and lines to temporary region lists
- }
- } else if (is_graphic_end(s) && (graphic_level > 0)) {
- graphic_level--;
- if (graphic_level == 0) {
- flush_graphic();
- }
- } else 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) {
- int found=FALSE;
-
- f = font::load_font("TR", &found);
- }
- str_translate_to_html(f, buf, MAX_STRING_LENGTH,
- &s[5], strlen(s)-5, FALSE);
- page_contents->add_html_command(&sbuf_style, buf, strlen(buf),
-
- // need to pass rest of string through to html output during flush
-
- env->vpos-env->size*r/72, env->hpos,
- env->vpos , env->hpos);
- // assume that the html command has no width, if it does then we hopefully troff
- // will have fudged this in a macro and requested that the formatting move right by
- // the appropriate width
- } else if (strncmp(s, "index:", 6) == 0) {
- cutoff_heading = atoi(&s[6]);
- }
- }
-}
-
-void set_image_type (char *type)
-{
- if (strcmp(type, "gif") == 0) {
- image_type = gif;
- } else if (strcmp(type, "png") == 0) {
- image_type = png;
- image_device = "png256";
- } else if (strncmp(type, "png", 3) == 0) {
- image_type = png;
- image_device = type;
- }
-}
-
-printer *make_printer()
-{
- return new html_printer;
-}
-
-static void usage();
-
-int main(int argc, char **argv)
-{
- program_name = argv[0];
- static char stderr_buf[BUFSIZ];
- setbuf(stderr, stderr_buf);
- int c;
- while ((c = getopt(argc, argv, "F:atTvdgmx?I:r:")) != EOF)
- switch(c) {
- case 'v':
- {
- extern const char *Version_string;
- printf("GNU grohtml (groff) version %s\n", Version_string);
- exit(0);
- break;
- }
- case 'a':
- auto_on = FALSE;
- break;
- case 't':
- table_on = FALSE;
- break;
- case 'T':
- table_image_on = FALSE;
- break;
- case 'F':
- font::command_line_font_dir(optarg);
- break;
- case 'I':
- // user specifying the type of images we should generate
- set_image_type(optarg);
- break;
- case 'r':
- // resolution (dots per inch for an image)
- image_res = atoi(optarg);
- break;
- case 'd':
- // debugging on
- debug_on = TRUE;
- break;
- case 'x':
- debug_table_on = TRUE;
- break;
- case 'g':
- // do not guess title and headings
- guess_on = FALSE;
- break;
- case 'm':
- // leave margins alone
- margin_on = TRUE;
- break;
- case '?':
- usage();
- break;
- default:
- assert(0);
- }
- if (optind >= argc) {
- do_file("-");
- } else {
- for (int i = optind; i < argc; i++)
- do_file(argv[i]);
- }
- delete pr;
- return 0;
-}
-
-static void usage()
-{
- fprintf(stderr, "usage: %s [-avdgmt?] [-r resolution] [-F dir] [-I imagetype] [files ...]\n",
- program_name);
- exit(1);
-}
diff --git a/src/devices/grohtml/html.h b/src/devices/grohtml/html.h
index d2c67530..3e442b8f 100644
--- a/src/devices/grohtml/html.h
+++ b/src/devices/grohtml/html.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 2000 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -18,6 +18,11 @@ 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. */
+#if !defined(HTML_H)
+# define HTML_H
+# undef DEBUGGING
+// #define DEBUGGING
+
class simple_output {
public:
simple_output(FILE *, int max_line_length);
@@ -40,7 +45,11 @@ public:
simple_output &end_line();
simple_output &put_raw_char(char);
simple_output &special(const char *);
- simple_output &put_html_char (char);
+ simple_output &enable_newlines(int);
+ simple_output &check_newline(int n);
+ simple_output &write_newline(void);
+ simple_output &space_or_newline (void);
+ simple_output &check_space (int n);
FILE *get_file();
private:
FILE *fp;
@@ -48,6 +57,7 @@ private:
int col;
int need_space;
int fixed_point;
+ int newlines; // can we issue newlines automatically?
};
inline FILE *simple_output::get_file()
@@ -55,3 +65,4 @@ inline FILE *simple_output::get_file()
return fp;
}
+#endif
diff --git a/src/devices/grohtml/ordered_list.h b/src/devices/grohtml/ordered_list.h
deleted file mode 100755
index b86ad9f0..00000000
--- a/src/devices/grohtml/ordered_list.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 1999, 2000 Free Software Foundation, Inc.
- *
- * Ordered list, a template module for simple ordered list manipulation.
- *
- * Gaius Mulley (gaius@glam.ac.uk)
- */
-
-template <class T> class list_element
-{
- public:
- list_element<T> *right;
- list_element<T> *left;
-
- list_element (T *in);
- T *data;
-};
-
-template <class T> class ordered_list
-{
- private:
- list_element<T> *head;
- list_element<T> *tail;
- list_element<T> *ptr;
- public:
- ordered_list (void);
- ~ ordered_list (void);
- void add (T* in);
- void sub_move_right (void);
- void move_right (void);
- void move_left (void);
- int is_empty (void);
- int is_equal_to_tail (void);
- int is_equal_to_head (void);
- void start_from_head (void);
- void start_from_tail (void);
- T *move_right_get_data (void);
- T *move_left_get_data (void);
- T *get_data (void);
-};
-
-
-template <class T> ordered_list<T>::ordered_list()
- : head(0), tail(0), ptr(0)
-{
-}
-
-template <class T> ordered_list<T>::~ordered_list()
-{
- list_element<T> *temp=head;
-
- do {
- temp = head;
- if (temp != 0) {
- head = head->right;
- delete temp;
- }
- } while ((head != 0) && (head != tail));
-}
-
-template <class T> list_element<T>::list_element(T *in)
- : right(0), left(0)
-{
- data = in;
-}
-
-template <class T> void ordered_list<T>::add(T *in)
-{
- list_element<T> *t = new list_element<T>(in); // create a new list element with data field initialized
- list_element<T> *last;
-
- if (in == 0) {
- fatal("cannot add NULL to ordered list");
- }
-
- if (head == 0) {
- head = t;
- tail = t;
- t->left = t;
- t->right = t;
- } else {
- last = tail;
-
- while ((last != head) && (in->is_less(in, last->data))) {
- last = last->left;
- }
-
- if (in->is_less(in, last->data)) {
- t->right = last;
- last->left->right = t;
- t->left = last->left;
- last->left = t;
- // now check for a new head
- if (last == head) {
- head = t;
- }
- } else {
- // add t onto beyond last
- t->right = last->right;
- t->left = last;
- last->right->left = t;
- last->right = t;
- // now check for a new tail
- if (last == tail) {
- tail = t;
- }
- }
- }
-}
-
-template <class T> void ordered_list<T>::sub_move_right (void)
-{
- list_element<T> *t=ptr->right;
-
- if (head == tail) {
- head = 0;
- if (tail != 0) {
- delete tail;
- }
- tail = 0;
- ptr = 0;
- } else {
- if (head == ptr) {
- head = head->right;
- }
- if (tail == ptr) {
- tail = tail->left;
- }
- ptr->left->right = ptr->right;
- ptr->right->left = ptr->left;
- ptr=t;
- }
-}
-
-template <class T> void ordered_list<T>::start_from_head (void)
-{
- ptr = head;
-}
-
-template <class T> void ordered_list<T>::start_from_tail (void)
-{
- ptr = tail;
-}
-
-template <class T> int ordered_list<T>::is_empty (void)
-{
- return( head == 0 );
-}
-
-template <class T> int ordered_list<T>::is_equal_to_tail (void)
-{
- return( ptr == tail );
-}
-
-template <class T> int ordered_list<T>::is_equal_to_head (void)
-{
- return( ptr == head );
-}
-
-template <class T> void ordered_list<T>::move_left (void)
-{
- ptr = ptr->left;
-}
-
-template <class T> void ordered_list<T>::move_right (void)
-{
- ptr = ptr->right;
-}
-
-template <class T> T* ordered_list<T>::get_data (void)
-{
- return( ptr->data );
-}
-
-template <class T> T* ordered_list<T>::move_right_get_data (void)
-{
- ptr = ptr->right;
- if (ptr == head) {
- return( 0 );
- } else {
- return( ptr->data );
- }
-}
-
-template <class T> T* ordered_list<T>::move_left_get_data (void)
-{
- ptr = ptr->left;
- if (ptr == tail) {
- return( 0 );
- } else {
- return( ptr->data );
- }
-}
diff --git a/src/devices/grohtml/output.cc b/src/devices/grohtml/output.cc
index d6dc1884..15b26f2c 100644
--- a/src/devices/grohtml/output.cc
+++ b/src/devices/grohtml/output.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 2000 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
*
* Gaius Mulley (gaius@glam.ac.uk) wrote output.cc
* but it owes a huge amount of ideas and raw code from
@@ -45,20 +45,20 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
# define FALSE (1==0)
#endif
-
/*
* the classes and methods for simple_output manipulation
*/
simple_output::simple_output(FILE *f, int n)
-: fp(f), max_line_length(n), col(0), need_space(0), fixed_point(0)
+: fp(f), max_line_length(n), col(0), need_space(0), fixed_point(0), newlines(0)
{
}
simple_output &simple_output::set_file(FILE *f)
{
+ if (fp)
+ fflush(fp);
fp = f;
- col = 0;
return *this;
}
@@ -103,6 +103,7 @@ simple_output &simple_output::begin_comment(const char *s)
putc('\n', fp);
fputs("<!-- ", fp);
fputs(s, fp);
+ need_space = 0;
col = 5 + strlen(s);
return *this;
}
@@ -112,7 +113,7 @@ simple_output &simple_output::end_comment()
if (need_space) {
putc(' ', fp);
}
- fputs(" -->\n", fp);
+ fputs("-->\n", fp);
col = 0;
need_space = 0;
return *this;
@@ -121,16 +122,67 @@ simple_output &simple_output::end_comment()
simple_output &simple_output::comment_arg(const char *s)
{
int len = strlen(s);
+ int i = 0;
if (col + len + 1 > max_line_length) {
fputs("\n ", fp);
col = 1;
}
- fputs(s, fp);
- col += len + 1;
+ while (i < len) {
+ if (s[i] != '\n') {
+ putc(s[i], fp);
+ col++;
+ }
+ i++;
+ }
+ need_space = 1;
return *this;
}
+/*
+ * check_newline - checks to see whether we are able to issue
+ * a newline and that one is needed.
+ */
+
+simple_output &simple_output::check_newline(int n)
+{
+ if ((col + n > max_line_length) && (newlines)) {
+ fputc('\n', fp);
+ need_space = 0;
+ col = 0;
+ }
+}
+
+/*
+ * space_or_newline - will emit a newline or a space later on
+ * depending upon the current column.
+ */
+
+simple_output &simple_output::space_or_newline (void)
+{
+ if ((col + 1 > max_line_length) && (newlines)) {
+ fputc('\n', fp);
+ need_space = 0;
+ col = 0;
+ } else {
+ need_space = 1;
+ }
+}
+
+/*
+ * write_newline - writes a newline providing that we
+ * are not in the first column.
+ */
+
+simple_output &simple_output::write_newline (void)
+{
+ if (col != 0) {
+ fputc('\n', fp);
+ need_space = 0;
+ col = 0;
+ }
+}
+
simple_output &simple_output::set_fixed_point(int n)
{
assert(n >= 0 && n <= 10);
@@ -146,14 +198,33 @@ simple_output &simple_output::put_raw_char(char c)
return *this;
}
+/*
+ * check_space - writes a space if required.
+ */
+
+simple_output &simple_output::check_space (int n)
+{
+ check_newline(n);
+ if (need_space) {
+ fputc(' ', fp);
+ need_space = 0;
+ col++;
+ }
+}
+
simple_output &simple_output::put_string(const char *s, int n)
{
int i=0;
+ check_space(n);
+
while (i<n) {
fputc(s[i], fp);
i++;
}
+#if defined(DEBUGGING)
+ fflush(fp); // just for testing
+#endif
col += n;
return *this;
}
@@ -162,12 +233,17 @@ simple_output &simple_output::put_translated_string(const char *s)
{
int i=0;
+ check_space(strlen(s));
+
while (s[i] != (char)0) {
if ((s[i] & 0x7f) == s[i]) {
fputc(s[i], fp);
}
i++;
}
+#if defined(DEBUGGING)
+ fflush(fp); // just for testing
+#endif
col += i;
return *this;
}
@@ -175,48 +251,24 @@ simple_output &simple_output::put_translated_string(const char *s)
simple_output &simple_output::put_string(const char *s)
{
int i=0;
+ int j=0;
+
+ check_space(strlen(s));
while (s[i] != '\0') {
fputc(s[i], fp);
- i++;
- }
- col += i;
- return *this;
-}
-
-struct html_2_postscript {
- char *html_char;
- char *postscript_char;
-};
-
-static struct html_2_postscript ps_char_conversions[] = {
- { "+-", "char177", },
- { "eq", "=" , },
- { "mu", "char215", },
- { NULL, NULL , },
-};
-
-
-/*
- * this is an aweful hack which attempts to translate html characters onto
- * postscript characters. Can this be done inside the devhtml files?
- *
- * or should we read the devps files and find out the translations?
- */
-
-simple_output &simple_output::put_troffps_char (const char *s)
-{
- int i=0;
-
- while (ps_char_conversions[i].html_char != NULL) {
- if (strcmp(s, ps_char_conversions[i].html_char) == 0) {
- put_string(ps_char_conversions[i].postscript_char);
- return *this;
+ if (s[i] == '\n') {
+ col = 0;
+ j = 0;
} else {
- i++;
+ j++;
}
+ i++;
}
- put_string(s);
+ col += j;
+#if defined(DEBUGGING)
+ fflush(fp); // just for testing
+#endif
return *this;
}
@@ -226,7 +278,6 @@ simple_output &simple_output::put_number(int n)
sprintf(buf, "%d", n);
int len = strlen(buf);
put_string(buf, len);
- need_space = 1;
return *this;
}
@@ -241,7 +292,6 @@ simple_output &simple_output::put_float(double d)
return *this;
}
-
simple_output &simple_output::put_symbol(const char *s)
{
int len = strlen(s);
@@ -255,3 +305,9 @@ simple_output &simple_output::put_symbol(const char *s)
need_space = 1;
return *this;
}
+
+simple_output &simple_output::enable_newlines (int auto_newlines)
+{
+ newlines = auto_newlines;
+ check_newline(0);
+}
diff --git a/src/devices/grohtml/post-html.cc b/src/devices/grohtml/post-html.cc
new file mode 100644
index 00000000..7f6490ca
--- /dev/null
+++ b/src/devices/grohtml/post-html.cc
@@ -0,0 +1,2667 @@
+// -*- C++ -*-
+/* Copyright (C) 2000, 2001 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
+ * James Clark (jjc@jclark.com) grops/ps.cc.
+ */
+
+/*
+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.h"
+#include "html-chars.h"
+#include "html-text.h"
+
+#include <time.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+
+#if !defined(TRUE)
+# define TRUE (1==1)
+#endif
+#if !defined(FALSE)
+# 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 */
+
+typedef enum {CENTERED, LEFT, RIGHT, INLINE} TAG_ALIGNMENT;
+
+/*
+ * 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);
+
+
+static int auto_links = TRUE; /* by default we enable automatic links at */
+ /* top of the document. */
+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 */
+
+
+/*
+ * start with a few favorites
+ */
+
+void stop () {}
+
+static int min (int a, int b)
+{
+ if (a < b) {
+ return( a );
+ } else {
+ return( b );
+ }
+}
+
+static int max (int a, int b)
+{
+ if (a > b) {
+ return( a );
+ } else {
+ return( b );
+ }
+}
+
+/*
+ * is_subsection - returns TRUE if a1..a2 is within b1..b2
+ */
+
+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)) );
+}
+
+/*
+ * 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
+ return( ! ((a1 > b2) || (a2 < b1)) );
+}
+
+/*
+ * is_digit - returns TRUE if character, ch, is a digit.
+ */
+
+static int is_digit (char ch)
+{
+ return( (ch >= '0') && (ch <= '9') );
+}
+
+/*
+ * the classes and methods for maintaining a list of files.
+ */
+
+struct file {
+ FILE *fp;
+ file *next;
+
+ file (FILE *f);
+};
+
+/*
+ * file - initialize all fields to NULL
+ */
+
+file::file (FILE *f)
+ : fp(f), next(0)
+{
+}
+
+class files {
+public:
+ files ();
+ FILE *get_file (void);
+ void start_of_list (void);
+ void move_next (void);
+ void add_new_file (FILE *f);
+private:
+ file *head;
+ file *tail;
+ file *ptr;
+};
+
+/*
+ * files - create an empty list of files.
+ */
+
+files::files ()
+ : head(0), tail(0), ptr(0)
+{
+}
+
+/*
+ * get_file - returns the FILE associated with ptr.
+ */
+
+FILE *files::get_file (void)
+{
+ if (ptr) {
+ return( ptr->fp );
+ } else {
+ return( 0 );
+ }
+}
+
+/*
+ * start_of_list - reset the ptr to the start of the list.
+ */
+
+void files::start_of_list (void)
+{
+ ptr = head;
+}
+
+/*
+ * move_next - moves the ptr to the next element on the list.
+ */
+
+void files::move_next (void)
+{
+ if (ptr != 0)
+ ptr = ptr->next;
+}
+
+/*
+ * add_new_file - adds a new file, f, to the list.
+ */
+
+void files::add_new_file (FILE *f)
+{
+ if (head == 0) {
+ head = new file(f);
+ tail = head;
+ } else {
+ tail->next = new file(f);
+ tail = tail->next;
+ }
+ ptr = tail;
+}
+
+/*
+ * the class and methods for styles
+ */
+
+struct style {
+ font *f;
+ int point_size;
+ int font_no;
+ int height;
+ int slant;
+ style ();
+ style (font *, int, int, int, int);
+ int operator == (const style &) const;
+ int operator != (const style &) const;
+};
+
+style::style()
+ : f(0)
+{
+}
+
+style::style(font *p, int sz, int h, int sl, int no)
+ : f(p), point_size(sz), font_no(no), height(h), slant(sl)
+{
+}
+
+int style::operator==(const style &s) const
+{
+ return (f == s.f && point_size == s.point_size
+ && height == s.height && slant == s.slant);
+}
+
+int style::operator!=(const style &s) const
+{
+ return !(*this == s);
+}
+
+/*
+ * the class and methods for retaining ascii text
+ */
+
+struct char_block {
+ enum { SIZE = 256 };
+ char buffer[SIZE];
+ int used;
+ char_block *next;
+
+ char_block();
+};
+
+char_block::char_block()
+: used(0), next(0)
+{
+}
+
+class char_buffer {
+public:
+ char_buffer();
+ ~char_buffer();
+ char *add_string(char *, unsigned int);
+private:
+ char_block *head;
+ char_block *tail;
+};
+
+char_buffer::char_buffer()
+: head(0), tail(0)
+{
+}
+
+char_buffer::~char_buffer()
+{
+ while (head != 0) {
+ char_block *temp = head;
+ head = head->next;
+ delete temp;
+ }
+}
+
+char *char_buffer::add_string (char *s, unsigned int length)
+{
+ int i=0;
+ unsigned int old_used;
+
+ if (tail == 0) {
+ tail = new char_block;
+ head = tail;
+ } else {
+ if (tail->used + length+1 > char_block::SIZE) {
+ tail->next = new char_block;
+ 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 {
+ tail->buffer[tail->used] = s[i];
+ tail->used++;
+ i++;
+ length--;
+ } while (length>0);
+
+ // add terminating nul character
+
+ tail->buffer[tail->used] = '\0';
+ tail->used++;
+
+ // and return start of new string
+
+ return( &tail->buffer[old_used] );
+}
+
+/*
+ * 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_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);
+
+ style text_style;
+ char *text_string;
+ unsigned int text_length;
+ int minv, maxv, minh, 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_line; // is the command a <line>?
+ int thickness; // the thickness of a line
+};
+
+text_glob::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_a_line, int line_thickness)
+ : text_style(*s), text_string(string), 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_line(is_a_line),
+ thickness(line_thickness)
+{
+}
+
+text_glob::text_glob ()
+ : text_string(0), text_length(0), minv(-1), maxv(-1), minh(-1), maxh(-1),
+ is_raw_command(FALSE), is_tag(FALSE), is_line(FALSE), thickness(0)
+{
+}
+
+text_glob::~text_glob ()
+{
+}
+
+/*
+ * is_a_line - returns TRUE if glob should be converted into an <hr>
+ */
+
+int text_glob::is_a_line (void)
+{
+ return( is_line );
+}
+
+/*
+ * is_a_tag - returns TRUE if glob contains a troff directive.
+ */
+
+int text_glob::is_a_tag (void)
+{
+ return( is_tag );
+}
+
+/*
+ * is_eol - returns TRUE if glob contains the tag eol
+ */
+
+int text_glob::is_eol (void)
+{
+ return( is_tag && (strcmp(text_string, "html-tag:eol") == 0) );
+}
+
+/*
+ * is_raw - returns TRUE if glob contains raw html.
+ */
+
+int text_glob::is_raw (void)
+{
+ return( is_raw_command );
+}
+
+/*
+ * the class and methods used to construct ordered double linked lists.
+ * In a previous implementation we used templates via #include "ordered-list.h",
+ * but this does assume that all C++ compilers can handle this feature. Pragmatically
+ * it is safer to assume this is not the case.
+ */
+
+struct element_list {
+ element_list *right;
+ element_list *left;
+ text_glob *datum;
+ int lineno;
+ int minv, maxv, minh, maxh;
+
+ element_list (text_glob *d,
+ int line_number,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal);
+ element_list ();
+};
+
+element_list::element_list ()
+ : right(0), left(0), datum(0), lineno(0), minv(-1), maxv(-1), minh(-1), maxh(-1)
+{
+}
+
+/*
+ * element_list - create a list element assigning the datum and region parameters.
+ */
+
+element_list::element_list (text_glob *in,
+ int line_number,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal)
+ : right(0), left(0), datum(in), lineno(line_number),
+ minv(min_vertical), minh(min_horizontal), maxv(max_vertical), maxh(max_horizontal)
+{
+}
+
+class list {
+public:
+ list ();
+ ~list ();
+ int is_less (element_list *a, element_list *b);
+ void add (text_glob *in,
+ int line_number,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal);
+ void sub_move_right (void);
+ void move_right (void);
+ void move_left (void);
+ int is_empty (void);
+ int is_equal_to_tail (void);
+ int is_equal_to_head (void);
+ void start_from_head (void);
+ void start_from_tail (void);
+ text_glob *move_right_get_data (void);
+ text_glob *move_left_get_data (void);
+ text_glob *get_data (void);
+private:
+ element_list *head;
+ element_list *tail;
+ element_list *ptr;
+};
+
+/*
+ * list - construct an empty list.
+ */
+
+list::list ()
+ : head(0), tail(0), ptr(0)
+{
+}
+
+/*
+ * ~list - destroy a complete list.
+ */
+
+list::~list()
+{
+ element_list *temp=head;
+
+ do {
+ temp = head;
+ if (temp != 0) {
+ head = head->right;
+ delete temp;
+ }
+ } while ((head != 0) && (head != tail));
+}
+
+/*
+ * is_less - returns TRUE if a is left of b if on the same line or
+ * if a is higher up the page than b.
+ */
+
+int list::is_less (element_list *a, element_list *b)
+{
+ // was if (is_intersection(a->minv+1, a->maxv-1, b->minv+1, b->maxv-1)) {
+ if (a->lineno < b->lineno) {
+ return( TRUE );
+ } else if (a->lineno > b->lineno) {
+ return( FALSE );
+ } else if (is_intersection(a->minv, a->maxv, b->minv, b->maxv)) {
+ return( a->minh < b->minh );
+ } else {
+ return( a->maxv < b->maxv );
+ }
+}
+
+/*
+ * add - adds a datum to the list in the order specified by the region position.
+ */
+
+void list::add (text_glob *in, int line_number, int min_vertical, int min_horizontal, int max_vertical, int max_horizontal)
+{
+ // create a new list element with datum and position fields initialized
+ element_list *t = new element_list(in, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal);
+ element_list *last;
+
+ if (head == 0) {
+ head = t;
+ tail = t;
+ t->left = t;
+ t->right = t;
+ } else {
+ last = tail;
+
+ while ((last != head) && (is_less(t, last))) {
+ last = last->left;
+ }
+
+ if (is_less(t, last)) {
+ t->right = last;
+ last->left->right = t;
+ t->left = last->left;
+ last->left = t;
+ // now check for a new head
+ if (last == head) {
+ head = t;
+ }
+ } else {
+ // add t beyond last
+ t->right = last->right;
+ t->left = last;
+ last->right->left = t;
+ last->right = t;
+ // now check for a new tail
+ if (last == tail) {
+ tail = t;
+ }
+ }
+ }
+}
+
+/*
+ * sub_move_right - removes the element which is currently pointed to by ptr
+ * from the list and moves ptr to the right.
+ */
+
+void list::sub_move_right (void)
+{
+ element_list *t=ptr->right;
+
+ if (head == tail) {
+ head = 0;
+ if (tail != 0) {
+ delete tail;
+ }
+ tail = 0;
+ ptr = 0;
+ } else {
+ if (head == ptr) {
+ head = head->right;
+ }
+ if (tail == ptr) {
+ tail = tail->left;
+ }
+ ptr->left->right = ptr->right;
+ ptr->right->left = ptr->left;
+ ptr=t;
+ }
+}
+
+/*
+ * start_from_head - assigns ptr to the head.
+ */
+
+void list::start_from_head (void)
+{
+ ptr = head;
+}
+
+/*
+ * start_from_tail - assigns ptr to the tail.
+ */
+
+void list::start_from_tail (void)
+{
+ ptr = tail;
+}
+
+/*
+ * is_empty - returns TRUE if the list has no elements.
+ */
+
+int list::is_empty (void)
+{
+ return( head == 0 );
+}
+
+/*
+ * is_equal_to_tail - returns TRUE if the ptr equals the tail.
+ */
+
+int list::is_equal_to_tail (void)
+{
+ return( ptr == tail );
+}
+
+/*
+ * is_equal_to_head - returns TRUE if the ptr equals the head.
+ */
+
+int list::is_equal_to_head (void)
+{
+ return( ptr == head );
+}
+
+/*
+ * move_left - moves the ptr left.
+ */
+
+void list::move_left (void)
+{
+ ptr = ptr->left;
+}
+
+/*
+ * move_right - moves the ptr right.
+ */
+
+void list::move_right (void)
+{
+ ptr = ptr->right;
+}
+
+/*
+ * get_datum - returns the datum referenced via ptr.
+ */
+
+text_glob* list::get_data (void)
+{
+ return( ptr->datum );
+}
+
+/*
+ * move_right_get_data - returns the datum referenced via ptr and moves
+ * ptr right.
+ */
+
+text_glob* list::move_right_get_data (void)
+{
+ ptr = ptr->right;
+ if (ptr == head) {
+ return( 0 );
+ } else {
+ return( ptr->datum );
+ }
+}
+
+/*
+ * move_left_get_data - returns the datum referenced via ptr and moves
+ * ptr right.
+ */
+
+text_glob* list::move_left_get_data (void)
+{
+ ptr = ptr->left;
+ if (ptr == tail) {
+ return( 0 );
+ } else {
+ return( ptr->datum );
+ }
+}
+
+/*
+ * page class and methods
+ */
+
+class page {
+public:
+ page (void);
+ void add (style *s, char *string, unsigned int length,
+ 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,
+ 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,
+ int line_number,
+ int min_vertical, int min_horizontal,
+ int max_vertical, int max_horizontal);
+ void add_line (style *s,
+ int line_number,
+ int x1, int y1, int x2, int y2,
+ int thickness);
+ void dump_page (void); // debugging method
+
+ // and the data
+
+ list glyphs; // position of glyphs and specials on page
+ char_buffer buffer; // all characters for this page
+};
+
+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)
+{
+ 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, 0);
+ glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal);
+ }
+}
+
+/*
+ * add_html - add a raw html command, for example mailto, line, background, image etc.
+ */
+
+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)
+{
+ 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, 0);
+ glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal);
+ }
+}
+
+/*
+ * add_tag - adds a troff tag, for example: .tl .sp .br
+ */
+
+void page::add_tag (style *s, char *string, unsigned int length,
+ 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, FALSE, 0);
+ glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal);
+ }
+}
+
+/*
+ * add_line - adds the <line> primitive providing that y1==y2
+ */
+
+void page::add_line (style *s,
+ int line_number,
+ int x1, int y1, int x2, int y2,
+ 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, thickness);
+ glyphs.add(g, line_number, min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2));
+ }
+}
+
+/*
+ * dump_page - dump the page contents for debugging purposes.
+ */
+
+void page::dump_page(void)
+{
+ text_glob *g;
+
+ printf("\n\ndebugging start\n");
+ glyphs.start_from_head();
+ do {
+ g = glyphs.get_data();
+ printf("%s ", g->text_string);
+ glyphs.move_right();
+ } while (! glyphs.is_equal_to_head());
+ printf("\ndebugging end\n\n");
+}
+
+/*
+ * font classes and methods
+ */
+
+class html_font : public font {
+ html_font(const char *);
+public:
+ int encoding_index;
+ char *encoding;
+ char *reencoded_name;
+ ~html_font();
+ static html_font *load_html_font(const char *);
+};
+
+html_font *html_font::load_html_font(const char *s)
+{
+ html_font *f = new html_font(s);
+ if (!f->load()) {
+ delete f;
+ return 0;
+ }
+ return f;
+}
+
+html_font::html_font(const char *nm)
+: font(nm)
+{
+}
+
+html_font::~html_font()
+{
+}
+
+/*
+ * a simple class to contain the header to this document
+ */
+
+class title_desc {
+public:
+ title_desc ();
+ ~title_desc ();
+
+ int has_been_written;
+ int has_been_found;
+ char text[MAX_STRING_LENGTH];
+};
+
+
+title_desc::title_desc ()
+ : has_been_written(FALSE), has_been_found(FALSE)
+{
+}
+
+title_desc::~title_desc ()
+{
+}
+
+class header_desc {
+public:
+ header_desc ();
+ ~header_desc ();
+
+ int no_of_headings; // how many headings have we found?
+ char_buffer headings; // all the headings used in the document
+ 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
+
+ void write_headings (FILE *f, int force);
+};
+
+header_desc::header_desc ()
+ : no_of_headings(0), header_level(2), written_header(0)
+{
+}
+
+header_desc::~header_desc ()
+{
+}
+
+/*
+ * write_headings - emits a list of links for the headings in this document
+ */
+
+void header_desc::write_headings (FILE *f, int force)
+{
+ text_glob *g;
+
+ if (auto_links || force) {
+ if (! headers.is_empty()) {
+ int h=1;
+
+ headers.start_from_head();
+ do {
+ g = headers.get_data();
+ fputs("<a href=\"#", f);
+ if (simple_anchors)
+ fprintf(f, ANCHOR_TEMPLATE, h);
+ else
+ fputs(g->text_string, f);
+ h++;
+ fputs("\">", f);
+ fputs(g->text_string, f);
+ fputs("</a><br>\n", f);
+ headers.move_right();
+ } while (! headers.is_equal_to_head());
+ fputs("\n", f);
+ }
+ }
+}
+
+class html_printer : public printer {
+ files file_list;
+ simple_output html;
+ int res;
+ int space_char_index;
+ int no_of_printed_pages;
+ int paper_length;
+ enum { SBUF_SIZE = 8192 };
+ char sbuf[SBUF_SIZE];
+ int sbuf_len;
+ int sbuf_start_hpos;
+ int sbuf_vpos;
+ int sbuf_end_hpos;
+ int sbuf_kern;
+ style sbuf_style;
+ style output_style;
+ int output_hpos;
+ int output_vpos;
+ int output_vpos_max;
+ int output_draw_point_size;
+ int line_thickness;
+ int output_line_thickness;
+ unsigned char output_space_code;
+ string defs;
+ char *inside_font_style;
+ int page_number;
+ title_desc title;
+ header_desc header;
+ int header_indent;
+ int supress_sub_sup;
+ int cutoff_heading;
+ page *page_contents;
+ html_text *current_paragraph;
+ int end_center;
+ TAG_ALIGNMENT next_tag;
+ int fill_on;
+ int linelength;
+ int pageoffset;
+ int indentation;
+ int pointsize;
+ int vertical_spacing;
+ int line_number;
+
+ void flush_sbuf ();
+ void set_style (const style &);
+ void set_space_code (unsigned char c);
+ void do_exec (char *, const environment *);
+ void do_import (char *, const environment *);
+ void do_def (char *, const environment *);
+ void do_mdef (char *, const environment *);
+ void do_file (char *, const environment *);
+ 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 (char code, const char *name);
+ 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);
+ 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 determine_space (text_glob *g);
+ void start_font (const char *name);
+ void end_font (const char *name);
+ int is_font_courier (font *f);
+ int is_courier_until_eol (void);
+ void start_size (int from, int to);
+ void do_font (text_glob *g);
+ void do_space (void);
+ void do_break (void);
+ void do_center (char *arg);
+ void do_eol (void);
+ void do_title (void);
+ void do_fill (int on);
+ void do_heading (char *arg);
+ void write_header (void);
+ void determine_header_level (int level);
+ void do_linelength (char *arg);
+ void do_pageoffset (char *arg);
+ void do_indentation (char *arg);
+ void do_verticalspacing (char *arg);
+ void do_pointsize (char *arg);
+ void do_centered_image (void);
+ void do_left_image (void);
+ void do_right_image (void);
+ void do_auto_image (text_glob *g, const char *filename);
+ void do_indent (char *arg);
+ void do_links (void);
+ void do_flush (void);
+ int is_in_middle (int left, int right);
+ void do_sup_or_sub (text_glob *g);
+ int start_subscript (text_glob *g);
+ int end_subscript (text_glob *g);
+ int start_superscript (text_glob *g);
+ int end_superscript (text_glob *g);
+
+ // 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);
+ font *make_font (const char *);
+ void end_of_line ();
+};
+
+printer *make_printer()
+{
+ return new html_printer;
+}
+
+static void usage();
+
+void html_printer::set_style(const style &sty)
+{
+ const char *fontname = sty.f->get_name();
+ if (fontname == 0)
+ fatal("no internalname specified for font");
+
+#if 0
+ change_font(fontname, (font::res/(72*font::sizescale))*sty.point_size);
+#endif
+}
+
+void html_printer::end_of_line()
+{
+ flush_sbuf();
+ line_number++;
+}
+
+/*
+ * emit_line - writes out a horizontal rule.
+ */
+
+void html_printer::emit_line (text_glob *g)
+{
+ // --fixme-- needs to know the length in percentage
+ html.put_string("<hr>");
+}
+
+/*
+ * emit_raw - writes the raw html information directly to the device.
+ */
+
+void html_printer::emit_raw (text_glob *g)
+{
+ do_font(g);
+ if (next_tag == INLINE) {
+ determine_space(g);
+ current_paragraph->do_emittext(g->text_string, g->text_length);
+ } else {
+ current_paragraph->done_para();
+ switch (next_tag) {
+
+ case CENTERED:
+ current_paragraph->do_para("align=center");
+ break;
+ case LEFT:
+ current_paragraph->do_para("align=left");
+ break;
+ case RIGHT:
+ current_paragraph->do_para("align=right");
+ break;
+ default:
+ fatal("unknown enumeration");
+ }
+ current_paragraph->do_emittext(g->text_string, g->text_length);
+ current_paragraph->done_para();
+ next_tag = INLINE;
+ supress_sub_sup = TRUE;
+ }
+}
+
+/*
+ * do_center - handle the .ce commands from troff.
+ */
+
+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->do_para("align=center");
+ end_center += n;
+ } else {
+ end_center = 0;
+ }
+}
+
+/*
+ * do_centered_image - set a flag such that the next html-tag is
+ * placed inside a centered paragraph.
+ */
+
+void html_printer::do_centered_image (void)
+{
+ next_tag = CENTERED;
+}
+
+/*
+ * do_right_image - set a flag such that the next html-tag is
+ * placed inside a right aligned paragraph.
+ */
+
+void html_printer::do_right_image (void)
+{
+ next_tag = RIGHT;
+}
+
+/*
+ * do_left_image - set a flag such that the next html-tag is
+ * placed inside a left aligned paragraph.
+ */
+
+void html_printer::do_left_image (void)
+{
+ next_tag = LEFT;
+}
+
+/*
+ * exists - returns TRUE if filename exists.
+ */
+
+static int exists (const char *filename)
+{
+ FILE *fp = fopen(filename, "r");
+
+ if (fp == 0) {
+ return( FALSE );
+ } else {
+ fclose(fp);
+ return( TRUE );
+ }
+}
+
+/*
+ * do_auto_image - tests whether the image, indicated by filename,
+ * is present, if so then it emits an html image tag.
+ * An image tag may be passed through from pic, eqn
+ * but the corresponding image might not be created.
+ * Consider .EQ delim $$ .EN or an empty .PS .PE.
+ */
+
+void html_printer::do_auto_image (text_glob *g, const char *filename)
+{
+ while (filename && (filename[0] == ' ')) {
+ filename++;
+ }
+ if (exists(filename)) {
+ /*
+ * utilize emit_raw by creating a new text_glob.
+ */
+ text_glob h = *g;
+ char buffer[MAX_STRING_LENGTH];
+
+ strcpy(buffer, "<img src=\"");
+ strncat(buffer, filename, MAX_STRING_LENGTH-strlen("<img src=\"")-1);
+ if (strlen(buffer) < MAX_STRING_LENGTH-3) {
+ strncat(buffer, "\">", 3);
+ h.text_string = (char *)&buffer;
+ h.text_length = strlen(buffer);
+ emit_raw(&h);
+ }
+ } else {
+ next_tag = INLINE;
+ }
+}
+
+/*
+ * do_title - handle the .tl commands from troff.
+ */
+
+void html_printer::do_title (void)
+{
+ text_glob *t;
+ int removed_from_head;
+ char buf[MAX_STRING_LENGTH];
+
+ if (page_number == 1) {
+ int found_title_start = FALSE;
+ 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_raw_command) {
+ /* skip raw commands
+ */
+ page_contents->glyphs.sub_move_right(); /* move onto next word */
+ } else if (t->is_eol()) {
+ /* end of title found
+ */
+ title.has_been_found = TRUE;
+ 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;
+ 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()));
+ } 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);
+ found_title_start = TRUE;
+ title.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));
+ }
+ // page_contents->glyphs.move_left(); /* move backwards to last word */
+ }
+}
+
+void html_printer::write_header (void)
+{
+ if (strlen(header.header_buffer) > 0) {
+ if (header.header_level > 7) {
+ header.header_level = 7;
+ }
+
+ if (cutoff_heading+2 > header.header_level) {
+ // firstly we must terminate any font and type faces
+ current_paragraph->done_para();
+ supress_sub_sup = TRUE;
+
+ // now we save the header so we can issue a list of links
+ 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);
+ header.headers.add(h,
+ header.no_of_headings,
+ header.no_of_headings, header.no_of_headings,
+ header.no_of_headings, header.no_of_headings); // and add this header to the header list
+
+ // lastly we generate a tag
+
+ html.put_string("\n<a name=\"");
+ if (simple_anchors) {
+ char buffer[MAX_LINE_LENGTH];
+
+ sprintf(buffer, ANCHOR_TEMPLATE, header.no_of_headings);
+ html.put_string(buffer);
+ } else {
+ html.put_string(header.header_buffer);
+ }
+ html.put_string("\"></a>\n");
+ } else {
+ current_paragraph->done_para();
+ supress_sub_sup = TRUE;
+ }
+
+ // 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(">\n");
+
+ current_paragraph->do_para("");
+ }
+}
+
+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++) {
+ if (header.header_buffer[i] == '.') {
+ level++;
+ }
+ }
+ }
+ header.header_level = level+1;
+}
+
+/*
+ * do_heading - handle the .SH and .NH and equivalent commands from troff.
+ */
+
+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, "");
+ page_contents->glyphs.move_right();
+ if (! page_contents->glyphs.is_equal_to_head()) {
+ g = page_contents->glyphs.get_data();
+ do {
+ if (! (g->is_a_line() || g->is_a_tag() || g->is_raw())) {
+ /*
+ * we ignore raw commands when constructing a heading
+ */
+ if (l != 0) {
+ strcat(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);
+ }
+ page_contents->glyphs.move_right();
+ g = page_contents->glyphs.get_data();
+ } while ((! page_contents->glyphs.is_equal_to_head()) &&
+ (! g->is_a_tag()));
+ }
+
+ determine_header_level(level);
+ write_header();
+
+ // finally set the output to neutral for after the header
+ g = page_contents->glyphs.get_data();
+ page_contents->glyphs.move_left(); // so that next time we use old g
+}
+
+/*
+ * is_courier_until_eol - returns TRUE if we can see a whole line which is courier
+ */
+
+int html_printer::is_courier_until_eol (void)
+{
+ text_glob *orig = page_contents->glyphs.get_data();
+ int result = TRUE;
+ text_glob *g;
+
+ if (! page_contents->glyphs.is_equal_to_tail()) {
+ page_contents->glyphs.move_right();
+ do {
+ g = page_contents->glyphs.get_data();
+ if (! is_font_courier(g->text_style.f)) {
+ result = FALSE;
+ }
+ page_contents->glyphs.move_right();
+ } while ((result) &&
+ (! 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();
+ }
+ }
+ return( result );
+}
+
+/*
+ * do_linelength - handle the .ll command from troff.
+ */
+
+void html_printer::do_linelength (char *arg)
+{
+ linelength = atoi(arg);
+}
+
+/*
+ * do_pageoffset - handle the .po command from troff.
+ */
+
+void html_printer::do_pageoffset (char *arg)
+{
+ pageoffset = atoi(arg);
+}
+
+/*
+ * do_indentation - handle the .in command from troff.
+ */
+
+void html_printer::do_indentation (char *arg)
+{
+ indentation = atoi(arg);
+}
+
+/*
+ * do_verticalspacing - handle the .vs command from troff.
+ */
+
+void html_printer::do_verticalspacing (char *arg)
+{
+ vertical_spacing = atoi(arg);
+}
+
+/*
+ * do_pointsize - handle the .ps command from troff.
+ */
+
+void html_printer::do_pointsize (char *arg)
+{
+ pointsize = atoi(arg);
+}
+
+/*
+ * do_fill - records whether troff has requested that text be filled.
+ */
+
+void html_printer::do_fill (int on)
+{
+ if (fill_on != on) {
+ if (is_font_courier(output_style.f) && (is_courier_until_eol())) {
+ if (on) {
+ current_paragraph->do_pre();
+ } else {
+ current_paragraph->done_pre();
+ }
+ }
+ }
+ fill_on = on;
+}
+
+/*
+ * do_eol - handle the end of line
+ */
+
+void html_printer::do_eol (void)
+{
+ if (! fill_on) {
+ current_paragraph->do_newline();
+ current_paragraph->do_break();
+ }
+ output_hpos = pageoffset;
+ if (end_center > 0) {
+ if (end_center > 1) {
+ current_paragraph->do_break();
+ }
+ end_center--;
+ if (end_center == 0) {
+ current_paragraph->done_para();
+ supress_sub_sup = TRUE;
+ }
+ }
+}
+
+/*
+ * do_flush - flushes all output and tags.
+ */
+
+void html_printer::do_flush (void)
+{
+ current_paragraph->done_para();
+}
+
+/*
+ * do_links - moves onto a new temporary file and sets auto_links to FALSE.
+ */
+
+void html_printer::do_links (void)
+{
+ current_paragraph->done_para();
+ 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
+}
+
+/*
+ * troff_tag - processes the troff tag and manipulates the troff state machine.
+ */
+
+void html_printer::troff_tag (text_glob *g)
+{
+ /*
+ * firstly skip over html-tag:
+ */
+ char *t=(char *)g->text_string+9;
+
+ if (g->is_eol()) {
+ do_eol();
+ } else if (strncmp(t, ".sp", 3) == 0) {
+ current_paragraph->do_space();
+ supress_sub_sup = TRUE;
+ } else if (strncmp(t, ".br", 3) == 0) {
+ current_paragraph->do_break();
+ output_hpos = pageoffset;
+ supress_sub_sup = TRUE;
+ } else if (strcmp(t, ".centered-image") == 0) {
+ do_centered_image();
+ } else if (strcmp(t, ".right-image") == 0) {
+ do_right_image();
+ } else if (strcmp(t, ".left-image") == 0) {
+ do_left_image();
+ } else if (strncmp(t, ".auto-image", 11) == 0) {
+ char *a = (char *)t+11;
+ do_auto_image(g, a);
+ } else if (strncmp(t, ".ce", 3) == 0) {
+ char *a = (char *)t+3;
+ supress_sub_sup = TRUE;
+ do_center(a);
+ } else if (strncmp(t, ".tl", 3) == 0) {
+ supress_sub_sup = TRUE;
+ do_title();
+ } else if (strncmp(t, ".fi", 3) == 0) {
+ do_fill(TRUE);
+ } else if (strncmp(t, ".nf", 3) == 0) {
+ do_fill(FALSE);
+ } else if ((strncmp(t, ".SH", 3) == 0) || (strncmp(t, ".NH", 3) == 0)) {
+ char *a = (char *)t+3;
+ do_heading(a);
+ } else if (strncmp(t, ".ll", 3) == 0) {
+ char *a = (char *)t+3;
+ do_linelength(a);
+ } else if (strncmp(t, ".po", 3) == 0) {
+ char *a = (char *)t+3;
+ do_pageoffset(a);
+ } else if (strncmp(t, ".in", 3) == 0) {
+ char *a = (char *)t+3;
+ do_indentation(a);
+ } else if (strncmp(t, ".vs", 3) == 0) {
+ char *a = (char *)t+3;
+ do_verticalspacing(a);
+ } else if (strcmp(t, ".links") == 0) {
+ do_links();
+ }
+}
+
+/*
+ * is_in_middle - returns TRUE if the positions left..right are in the center of the page.
+ */
+
+int html_printer::is_in_middle (int left, int right)
+{
+ return( abs(abs(left-pageoffset) - abs(pageoffset+linelength-right)) <= CENTER_TOLERANCE );
+}
+
+/*
+ * flush_globs - runs through the text glob list and emits html.
+ */
+
+void html_printer::flush_globs (void)
+{
+ text_glob *g;
+
+ if (! page_contents->glyphs.is_empty()) {
+ page_contents->glyphs.start_from_head();
+ do {
+ g = page_contents->glyphs.get_data();
+
+ if (strcmp(g->text_string, "ZZZZ") == 0) {
+ stop();
+ }
+
+ if (g->is_raw()) {
+ emit_raw(g);
+ } else if (g->is_a_tag()) {
+ troff_tag(g);
+ } else if (g->is_a_line()) {
+ emit_line(g);
+ } else {
+ translate_to_html(g);
+ }
+ /*
+ * after processing the title (and removing it) the glyph list might be empty
+ */
+ if (! page_contents->glyphs.is_empty()) {
+ page_contents->glyphs.move_right();
+ }
+ } while (! page_contents->glyphs.is_equal_to_head());
+ }
+}
+
+void html_printer::flush_page (void)
+{
+ supress_sub_sup = TRUE;
+ flush_sbuf();
+ // page_contents->dump_page();
+ flush_globs();
+ current_paragraph->done_para();
+
+ // move onto a new page
+ delete page_contents;
+ page_contents = new page;
+}
+
+/*
+ * determine_space - works out whether we need to write a space.
+ * If last glyth 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
+ */
+ while (output_hpos < g->minh) {
+ output_hpos += space_width;
+ current_paragraph->emit_space();
+ }
+ } else {
+ if ((output_vpos != g->minv) || (output_hpos < g->minh)) {
+ current_paragraph->emit_space();
+ }
+ }
+}
+
+/*
+ * is_font_courier - returns TRUE if the font, f, is courier.
+ */
+
+int html_printer::is_font_courier (font *f)
+{
+ if (f != 0) {
+ const char *fontname = f->get_name();
+
+ return( (fontname != 0) && (fontname[0] == 'C') );
+ }
+ return( FALSE );
+}
+
+/*
+ * end_font - shuts down the font corresponding to fontname.
+ */
+
+void html_printer::end_font (const char *fontname)
+{
+ if (strcmp(fontname, "B") == 0) {
+ current_paragraph->done_bold();
+ } else if (strcmp(fontname, "I") == 0) {
+ current_paragraph->done_italic();
+ } else if (strcmp(fontname, "BI") == 0) {
+ current_paragraph->done_bold();
+ current_paragraph->done_italic();
+ } else if (strcmp(fontname, "CR") == 0) {
+ current_paragraph->done_tt();
+ current_paragraph->done_pre();
+ }
+}
+
+/*
+ * start_font - starts the font corresponding to name.
+ */
+
+void html_printer::start_font (const char *fontname)
+{
+ if (strcmp(fontname, "R") == 0) {
+ current_paragraph->done_bold();
+ current_paragraph->done_italic();
+ current_paragraph->done_tt();
+ } else if (strcmp(fontname, "B") == 0) {
+ current_paragraph->do_bold();
+ } else if (strcmp(fontname, "I") == 0) {
+ current_paragraph->do_italic();
+ } else if (strcmp(fontname, "BI") == 0) {
+ current_paragraph->do_bold();
+ current_paragraph->do_italic();
+ } else if (strcmp(fontname, "CR") == 0) {
+ if ((! fill_on) && (is_courier_until_eol())) {
+ current_paragraph->do_pre();
+ }
+ current_paragraph->do_tt();
+ }
+}
+
+/*
+ * start_size - from is old font size, to is the new font size.
+ * The html increase <big> and <small> decrease alters the
+ * font size by 20%. We try and map these onto glyph sizes.
+ */
+
+void html_printer::start_size (int from, int to)
+{
+ if (from < to) {
+ while (from < to) {
+ current_paragraph->do_big();
+ from += SIZE_INCREMENT;
+ }
+ } else if (from > to) {
+ while (from > to) {
+ current_paragraph->do_small();
+ from -= SIZE_INCREMENT;
+ }
+ }
+}
+
+/*
+ * do_font - checks to see whether we need to alter the html font.
+ */
+
+void html_printer::do_font (text_glob *g)
+{
+ /*
+ * check if the output_style.point_size has not been set yet
+ * this allow users to place .ps at the top of their troff files
+ * and grohtml can then treat the .ps value as the base font size (3)
+ */
+ if (output_style.point_size == -1) {
+ output_style.point_size = pointsize;
+ }
+
+ if (g->text_style.f != output_style.f) {
+ if (output_style.f != 0) {
+ end_font(output_style.f->get_name());
+ }
+ output_style.f = g->text_style.f;
+ if (output_style.f != 0) {
+ start_font(output_style.f->get_name());
+ }
+ }
+ if (output_style.point_size != g->text_style.point_size) {
+ do_sup_or_sub(g);
+ if ((output_style.point_size > 0) &&
+ (g->text_style.point_size > 0)) {
+ start_size(output_style.point_size, g->text_style.point_size);
+ }
+ if (g->text_style.point_size > 0) {
+ output_style.point_size = g->text_style.point_size;
+ }
+ }
+}
+
+/*
+ * start_subscript - returns TRUE if, g, looks like a subscript start.
+ */
+
+int html_printer::start_subscript (text_glob *g)
+{
+ int r = font::res;
+ int height = output_style.point_size*r/72;
+
+ return( (output_style.point_size != 0) &&
+ (output_vpos < g->minv) &&
+ (output_vpos-height > g->maxv) &&
+ (output_style.point_size > g->text_style.point_size) );
+}
+
+/*
+ * start_superscript - returns TRUE if, g, looks like a superscript start.
+ */
+
+int html_printer::start_superscript (text_glob *g)
+{
+ int r = font::res;
+ int height = output_style.point_size*r/72;
+
+ return( (output_style.point_size != 0) &&
+ (output_vpos > g->minv) &&
+ (output_vpos-height < g->maxv) &&
+ (output_style.point_size > g->text_style.point_size) );
+}
+
+/*
+ * end_subscript - returns TRUE if, g, looks like the end of a subscript.
+ */
+
+int html_printer::end_subscript (text_glob *g)
+{
+ int r = font::res;
+ int height = output_style.point_size*r/72;
+
+ return( (output_style.point_size != 0) &&
+ (g->minv < output_vpos) &&
+ (output_vpos-height > g->maxv) &&
+ (output_style.point_size < g->text_style.point_size) );
+}
+
+/*
+ * end_superscript - returns TRUE if, g, looks like the end of a superscript.
+ */
+
+int html_printer::end_superscript (text_glob *g)
+{
+ int r = font::res;
+ int height = output_style.point_size*r/72;
+
+ return( (output_style.point_size != 0) &&
+ (g->minv > output_vpos) &&
+ (output_vpos-height < g->maxv) &&
+ (output_style.point_size < g->text_style.point_size) );
+}
+
+/*
+ * do_sup_or_sub - checks to see whether the next glyph is a subscript/superscript
+ * start/end and it calls the services of html-text to issue the
+ * appropriate tags.
+ */
+
+void html_printer::do_sup_or_sub (text_glob *g)
+{
+ if (! supress_sub_sup) {
+ if (start_subscript(g)) {
+ current_paragraph->do_sub();
+ } else if (start_superscript(g)) {
+ current_paragraph->do_sup();
+ } else if (end_subscript(g)) {
+ current_paragraph->done_sub();
+ } else if (end_superscript(g)) {
+ current_paragraph->done_sup();
+ }
+ }
+}
+
+/*
+ * translate_to_html - translates a textual string into html text
+ */
+
+void html_printer::translate_to_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));
+ output_vpos = g->minv;
+ output_hpos = g->maxh;
+ output_vpos_max = g->maxv;
+ supress_sub_sup = FALSE;
+}
+
+/*
+ * flush_sbuf - flushes the current sbuf into the list of glyphs.
+ */
+
+void html_printer::flush_sbuf()
+{
+ if (sbuf_len > 0) {
+ int r=font::res; // resolution of the device
+ set_style(sbuf_style);
+
+ page_contents->add(&sbuf_style, sbuf, sbuf_len,
+ 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;
+ }
+}
+
+void html_printer::set_line_thickness(const environment *env)
+{
+ line_thickness = env->size;
+}
+
+void html_printer::draw(int code, int *p, int np, const environment *env)
+{
+ switch (code) {
+
+ case 'l':
+ if (np == 2) {
+ page_contents->add_line(&sbuf_style,
+ line_number,
+ env->hpos, env->vpos, env->hpos+p[0], env->vpos+p[1], line_thickness);
+ } else {
+ error("2 arguments required for line");
+ }
+ 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 'P':
+ // fall through
+ 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
+ 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
+
+ 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;
+ }
+
+ default:
+ error("unrecognised drawing command `%1'", char(code));
+ break;
+ }
+}
+
+html_printer::html_printer()
+: html(0, MAX_LINE_LENGTH),
+ no_of_printed_pages(0),
+ sbuf_len(0),
+ output_hpos(-1),
+ output_vpos(-1),
+ output_vpos_max(-1),
+ line_thickness(-1),
+ inside_font_style(0),
+ page_number(0),
+ header_indent(-1),
+ supress_sub_sup(TRUE),
+ cutoff_heading(100),
+ end_center(0),
+ next_tag(INLINE),
+ fill_on(TRUE),
+ linelength(0),
+ pageoffset(0),
+ indentation(0),
+ line_number(0)
+{
+#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 1");
+ if (font::vert != 40)
+ fatal("vertical resolution must be 1");
+#if 0
+ // should be sorted html..
+ if (font::res % (font::sizescale*72) != 0)
+ fatal("res must be a multiple of 72*sizescale");
+#endif
+ int r = font::res;
+ int point = 0;
+ while (r % 10 == 0) {
+ r /= 10;
+ point++;
+ }
+ res = r;
+ html.set_fixed_point(point);
+ space_char_index = font::name_to_index("space");
+ paper_length = font::paperlength;
+ if (paper_length == 0)
+ paper_length = 11*font::res;
+
+ page_contents = new page();
+}
+
+/*
+ * 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 (char code, const char *name)
+{
+ 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 (html_glyph != NULL) {
+ int l = strlen(html_glyph);
+ int i;
+
+ for (i=0; i<l; i++) {
+ add_char_to_sbuf(html_glyph[i]);
+ }
+ }
+ }
+ }
+}
+
+int html_printer::sbuf_continuation (unsigned char code, const char *name,
+ const environment *env, int w)
+{
+ if (sbuf_end_hpos == env->hpos) {
+ add_to_sbuf(code, name);
+ sbuf_end_hpos += w + sbuf_kern;
+ return( TRUE );
+ } else {
+ if ((sbuf_len < SBUF_SIZE-1) && (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);
+ sbuf_end_hpos = env->hpos + w;
+ 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 );
+ }
+}
+
+/*
+ * get_html_translation - given the position of the character and its name
+ * return the device encoding for such character.
+ */
+
+char *get_html_translation (font *f, const char *name)
+{
+ int index;
+
+ if ((f == 0) || (name == 0) || (strcmp(name, "") == 0)) {
+ return( NULL );
+ } else {
+ index = f->name_to_index((char *)name);
+ 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 );
+ }
+ }
+ }
+}
+
+/*
+ * char_translate_to_html - convert a single non escaped character
+ * into the appropriate html character.
+ */
+
+int char_translate_to_html (font *f, char *buf, int buflen, char ch, int b, int and_single)
+{
+ 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) {
+ 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 {
+ /*
+ * do not attempt to encode single characters
+ */
+ 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++;
+ }
+ } else {
+ b = char_translate_to_html(f, buf, buflen, str[i], b, and_single);
+ i++;
+ }
+ }
+ buf[min(b, buflen)] = (char)0;
+}
+
+/*
+ * set_char - adds a character into the sbuf if it is a continuation with the previous
+ * word otherwise flush the current sbuf and add character anew.
+ */
+
+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);
+ 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))) {
+ 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;
+ }
+}
+
+/*
+ * write_title - writes the title to this document
+ */
+
+void html_printer::write_title (int in_head)
+{
+ if (title.has_been_found) {
+ if (in_head) {
+ html.put_string("<title>");
+ html.put_string(title.text);
+ html.put_string("</title>\n\n");
+ } else {
+ title.has_been_written = TRUE;
+ html.put_string("<h1 align=center>");
+ html.put_string(title.text);
+ html.put_string("</h1>\n\n");
+ }
+ }
+}
+
+/*
+ * write_rule - emits a html rule tag, if the auto_rule boolean is true.
+ */
+
+static void write_rule (void)
+{
+ if (auto_rule)
+ fputs("<hr>\n", stdout);
+}
+
+void html_printer::begin_page(int n)
+{
+ page_number = n;
+ html.begin_comment("Page: ").comment_arg(i_to_a(page_number)).end_comment();;
+ no_of_printed_pages++;
+
+ output_style.f = 0;
+ output_style.point_size= -1;
+ output_space_code = 32;
+ output_draw_point_size = -1;
+ output_line_thickness = -1;
+ output_hpos = -1;
+ output_vpos = -1;
+ output_vpos_max = -1;
+ current_paragraph = new html_text(&html);
+ current_paragraph->do_para("");
+}
+
+void html_printer::end_page(int)
+{
+ flush_sbuf();
+ flush_page();
+}
+
+font *html_printer::make_font(const char *nm)
+{
+ return html_font::load_html_font(nm);
+}
+
+html_printer::~html_printer()
+{
+ current_paragraph->done_para();
+ html.set_file(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);
+ write_title(FALSE);
+ header.write_headings(stdout, FALSE);
+ write_rule();
+ {
+ extern const char *Version_string;
+ html.begin_comment("Creator : ")
+ .comment_arg("groff ")
+ .comment_arg("version ")
+ .comment_arg(Version_string)
+ .end_comment();
+ }
+ {
+#ifdef LONG_FOR_TIME_T
+ long
+#else
+ time_t
+#endif
+ t = time(0);
+ html.begin_comment("CreationDate: ")
+ .comment_arg(ctime(&t))
+ .end_comment();
+ }
+ html.begin_comment("Total number of pages: ").comment_arg(i_to_a(no_of_printed_pages)).end_comment();
+ html.end_line();
+ /*
+ * now run through the file list copying each temporary file in turn and emitting the links.
+ */
+ file_list.start_of_list();
+ while (file_list.get_file() != 0) {
+ if (fseek(file_list.get_file(), 0L, 0) < 0)
+ fatal("fseek on temporary file failed");
+ html.copy_file(file_list.get_file());
+ fclose(file_list.get_file());
+ file_list.move_next();
+ if (file_list.get_file() != 0)
+ header.write_headings(stdout, TRUE);
+ }
+ write_rule();
+ fputs("</body>\n", stdout);
+ fputs("</html>\n", stdout);
+}
+
+/*
+ * special - handle all x X requests from troff. For post-html they allow users
+ * to pass raw html commands, turn auto linked headings off/on and
+ * also allow troff to emit tags to indicate when a: .br, .sp etc occurs.
+ */
+
+void html_printer::special(char *s, const environment *env)
+{
+ 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);
+ 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) {
+ int found=FALSE;
+
+ 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);
+
+ /*
+ * 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.
+ */
+ } 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),
+ line_number,
+ env->vpos-env->size*r/72, env->hpos,
+ env->vpos , env->hpos);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ static char stderr_buf[BUFSIZ];
+ setbuf(stderr, stderr_buf);
+ int c;
+ while ((c = getopt(argc, argv, "o:i:F:vd?lrn")) != EOF)
+ switch(c) {
+ case 'v':
+ {
+ extern const char *Version_string;
+ fprintf(stderr, "post-grohtml version %s\n", Version_string);
+ fflush(stderr);
+ break;
+ }
+ case 'F':
+ font::command_line_font_dir(optarg);
+ break;
+ case 'l':
+ auto_links = FALSE;
+ break;
+ case 'r':
+ auto_rule = FALSE;
+ break;
+ case '?':
+ usage();
+ break;
+ case 'o':
+ /* handled by pre-html */
+ break;
+ case 'i':
+ /* handled by pre-html */
+ break;
+ case 'n':
+ simple_anchors = TRUE;
+ break;
+ default:
+ assert(0);
+ }
+ if (optind >= argc) {
+ do_file("-");
+ } else {
+ for (int i = optind; i < argc; i++)
+ do_file(argv[i]);
+ }
+ delete pr;
+ return 0;
+}
+
+static void usage()
+{
+ fprintf(stderr, "usage: %s [-vld?n] [-F dir] [files ...]\n",
+ program_name);
+ exit(1);
+}
diff --git a/src/devices/grohtml2/Makefile.in b/src/devices/grohtml2/Makefile.in
deleted file mode 100755
index bca59ad7..00000000
--- a/src/devices/grohtml2/Makefile.in
+++ /dev/null
@@ -1,9 +0,0 @@
-PROG=post-grohtml
-MAN1=
-XLIBS=$(LIBDRIVER) $(LIBGROFF)
-MLIB=$(LIBM)
-OBJS=\
- post-html.o
-CCSRCS=\
- $(srcdir)/post-html.cc
-
diff --git a/src/devices/grohtml2/Makefile.sub b/src/devices/grohtml2/Makefile.sub
deleted file mode 100755
index f43a276d..00000000
--- a/src/devices/grohtml2/Makefile.sub
+++ /dev/null
@@ -1,9 +0,0 @@
-PROG=post-grohtml
-MAN1=
-# MAN1=grohtml.n
-XLIBS=$(LIBDRIVER) $(LIBGROFF)
-MLIB=$(LIBM)
-OBJS=\
- post-html.o
-CCSRCS=\
- $(srcdir)/post-html.cc
diff --git a/src/devices/grohtml2/post-html.cc b/src/devices/grohtml2/post-html.cc
deleted file mode 100755
index 3ef4daa8..00000000
--- a/src/devices/grohtml2/post-html.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// -*- C++ -*-
-/* Copyright (C) 1999, 2000 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
- * James Clark (jjc@jclark.com) grops/ps.cc.
- */
-
-/*
-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 <time.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include <stdio.h>
-#include <fcntl.h>
-
-#if !defined(TRUE)
-# define TRUE (1==1)
-#endif
-#if !defined(FALSE)
-# define FALSE (1==0)
-#endif
-
-printer *make_printer()
-{
- // return new html_printer;
- return( 0 );
-}
-
-static void usage();
-
-int main(int argc, char **argv)
-{
- program_name = argv[0];
- static char stderr_buf[BUFSIZ];
- setbuf(stderr, stderr_buf);
- int c;
- while ((c = getopt(argc, argv, "F:atTvdgmx?I:r:")) != EOF)
- switch(c) {
- case 'v':
- {
- extern const char *Version_string;
- printf("GNU post-grohtml (groff) version %s\n", Version_string);
- exit(0);
- break;
- }
- case 'F':
- font::command_line_font_dir(optarg);
- break;
- case '?':
- usage();
- break;
- default:
- assert(0);
- }
- if (optind >= argc) {
- do_file("-");
- } else {
- for (int i = optind; i < argc; i++)
- do_file(argv[i]);
- }
- delete pr;
- return 0;
-}
-
-static void usage()
-{
- fprintf(stderr, "usage: %s [-avdgmt?] [-r resolution] [-F dir] [-I imagetype] [files ...]\n",
- program_name);
- exit(1);
-}
diff --git a/src/preproc/html2/pre-html.h b/src/include/html-strings.h
index 7f56600d..375f5fba 100755..100644
--- a/src/preproc/html2/pre-html.h
+++ b/src/include/html-strings.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 2000 Free Software Foundation, Inc.
+/* Copyright (C) 2001 Free Software Foundation, Inc.
Written by Gaius Mulley (gaius@glam.ac.uk).
This file is part of groff.
@@ -19,19 +19,12 @@ with groff; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*
- * defines functions implemented within pre-html.c
+ * defines the image tags issued by the pre-processors (tbl, pic, eqn)
+ * and later detected by pre-html.cc
*/
-#if !defined(PREHTMLH)
-# define PREHTMLH
-# if defined(PREHTMLC)
-# define EXTERN
-# else
-# define EXTERN extern
-# endif
-
-
-extern void sys_fatal (const char *s);
-
-#undef EXTERN
-#endif
+#define HTML_IMAGE_INLINE ".HTML-IMAGE-INLINE"
+#define HTML_IMAGE_CENTERED ".HTML-IMAGE"
+#define HTML_IMAGE_RIGHT ".HTML-IMAGE-RIGHT"
+#define HTML_IMAGE_LEFT ".HTML-IMAGE-LEFT"
+#define HTML_IMAGE_END ".HTML-IMAGE-END"
diff --git a/src/include/htmlindicate.h b/src/include/htmlindicate.h
index a375fb22..488fdbdc 100755
--- a/src/include/htmlindicate.h
+++ b/src/include/htmlindicate.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 2000 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
Written by Gaius Mulley <gaius@glam.ac.uk>
This file is part of groff.
@@ -24,35 +24,41 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*
* graphic_start - emit a html graphic start indicator, but only
* if one has not already been issued.
+ *
+ * The boolean, is_inline, should be:
+ *
+ * FALSE if this is called via EQ, TS, PS, and
+ * TRUE if issued via delim $$ $ x over y $ etc.
*/
-extern void graphic_start (void);
+extern void graphic_start (int is_inline);
/*
* graphic_end - emit a html graphic end indicator, but only
* if a corresponding matching graphic-start has
* been issued.
+ *
*/
extern void graphic_end (void);
/*
- * html_begin_suppress - if the 'htmlflip' variable is set to 1 then
- * all text following this line will be suppressed by troff
- * and if the -Thtml2 device is specified a generic IMAGE tag
- * is emitted which is later filled in by the pre-html preprocessor.
+ * html_begin_suppress - suppresses output for the html device
+ * and resets the min/max registers for -Tps
+ *
+ * The boolean, is_inline, should be:
+ *
+ * FALSE if this is called via EQ, TS, PS, and
+ * TRUE if issued via delim $$ $ x over y $ etc.
*/
-extern void html_begin_suppress (void);
+extern void html_begin_suppress (int is_inline);
+
/*
- * html_end_suppress - if the 'htmlflip' variable has been set then
- * enable generation of text after this line of troff.
- * If 'htmlflip' and -Thtml2 is set then issue the
- * upper x,y and lower x,y coordinates to stderr via
- * a troff '.tm' command.
+ * html_end_suppress - end the suppression of output.
*/
extern void html_end_suppress (void);
diff --git a/src/include/printer.h b/src/include/printer.h
index 974c9d5b..d7253d03 100644
--- a/src/include/printer.h
+++ b/src/include/printer.h
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2001 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -48,6 +48,7 @@ public:
void set_numbered_char(int n, const environment *env, int *widthp = 0);
int set_char_and_width(const char *nm, const environment *env,
int *widthp, font **f);
+ font *get_font_from_index(int fontno);
virtual void draw(int code, int *p, int np, const environment *env);
virtual void begin_page(int) = 0;
virtual void end_page(int page_length) = 0;
diff --git a/src/libs/libdriver/printer.cc b/src/libs/libdriver/printer.cc
index 770aa507..f7c20384 100644
--- a/src/libs/libdriver/printer.cc
+++ b/src/libs/libdriver/printer.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2001 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -192,6 +192,14 @@ void printer::set_numbered_char(int num, const environment *env, int *widthp)
set_char(i, f, env, w, 0);
}
+font *printer::get_font_from_index(int fontno)
+{
+ if ((fontno >= 0) && (fontno < nfonts))
+ return(font_table[fontno]);
+ else
+ return(0);
+}
+
// This utility function adjusts the specified center of the
// arc so that it is equidistant between the specified start
// and end points. (p[0], p[1]) is a vector from the current
diff --git a/src/libs/libgroff/htmlindicate.cc b/src/libs/libgroff/htmlindicate.cc
index 6b5913f3..0eb2c1c0 100755
--- a/src/libs/libgroff/htmlindicate.cc
+++ b/src/libs/libgroff/htmlindicate.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001 Free Software Foundation, Inc.
Written by Gaius Mulley (gaius@glam.ac.uk)
This file is part of groff.
@@ -23,83 +23,72 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "nonposix.h"
#include "stringclass.h"
+#include "html-strings.h"
/*
* this file contains a very simple set of routines shared by
* tbl, pic, eqn which help the html device driver to make
* sensible formatting choices. Currently it simply indicates
- * when a region of gyphs should be rendered as an image rather
- * than html. In the future it should be expanded so to enable:
- *
- * tbl to inform grohtml about table widths.
- * troff to inform grohtml about tab positions and whether
- * we are entering two/three column mode.
+ * to pre-html when an image is about to be created this is then
+ * passes to pre-html.
+ * Pre-html runs troff twice once with -Thtml and once with -Tps.
+ * troff -Thtml device driver emits a <src='image'.png> tag
+ * and the postscript device driver works out the min/max limits
+ * of the graphic region. These region limits are read by pre-html
+ * and an image is generated via troff -Tps -> gs -> png
*/
-
static int is_in_graphic_start = 0;
/*
- * html_begin_suppress - if the 'htmlflip' variable is set to 1 then
- * all text following this line will be suppressed by troff
- * and if the -Thtml2 device is specified a generic IMAGE tag
- * is emitted which is later filled in by the pre-html preprocessor.
+ * html_begin_suppress -
*/
-void html_begin_suppress (void)
+void html_begin_suppress (int is_inline)
{
- /*
- * the pre-html processor looks for <pre-html-image> and replaces it
- * with a sensible name
- */
- put_string(".if r html2enable .if '\\*(.T'html2' .IMAGE <pre-html-image>\n", stdout);
-#if 1
- // debugging information
- put_string(".if r html2enable .if !r htmlflip .tm \"htmlflip was not set?\"\n", stdout);
-#endif
- put_string(".if r html2enable .if r htmlflip .output 1-\\n[htmlflip]\n", stdout);
+ if (is_inline) {
+ put_string(HTML_IMAGE_INLINE, stdout);
+ } else {
+ put_string(HTML_IMAGE_CENTERED, stdout);
+ }
+ put_string("\n", stdout);
}
/*
- * html_end_suppress - if the 'htmlflip' variable is 1 then
- * enable generation of text after this line of troff.
- * If 'htmlflip' and -Thtml2 is set then issue the
- * upper x,y and lower x,y coordinates to stderr via
- * a troff '.tm' command.
+ * html_end_suppress -
*/
void html_end_suppress (void)
{
- put_string(".if r html2enable .if r htmlflip .if !'\\*(.T'html2' .tm grohtml-info:page \\n% \\n[opminx] \\n[opminy] \\n[opmaxx] \\n[opmaxy] \\n[.H] \\n[.V] \\n[.F]\n",
- stdout);
- put_string(".if r html2enable .if r htmlflip .output \\n[htmlflip]\n", stdout);
+ put_string(HTML_IMAGE_END, stdout);
+ put_string("\n", stdout);
}
/*
- * graphic_start - emit a html graphic start indicator, but only
- * if one has not already been issued.
+ * graphic_start - The boolean, is_inline, should be:
+ *
+ * FALSE if this is called via EQ, TS, PS, and
+ * TRUE if issued via delim $$ $ x over y $ etc.
*/
-void graphic_start (void)
+void graphic_start (int is_inline)
{
if (! is_in_graphic_start) {
- put_string(".if '\\*(.T'html' \\X(graphic-start(\\c\n", stdout);
- html_begin_suppress();
+ put_string(".if '\\*(.T'html-old' \\X(graphic-start(\\c\n", stdout);
+ html_begin_suppress(is_inline);
is_in_graphic_start = 1;
}
}
/*
- * graphic_end - emit a html graphic end indicator, but only
- * if a corresponding matching graphic-start has
- * been issued.
+ * graphic_end - tell troff that the image region is ending.
*/
void graphic_end (void)
{
if (is_in_graphic_start) {
- put_string(".if '\\*(.T'html' \\X(graphic-end(\\c\n", stdout);
html_end_suppress();
+ put_string(".if '\\*(.T'html-old' \\X(graphic-end(\\c\n", stdout);
is_in_graphic_start = 0;
}
}
diff --git a/src/preproc/eqn/main.cc b/src/preproc/eqn/main.cc
index 1cc03303..354b66eb 100644
--- a/src/preproc/eqn/main.cc
+++ b/src/preproc/eqn/main.cc
@@ -1,5 +1,6 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+ Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -79,8 +80,8 @@ void do_file(FILE *fp, const char *filename)
&& linebuf[1] == 'E'
&& linebuf[2] == 'Q'
&& (linebuf[3] == ' ' || linebuf[3] == '\n' || compatible_flag)) {
+ graphic_start(0);
put_string(linebuf, stdout);
- graphic_start();
int start_lineno = current_lineno + 1;
str.clear();
for (;;) {
@@ -167,7 +168,7 @@ static int inline_equation(FILE *fp, string &linebuf, string &str)
ptr = &linebuf[0];
}
str += '\0';
- graphic_start();
+ graphic_start(1);
init_lex(str.contents(), current_filename, start_lineno);
yyparse();
start = delim_search(ptr, start_delim);
@@ -325,8 +326,15 @@ int main(int argc, char **argv)
init_table(device);
init_char_table();
printf(".if !'\\*(.T'%s' "
+ ".if !'\\*(.T'html' " /* the html device uses `-Tps' to render
+ equations as images */
".tm warning: %s should have been given a `-T\\*(.T' option\n",
device, program_name);
+ printf(".if '\\*(.T'html' "
+ ".if !'%s'ps' "
+ ".tm1 \"warning: %s should have been given a `-Tps' option\n"
+ ".tm1 \" (it is advisable to invoke groff via: groff -Thtml -e)\n",
+ device, program_name);
if (load_startup_file) {
char *path;
FILE *fp = config_macro_path.open_file(STARTUP_FILE, &path);
diff --git a/src/preproc/html2/Makefile.sub b/src/preproc/html2/Makefile.sub
deleted file mode 100755
index 9d5045a9..00000000
--- a/src/preproc/html2/Makefile.sub
+++ /dev/null
@@ -1,7 +0,0 @@
-PROG=pre-grohtml
-# MAN1=pre-grohtml.n
-MAN1=
-XLIBS=$(LIBGROFF)
-OBJS=pre-html.o pushbackbuffer.o
-CCSRCS=$(srcdir)/pre-html.cc $(srcdir)/pushbackbuffer.cc
-NAMEPREFIX=$(g)
diff --git a/src/preproc/html2/image.cc b/src/preproc/html2/image.cc
deleted file mode 100755
index e05ee3dc..00000000
--- a/src/preproc/html2/image.cc
+++ /dev/null
@@ -1,448 +0,0 @@
-// -*- C++ -*-
-/* Copyright (C) 2000 Free Software Foundation, Inc.
- Written by Gaius Mulley (gaius@glam.ac.uk) but owes much
- of the code from James Clark (jjc@jclark.com).
-
-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 <stdio.h>
-#include <signal.h>
-#include <ctype.h>
-#include <string.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <errno.h>
-#include "lib.h"
-#include "errarg.h"
-#include "error.h"
-#include "stringclass.h"
-#include "posix.h"
-
-#include <errno.h>
-#include <sys/types.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef _POSIX_VERSION
-#include <sys/wait.h>
-#define PID_T pid_t
-#else /* not _POSIX_VERSION */
-#define PID_T int
-#endif /* not _POSIX_VERSION */
-
-extern char *strerror();
-
-static char *file_contents;
-static int stdoutfd =1; // output file descriptor - normally 1 but might move
- // -1 means closed
-
-#define DEBUGGING
-
-/*
- * eventually it would be nice to have the choice of image devices.
- * This could be implemented once we have a -Tpng or -Tpdf device driver.
- * For now we use what is available.. postscript, ghostscript + png utils.
- */
-
-#define IMAGEDEVICE "-Tps"
-
-
-static int do_file(const char *filename);
-
-/*
- * sys_fatal - writes a fatal error message. Taken from src/roff/groff/pipeline.c
- */
-
-static void sys_fatal(const char *s)
-{
- fprintf(stderr, "%s: %s: %s", program_name, s, strerror(errno));
-}
-
- sprintf(buffer,
- "echo showpage | gs -q -dSAFER -sDEVICE=%s -r%d -g%dx%d -sOutputFile=- %s - 2> /dev/null > %s.png \n",
- image_device,
- image_res,
- (end_region_hpos-start_region_hpos)*image_res/font::res+IMAGE_BOARDER_PIXELS,
- (end_region_vpos-start_region_vpos)*image_res/font::res+IMAGE_BOARDER_PIXELS,
- ps_src, image_name);
-
-
-/*
- * the class and methods for retaining ascii text
- */
-
-struct char_block {
- enum { SIZE = 256 };
- char buffer[SIZE];
- int used;
- char_block *next;
-
- char_block();
-};
-
-char_block::char_block()
-: used(0), next(0)
-{
-}
-
-class char_buffer {
-public:
- char_buffer();
- ~char_buffer();
- int read_file(FILE *fp);
- int do_html(int argc, char *argv[]);
- int do_image(int argc, char *argv[]);
- int write_file(int is_html);
-private:
- char_block *head;
- char_block *tail;
-};
-
-char_buffer::char_buffer()
-: head(0), tail(0)
-{
-}
-
-char_buffer::~char_buffer()
-{
- while (head != 0) {
- char_block *temp = head;
- head = head->next;
- delete temp;
- }
-}
-
-int char_buffer::read_file (FILE *fp)
-{
- int i=0;
- unsigned int old_used;
- int n;
-
- while (! feof(fp)) {
- if (tail == 0) {
- tail = new char_block;
- head = tail;
- } else {
- if (tail->used == char_block::SIZE) {
- tail->next = new char_block;
- tail = tail->next;
- }
- }
- // at this point we have a tail which is ready for the the next SIZE bytes of the file
-
- n = fread(tail->buffer, sizeof(char), char_block::SIZE-tail->used, fp);
- if (n <= 0) {
- // error
- return( 0 );
- } else {
- tail->used += n*sizeof(char);
- }
- }
- return( 1 );
-}
-
-/*
- * writeNbytes - writes n bytes to stdout.
- */
-
-static void writeNbytes (char *s, int l)
-{
- int n=0;
- int r;
-
- while (n<l) {
- r = write(stdoutfd, s, l-n);
- if (r<0) {
- sys_fatal("write");
- }
- n += r;
- s += r;
- }
-}
-
-/*
- * writeString - writes a string to stdout.
- */
-
-static void writeString (char *s)
-{
- writeNbytes(s, strlen(s));
-}
-
-/*
- * write_file - writes the buffer to stdout (troff).
- * It prepends the number register set to 1 if stdout is
- * connected to troff -Thtml and 0 if connected to troff -Tps
- */
-
-int char_buffer::write_file (int is_html)
-{
- char_block *t=head;
- int r;
-
- fprintf(stderr, "output to pipeline\n");
- if (is_html) {
- writeString(".nr htmlflip 1\n");
- } else {
- writeString(".nr htmlflip 0\n");
- fprintf(stderr, ".nr htmlflip 0\n");
- }
- if (t != 0) {
- do {
- writeNbytes(t->buffer, t->used);
- fprintf(stderr, "hunk..\n");
- t = t->next;
- } while ((t != head) && (t != 0));
- }
- if (close(stdoutfd) < 0)
- sys_fatal("close");
-
- // now we grab fd=1 so that the next pipe cannot use fd=1
- if (stdoutfd == 1) {
- if (dup(2) != stdoutfd) {
- sys_fatal("dup failed to use fd=1");
- }
- }
-
- return( 1 );
-}
-
-/*
- * replaceFd - replace a file descriptor, was, with, willbe.
- */
-
-static void replaceFd (int was, int willbe)
-{
- int dupres;
-
- if (was != willbe) {
- if (close(was)<0) {
- sys_fatal("close");
- }
- dupres = dup(willbe);
- if (dupres != was) {
- sys_fatal("dup");
- fprintf(stderr, "trying to replace fd=%d with %d dup used %d\n", was, willbe, dupres);
- if (willbe == 1) {
- fprintf(stderr, "likely that stdout should be opened before %d\n", was);
- }
- exit(1);
- }
- if (close(willbe) < 0) {
- sys_fatal("close");
- }
- }
-}
-
-/*
- * waitForChild - waits for child, pid, to exit.
- */
-
-static void waitForChild (PID_T pid)
-{
- PID_T waitpd;
- int status;
-
- waitpd = wait(&status);
- if (waitpd != pid)
- sys_fatal("wait");
-}
-
-/*
- * do_html - sets the troff number htmlflip and
- * writes out the buffer to troff -Thtml
- */
-
-int char_buffer::do_html(int argc, char *argv[])
-{
- int pdes[2];
- PID_T pid;
-
- if (pipe(pdes) < 0)
- sys_fatal("pipe");
-
- argv++; // skip pre-grohtml argv[0]
- pid = fork();
- if (pid < 0)
- sys_fatal("fork");
-
- if (pid == 0) {
- // child
- replaceFd(0, pdes[0]);
- // close end we are not using
- if (close(pdes[1])<0)
- sys_fatal("close");
-
- execvp(argv[0], argv);
- error("couldn't exec %1: %2", argv[0], strerror(errno), (char *)0);
- fflush(stderr); /* just in case error() doesn't */
- exit(1);
- } else {
- // parent
-
- replaceFd(1, pdes[1]);
- // close end we are not using
- if (close(pdes[0])<0)
- sys_fatal("close");
-
- write_file(1);
- waitForChild(pid);
- }
- return( 0 );
-}
-
-/*
- * alterToDeviceImage - manipulates the argv to include IMAGEDEVICE rather than -Thtml2
- */
-
-static void alterToDeviceImage (int argc, char *argv[])
-{
- int i=0;
-
- while (i < argc) {
- if (strcmp(argv[i], "-Thtml2") == 0) {
- argv[i] = IMAGEDEVICE;
- }
- i++;
- }
- argv[1] = "groff"; /* rather than troff */
-}
-
-/*
- * do_image - sets the troff number htmlflip and
- * writes out the buffer to troff -Tps
- */
-
-int char_buffer::do_image(int argc, char *argv[])
-{
- PID_T pid;
- int pdes[2];
-
- if (pipe(pdes) < 0)
- sys_fatal("pipe");
-
- alterToDeviceImage(argc, argv);
- argv++; // skip pre-grohtml argv[0]
-
- pid = fork();
- if (pid == 0) {
- // child
-
-#if defined(DEBUGGING)
- int psFd = creat("/tmp/prehtml-ps", S_IWUSR|S_IRUSR);
- int regionFd = creat("/tmp/prehtml-region", S_IWUSR|S_IRUSR);
-#else
- int psFd = mkstemp(xtmptemplate("-ps-"));
- int regionFd = mkstemp(xtmptemplate("-regions-"));
-#endif
-
- fprintf(stderr, "about to exec %s\n", argv[0]);
- replaceFd(1, psFd);
- replaceFd(0, pdes[0]);
- replaceFd(2, regionFd);
-
- // close end we are not using
- if (close(pdes[1])<0)
- sys_fatal("close");
-
- execvp(argv[0], argv);
- error("couldn't exec %1: %2", argv[0], strerror(errno), (char *)0);
- fflush(stderr); /* just in case error() doesn't */
- exit(1);
- } else {
- // parent
-
- replaceFd(1, pdes[1]);
- write_file(0);
- waitForChild(pid);
- }
- return( 0 );
-}
-
-static char_buffer inputFile;
-
-
-/*
- * usage - emit usage arguments and exit.
- */
-
-void usage()
-{
- fprintf(stderr, "usage: %s troffname [ troff flags ] [ files ]\n", program_name);
- exit(1);
-}
-
-int main(int argc, char **argv)
-{
- program_name = argv[0];
- int i; // skip over troff name
- int found=0;
- int ok=1;
-
- for (i = 2; i < argc; i++) {
- if (argv[i][0] == '-') {
- if (argv[i][1] == 'v') {
- extern const char *Version_string;
- fprintf(stderr, "GNU pre-grohtml version %s\n", Version_string);
- fflush(stderr);
- }
- } else {
- ok = do_file(argv[i]);
- if (! ok) {
- return( 0 );
- }
- found = 1;
- }
- }
-
- if (! found) {
- do_file("-");
- }
- ok = inputFile.do_html(argc, argv);
- if (ok == 0) {
- ok = inputFile.do_image(argc, argv);
- if (ok == 0) {
- // generateImages();
- }
- }
- return ok;
-}
-
-static int do_file(const char *filename)
-{
- FILE *fp;
-
- current_filename = filename;
- if (strcmp(filename, "-") == 0) {
- fp = stdin;
- } else {
- fp = fopen(filename, "r");
- if (fp == 0) {
- error("can't open `%1': %2", filename, strerror(errno));
- return 0;
- }
- }
-
- if (inputFile.read_file(fp)) {
- }
-
- if (fp != stdin)
- fclose(fp);
- current_filename = 0;
- return 1;
-}
diff --git a/src/preproc/html2/pre-html.cc b/src/preproc/html2/pre-html.cc
deleted file mode 100755
index b282a8b7..00000000
--- a/src/preproc/html2/pre-html.cc
+++ /dev/null
@@ -1,773 +0,0 @@
-// -*- C++ -*-
-/* Copyright (C) 2000 Free Software Foundation, Inc.
- Written by Gaius Mulley (gaius@glam.ac.uk).
-
-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. */
-
-#define PREHTMLC
-
-#include <stdio.h>
-#include <signal.h>
-#include <ctype.h>
-#include <string.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <errno.h>
-#include "lib.h"
-#include "errarg.h"
-#include "error.h"
-#include "stringclass.h"
-#include "posix.h"
-
-#include <errno.h>
-#include <sys/types.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef _POSIX_VERSION
-#include <sys/wait.h>
-#define PID_T pid_t
-#else /* not _POSIX_VERSION */
-#define PID_T int
-#endif /* not _POSIX_VERSION */
-
-extern char *strerror();
-
-#include "pre-html.h"
-#include "pushbackbuffer.h"
-
-#define POSTSCRIPTRES 72000 // maybe there is a better way to find this? --fixme--
-#define DEFAULT_IMAGE_RES 80
-#define IMAGE_BOARDER_PIXELS 10
-
-// #define TRANSPARENT "-background \"#FFF\" -transparent \"#FFF\""
-#define TRANSPARENT ""
-
-#define DEBUGGING
-
-#if !defined(TRUE)
-# define TRUE (1==1)
-#endif
-#if !defined(FALSE)
-# define FALSE (1==0)
-#endif
-
-void stop() {}
-
-
-static int stdoutfd =1; // output file descriptor - normally 1 but might move
- // -1 means closed
-static char *psFileName =0; // name of postscript file
-static char *regionFileName=0; // name of file containing all image regions
-static char *image_device = "pnmraw";
-static int image_res = DEFAULT_IMAGE_RES;
-
-
-/*
- * Images are generated via postscript, gs and the pnm utilities.
- */
-
-#define IMAGEDEVICE "-Tps"
-
-
-static int do_file(const char *filename);
-
-/*
- * sys_fatal - writes a fatal error message. Taken from src/roff/groff/pipeline.c
- */
-
-void sys_fatal (const char *s)
-{
- fprintf(stderr, "%s: %s: %s", program_name, s, strerror(errno));
-}
-
-/*
- * the class and methods for retaining ascii text
- */
-
-struct char_block {
- enum { SIZE = 256 };
- char buffer[SIZE];
- int used;
- char_block *next;
-
- char_block();
-};
-
-char_block::char_block()
-: used(0), next(0)
-{
-}
-
-class char_buffer {
-public:
- char_buffer();
- ~char_buffer();
- int read_file(FILE *fp);
- int do_html(int argc, char *argv[]);
- int do_image(int argc, char *argv[]);
- void write_file_html(void);
- void write_file_troff(void);
- void write_upto_newline (char_block **t, int *i);
- int can_see(char_block **t, int *i, char *string);
-private:
- char_block *head;
- char_block *tail;
-};
-
-char_buffer::char_buffer()
-: head(0), tail(0)
-{
-}
-
-char_buffer::~char_buffer()
-{
- while (head != 0) {
- char_block *temp = head;
- head = head->next;
- delete temp;
- }
-}
-
-int char_buffer::read_file (FILE *fp)
-{
- int i=0;
- unsigned int old_used;
- int n;
-
- while (! feof(fp)) {
- if (tail == 0) {
- tail = new char_block;
- head = tail;
- } else {
- if (tail->used == char_block::SIZE) {
- tail->next = new char_block;
- tail = tail->next;
- }
- }
- // at this point we have a tail which is ready for the next SIZE bytes of the file
-
- n = fread(tail->buffer, sizeof(char), char_block::SIZE-tail->used, fp);
- if (n <= 0) {
- // error
- return( 0 );
- } else {
- tail->used += n*sizeof(char);
- }
- }
- return( 1 );
-}
-
-/*
- * writeNbytes - writes n bytes to stdout.
- */
-
-static void writeNbytes (char *s, int l)
-{
- int n=0;
- int r;
-
- while (n<l) {
- r = write(stdoutfd, s, l-n);
- if (r<0) {
- sys_fatal("write");
- }
- n += r;
- s += r;
- }
-}
-
-/*
- * writeString - writes a string to stdout.
- */
-
-static void writeString (char *s)
-{
- writeNbytes(s, strlen(s));
-}
-
-/*
- * write_upto_newline - writes the contents of the buffer until a newline is seen.
- */
-
-void char_buffer::write_upto_newline (char_block **t, int *i)
-{
- int j=*i;
-
- if (*t) {
- while ((j < (*t)->used) && ((*t)->buffer[j] != '\n')) {
- j++;
- }
- if ((j < (*t)->used) && ((*t)->buffer[j] == '\n')) {
- j++;
- }
- writeNbytes((*t)->buffer+(*i), j-(*i));
- if (j == (*t)->used) {
- *i = 0;
- *t = (*t)->next;
- write_upto_newline(t, i);
- } else {
- // newline was seen
- *i = j;
- }
- }
-}
-
-/*
- * can_see - returns TRUE if we can see string in t->buffer[i] onwards
- */
-
-int char_buffer::can_see(char_block **t, int *i, char *string)
-{
- int j = 0;
- int l = strlen(string);
- int k = *i;
- char_block *s = *t;
-
- while (s) {
- while ((k<s->used) && (j<l) && (s->buffer[k] == string[j])) {
- j++;
- k++;
- }
- if (j == l) {
- *i = k;
- *t = s;
- return( TRUE );
- } else if ((k<s->used) && (s->buffer[k] != string[j])) {
- return( FALSE );
- }
- s = s->next;
- k = 0;
- }
- return( FALSE );
-}
-
-/*
- * write_file_troff - writes the buffer to stdout (troff).
- * It prepends the number register set to 0.
- */
-
-void char_buffer::write_file_troff (void)
-{
- char_block *t=head;
- int r;
-
- writeString(".nr html2enable 0\n");
- writeString(".nr htmlflip 0\n");
- if (t != 0) {
- do {
- writeNbytes(t->buffer, t->used);
- t = t->next;
- } while ((t != head) && (t != 0));
- }
- if (close(stdoutfd) < 0)
- sys_fatal("close");
-
- // now we grab fd=1 so that the next pipe cannot use fd=1
- if (stdoutfd == 1) {
- if (dup(2) != stdoutfd) {
- sys_fatal("dup failed to use fd=1");
- }
- }
-}
-
-/*
- * the image class remembers the position of all images in the postscript file
- * and assigns names for each image.
- */
-
-struct imageItem {
- imageItem *next;
- int X1;
- int Y1;
- int X2;
- int Y2;
- char *imageName;
- int resolution;
- int pageNo;
-
- imageItem (int x1, int y1, int x2, int y2, int page, int res, char *name);
- ~imageItem ();
-};
-
-/*
- * imageItem - constructor
- */
-
-imageItem::imageItem (int x1, int y1, int x2, int y2, int page, int res, char *name)
-{
- X1 = x1;
- Y1 = y1;
- X2 = x2;
- Y2 = y2;
- pageNo = page;
- resolution = res;
- imageName = name;
- next = 0;
-}
-
-/*
- * imageItem - deconstructor
- */
-
-imageItem::~imageItem ()
-{
-}
-
-/*
- * imageList - class containing a list of imageItems.
- */
-
-class imageList {
-private:
- imageItem *head;
- imageItem *tail;
- int count;
-public:
- imageList();
- ~imageList();
- void add(int x1, int y1, int x2, int y2, int page, int res);
- char *get(int i);
-};
-
-/*
- * imageList - constructor.
- */
-
-imageList::imageList ()
- : head(0), tail(0), count(0)
-{
-}
-
-/*
- * imageList - deconstructor.
- */
-
-imageList::~imageList ()
-{
- while (head != 0) {
- imageItem *i = head;
- head = head->next;
- delete i;
- }
-}
-
-/*
- * createImage - generates a png file from the information held in, i, and
- * the postscript file.
- */
-
-static void createImage (imageItem *i)
-{
- if (i->X1 != -1) {
- char buffer[4096];
-
- sprintf(buffer,
- "echo showpage | gs -q -dFirstPage=%d -dLastPage=%d -dSAFER -sDEVICE=%s -r%d -sOutputFile=- %s - 2> /dev/null | pnmcut %d %d %d %d | pnmtopng %s > %s.png \n",
- i->pageNo, i->pageNo,
- image_device,
- image_res,
- psFileName,
- i->X1*image_res/POSTSCRIPTRES-IMAGE_BOARDER_PIXELS,
- i->Y1*image_res/POSTSCRIPTRES-IMAGE_BOARDER_PIXELS,
- (i->X2-i->X1)*image_res/POSTSCRIPTRES+2*IMAGE_BOARDER_PIXELS,
- (i->Y2-i->Y1)*image_res/POSTSCRIPTRES+2*IMAGE_BOARDER_PIXELS,
- TRANSPARENT,
- i->imageName);
- // fprintf(stderr, buffer);
- system(buffer);
- } else {
- fprintf(stderr, "ignoring image as x1 coord is -1\n");
- fflush(stderr);
- }
-}
-
-/*
- * add - an image description to the imageList.
- */
-
-void imageList::add (int x1, int y1, int x2, int y2, int page, int res)
-{
- char *name = (char *)malloc(50);
-
- if (name == 0)
- sys_fatal("malloc");
-
- if (x1 == -1) {
- name[0] = (char)0;
- } else {
- count++;
- sprintf(name, "grohtml-%d", count);
- }
- imageItem *i = new imageItem(x1, y1, x2, y2, page, res, name);
-
- if (head == 0) {
- head = i;
- tail = i;
- } else {
- tail->next = i;
- tail = i;
- }
- createImage(i);
-}
-
-/*
- * get - returns the name for image number, i.
- */
-
-char *imageList::get(int i)
-{
- imageItem *t=head;
-
- while (i>0) {
- if (i == 1) {
- if (t->X1 == -1) {
- return( NULL );
- } else {
- return( t->imageName );
- }
- }
- t = t->next;
- i--;
- }
-}
-
-static imageList listOfImages; // list of images defined by the region file.
-
-/*
- * write_file_html - writes the buffer to stdout (troff).
- * It prepends the number register set to 1 and writes
- * out the file replacing template image names with
- * actual image names.
- */
-
-void char_buffer::write_file_html (void)
-{
- char_block *t =head;
- int imageNo=0;
- char *name;
- int i=0;
-
- writeString(".nr html2enable 1\n");
- writeString(".nr htmlflip 1\n");
- if (t != 0) {
- stop();
- do {
- if (can_see(&t, &i, ".if '\\*(.T'html2' .IMAGE <pre-html-image>\n")) {
- imageNo++;
- name = listOfImages.get(imageNo);
- if (name != 0) {
- writeString(".if '\\*(.T'html2' .IMAGE \"");
- writeString(name);
- writeString(".png\"\n");
- }
- } else {
- write_upto_newline(&t, &i);
- }
- } while (t != 0);
- }
- if (close(stdoutfd) < 0)
- sys_fatal("close");
-
- // now we grab fd=1 so that the next pipe cannot use fd=1
- if (stdoutfd == 1) {
- if (dup(2) != stdoutfd) {
- sys_fatal("dup failed to use fd=1");
- }
- }
-}
-
-/*
- * generateImages - parses the region file and generates images
- * from the postscript file. The region file
- * contains the x1,y1 x2,y2 extents of each
- * image.
- */
-
-static void generateImages (char *regionFileName)
-{
- pushBackBuffer *f=new pushBackBuffer(regionFileName);
- char ch;
-
- if (f->putPB('\n') == '\n') {
- }
- while (f->putPB(f->getPB()) != eof) {
- if (f->isString("\ngrohtml-info:page")) {
- int page= f->readInt();
- int x1 = f->readInt();
- int y1 = f->readInt();
- int x2 = f->readInt();
- int y2 = f->readInt();
- int res = POSTSCRIPTRES; // --fixme-- prefer (f->readInt()) providing that troff can discover the value
- listOfImages.add(x1, y1, x2, y2, page, res);
- }
- ch = f->getPB();
- }
-}
-
-/*
- * replaceFd - replace a file descriptor, was, with, willbe.
- */
-
-static void replaceFd (int was, int willbe)
-{
- int dupres;
-
- if (was != willbe) {
- if (close(was)<0) {
- sys_fatal("close");
- }
- dupres = dup(willbe);
- if (dupres != was) {
- sys_fatal("dup");
- fprintf(stderr, "trying to replace fd=%d with %d dup used %d\n", was, willbe, dupres);
- if (willbe == 1) {
- fprintf(stderr, "likely that stdout should be opened before %d\n", was);
- }
- exit(1);
- }
- if (close(willbe) < 0) {
- sys_fatal("close");
- }
- }
-}
-
-/*
- * waitForChild - waits for child, pid, to exit.
- */
-
-static void waitForChild (PID_T pid)
-{
- PID_T waitpd;
- int status;
-
- waitpd = wait(&status);
- if (waitpd != pid)
- sys_fatal("wait");
-}
-
-/*
- * alterDeviceTo - if toImage is set then the arg list is altered to include
- * IMAGEDEVICE and we invoke groff rather than troff.
- * else
- * set -Thtml2 and troff
- */
-
-static void alterDeviceTo (int argc, char *argv[], int toImage)
-{
- int i=0;
-
- if (toImage) {
- while (i < argc) {
- if (strcmp(argv[i], "-Thtml2") == 0) {
- argv[i] = IMAGEDEVICE;
- }
- i++;
- }
- argv[1] = "groff"; /* rather than troff */
- } else {
- while (i < argc) {
- if (strcmp(argv[i], IMAGEDEVICE) == 0) {
- argv[i] = "-Thtml2";
- }
- i++;
- }
- argv[1] = "troff"; /* use troff */
- }
-}
-
-/*
- * do_html - sets the troff number htmlflip and
- * writes out the buffer to troff -Thtml
- */
-
-int char_buffer::do_html(int argc, char *argv[])
-{
- int pdes[2];
- PID_T pid;
-
- if (pipe(pdes) < 0)
- sys_fatal("pipe");
-
- alterDeviceTo(argc, argv, 0);
- argv++; // skip pre-grohtml argv[0]
- pid = fork();
- if (pid < 0)
- sys_fatal("fork");
-
- if (pid == 0) {
- // child
- replaceFd(0, pdes[0]);
- // close end we are not using
- if (close(pdes[1])<0)
- sys_fatal("close");
-
- execvp(argv[0], argv);
- error("couldn't exec %1: %2", argv[0], strerror(errno), (char *)0);
- fflush(stderr); /* just in case error() doesn't */
- exit(1);
- } else {
- // parent
-
- replaceFd(1, pdes[1]);
- // close end we are not using
- if (close(pdes[0])<0)
- sys_fatal("close");
-
- write_file_html();
- waitForChild(pid);
- }
- return( 0 );
-}
-
-/*
- * do_image - sets the troff number htmlflip and
- * writes out the buffer to troff -Tps
- */
-
-int char_buffer::do_image(int argc, char *argv[])
-{
- PID_T pid;
- int pdes[2];
-
- if (pipe(pdes) < 0)
- sys_fatal("pipe");
-
- alterDeviceTo(argc, argv, 1);
- argv++; // skip pre-grohtml argv[0]
-
- pid = fork();
- if (pid == 0) {
- // child
-
-#if defined(DEBUGGING)
- int psFd = creat(psFileName, S_IWUSR|S_IRUSR);
- int regionFd = creat(regionFileName, S_IWUSR|S_IRUSR);
-#else
- int psFd = mkstemp(psFileName);
- int regionFd = mkstemp(regionFileName);
-#endif
-
- replaceFd(1, psFd);
- replaceFd(0, pdes[0]);
- replaceFd(2, regionFd);
-
- // close end we are not using
- if (close(pdes[1])<0)
- sys_fatal("close");
-
- execvp(argv[0], argv);
- error("couldn't exec %1: %2", argv[0], strerror(errno), (char *)0);
- fflush(stderr); /* just in case error() doesn't */
- exit(1);
- } else {
- // parent
-
- replaceFd(1, pdes[1]);
- write_file_troff();
- waitForChild(pid);
- }
- return( 0 );
-}
-
-static char_buffer inputFile;
-
-
-/*
- * usage - emit usage arguments and exit.
- */
-
-void usage()
-{
- fprintf(stderr, "usage: %s troffname [ troff flags ] [ files ]\n", program_name);
- exit(1);
-}
-
-/*
- * makeTempFiles - name the temporary files
- */
-
-static void makeTempFiles (void)
-{
-#if defined(DEBUGGING)
- psFileName = "/tmp/prehtml-ps";
- regionFileName = "/tmp/prehtml-region";
-#else
- psFileName = xtmptemplate("-ps-");
- regionFileName = xtmptemplate("-regions-");
-#endif
-}
-
-int main(int argc, char **argv)
-{
- program_name = argv[0];
- int i; // skip over troff name
- int found=0;
- int ok=1;
-
- for (i = 2; i < argc; i++) {
- if (argv[i][0] == '-') {
- if (argv[i][1] == 'v') {
- extern const char *Version_string;
- printf("GNU pre-grohtml (groff) version %s\n", Version_string);
- exit(0);
- }
- } else {
- ok = do_file(argv[i]);
- if (! ok) {
- return( 0 );
- }
- found = 1;
- }
- }
-
- if (! found) {
- do_file("-");
- }
- makeTempFiles();
- ok = inputFile.do_image(argc, argv);
- if (ok == 0) {
- generateImages(regionFileName);
- ok = inputFile.do_html(argc, argv);
- }
- return ok;
-}
-
-static int do_file(const char *filename)
-{
- FILE *fp;
-
- current_filename = filename;
- if (strcmp(filename, "-") == 0) {
- fp = stdin;
- } else {
- fp = fopen(filename, "r");
- if (fp == 0) {
- error("can't open `%1': %2", filename, strerror(errno));
- return 0;
- }
- }
-
- if (inputFile.read_file(fp)) {
- }
-
- if (fp != stdin)
- fclose(fp);
- current_filename = 0;
- return 1;
-}
diff --git a/src/preproc/html2/pushbackbuffer.cc b/src/preproc/html2/pushbackbuffer.cc
deleted file mode 100755
index edd31c97..00000000
--- a/src/preproc/html2/pushbackbuffer.cc
+++ /dev/null
@@ -1,308 +0,0 @@
-// -*- C++ -*-
-/* Copyright (C) 2000 Free Software Foundation, Inc.
- Written by Gaius Mulley (gaius@glam.ac.uk).
-
-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 <stdio.h>
-#include <signal.h>
-#include <ctype.h>
-#include <string.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <errno.h>
-#include "lib.h"
-#include "errarg.h"
-#include "error.h"
-#include "stringclass.h"
-#include "posix.h"
-
-#include <errno.h>
-#include <sys/types.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "pushbackbuffer.h"
-#include "pre-html.h"
-
-#if !defined(TRUE)
-# define TRUE (1==1)
-#endif
-
-#if !defined(FALSE)
-# define FALSE (1==0)
-#endif
-
-# define ERROR(X) (fprintf(stderr, "%s:%d error %s\n", __FILE__, __LINE__, X) && \
- (fflush(stderr)) && localexit(1))
-
-
-#define MAXPUSHBACKSTACK 4096 /* maximum number of character that can be pushed back */
-
-
-/*
- * constructor for pushBackBuffer
- */
-
-pushBackBuffer::pushBackBuffer (char *filename)
-{
- charStack = (char *)malloc(MAXPUSHBACKSTACK);
- if (charStack == 0) {
- sys_fatal("malloc");
- }
- stackPtr = 0; /* index to push back stack */
- debug = 0;
- verbose = 0;
- eofFound = FALSE;
- lineNo = 1;
- if (strcmp(filename, "") != 0) {
- stdIn = dup(0);
- close(0);
- if (open(filename, O_RDONLY) != 0) {
- sys_fatal("when tring to read graph file");
- } else {
- fileName = filename;
- }
- }
-}
-
-pushBackBuffer::~pushBackBuffer ()
-{
- int old;
-
- if (charStack != 0) {
- free(charStack);
- }
- close(0);
- /* restore stdin in file descriptor 0 */
- old = dup(stdIn);
- close(stdIn);
-}
-
-/*
- * localexit - wraps exit with a return code to aid the ERROR macro.
- */
-
-int localexit (int i)
-{
- exit(i);
- return( 1 );
-}
-
-/*
- * getPB - returns a character, possibly a pushed back character.
- */
-
-char pushBackBuffer::getPB (void)
-{
- if (stackPtr>0) {
- stackPtr--;
- return( charStack[stackPtr] );
- } else {
- char ch;
-
- if (read(0, &ch, 1) == 1) {
- if (verbose) {
- printf("%c", ch);
- }
- if (ch == '\n') {
- lineNo++;
- }
- return( ch );
- } else {
- eofFound = TRUE;
- return( eof );
- }
- }
-}
-
-/*
- * putPB - pushes a character onto the push back stack.
- * The same character is returned.
- */
-
-char pushBackBuffer::putPB (char ch)
-{
- if (stackPtr<MAXPUSHBACKSTACK) {
- charStack[stackPtr] = ch ;
- stackPtr++;
- } else {
- ERROR("max push back stack exceeded, increase MAXPUSHBACKSTACK constant");
- }
- return( ch );
-}
-
-/*
- * isWhite - returns TRUE if a white character is found. This character is NOT consumed.
- */
-
-static int isWhite (char ch)
-{
- return( (ch==' ') || (ch == '\t') || (ch == '\n') );
-}
-
-/*
- * skipToNewline - skips characters until a newline is seen.
- */
-
-void pushBackBuffer::skipToNewline (void)
-{
- char ch;
-
- while ((putPB(getPB()) != '\n') && (! eofFound)) {
- ch = getPB();
- }
-}
-
-/*
- * skipUntilToken - skips until a token is seen
- */
-
-void pushBackBuffer::skipUntilToken (void)
-{
- char ch;
-
- while ((isWhite(putPB(getPB())) || (putPB(getPB()) == '#')) && (! eofFound)) {
- ch = getPB();
- if (ch == '#') {
- skipToNewline();
- }
- }
-}
-
-/*
- * isString - returns TRUE if the string, s, matches the pushed back string.
- * if TRUE is returned then this string is consumed, otherwise it is
- * left alone.
- */
-
-int pushBackBuffer::isString (char *s)
-{
- int length=strlen(s);
- int i=0;
- int j;
-
- while ((i<length) && (putPB(getPB())==s[i])) {
- if (getPB() != s[i]) {
- ERROR("assert failed");
- }
- i++;
- }
- if (i==length) {
- return( TRUE );
- } else {
- i--;
- while (i>=0) {
- if (putPB(s[i]) != s[i]) {
- ERROR("assert failed");
- }
- i--;
- }
- }
- return( FALSE );
-}
-
-/*
- * isDigit - returns TRUE if the character, ch, is a digit.
- */
-
-static int isDigit (char ch)
-{
- return( ((ch>='0') && (ch<='9')) );
-}
-
-/*
- * isHexDigit - returns TRUE if the character, ch, is a hex digit.
- */
-
-static int isHexDigit (char ch)
-{
- return( (isDigit(ch)) || ((ch>='a') && (ch<='f')) );
-}
-
-/*
- * readInt - returns an integer from the input stream.
- */
-
-int pushBackBuffer::readInt (void)
-{
- int c =0;
- int i =0;
- int s =1;
- char ch=getPB();
-
- while (isWhite(ch)) {
- ch=getPB();
- }
- // now read integer
-
- if (ch == '-') {
- s = -1;
- ch = getPB();
- }
- while (isDigit(ch)) {
- i *= 10;
- if ((ch>='0') && (ch<='9')) {
- i += (int)(ch-'0');
- }
- ch = getPB();
- c++;
- }
- if (ch != putPB(ch)) {
- ERROR("assert failed");
- }
- return( i*s );
-}
-
-/*
- * convertToFloat - converts integers, a and b into a.b
- */
-
-static float convertToFloat (int a, int b)
-{
- int c=10;
- float f;
-
- while (b>c) {
- c *= 10;
- }
- f = ((float)a) + (((float)b)/((float)c));
- return( f );
-}
-
-/*
- * readNumber - returns a float representing the word just read.
- */
-
-float pushBackBuffer::readNumber (void)
-{
- int integer;
- int fraction;
- char ch;
- float f;
-
- integer = readInt();
- if (putPB(getPB()) == '.') {
- ch = getPB();
- fraction = readInt();
- f = convertToFloat(integer, fraction);
- return( f );
- } else {
- return( (float)integer );
- }
-}
diff --git a/src/preproc/html2/pushbackbuffer.h b/src/preproc/html2/pushbackbuffer.h
deleted file mode 100755
index 8c3ff9b7..00000000
--- a/src/preproc/html2/pushbackbuffer.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// -*- C -*-
-/* Copyright (C) 2000 Free Software Foundation, Inc.
- Written by Gaius Mulley (gaius@glam.ac.uk).
-
-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. */
-
-
-#define eof (char)-1
-
-
-/*
- * defines the class and methods implemented within pbbuffer.cc
- */
-
-class pushBackBuffer
-{
- private:
- char *charStack;
- int stackPtr; /* index to push back stack */
- int debug;
- int verbose;
- int eofFound;
- char *fileName;
- int lineNo;
- int stdIn;
-
- public:
- pushBackBuffer (char *);
- ~ pushBackBuffer ();
- char getPB (void);
- char putPB (char ch);
- void skipUntilToken (void);
- void skipToNewline (void);
- float readNumber (void);
- int readInt (void);
- int isString (char *string);
-};
-
-
diff --git a/src/preproc/pic/troff.cc b/src/preproc/pic/troff.cc
index 2f0496bf..62fe540a 100644
--- a/src/preproc/pic/troff.cc
+++ b/src/preproc/pic/troff.cc
@@ -1,5 +1,6 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+ Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -268,12 +269,12 @@ void troff_output::start_picture(double sc,
scale = compute_scale(sc, ll, ur);
height = (ur.y - ll.y)/scale;
double width = (ur.x - ll.x)/scale;
+ graphic_start(0);
printf(".PS %.3fi %.3fi", height, width);
if (args)
printf(" %s\n", args);
else
putchar('\n');
- graphic_start();
printf(".\\\" %g %g %g %g\n", ll.x, ll.y, ur.x, ur.y);
printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height, width, 0.0);
printf(".nr " FILL_REG " \\n(.u\n.nf\n");
@@ -292,10 +293,10 @@ void troff_output::finish_picture()
printf(".if \\n(" FILL_REG " .fi\n");
printf(".br\n");
printf(".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
- graphic_end();
// this is a little gross
set_location(current_filename, current_lineno);
fputs(flyback_flag ? ".PF\n" : ".PE\n", stdout);
+ graphic_end();
}
void troff_output::command(const char *s,
diff --git a/src/preproc/tbl/main.cc b/src/preproc/tbl/main.cc
index 53ce7577..d13f026c 100644
--- a/src/preproc/tbl/main.cc
+++ b/src/preproc/tbl/main.cc
@@ -1,5 +1,6 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+ Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -218,6 +219,8 @@ void process_input_file(FILE *fp)
break;
case HAD_TS:
if (c == ' ' || c == '\n' || compatible_flag) {
+ printf(".if '\\*(.T'html' \\X(table-start(\n");
+ html_begin_suppress(0);
putchar('.');
putchar('T');
putchar('S');
@@ -230,25 +233,25 @@ void process_input_file(FILE *fp)
c = getc(fp);
}
putchar('\n');
- printf(".if '\\*(.T'html' \\X(table-start(\n");
- html_begin_suppress();
current_lineno++;
{
table_input input(fp);
process_table(input);
set_troff_location(current_filename, current_lineno);
if (input.ended()) {
- printf(".if '\\*(.T'html' \\X(table-end(\n");
- html_end_suppress();
fputs(".TE", stdout);
while ((c = getc(fp)) != '\n') {
if (c == EOF) {
+ printf(".if '\\*(.T'html' \\X(table-end(\n");
+ html_end_suppress();
putchar('\n');
return;
}
putchar(c);
}
putchar('\n');
+ printf(".if '\\*(.T'html' \\X(table-end(\n");
+ html_end_suppress();
current_lineno++;
}
}
diff --git a/src/roff/groff/groff.cc b/src/roff/groff/groff.cc
index 0dd67b68..ff0b9d67 100644
--- a/src/roff/groff/groff.cc
+++ b/src/roff/groff/groff.cc
@@ -1,5 +1,5 @@
// -*- C++ -*-
-/* Copyright (C) 1989-2000 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2000, 2001 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -208,7 +208,7 @@ int main(int argc, char **argv)
safer_flag = 0;
break;
case 'T':
- if (strcmp(optarg, "html2") == 0) {
+ if (strcmp(optarg, "html") == 0) {
// force soelim to aid the html preprocessor
commands[SOELIM_INDEX].set_name(command_prefix, "soelim");
}
@@ -275,6 +275,13 @@ int main(int argc, char **argv)
if (predriver) {
commands[TROFF_INDEX].insert_arg(commands[TROFF_INDEX].get_name());
+ const char *p = Pargs.contents();
+ const char *end = p + Pargs.length();
+ while (p < end) {
+ // pass the device arguments to the predrivers as well
+ commands[TROFF_INDEX].insert_arg(p);
+ p = strchr(p, '\0') + 1;
+ }
commands[TROFF_INDEX].set_name(predriver);
}
@@ -332,7 +339,12 @@ int main(int argc, char **argv)
commands[SPOOL_INDEX].set_name(0);
}
commands[TROFF_INDEX].append_arg("-T", device);
- commands[EQN_INDEX].append_arg("-T", device);
+ // html renders equations as images via ps
+ if (strcmp(device, "html") == 0)
+ commands[EQN_INDEX].append_arg("-Tps");
+ else
+ commands[EQN_INDEX].append_arg("-T", device);
+
commands[GRN_INDEX].append_arg("-T", device);
int first_index;
diff --git a/src/roff/troff/div.cc b/src/roff/troff/div.cc
index 6de99c45..46661941 100644
--- a/src/roff/troff/div.cc
+++ b/src/roff/troff/div.cc
@@ -753,6 +753,7 @@ void space_request()
else
// The line might have had line spacing that was truncated.
truncated_space += n;
+ curenv->add_html_tag(".sp", n.to_units());
tok.next();
}
@@ -819,6 +820,7 @@ void flush_output()
curenv->do_break();
if (the_output)
the_output->flush();
+ curenv->add_html_tag(".fl");
tok.next();
}
diff --git a/src/roff/troff/env.cc b/src/roff/troff/env.cc
index 6ae7f22a..eee3f108 100644
--- a/src/roff/troff/env.cc
+++ b/src/roff/troff/env.cc
@@ -577,6 +577,8 @@ environment::environment(symbol nm)
#ifdef WIDOW_CONTROL
widow_control(0),
#endif /* WIDOW_CONTROL */
+ need_eol(0),
+ ignore_next_eol(0),
name(nm),
control_char('.'),
no_break_control_char('\''),
@@ -658,6 +660,8 @@ environment::environment(const environment *e)
#ifdef WIDOW_CONTROL
widow_control(e->widow_control),
#endif /* WIDOW_CONTROL */
+ need_eol(0),
+ ignore_next_eol(0),
name(e->name), // so that eg `.if "\n[.ev]"0"' works
control_char(e->control_char),
no_break_control_char(e->no_break_control_char),
@@ -1079,6 +1083,7 @@ void point_size()
if (n <= 0)
n = 1;
curenv->set_size(n);
+ curenv->add_html_tag(".ps", n);
}
else
curenv->set_size(0);
@@ -1105,6 +1110,7 @@ void fill()
if (break_flag)
curenv->do_break();
curenv->fill = 1;
+ curenv->add_html_tag(".fi");
tok.next();
}
@@ -1112,9 +1118,14 @@ void no_fill()
{
while (!tok.newline() && !tok.eof())
tok.next();
- if (break_flag)
+ if (break_flag) {
curenv->do_break();
+ curenv->add_html_tag(".br");
+ }
curenv->fill = 0;
+ curenv->add_html_tag(".nf");
+ curenv->ignore_next_eol = 1;
+ curenv->add_html_tag(".po", topdiv->get_page_offset().to_units());
tok.next();
}
@@ -1131,6 +1142,7 @@ void center()
curenv->do_break();
curenv->right_justify_lines = 0;
curenv->center_lines = n;
+ curenv->add_html_tag(".ce", n);
tok.next();
}
@@ -1147,6 +1159,7 @@ void right_justify()
curenv->do_break();
curenv->center_lines = 0;
curenv->right_justify_lines = n;
+ curenv->add_html_tag(".rj", n);
tok.next();
}
@@ -1163,6 +1176,7 @@ void line_length()
temp = curenv->prev_line_length;
curenv->prev_line_length = curenv->line_length;
curenv->line_length = temp;
+ curenv->add_html_tag(".ll", temp.to_units());
skip_line();
}
@@ -1249,6 +1263,7 @@ void indent()
curenv->have_temporary_indent = 0;
curenv->prev_indent = curenv->indent;
curenv->indent = temp;
+ curenv->add_html_tag(".in", temp.to_units());
tok.next();
}
@@ -1269,6 +1284,7 @@ void temporary_indent()
if (!err) {
curenv->temporary_indent = temp;
curenv->have_temporary_indent = 1;
+ curenv->add_html_tag(".ti", temp.to_units());
}
tok.next();
}
@@ -1940,15 +1956,121 @@ void environment::final_break()
do_break();
}
-void environment::add_html_tag (const char *name)
+/*
+ * add_html_tag_eol - add an end of line tag if appropriate.
+ */
+
+void environment::add_html_tag_eol(void)
{
- if (is_html2) {
- // need to emit tag for post-grohtml
+ if (is_html) {
+ if (ignore_next_eol > 0)
+ ignore_next_eol--;
+ else if (need_eol > 0) {
+ need_eol--;
+ add_html_tag("eol");
+ }
+ else if (!fill) {
+ add_html_tag("eol");
+ }
+ }
+}
+
+/*
+ * add_html_tag - emits a special html-tag: to help post-grohtml understand
+ * the key troff commands
+ */
+
+void environment::add_html_tag(const char *name)
+{
+ if (is_html) {
+ /*
+ * need to emit tag for post-grohtml
+ * but we check to see whether we can emit specials
+ */
+ if (curdiv == topdiv && topdiv->before_first_page)
+ topdiv->begin_page();
macro *m = new macro;
+ m->append_str("html-tag:");
+ for (const char *p = name; *p; p++)
+ if (!illegal_input_char((unsigned char)*p))
+ m->append(*p);
+ add_node(new special_node(*m));
+ }
+}
+
+/*
+ * add_html_tag - emits a special html-tag: to help post-grohtml understand
+ * the key troff commands, it appends a string representation
+ * of i.
+ */
+void environment::add_html_tag(const char *name, int i)
+{
+ if (is_html) {
+ if (strcmp(name, ".ce") == 0) {
+ if (i == 0)
+ need_eol = 0;
+ else {
+ need_eol = i;
+ ignore_next_eol = 1; // since the .ce creates an eol
+ }
+ }
+ /*
+ * need to emit tag for post-grohtml
+ * but we check to see whether we can emit specials
+ */
+ if (curdiv == topdiv && topdiv->before_first_page)
+ topdiv->begin_page();
+ macro *m = new macro;
+ m->append_str("html-tag:");
for (const char *p = name; *p; p++)
if (!illegal_input_char((unsigned char)*p))
m->append(*p);
+ m->append(' ');
+ m->append_int(i);
+ // output_pending_lines();
+ output(new special_node(*m), !fill, 0, 0, 0);
+ // output_pending_lines();
+ }
+}
+
+/*
+ * add_html_tag_tabs - emits the tab settings for post-grohtml
+ */
+
+void environment::add_html_tag_tabs(void)
+{
+ if (is_html) {
+ /*
+ * need to emit tag for post-grohtml
+ * but we check to see whether we can emit specials
+ */
+ if (curdiv == topdiv && topdiv->before_first_page)
+ topdiv->begin_page();
+ macro *m = new macro;
+ hunits d, l;
+ enum tab_type t;
+ m->append_str("html-tag:.ta ");
+ do {
+ t = curenv->tabs.distance_to_next_tab(l, &d);
+ l += d;
+ switch (t) {
+ case TAB_LEFT:
+ m->append_str(" L ");
+ m->append_int(d.to_units());
+ break;
+ case TAB_CENTER:
+ m->append_str(" C ");
+ m->append_int(d.to_units());
+ break;
+ case TAB_RIGHT:
+ m->append_str(" R ");
+ m->append_int(d.to_units());
+ break;
+ case TAB_NONE:
+ break;
+ }
+ } while ((t != TAB_NONE) && (l<get_line_length())) ;
output_pending_lines();
output(new special_node(*m), !fill, 0, 0, 0);
output_pending_lines();
@@ -1958,7 +2080,6 @@ void environment::add_html_tag (const char *name)
void environment::do_break()
{
if (curdiv == topdiv && topdiv->before_first_page) {
- add_html_tag("html-tag:eol");
topdiv->begin_page();
return;
}
@@ -1989,7 +2110,6 @@ void environment::do_break()
break;
}
}
- add_html_tag("html-tag:eol");
node *tem = line;
line = 0;
output_line(tem, width_total);
@@ -2011,8 +2131,10 @@ void break_request()
{
while (!tok.newline() && !tok.eof())
tok.next();
- if (break_flag)
+ if (break_flag) {
curenv->do_break();
+ curenv->add_html_tag(".br");
+ }
tok.next();
}
@@ -2383,6 +2505,7 @@ void set_tabs()
}
}
curenv->tabs = tabs;
+ curenv->add_html_tag_tabs();
skip_line();
}
@@ -2494,10 +2617,12 @@ void environment::handle_tab(int is_leader)
case TAB_NONE:
return;
case TAB_LEFT:
+ add_html_tag("tab left");
add_node(make_tab_node(d));
return;
case TAB_RIGHT:
case TAB_CENTER:
+ add_html_tag("tab center");
tab_width = 0;
tab_distance = d;
tab_contents = 0;
diff --git a/src/roff/troff/env.h b/src/roff/troff/env.h
index a5bee15d..521bccf7 100644
--- a/src/roff/troff/env.h
+++ b/src/roff/troff/env.h
@@ -179,6 +179,8 @@ class environment {
#ifdef WIDOW_CONTROL
int widow_control;
#endif /* WIDOW_CONTROL */
+ int need_eol;
+ int ignore_next_eol;
tab_type distance_to_next_tab(hunits *);
void start_line();
@@ -271,7 +273,10 @@ public:
void possibly_break_line(int forced = 0);
void do_break(); // .br
void final_break();
- void add_html_tag (const char *name);
+ void add_html_tag_eol(void);
+ void add_html_tag(const char *);
+ void add_html_tag(const char *, int);
+ void add_html_tag_tabs(void);
void newline();
void handle_tab(int is_leader = 0); // do a tab or leader
void add_node(node *);
diff --git a/src/roff/troff/input.cc b/src/roff/troff/input.cc
index e79f17d6..aeca49c1 100644
--- a/src/roff/troff/input.cc
+++ b/src/roff/troff/input.cc
@@ -110,7 +110,8 @@ static symbol blank_line_macro_name;
int compatible_flag = 0;
int ascii_output_flag = 0;
int suppress_output_flag = 0;
-int is_html2 = 0;
+int is_html = 0;
+int html_level = 0; // number of nested .html-begin requests
int tcommand_flag = 0;
int safer_flag = 1; // safer by default
@@ -310,8 +311,10 @@ int file_iterator::next_file(FILE *f, const char *s)
int file_iterator::fill(node **)
{
- if (newline_flag)
+ if (newline_flag) {
+ curenv->add_html_tag_eol();
lineno++;
+ }
newline_flag = 0;
unsigned char *p = buf;
ptr = p;
@@ -912,6 +915,7 @@ public:
int interpret(macro *);
int same(node *);
const char *type();
+ int force_tprint();
};
int non_interpreted_char_node::same(node *nd)
@@ -924,6 +928,11 @@ const char *non_interpreted_char_node::type()
return "non_interpreted_char_node";
}
+int non_interpreted_char_node::force_tprint()
+{
+ return 0;
+}
+
non_interpreted_char_node::non_interpreted_char_node(unsigned char n) : c(n)
{
assert(n != 0);
@@ -943,6 +952,7 @@ int non_interpreted_char_node::interpret(macro *mac)
static void do_width();
static node *do_non_interpreted();
static node *do_special();
+static node *do_suppress();
static void do_register();
static node *do_overstrike()
@@ -1129,6 +1139,7 @@ public:
token_node *get_token_node();
int same(node *);
const char *type();
+ int force_tprint();
};
token_node::token_node(const token &t) : tk(t)
@@ -1155,6 +1166,11 @@ const char *token_node::type()
return "token_node";
}
+int token_node::force_tprint()
+{
+ return 0;
+}
+
token::token() : nd(0), type(TOKEN_EMPTY)
{
}
@@ -1552,6 +1568,12 @@ void token::next()
nd = do_overstrike();
type = TOKEN_NODE;
return;
+ case 'O':
+ nd = do_suppress();
+ if (!nd)
+ break;
+ type = TOKEN_NODE;
+ return;
case 'p':
type = TOKEN_SPREAD;
return;
@@ -2051,7 +2073,6 @@ int_stack::~int_stack()
top = top->next;
delete temp;
}
-
}
int int_stack::is_empty()
@@ -2508,6 +2529,18 @@ void macro::append(unsigned char c)
++length;
}
+void macro::append_str(const char *s)
+{
+ int i = 0;
+
+ if (s) {
+ while (s[i] != (char)0) {
+ append(s[i]);
+ i++;
+ }
+ }
+}
+
void macro::append(node *n)
{
assert(n != 0);
@@ -2524,6 +2557,23 @@ void macro::append(node *n)
++length;
}
+void macro::append_unsigned(unsigned int i)
+{
+ unsigned int j = i / 10;
+ if (j != 0)
+ append_unsigned(j);
+ append(((unsigned char)(((int)'0') + i % 10)));
+}
+
+void macro::append_int(int i)
+{
+ if (i < 0) {
+ append('-');
+ i = -i;
+ }
+ append_unsigned((unsigned int)i);
+}
+
void macro::print_size()
{
errprint("%1", length);
@@ -3991,6 +4041,7 @@ public:
node *copy();
int same(node *);
const char *type();
+ int force_tprint();
};
non_interpreted_node::non_interpreted_node(const macro &m) : mac(m)
@@ -4007,6 +4058,11 @@ const char *non_interpreted_node::type()
return "non_interpreted_node";
}
+int non_interpreted_node::force_tprint()
+{
+ return 0;
+}
+
node *non_interpreted_node::copy()
{
return new non_interpreted_node(mac);
@@ -4111,6 +4167,22 @@ node *do_special()
return new special_node(mac);
}
+node *do_suppress()
+{
+ tok.next();
+ int c = tok.ch();
+
+ if (c == '0')
+ return new suppress_node(0, 0);
+ else if (c == '1')
+ return new suppress_node(1, 0);
+ else if (c == '2')
+ return new suppress_node(1, 1);
+ else
+ error("invalid argument to \\O");
+ return 0;
+}
+
void special_node::tprint(troff_output_file *out)
{
tprint_start(out);
@@ -4342,6 +4414,67 @@ void else_request()
}
}
+/*
+ * html_begin - if this is the outermost html_begin request then execute the
+ * rest of the line, else skip line
+ */
+
+void html_begin()
+{
+ html_level++;
+ if (html_level == 1)
+ begin_alternative();
+ else
+ skip_alternative();
+}
+
+/*
+ * html_end - if this is the outermost html_end request then execute the
+ * rest of the line, else skip line
+ */
+
+void html_end()
+{
+ html_level--;
+ if (html_level == 0)
+ begin_alternative();
+ else
+ skip_alternative();
+ if (html_level < 0)
+ html_level = 0;
+}
+
+/*
+ * html_image - implements the directive `.html_image {l|r|c|i} filename'
+ * which places the filename into a node which is later
+ * written out
+ *
+ * . either as a special in the form of an image tag for -Thtml
+ * . or as an image region definition for all other devices
+ *
+ */
+
+void html_image()
+{
+ if (has_arg()) {
+ char position = tok.ch();
+ if (!(position == 'l'
+ || position == 'r'
+ || position == 'c'
+ || position == 'i')) {
+ error("l, r, c, or i expected (got %1)", tok.description());
+ position = 'c';
+ }
+ else {
+ tok.next();
+ symbol filename = get_long_name(1);
+ if (!filename.is_null())
+ curenv->add_node(new suppress_node(filename, position));
+ }
+ }
+ skip_line();
+}
+
static int while_depth = 0;
static int while_break_flag = 0;
@@ -5832,7 +5965,7 @@ int main(int argc, char **argv)
case 'T':
device = optarg;
tflag = 1;
- is_html2 = (strcmp(device, "html2") == 0);
+ is_html = (strcmp(device, "html") == 0);
break;
case 'C':
compatible_flag = 1;
@@ -5946,7 +6079,7 @@ int main(int argc, char **argv)
init_column_requests();
#endif /* COLUMN */
init_node_requests();
- init_output_requests();
+ init_html_requests();
number_reg_dictionary.define(".T", new constant_reg(tflag ? "1" : "0"));
init_registers();
init_reg_requests();
@@ -6020,69 +6153,51 @@ static void init_registers()
}
/*
- * .output request and associated registers
+ * registers associated with \O
*/
static int output_reg_minx_contents = -1;
static int output_reg_miny_contents = -1;
static int output_reg_maxx_contents = -1;
static int output_reg_maxy_contents = -1;
+static int output_low_mark_miny = -1; // internal only (limits miny)
-void check_output_limits (int x, int y)
+void check_output_limits(int x, int y)
{
- if ((output_reg_minx_contents == -1) || (x < output_reg_minx_contents)) {
+ if ((output_reg_minx_contents == -1) || (x < output_reg_minx_contents))
output_reg_minx_contents = x;
- }
- if (x > output_reg_maxx_contents) {
+ if (x > output_reg_maxx_contents)
output_reg_maxx_contents = x;
- }
- if ((output_reg_miny_contents == -1) || (y < output_reg_miny_contents)) {
+ if (((output_reg_miny_contents == -1) || (y < output_reg_miny_contents))
+ && (y >= output_low_mark_miny))
output_reg_miny_contents = y;
- }
- if (y > output_reg_maxy_contents) {
+ if (y > output_reg_maxy_contents)
output_reg_maxy_contents = y;
- }
- // fprintf(stderr, "x = %d y=%d miny=%d maxy=%d\n", x, y, output_reg_miny_contents, output_reg_maxy_contents);
}
-void reset_output_registers()
+void reset_output_registers(int miny)
{
// fprintf(stderr, "reset_output_registers\n");
+ output_low_mark_miny = miny;
output_reg_minx_contents = -1;
output_reg_miny_contents = -1;
output_reg_maxx_contents = -1;
output_reg_maxy_contents = -1;
}
-void output_request()
+void get_output_registers(int *minx, int *miny, int *maxx, int *maxy)
{
- if (has_arg()) {
- int n;
-
- if (! get_integer(&n)) {
- error("missing integer argument for output request");
- n = 1;
- }
-
- if (break_flag)
- curenv->do_break();
-
- if (!the_output)
- init_output();
- if (n == 0) {
- the_output->off();
- } else {
- the_output->on();
- }
- } else {
- error("missing argument for output request");
- }
- skip_line();
+ *minx = output_reg_minx_contents;
+ *miny = output_reg_miny_contents;
+ *maxx = output_reg_maxx_contents;
+ *maxy = output_reg_maxy_contents;
}
-void init_output_requests()
+void init_html_requests()
{
- init_request("output", output_request);
+ init_request("html-begin", html_begin);
+ init_request("html-end", html_end);
+ init_request("html-image", html_image);
}
void init_input_requests()
diff --git a/src/roff/troff/node.cc b/src/roff/troff/node.cc
index 44ccda7b..3770aab9 100644
--- a/src/roff/troff/node.cc
+++ b/src/roff/troff/node.cc
@@ -55,6 +55,14 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#endif /* not _POSIX_VERSION */
+/*
+ * how many boundaries of images have been written? Useful for
+ * debugging grohtml
+ */
+
+static int image_no=0;
+static int suppress_start_page=0;
+
#define STORE_WIDTH 1
symbol HYPHEN_SYMBOL("hy");
@@ -322,7 +330,7 @@ void font_info::set_conditional_bold(int fontno, hunits offset)
}
conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x)
- : next(x), fontno(f), offset(h)
+: next(x), fontno(f), offset(h)
{
}
@@ -405,9 +413,9 @@ hunits font_info::get_half_narrow_space_width(font_size fs)
tfont_spec::tfont_spec(symbol nm, int n, font *f,
font_size s, int h, int sl)
- : name(nm), input_position(n), fm(f), size(s),
- is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
- height(h), slant(sl)
+: name(nm), input_position(n), fm(f), size(s),
+ is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
+ height(h), slant(sl)
{
if (height == size.to_scaled_points())
height = 0;
@@ -671,6 +679,7 @@ public:
void put_filename(const char *filename);
void on();
void off();
+ int is_on();
int is_printing();
void copy_file(hunits x, vunits y, const char *filename);
};
@@ -742,6 +751,7 @@ public:
void right(hunits);
void down(vunits);
void moveto(hunits, vunits);
+ void start_special(tfont *tf);
void start_special();
void special_char(unsigned char c);
void end_special();
@@ -785,6 +795,22 @@ inline void troff_output_file::put(int i)
put_string(i_to_a(i), fp);
}
+void troff_output_file::start_special(tfont *tf)
+{
+ flush_tbuf();
+
+ /*
+ * although this is extremely unlikely to have an effect on other devices
+ * this way is safer. Currently this is only needed for html.
+ */
+ if (is_html && tf) {
+ if (tf != current_tfont)
+ set_font(tf);
+ }
+ do_motion();
+ put("x X ");
+}
+
void troff_output_file::start_special()
{
flush_tbuf();
@@ -815,7 +841,8 @@ void troff_output_file::really_print_line(hunits x, vunits y, node *n,
{
moveto(x, y);
while (n != 0) {
- n->tprint(this);
+ if (is_on() || (n->force_tprint()))
+ n->tprint(this);
n = n->next;
}
flush_tbuf();
@@ -1367,7 +1394,7 @@ void real_output_file::transparent_char(unsigned char c)
void real_output_file::print_line(hunits x, vunits y, node *n,
vunits before, vunits after, hunits width)
{
- if (printing && output_on)
+ if (printing)
really_print_line(x, y, n, before, after, width);
delete_node_list(n);
}
@@ -1392,10 +1419,6 @@ void real_output_file::on()
if (output_on == 0) {
output_on = 1;
}
- /*
- * lastly we reset the output registers
- */
- reset_output_registers();
}
void real_output_file::off()
@@ -1404,6 +1427,11 @@ void real_output_file::off()
output_on = 0;
}
+int real_output_file::is_on()
+{
+ return( output_on );
+}
+
void real_output_file::really_on()
{
}
@@ -1527,6 +1555,7 @@ public:
int character_type();
int same(node *);
const char *type();
+ int force_tprint();
};
glyph_node *glyph_node::free_list = 0;
@@ -1549,6 +1578,7 @@ public:
void asciify(macro *);
int same(node *);
const char *type();
+ int force_tprint();
};
class kern_pair_node : public node {
@@ -1574,6 +1604,7 @@ public:
void asciify(macro *);
int same(node *);
const char *type();
+ int force_tprint();
void vertical_extent(vunits *, vunits *);
};
@@ -1602,6 +1633,7 @@ public:
void asciify(macro *);
int same(node *);
const char *type();
+ int force_tprint();
};
void *glyph_node::operator new(size_t n)
@@ -1793,14 +1825,14 @@ void glyph_node::ascii_print(ascii_output_file *ascii)
ligature_node::ligature_node(charinfo *c, tfont *t,
node *gn1, node *gn2, node *x)
- : glyph_node(c, t, x), n1(gn1), n2(gn2)
+: glyph_node(c, t, x), n1(gn1), n2(gn2)
{
}
#ifdef STORE_WIDTH
ligature_node::ligature_node(charinfo *c, tfont *t, hunits w,
node *gn1, node *gn2, node *x)
- : glyph_node(c, t, w, x), n1(gn1), n2(gn2)
+: glyph_node(c, t, w, x), n1(gn1), n2(gn2)
{
}
#endif
@@ -1841,12 +1873,12 @@ node *ligature_node::add_self(node *n, hyphen_list **p)
}
kern_pair_node::kern_pair_node(hunits n, node *first, node *second, node *x)
- : node(x), amount(n), n1(first), n2(second)
+: node(x), amount(n), n1(first), n2(second)
{
}
dbreak_node::dbreak_node(node *n, node *p, node *x)
- : node(x), none(n), pre(p), post(0)
+: node(x), none(n), pre(p), post(0)
{
}
@@ -2005,6 +2037,7 @@ public:
node *copy();
int same(node *);
const char *type();
+ int force_tprint();
hyphenation_type get_hyphenation_type();
};
@@ -2027,6 +2060,11 @@ const char *hyphen_inhibitor_node::type()
return "hyphen_inhibitor_node";
}
+int hyphen_inhibitor_node::force_tprint()
+{
+ return 0;
+}
+
hyphenation_type hyphen_inhibitor_node::get_hyphenation_type()
{
return HYPHEN_INHIBIT;
@@ -2096,6 +2134,11 @@ node *node::last_char_node()
return 0;
}
+int node::force_tprint()
+{
+ return 0;
+}
+
hunits hmotion_node::width()
{
return n;
@@ -2172,6 +2215,7 @@ public:
hunits skew();
node *add_self(node *, hyphen_list **);
const char *type();
+ int force_tprint();
};
node *node::add_italic_correction(hunits *width)
@@ -2309,6 +2353,7 @@ public:
tfont *get_tfont();
int same(node *);
const char *type();
+ int force_tprint();
};
break_char_node::break_char_node(node *n, int c, node *x)
@@ -2657,6 +2702,11 @@ node *space_node::copy()
return new space_node(n, set);
}
+int space_node::force_tprint()
+{
+ return 0;
+}
+
int space_node::nspaces()
{
return set ? 0 : 1;
@@ -3216,11 +3266,25 @@ int node::interpret(macro *)
special_node::special_node(const macro &m)
: mac(m)
{
+ font_size fs = curenv->get_font_size();
+ int char_height = curenv->get_char_height();
+ int char_slant = curenv->get_char_slant();
+ int fontno = curenv->get_font();
+ tf = font_table[fontno]->get_tfont(fs, char_height, char_slant,
+ fontno);
+ if (curenv->is_composite())
+ tf = tf->get_plain();
+}
+
+special_node::special_node(const macro &m, tfont *t)
+: mac(m), tf(t)
+{
}
int special_node::same(node *n)
{
- return mac == ((special_node *)n)->mac;
+ return ((mac == ((special_node *)n)->mac) &&
+ (tf == ((special_node *)n)->tf));
}
const char *special_node::type()
@@ -3228,14 +3292,19 @@ const char *special_node::type()
return "special_node";
}
+int special_node::force_tprint()
+{
+ return 0;
+}
+
node *special_node::copy()
{
- return new special_node(mac);
+ return new special_node(mac, tf);
}
void special_node::tprint_start(troff_output_file *out)
{
- out->start_special();
+ out->start_special(get_tfont());
}
void special_node::tprint_char(troff_output_file *out, unsigned char c)
@@ -3248,6 +3317,200 @@ void special_node::tprint_end(troff_output_file *out)
out->end_special();
}
+tfont *special_node::get_tfont()
+{
+ return tf;
+}
+
+/* suppress_node */
+
+suppress_node::suppress_node(int on_or_off, int issue_limits)
+: is_on(on_or_off), emit_limits(issue_limits), filename(0), position(0)
+{
+}
+
+suppress_node::suppress_node(symbol f, char p)
+: is_on(2), emit_limits(0), filename(f), position(p)
+{
+}
+
+suppress_node::suppress_node(int issue_limits, int on_or_off, symbol f, char p)
+: is_on(on_or_off), emit_limits(issue_limits), filename(f), position(p)
+{
+}
+
+int suppress_node::same(node *n)
+{
+ return ((is_on == ((suppress_node *)n)->is_on)
+ && (emit_limits == ((suppress_node *)n)->emit_limits)
+ && (filename == ((suppress_node *)n)->filename)
+ && (position == ((suppress_node *)n)->position));
+;
+}
+
+const char *suppress_node::type()
+{
+ return "suppress_node";
+}
+
+node *suppress_node::copy()
+{
+ return new suppress_node(emit_limits, is_on, filename, position);
+}
+
+int get_reg_int (const char *p)
+{
+ reg *r = (reg *)number_reg_dictionary.lookup(p);
+ units prev_value;
+ if (r && (r->get_value(&prev_value)))
+ return( (int)prev_value );
+ else
+ warning(WARN_REG, "number register `%1' not defined", p);
+ return( 0 );
+}
+
+const char *get_reg_str (const char *p)
+{
+ reg *r = (reg *)number_reg_dictionary.lookup(p);
+ if (r)
+ return r->get_string();
+ else
+ warning(WARN_REG, "register `%1' not defined", p);
+ return( 0 );
+}
+
+void suppress_node::put(troff_output_file *out, const char *s)
+{
+ int i=0;
+
+ while (s[i] != (char)0) {
+ out->special_char(s[i]);
+ i++;
+ }
+}
+
+/*
+ * We prefer to remember the last position, rather than have a .html-start
+ * followed by html-end-center, html-end-left as it is more natural to
+ * express an image by:
+ *
+ * .html-image-left
+ *
+ * .html-image-end
+ *
+ * similar to other troff commands, although this method is slightly more
+ * messy to implement.
+ */
+
+static char last_position = 0;
+static const char *last_image_filename = 0;
+
+inline int min(int a, int b)
+{
+ return a < b ? a : b;
+}
+
+/*
+ * tprint - if (is_on == 2)
+ * remember current position (l, r, c, i) and filename
+ * else
+ * if (emit_limits)
+ * if (html)
+ * emit image tag
+ * else
+ * emit postscript bounds for image
+ * else
+ * if (suppress boolean differs from current state)
+ * alter state
+ * reset registers
+ * record current page
+ * set low water mark.
+ */
+
+void suppress_node::tprint(troff_output_file *out)
+{
+ int current_page = get_reg_int("%");
+ // firstly check to see whether this suppress node contains
+ // an image filename & position.
+ if (is_on == 2) {
+ // remember position and filename
+ last_position = position;
+ last_image_filename = filename.contents();
+ }
+ else {
+ // now check whether the suppress node requires us to issue limits.
+ if (emit_limits) {
+ char name[8192];
+ image_no++;
+ // remember that the filename will contain a %d in which the
+ // image_no is placed
+ sprintf(name, last_image_filename, image_no);
+ if (is_html) {
+ switch (last_position) {
+ case 'c':
+ out->start_special();
+ put(out, "html-tag:.centered-image");
+ break;
+ case 'r':
+ out->start_special();
+ put(out, "html-tag:.right-image");
+ break;
+ case 'l':
+ out->start_special();
+ put(out, "html-tag:.left-image");
+ break;
+ case 'i':
+ ;
+ default:
+ ;
+ }
+ out->end_special();
+ out->start_special();
+ put(out, "html-tag:.auto-image ");
+ put(out, name);
+ out->end_special();
+ }
+ else {
+ // postscript (or other device)
+ if (current_page != suppress_start_page)
+ error("suppression limit registers span more than one page;\n"
+ "image description %1 will be wrong", image_no);
+ // remember that the filename will contain a %d in which the
+ // image_no is placed */
+ fprintf(stderr,
+ "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n",
+ current_page,
+ get_reg_int("opminx"), get_reg_int("opminy"),
+ get_reg_int("opmaxx"), min(get_reg_int("opmaxy"),
+ out->get_vpos()),
+ // page offset + line length
+ get_reg_int(".o") + get_reg_int(".l"),
+ name, hresolution, vresolution, get_reg_str(".F"));
+ fflush(stderr);
+ }
+ }
+ else {
+ if (is_on)
+ out->on();
+ else
+ out->off();
+ // lastly we reset the output registers
+ reset_output_registers(out->get_vpos());
+ suppress_start_page = current_page;
+ }
+ }
+}
+
+int suppress_node::force_tprint()
+{
+ return is_on;
+}
+
+hunits suppress_node::width()
+{
+ return H0;
+}
+
/* composite_node */
class composite_node : public charinfo_node {
@@ -3269,6 +3532,7 @@ public:
tfont *get_tfont();
int same(node *);
const char *type();
+ int force_tprint();
void vertical_extent(vunits *, vunits *);
vunits vertical_width();
};
@@ -3433,6 +3697,11 @@ node *unbreakable_space_node::copy()
return new unbreakable_space_node(n, set, num_spaces);
}
+int unbreakable_space_node::force_tprint()
+{
+ return 0;
+}
+
breakpoint *unbreakable_space_node::get_breakpoints(hunits, int,
breakpoint *rest, int)
{
@@ -3459,7 +3728,7 @@ hvpair::hvpair()
}
draw_node::draw_node(char c, hvpair *p, int np, font_size s)
- : npoints(np), sz(s), code(c)
+: npoints(np), sz(s), code(c)
{
point = new hvpair[npoints];
for (int i = 0; i < npoints; i++)
@@ -3482,6 +3751,11 @@ const char *draw_node::type()
return "draw_node";
}
+int draw_node::force_tprint()
+{
+ return 0;
+}
+
draw_node::~draw_node()
{
if (point)
@@ -4035,6 +4309,11 @@ const char *extra_size_node::type()
return "extra_size_node";
}
+int extra_size_node::force_tprint()
+{
+ return 0;
+}
+
int vertical_size_node::same(node *nd)
{
return n == ((vertical_size_node *)nd)->n;
@@ -4045,6 +4324,11 @@ const char *vertical_size_node::type()
return "vertical_size_node";
}
+int vertical_size_node::force_tprint()
+{
+ return 0;
+}
+
int hmotion_node::same(node *nd)
{
return n == ((hmotion_node *)nd)->n;
@@ -4055,6 +4339,11 @@ const char *hmotion_node::type()
return "hmotion_node";
}
+int hmotion_node::force_tprint()
+{
+ return 0;
+}
+
int space_char_hmotion_node::same(node *nd)
{
return n == ((space_char_hmotion_node *)nd)->n;
@@ -4065,6 +4354,11 @@ const char *space_char_hmotion_node::type()
return "space_char_hmotion_node";
}
+int space_char_hmotion_node::force_tprint()
+{
+ return 0;
+}
+
int vmotion_node::same(node *nd)
{
return n == ((vmotion_node *)nd)->n;
@@ -4075,6 +4369,11 @@ const char *vmotion_node::type()
return "vmotion_node";
}
+int vmotion_node::force_tprint()
+{
+ return 0;
+}
+
int hline_node::same(node *nd)
{
return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n);
@@ -4085,6 +4384,11 @@ const char *hline_node::type()
return "hline_node";
}
+int hline_node::force_tprint()
+{
+ return 0;
+}
+
int vline_node::same(node *nd)
{
return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n);
@@ -4095,6 +4399,11 @@ const char *vline_node::type()
return "vline_node";
}
+int vline_node::force_tprint()
+{
+ return 0;
+}
+
int dummy_node::same(node * /*nd*/)
{
return 1;
@@ -4105,6 +4414,11 @@ const char *dummy_node::type()
return "dummy_node";
}
+int dummy_node::force_tprint()
+{
+ return 0;
+}
+
int transparent_dummy_node::same(node * /*nd*/)
{
return 1;
@@ -4115,6 +4429,11 @@ const char *transparent_dummy_node::type()
return "transparent_dummy_node";
}
+int transparent_dummy_node::force_tprint()
+{
+ return 0;
+}
+
int transparent_dummy_node::ends_sentence()
{
return 2;
@@ -4130,6 +4449,11 @@ const char *zero_width_node::type()
return "zero_width_node";
}
+int zero_width_node::force_tprint()
+{
+ return 0;
+}
+
int italic_corrected_node::same(node *nd)
{
return (x == ((italic_corrected_node *)nd)->x
@@ -4141,6 +4465,10 @@ const char *italic_corrected_node::type()
return "italic_corrected_node";
}
+int italic_corrected_node::force_tprint()
+{
+ return 0;
+}
left_italic_corrected_node::left_italic_corrected_node(node *x)
: node(x), n(0)
@@ -4196,6 +4524,11 @@ const char *left_italic_corrected_node::type()
return "left_italic_corrected_node";
}
+int left_italic_corrected_node::force_tprint()
+{
+ return 0;
+}
+
int left_italic_corrected_node::same(node *nd)
{
return (x == ((left_italic_corrected_node *)nd)->x
@@ -4300,6 +4633,11 @@ const char *overstrike_node::type()
return "overstrike_node";
}
+int overstrike_node::force_tprint()
+{
+ return 0;
+}
+
int bracket_node::same(node *nd)
{
return same_node_list(list, ((bracket_node *)nd)->list);
@@ -4310,6 +4648,11 @@ const char *bracket_node::type()
return "bracket_node";
}
+int bracket_node::force_tprint()
+{
+ return 0;
+}
+
int composite_node::same(node *nd)
{
return ci == ((composite_node *)nd)->ci
@@ -4321,6 +4664,11 @@ const char *composite_node::type()
return "composite_node";
}
+int composite_node::force_tprint()
+{
+ return 0;
+}
+
int glyph_node::same(node *nd)
{
return ci == ((glyph_node *)nd)->ci && tf == ((glyph_node *)nd)->tf;
@@ -4331,6 +4679,11 @@ const char *glyph_node::type()
return "glyph_node";
}
+int glyph_node::force_tprint()
+{
+ return 0;
+}
+
int ligature_node::same(node *nd)
{
return (same_node(n1, ((ligature_node *)nd)->n1)
@@ -4343,6 +4696,11 @@ const char *ligature_node::type()
return "ligature_node";
}
+int ligature_node::force_tprint()
+{
+ return 0;
+}
+
int kern_pair_node::same(node *nd)
{
return (amount == ((kern_pair_node *)nd)->amount
@@ -4355,6 +4713,11 @@ const char *kern_pair_node::type()
return "kern_pair_node";
}
+int kern_pair_node::force_tprint()
+{
+ return 0;
+}
+
int dbreak_node::same(node *nd)
{
return (same_node_list(none, ((dbreak_node *)nd)->none)
@@ -4367,6 +4730,11 @@ const char *dbreak_node::type()
return "dbreak_node";
}
+int dbreak_node::force_tprint()
+{
+ return 0;
+}
+
int break_char_node::same(node *nd)
{
return (break_code == ((break_char_node *)nd)->break_code
@@ -4378,6 +4746,11 @@ const char *break_char_node::type()
return "break_char_node";
}
+int break_char_node::force_tprint()
+{
+ return 0;
+}
+
int line_start_node::same(node * /*nd*/)
{
return 1;
@@ -4388,6 +4761,11 @@ const char *line_start_node::type()
return "line_start_node";
}
+int line_start_node::force_tprint()
+{
+ return 0;
+}
+
int space_node::same(node *nd)
{
return n == ((space_node *)nd)->n && set == ((space_node *)nd)->set;
@@ -4409,6 +4787,11 @@ const char *word_space_node::type()
return "word_space_node";
}
+int word_space_node::force_tprint()
+{
+ return 0;
+}
+
int unbreakable_space_node::same(node *nd)
{
return (n == ((unbreakable_space_node *)nd)->n
@@ -4430,6 +4813,11 @@ const char *diverted_space_node::type()
return "diverted_space_node";
}
+int diverted_space_node::force_tprint()
+{
+ return 0;
+}
+
int diverted_copy_file_node::same(node *nd)
{
return filename == ((diverted_copy_file_node *)nd)->filename;
@@ -4440,6 +4828,11 @@ const char *diverted_copy_file_node::type()
return "diverted_copy_file_node";
}
+int diverted_copy_file_node::force_tprint()
+{
+ return 0;
+}
+
// Grow the font_table so that its size is > n.
static void grow_font_table(int n)
@@ -4872,9 +5265,8 @@ track_kerning_function::track_kerning_function() : non_zero(0)
track_kerning_function::track_kerning_function(int min_s, hunits min_a,
int max_s, hunits max_a)
- : non_zero(1),
- min_size(min_s), min_amount(min_a),
- max_size(max_s), max_amount(max_a)
+: non_zero(1), min_size(min_s), min_amount(min_a), max_size(max_s),
+ max_amount(max_a)
{
}
diff --git a/src/roff/troff/node.h b/src/roff/troff/node.h
index 8366b01f..c861262e 100644
--- a/src/roff/troff/node.h
+++ b/src/roff/troff/node.h
@@ -57,6 +57,7 @@ struct node {
virtual ~node();
virtual node *copy() = 0;
+ virtual int force_tprint () = 0;
virtual hunits width();
virtual hunits subscript_correction();
virtual hunits italic_correction();
@@ -133,6 +134,7 @@ public:
line_start_node() {}
node *copy() { return new line_start_node; }
int same(node *);
+ int force_tprint();
const char *type();
void asciify(macro *);
};
@@ -169,6 +171,7 @@ public:
void ascii_print(ascii_output_file *);
int same(node *);
const char *type();
+ int force_tprint();
};
class word_space_node : public space_node {
@@ -183,6 +186,7 @@ public:
void asciify(macro *);
const char *type();
int merge_space(hunits);
+ int force_tprint();
};
class unbreakable_space_node : public word_space_node {
@@ -193,6 +197,7 @@ public:
int same(node *);
void asciify(macro *);
const char *type();
+ int force_tprint();
breakpoint *get_breakpoints(hunits width, int nspaces, breakpoint *rest = 0,
int is_inner = 0);
int nbreaks();
@@ -208,6 +213,7 @@ public:
int reread(int *);
int same(node *);
const char *type();
+ int force_tprint();
};
class diverted_copy_file_node : public node {
@@ -219,6 +225,7 @@ public:
int reread(int *);
int same(node *);
const char *type();
+ int force_tprint();
};
class extra_size_node : public node {
@@ -229,17 +236,19 @@ public:
node *copy();
int same(node *);
const char *type();
+ int force_tprint();
};
class vertical_size_node : public node {
vunits n;
- public:
+public:
vertical_size_node(vunits i) : n(i) {}
void set_vertical_size(vertical_size *);
void asciify(macro *);
node *copy();
int same(node *);
const char *type();
+ int force_tprint();
};
class hmotion_node : public node {
@@ -253,6 +262,7 @@ public:
void ascii_print(ascii_output_file *);
int same(node *);
const char *type();
+ int force_tprint();
};
class space_char_hmotion_node : public hmotion_node {
@@ -263,23 +273,25 @@ public:
void asciify(macro *);
int same(node *);
const char *type();
+ int force_tprint();
};
class vmotion_node : public node {
vunits n;
- public:
+public:
vmotion_node(vunits i) : n(i) {}
void tprint(troff_output_file *);
node *copy();
vunits vertical_width();
int same(node *);
const char *type();
+ int force_tprint();
};
class hline_node : public node {
hunits x;
node *n;
- public:
+public:
hline_node(hunits i, node *c, node *next = 0) : node(next), x(i), n(c) {}
~hline_node();
node *copy();
@@ -287,12 +299,13 @@ class hline_node : public node {
void tprint(troff_output_file *);
int same(node *);
const char *type();
+ int force_tprint();
};
class vline_node : public node {
vunits x;
node *n;
- public:
+public:
vline_node(vunits i, node *c, node *next= 0) : node(next), x(i), n(c) {}
~vline_node();
node *copy();
@@ -302,15 +315,17 @@ class vline_node : public node {
void vertical_extent(vunits *, vunits *);
int same(node *);
const char *type();
+ int force_tprint();
};
class dummy_node : public node {
- public:
+public:
dummy_node(node *nd = 0) : node(nd) {}
node *copy();
int same(node *);
const char *type();
+ int force_tprint();
hyphenation_type get_hyphenation_type();
};
@@ -320,19 +335,21 @@ public:
node *copy();
int same(node *);
const char *type();
+ int force_tprint();
int ends_sentence();
hyphenation_type get_hyphenation_type();
};
class zero_width_node : public node {
node *n;
- public:
+public:
zero_width_node(node *gn);
~zero_width_node();
node *copy();
void tprint(troff_output_file *);
int same(node *);
const char *type();
+ int force_tprint();
void append(node *);
int character_type();
void vertical_extent(vunits *min, vunits *max);
@@ -350,6 +367,7 @@ public:
node *copy();
int same(node *);
const char *type();
+ int force_tprint();
hunits width();
node *last_char_node();
void vertical_extent(vunits *, vunits *);
@@ -379,6 +397,7 @@ public:
hunits width();
int same(node *);
const char *type();
+ int force_tprint();
};
class bracket_node : public node {
@@ -393,19 +412,43 @@ public:
hunits width();
int same(node *);
const char *type();
+ int force_tprint();
};
class special_node : public node {
macro mac;
+ tfont *tf;
void tprint_start(troff_output_file *);
void tprint_char(troff_output_file *, unsigned char);
void tprint_end(troff_output_file *);
public:
special_node(const macro &);
+ special_node(const macro &, tfont *t);
+ node *copy();
+ void tprint(troff_output_file *);
+ int same(node *);
+ const char *type();
+ int force_tprint();
+ tfont *get_tfont();
+};
+
+class suppress_node : public node {
+ int is_on;
+ int emit_limits; // must we issue the extent of the area written out?
+ symbol filename;
+ char position;
+public:
+ suppress_node(int, int);
+ suppress_node(symbol f, char p);
+ suppress_node(int, int, symbol f, char p);
node *copy();
void tprint(troff_output_file *);
+ hunits width();
int same(node *);
const char *type();
+ int force_tprint();
+private:
+ void put(troff_output_file *out, const char *s);
};
struct hvpair {
@@ -429,6 +472,7 @@ public:
void tprint(troff_output_file *);
int same(node *);
const char *type();
+ int force_tprint();
};
class charinfo;
diff --git a/src/roff/troff/reg.h b/src/roff/troff/reg.h
index fe04f2ab..8d403d44 100644
--- a/src/roff/troff/reg.h
+++ b/src/roff/troff/reg.h
@@ -1,5 +1,6 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+ Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -67,7 +68,7 @@ public:
extern object_dictionary number_reg_dictionary;
extern void set_number_reg(symbol nm, units n);
extern void check_output_limits(int x, int y);
-extern void reset_output_registers (void);
+extern void reset_output_registers (int miny);
reg *lookup_number_reg(symbol);
#if 0
diff --git a/src/roff/troff/request.h b/src/roff/troff/request.h
index a26ebf48..7e361766 100644
--- a/src/roff/troff/request.h
+++ b/src/roff/troff/request.h
@@ -1,5 +1,6 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+ Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -55,6 +56,9 @@ public:
macro &operator=(const macro &);
void append(unsigned char);
void append(node *);
+ void append_unsigned(unsigned int i);
+ void append_int(int i);
+ void append_str(const char *);
void invoke(symbol);
macro *to_macro();
void print_size();
@@ -66,7 +70,7 @@ public:
};
extern void init_input_requests();
-extern void init_output_requests();
+extern void init_html_requests();
extern void init_div_requests();
extern void init_node_requests();
extern void init_reg_requests();
diff --git a/src/roff/troff/troff.h b/src/roff/troff/troff.h
index 5702d24e..254c6264 100644
--- a/src/roff/troff/troff.h
+++ b/src/roff/troff/troff.h
@@ -1,5 +1,6 @@
// -*- C++ -*-
-/* Copyright (C) 1989, 1990, 1991, 1992, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
+ Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.com)
This file is part of groff.
@@ -42,7 +43,7 @@ extern units units_per_inch;
extern int ascii_output_flag;
extern int suppress_output_flag;
-extern int is_html2;
+extern int is_html;
extern int tcommand_flag;
extern int vresolution;
diff --git a/tmac/Makefile.sub b/tmac/Makefile.sub
index 3d4a7239..98d4683a 100644
--- a/tmac/Makefile.sub
+++ b/tmac/Makefile.sub
@@ -6,7 +6,7 @@ MAN7=\
groff_me.n \
groff_mdoc.n \
groff_mdoc.samples.n \
- groff_markup.n
+ groff_mwww.n
NORMALFILES=\
mandoc.tmac andoc.tmac an-old.tmac \
@@ -21,7 +21,7 @@ NORMALFILES=\
tty.tmac tty-char.tmac latin1.tmac \
X.tmac Xps.tmac \
lj4.tmac \
- html.tmac html2.tmac html-tags.tmac markup.tmac arkup.tmac \
+ html.tmac html-old.tmac mwww.tmac www.tmac \
eqnrc \
troffrc troffrc-end \
hyphen.us
diff --git a/tmac/an-old.tmac b/tmac/an-old.tmac
index 7d8ca666..5b406a07 100644
--- a/tmac/an-old.tmac
+++ b/tmac/an-old.tmac
@@ -41,12 +41,25 @@
.if !r D .nr D 0
.if !r C .nr C 0
.if !r S .nr S 10
-.if r P .pn 0\n[P]
+.\" we must use consecutive page numbers when using postscript to generate
+.\" html images, and we must not reset the page number at the beginning
+.\" (the `ps4html' register is automatically added to the command line by
+.\" the pre-html preprocessor)
+.if !r ps4html \
+. if r P .pn 0\n[P]
.if !r cR \{\
. ie n .nr cR 1
. el .nr cR 0
.\}
.
+.\" compute the value of '\*(.T'html':'\*(.T'html-old'
+.\" XXX: it would be nice to allow logical or with strings
+.
+.nr html-or-html-old 0
+.if '\*(.T'html-old' .nr html-or-html-old 1
+.if '\*(.T'html' .nr html-or-html-old 1
+.if \\n[html-or-html-old] .nr C 1
+.if r ps4html .nr C 1
.
.de set-an-margin
. nr an-margin \\n[IN]
@@ -54,6 +67,10 @@
.
.\" .TH title section extra1 extra2 extra3
.de TH
+. if '\*(.T'html' \{\
+. HTML-TAG ".tl"
+\\$1
+. \}
. cp 0
.
. de an-init \" We have to do it like this to get multiple man pages right.
@@ -95,8 +112,8 @@
. ps \\n[PS]u
. vs \\n[VS]u
.
-. ie '\*[.T]'html' .nr IN 1.2i
-. el .nr IN 7.2n
+. ie '\*[.T]'html-old' .nr IN 1.2i
+. el .nr IN 7.2n
. PD
. nr SN 3n \" the indentation of sub-sub-headings relative to sub-headings
. nr an-level 1
@@ -136,7 +153,7 @@
. ev 1
. ps \\n[PS]u
. vs \\n[VS]u
-. ie '\*[.T]'html' \
+. ie \\n[html-or-html-old] \
. tl ''''
. el \{\
. if !\\n[cR] \
@@ -161,7 +178,7 @@
. ev 1
. ps \\n[PS]u
. vs \\n[VS]u
-. ie '\*[.T]'html' \{\
+. ie \\n[html-or-html-old] \{\
. ds an-page-string
. ds an-extra1
. ds an-extra2
@@ -174,7 +191,7 @@
. ds an-page-string \\n[X]\\n[an-page-letter]
. \}
. \}
-. ie '\*[.T]'html' \
+. ie \\n[html-or-html-old] \
. tl ''''
. el \{\
. ie \\n[D] \{\
@@ -206,6 +223,7 @@
. fi
. in \\n[an-margin]u
. ti 0
+. HTML-TAG ".NH \\n[an-level]"
. it 1 an-trap
. nr an-no-space-flag 1
. nr an-break-flag 1
@@ -448,7 +466,7 @@
.ds lq \(lq
.ds rq \(rq
.
-.hy 14
+.if !\\n[html-or-html-old] .hy 14
.
.\" Load local modifications.
.mso man.local
diff --git a/tmac/arkup.tmac b/tmac/arkup.tmac
deleted file mode 100755
index 8c52d121..00000000
--- a/tmac/arkup.tmac
+++ /dev/null
@@ -1,162 +0,0 @@
-.\" arkup.tmac
-.\"
-.\" A simple set of macros to provide HTML documents with basic
-.\" www functionality. It will work with any macro set.
-.\"
-.de HTML
-. if '\*(.T'html' \{\
-.\" the following line makes the vertical mode leave, so to say
-\&
-\X^html:\\$*^
-. \}
-..
-.de HTMLINDEX
-. if '\*(.T'html' \X^index:\\$*^
-..
-.\"
-.\" BODYCOLOR - $1 is foreground color
-.\" $2 is background color
-.\" $3 is the color of an active hypertext link
-.\" $4 is the color of a hypertext link not yet visited
-.\" $5 is the color of a visited hypertext link
-.\"
-.de BODYCOLOR
-. HTML <body text=\\$1 bgcolor=\\$2 link=\\$3 alink=\\$4 vlink=\\$5>
-..
-.\"
-.\" BACKGROUND - $1 is the background image file
-.\"
-.de BACKGROUND
-. HTML <body background=\\$1>
-..
-.\"
-.\" URL - $1 is the classical underlined blue text
-.\" $2 is the url
-.\" $3 is optional stuff printed immediately after $3
-.\"
-.de URL
-. ie '\*(.T'html' \{\
-. HTML <a href="\\$2">\\$1</a>\\$3
-. \}
-. el \{\
-\\$1 \(la\fC\\$2\fP\(ra\\$3
-. \}
-..
-.\"
-.\" FTP - $1 is the classical underlined blue text
-.\" $2 is the ftp url
-.\" $3 is optional stuff printed immediately after $2
-.de FTP
-. ie '\*(.T'html' \{\
-. HTML <a href=\\$2>\\$1</a>\\$3
-. \}
-. el \{\
-\\$1 \(la\fC\\$2\fP\(ra\\$3
-. \}
-..
-.\"
-.\" MAILTO - generate html email reference
-.\" $1 is the email address (without the `mailto:' prefix)
-.\" $2 is the optional name
-.\" $3 is optional stuff printed immediately after $2 (resp. $1)
-.\"
-.\" example:
-.\"
-.\" Foobar has been written by
-.\" .MAILTO fred@foo.bar "Fredrick Bloggs" .
-.\"
-.de MAILTO
-.\"
-.\" force reset after a potential heading by performing some motion..
-.\" how do we do this --fixme--
-.\" \h'\w' ''\h'-\w' '' doesn't work..
-. ie '\*(.T'html' \{\
-. ie '\\$2'' \{\
-. HTML "<a href=mailto:\\$1>\\$1</a>\\$3"
-. \}
-. el \{\
-. HTML "<a href=mailto:\\$1>\\$2</a>\\$3"
-. \}
-. \}
-. el \{\
-. ie '\\$2'' \{\
-\fC\\$1\fP\\$3
-. \}
-. el \{\
-\\$2 \(la\fC\\$1\fP\(ra\\$3
-. \}
-. \}
-..
-.\"
-.\" TAG - generate an html name $1
-.\"
-.de TAG
-. HTML <a name="\\$1"></a>
-..
-.\"
-.\" IMAGE - reference an image
-.\" $1 is the image file
-.\" $2 is the x width (default if absent 400 pixels)
-.\" $3 is the y width (default if absent is the x value)
-.\"
-.de IMAGE
-. ie '\*(.T'html' \{\
-. nr HTMLWIDTH 400
-. if '\\$2'' \{\
-. nr HTMLWIDTH \\$2
-. \}
-. nr HTMLHEIGHT \\n[HTMLWIDTH]
-. if '\\$3'' \{\
-. nr HTMLHEIGHT \\$3
-. \}
-. HTML <img src="\\$1" width=\\n[HTMLWIDTH height=\\n[HTMLHEIGHT]>
-. \}
-. el \{\
-. B1
-\(la\fC\\$1\fP\(ra
-. B2
-. \}
-..
-.\"
-.\" CDFTP - if we are processing this on machine \\$1 then we create a
-.\" FTP reference using \\$2 --> \\$3
-.\"
-.\" otherwise we create a URL from \\$2 --> \\$4
-.\"
-.\" example:
-.\"
-.\" .CDFTP "foobar" "somegnusoftware.tar.gz" \
-.\" "ftp://ftp.gnu.org/gnu/somegnusoftware.tar.gz" \
-.\" "../../../TARGZ/somegnusoftware.tar.gz"
-.\"
-.\" meaning if we are on machine foobar then generate an ftp url
-.\" to the GNU anonymous ftp server otherwise generate a file url
-.\" to a local copy (cdrom maybe)
-.\"
-.\" Useful when one machine is designated as a cdrom burner and another
-.\" designated as an appache server.
-.\" The same source for web pages can be burnt onto a CD and also
-.\" served across the network. It doesn't solve the problem of one
-.\" machine doing both though :-(
-.\"
-.\"
-.\".de CDFTP
-.\". sy /bin/rm -f /tmp/n.tmac
-.\". sy /bin/echo ".ds HOSTNAME `hostname --short`" > /tmp/n.tmac
-.\". so /tmp/n.tmac
-.\". sy /bin/rm -f /tmp/n.tmac
-.\". ie '\\*[HOSTNAME]'\\$1' \{\
-.\". FTP "\\$2" "\\$3"
-.\". \}
-.\". el \{\
-.\". URL "\\$2" "\\$4"
-.\". \}
-.\"..
-.de LINE
-. HTML <hr>
-..
-.\"
-.\" it doesn't make sense to use hyphenation with html, so we turn it off.
-.\"
-.hy 0
-.nr HY 0
diff --git a/tmac/eqnrc b/tmac/eqnrc
index 4c6a5a15..5b9598fa 100644
--- a/tmac/eqnrc
+++ b/tmac/eqnrc
@@ -15,12 +15,12 @@ ifdef X100 ! define X %1% !
ifdef X75-12 ! define X %1% !
ifdef X100-12 ! define X %1% !
-ifdef ps ! define ps|X|html|html2 %1% !
-ifdef X ! define ps|X|html|html2 %1% !
-ifdef html ! define ps|X|html|html2 %1% !
-ifdef html2 ! define ps|X|html|html2 %1% !
+ifdef ps ! define ps|X|html|html-old %1% !
+ifdef X ! define ps|X|html|html-old %1% !
+ifdef html ! define ps|X|html|html-old %1% !
+ifdef html-old ! define ps|X|html|html-old %1% !
-ifdef ps|X|html|html2 ! sdefine inf %"\s[\En[.s]*13u/10u]\v'12M'\(if\v'-12M'\s0"% !
+ifdef ps|X|html|html-old ! sdefine inf %"\s[\En[.s]*13u/10u]\v'12M'\(if\v'-12M'\s0"% !
ifdef dvi !
sdefine int %{type "operator" vcenter \(is}%
@@ -48,7 +48,7 @@ set big_op_spacing5 10
ifdef X ! set axis_height 32 !
-ifdef ps|X|html|html2 ! set draw_lines 1 !
+ifdef ps|X|html|html-old ! set draw_lines 1 !
ifdef ascii ! define n %1% !
ifdef latin1 ! define n %1% !
@@ -59,6 +59,6 @@ set nroff 1
!
undef X
-undef ps|X|html|html2
+undef ps|X|html|html-old
undef n
.EN
diff --git a/tmac/groff_man.man b/tmac/groff_man.man
index 5f2f1554..420e2840 100644
--- a/tmac/groff_man.man
+++ b/tmac/groff_man.man
@@ -362,7 +362,7 @@ of the next line appears in italic.
.
The default indentation is 7.2n for all output devices except for
.B grohtml
-which uses 1.2i instead.
+which ignores indentation.
.TP
.B .DT
Sets tabs every 0.5 inches.
diff --git a/tmac/groff_markup.man b/tmac/groff_mwww.man
index 74cc40f0..d57eaddb 100755
--- a/tmac/groff_markup.man
+++ b/tmac/groff_mwww.man
@@ -1,4 +1,4 @@
-.TH GROFF_MARKUP @MAN7EXT@ "@MDATE@" "Groff Version @VERSION@"
+.TH GROFF_MWWW @MAN7EXT@ "@MDATE@" "Groff Version @VERSION@"
.\" Copyright (C) 2000 Free Software Foundation, Inc.
.\" Written by Gaius Mulley (gaius@glam.ac.uk)
.\"
@@ -18,23 +18,26 @@
.\" with groff; see the file COPYING. If not, write to the Free Software
.\" Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.\"
-.\" user level guide to using the -markup macroset
+.\" user level guide to using the -mwww macroset
.\"
-.do mso arkup.tmac
-.LINE
+.do mso www.tmac
+.\" we need the .LINKS here as we use it in the middle as an example
+.\" once the user requests .LINKS then the automatic generation of links
+.\" at the top of the document is suppresed.
+.LINKS
.SH NAME
-groff_markup \- groff macros for authoring web pages
+groff_mwww \- groff macros for authoring web pages
.LINE
.SH SYNOPSIS
-.B "groff \-markup"
+.B "groff \-mwww"
[ options ]
file ...
.SH DESCRIPTION
-This manual page describes the GNU \-markup macros, which is part of the
+This manual page describes the GNU \-mwww macros, which is part of the
groff document formatting system.
The manual page is very a basic guide, and the html device driver
.RB ( grohtml )
-is still very alpha.
+has been completely rewritten but still remains as in an alpha state.
It has been included into the distribution so that a lot of people have a
chance to test it.
Note that this macro file will be automatically called (via the
@@ -106,6 +109,8 @@ An \fCHTMLINDEX\fP of 2 will mean that a heading
.sp
will not be included in the links either as it is said to have a heading
level of three.
+Another method for switching automatic headings is via the command line
+switch \fC-P-l\fP.
.TP
.B BODYCOLOR
takes five parameters: foreground, background, active hypertext link,
@@ -152,18 +157,15 @@ and
This is achieved by the following macros:
.sp
.nf
-\s-2\fC\&.MAILTO wl@gnu.org "Werner Lemberg"\fP
-.sp
-\fC\&.MAILTO Ted.Harding@nessie.mcc.ac.uk \\
-.br
-"Ted Harding" .\s+2\fP
+\s-2\fC\&.MAILTO wl@gnu.org "Werner Lemberg"
+\&.MAILTO Ted.Harding@nessie.mcc.ac.uk "Ted Harding" .\s+2\fP
.fi
.sp
Note that all the urls actually are treated as consuming no textual space
in groff.
This could be considered as a bug since it causes some problems.
-To circumvent this, \fCarkup.tmac\fP inserts a zero-width character which
-expands to a harmless space (only if in HTML mode)
+To circumvent this, \fCwww.tmac\fP inserts a zero-width character which
+expands to a harmless space (only if run with -Thtml).
.TP
.B FTP
indicates that data can be obtained via ftp.
@@ -176,9 +178,10 @@ As an example, here the location of the
ftp://ftp.ffii.org/pub/groff/devel/groff-current.tar.gz .
The macro example above was specified by:
.sp
+.nf
\s-2\fC\&.FTP "current groff development distribution" \\
-.br
ftp://ftp.ffii.org/pub/groff/devel/groff-current.tar.gz .\fP\s+2
+.fi
.sp
.TP
.B IMAGE
@@ -214,95 +217,48 @@ a local reference.
This link was achieved via placing a TAG in the URL description above;
the source looks like this:
.sp
+.nf
\s-2\fC\&.TP
-.br
\&.B URL
-.br
generates
-.br
\&.TAG URL
-.br
a URL using either two or three
-.br
arguments.
-.br
-$1 is the name of the link, $2 is the actual URL
-.br
-\fP\s+2etc.
+$1 is the name of the link, $2 is the actual URL.\fP\s+2
+.fi
.sp
-.\".TP
-.\".B CDFTP
-.\"takes four arguments.
-.\"Basically it is the FTP macro with optional local reference.
-.\"It was designed to allow the same groff source to be built on two different
-.\"machines and access the ftp data differently.
-.\"For example, on a web server you might wish for the web page to reference
-.\"a web site.
-.\"However, if you were producing a CDROM of your information you might wish
-.\"for the ftp data to be also stored on your CDROM and referenced as a file.
-.\"An example to get the current groff development distribution
-.\".CDFTP merlin "click here." \
-.\"ftp://ftp.ffii.org/pub/groff/devel/groff-current.tar.gz \
-.\"../../groff.tar.gz
-.\"The source for this CDFTP invocation is
-.\".sp
-.\"\fC\s-2\&.CDFTP merlin "click here." \
-.\"ftp://ftp.ffii.org/pub/groff/devel/groff-current.tar.gz \
-.\"../../groff.tar.gz\fP\s+2
-.\".sp
-.\"which means if the html is generated on machine \fCmerlin\fP
-.\"then generate a URL to \fC../../groff.tar.gz\fP.
-.\"Otherwise construct an FTP URL to
-.\"\fCftp://ftp.ffii.org/pub/groff/devel/groff-current.tar.gz\fP.
.TP
.B LINE
generates a full width horizontal rule.
Example:
.sp
+.nf
\fC\s-2\&.LINE\fP\s+2
+.fi
.sp
+.TP
+.B LINKS
+.TAG LINK
+requests that grohtml place the automatically generated links at this position.
+For example:
+.LINKS
.SH
SECTION HEADING LINKS
.LP
By default
.B grohtml
generates links to all section headings and places these at the top of the
-html document.
-.B Grohtml
-has to guess what a section heading looks like \(em remember that all
-.B grohtml
-actually sees is a device independent language telling it where to place
-text, draw lines, change font sizes and faces etc.
-It believes a section heading to be a line of bold text which starts at the
-left most margin.
-Consequently it may misinterpret.
-Users can turn off all heading and title guessing by giving invoking groff
-with \fCgroff -P-g\fP.
+html document. (See
+.URL LINKS #LINK
+for details of how to switch this off or alter the position.
.SH
LIMITATIONS OF GROHTML
.LP
-Although basic text can be translated in a straightforward fashion there are
-some areas where
-.B grohtml
-has to try and guess text relationship.
-In particular, whenever
-.B grohtml
-encounters text tables and indented paragraphs or two column mode it will
-try and utilize the html table construct to preserve columns.
-.B Grohtml
-also attempts to work out which lines should be automatically formatted by
-the browser.
-Ultimately in trying to make reasonable guesses most of the time it will
-make mistakes.
-Hopefully these mistakes will happen less and less as we get bug reports
-and patches :-).
-.PP
-Tbl, pic, eqn's are also generated using images which may be
-considered a limitation.
+Tbl information is currently rendered as a png image.
.SH FILES
-@MACRODIR@/markup.tmac (a wrapper for arkup.tmac)
+@MACRODIR@/mwww.tmac (a wrapper for www.tmac)
.br
-@MACRODIR@/arkup.tmac
+@MACRODIR@/www.tmac
.SH "SEE ALSO"
.BR groff (@MAN1EXT@),
.BR @g@troff (@MAN1EXT@)
@@ -310,7 +266,7 @@ considered a limitation.
.LP
.SH AUTHOR
.B Grohtml
-is written by
+was written by
.MAILTO gaius@glam.ac.uk "Gaius Mulley"
.LINE
.SH BUGS
@@ -318,4 +274,3 @@ Report bugs to the
.MAILTO bug-groff@gnu.org "Groff Bug Mailing List" .
Include a complete, self-contained example that will allow the bug to be
reproduced, and say which version of groff you are using.
-.LINE
diff --git a/tmac/groff_tmac.man b/tmac/groff_tmac.man
index bd8f4d86..331fe807 100755
--- a/tmac/groff_tmac.man
+++ b/tmac/groff_tmac.man
@@ -431,7 +431,7 @@ in the groff source package.
.LP
The groff tmac macro packages are
.BR groff_man (@MAN7EXT@),
-.BR groff_markup (@MAN7EXT@),
+.BR groff_mwww (@MAN7EXT@),
.BR groff_mdoc (@MAN7EXT@),
.BR groff_mdoc.samples (@MAN7EXT@),
.BR groff_me (@MAN7EXT@),
diff --git a/tmac/html2.tmac b/tmac/html-old.tmac
index e98aa4ae..662cf58f 100755
--- a/tmac/html2.tmac
+++ b/tmac/html-old.tmac
@@ -1,4 +1,4 @@
-.\" html2.tmac
+.\" html-old.tmac
.\"
.nr _C \n(.C
.cp 0
@@ -43,7 +43,7 @@
.if !c\(rh .char \(rh ->
.if !c\(bq .tr \(bq,
.if !c\(aq .tr \(aq'
-.if '\*(.T'html' .char \[radicalex] \h'-\w'\(sr'u'\[radicalex]\h'\w'\(sr'u'
+.if '\*(.T'html-old' .char \[radicalex] \h'-\w'\(sr'u'\[radicalex]\h'\w'\(sr'u'
.if !\n(_C .mso pspic.tmac
.cp \n(_C
.\" now turn off all headers and footers for ms, me and mm macro sets
@@ -55,10 +55,8 @@
.if d of .of '''
.if d oh .oh '''
.if d eh .eh '''
-.\" it doesn't make sense to use hyphenation with html, so we turn it off.
+.\" it doesn't make sense to use hyphenation with html-old, so we turn it off.
.hy 0
.nr HY 0
.\" avoid line breaks after hyphen-like characters.
.cflags 0 -\(hy\(em\(en\[shc]
-.\" now load the tag macros
-.mso html-tags.tmac
diff --git a/tmac/html-tags.tmac b/tmac/html-tags.tmac
deleted file mode 100755
index e1715afa..00000000
--- a/tmac/html-tags.tmac
+++ /dev/null
@@ -1,49 +0,0 @@
-.\" html-tags.tmac - issues tags for post-html2
-.\"
-.als html-sp-old sp
-.de sp
-\X^html-tag:.sp \\$*^
-. html-sp-old \\$*
-..
-.als html-br-old br
-.de br
-\X^html-tag:.br \\$*^
-. html-br-old \\$*
-..
-.als html-ce-old ce
-.de ce
-\X^html-tag:.ce \\$*^
-. html-ce-old \\$*
-..
-.als html-tl-old tl
-.de tl
-\X^html-tag:.tl \\$*^
-. html-tl-old \\$*
-..
-.als html-in-old in
-.de in
-\X^html-tag:.in \\$*^
-. html-in-old \\$*
-..
-.als html-ti-old ti
-.de ti
-\X^html-tag:.ti \\$*^
-. html-ti-old \\$*
-..
-.als html-ta-old ta
-.de ta
-\X^html-tag:.ta \\$*^
-. html-ta-old \\$*
-..
-.\" these definitions should be removed once grohtml2 has been finished
-.\" and arkup.html is working with html2 (actually expect html2 to replace html).
-.de HTML
-. if '\*(.T'html2' \{\
-.\" the following line makes the vertical mode leave, so to say
-\&
-\X^html:\\$*^
-. \}
-..
-.de IMAGE
-. HTML <img src="\\$1">
-..
diff --git a/tmac/html.tmac b/tmac/html.tmac
index 05457807..199245b1 100644
--- a/tmac/html.tmac
+++ b/tmac/html.tmac
@@ -10,13 +10,6 @@
.ftr HO HI
.ftr HX HBI
.ftr NX NBI
-.char \(ru \D'l .5m 0'
-.char \(ul \v'.25m'\D'l .5m 0'\v'-.25m'
-.char \(br \v'.25m'\D'l 0 -1m'\v'.75m'
-.char \(rn \v'-.75m'\D'l .5m 0'\v'.75m'
-.\" .char ~ \v'-.55m'\\s[\\n(.s/2u]\v'.2m'\(ti\v'-.2m'\s0\v'.55m'
-.\" .char ^ \v'-.55m'\\s[\\n(.s/2u]\v'.3m'\(ha\v'-.3m'\s0\v'.55m'
-.if !c\(va .char \(va \o'\(ua\(da'
.if !c\(em .char \(em --
.if !c\(en .char \(en \-
.if !c\(fi .char \(fi fi
@@ -24,39 +17,32 @@
.if !c\(ff .char \(ff ff
.if !c\(Fi .char \(Fi ffi
.if !c\(Fl .char \(Fl ffl
-.if !c\(ci .char \(ci \v'-.25m'\h'.05m'\D'c .5m'\h'.05m'\v'.25m'
-.if !c\(sq .char \(sq \h'.05m'\D'l .5m 0'\D'l 0 -.5m'\D'l -.5m 0'\D'l 0 .5m'\h'.55m'
-.if !c\(ga .char \(ga \Z'\v'-.7m'\D'l .22m .18m''\h'.33m'
-.if !c\(dg .char \(dg \Z'\h'.25m'\v'.15m'\D'l 0 -.8m'\v'.2m'\h'-.195m'\
-\D'l .39m 0''\h'.5m'
-.if !c\(dd .char \(dd \Z'\h'.25m'\v'.15m'\D'l 0 -.8m'\v'.2m'\h'-.195m'\
-\D'l .39m 0'\v'.4m'\D'l -.39m 0''\h'.5m'
.if !c\(lq .char \(lq ``
.if !c\(rq .char \(rq ''
.if !c\(Bq .char \(bq ,,
-.if !c\(OE .char \(OE O\h'-.25m'E
-.if !c\(oe .char \(oe o\h'-.14m'e
-.if !c\(ah .char \(ah \v'-.55m'\s[\En[.s]/2u]v\s0\v'.55m'
-.if !c\(ao .char \(ao \v'-.55m'\s[\En[.s]*6u/10u]\D'c .25m'\s0\v'.55m'
-.if !c\(ho .char \(ho \s[\En[.s]/2u]\v'.4m'c\v'-.4m'\s0
+.if !c\(OE .char \(OE OE
+.if !c\(oe .char \(oe oe
.if !c\(lh .char \(lh <-
.if !c\(rh .char \(rh ->
.if !c\(bq .tr \(bq,
.if !c\(aq .tr \(aq'
-.if '\*(.T'html' .char \[radicalex] \h'-\w'\(sr'u'\[radicalex]\h'\w'\(sr'u'
.if !\n(_C .mso pspic.tmac
.cp \n(_C
.\" now turn off all headers and footers for ms, me and mm macro sets
-.if d EF .EF '''
-.if d EH .EH '''
-.if d OF .OF '''
-.if d OH .OH '''
-.if d ef .ef '''
-.if d of .of '''
-.if d oh .oh '''
-.if d eh .eh '''
+.if d EF .EF ''''
+.if d EH .EH ''''
+.if d OF .OF ''''
+.if d OH .OH ''''
+.if d ef .ef ''''
+.if d of .of ''''
+.if d oh .oh ''''
+.if d eh .eh ''''
+.tl ''''
.\" it doesn't make sense to use hyphenation with html, so we turn it off.
+.\" avoid line breaks after hyphen-like characters.
.hy 0
.nr HY 0
.\" avoid line breaks after hyphen-like characters.
.cflags 0 -\(hy\(em\(en\[shc]
+.pl 99999
+.\" eof of file, make sure this is the last time
diff --git a/tmac/markup.tmac b/tmac/mwww.tmac
index 787b6db6..787b6db6 100755
--- a/tmac/markup.tmac
+++ b/tmac/mwww.tmac
diff --git a/tmac/pspic.tmac b/tmac/pspic.tmac
index 77b52ec2..ab066686 100644
--- a/tmac/pspic.tmac
+++ b/tmac/pspic.tmac
@@ -5,18 +5,25 @@
.\" the picture would go.
.de PSPIC
.nr ps-offset-mode 0
-.if '\\$1'-L' \{\
+.ie '\\$1'-L' \{\
. nr ps-offset-mode 1
. shift
+. HTML-DO-IMAGE \\$1 l
.\}
-.if '\\$1'-R' \{\
-. nr ps-offset-mode 2
-. shift
-.\}
-.if '\\$1'-I' \{\
-. nr ps-offset-mode 3
-. nr ps-offset (m;\\$2)
-. shift 2
+.el \{\
+. ie '\\$1'-R' \{\
+. nr ps-offset-mode 2
+. shift
+. HTML-DO-IMAGE \\$1 r
+. \}
+. el \{\
+. if '\\$1'-I' \{\
+. nr ps-offset-mode 3
+. nr ps-offset (m;\\$2)
+. shift 2
+. \}
+. HTML-DO-IMAGE \\$1 i
+. \}
.\}
.br
.psbb \\$1
@@ -49,4 +56,5 @@
. br
. sp \\n[ps-desht]u
.\}
+.HTML-IMAGE-END
..
diff --git a/tmac/s.tmac b/tmac/s.tmac
index 507e5547..9a8d65e9 100644
--- a/tmac/s.tmac
+++ b/tmac/s.tmac
@@ -144,6 +144,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
. als FE @FE
.\}
.wh 0 pg@top
+.CHECK-FOOTER-AND-KEEP
..
.wh 0 cov*first-page-init
.\" This handles the case where FS occurs before TL or LP.
@@ -165,13 +166,14 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.rn @AB AB
.rn @AU AU
.rn @AI AI
-.di cov*tl-div
+.if !'\*(.T'html' .di cov*tl-div
.par@reset
.ft B
.ps +2
.vs +3p
.ll (u;\\n[LL]*5/6)
.nr cov*n-au 0
+.HTML-TAG ".tl"
..
.de @AU
.par@reset
@@ -186,7 +188,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.ps \\n[PS]
..
.de @AI
-.par@reset
+.if !'\*(.T'html' .par@reset
.if !'\\n(.z'' \{\
. br
. di
@@ -249,7 +251,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
. di
.\}
.cov*ab-init
-.di cov*ab-div
+.if !'\*(.T'html' .di cov*ab-div
.par@ab-indent
.par@reset
.if !'\\$1'no' \{\
@@ -261,9 +263,20 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.\}
.ns
.@PP
+.if '\*(.T'html' \{\
+. cov*tl-au-print
+. als cov*tl-au-print @nop
+. par@reset-env
+. par@reset
+. cov*print
+.\}
..
.de AE
-.ie '\\n(.z'cov*ab-div' \{\
+.ie '\*(.T'html' \{\
+. als AE cov*err-not-again
+.\}
+.el \{\
+. ie '\\n(.z'cov*ab-div' \{\
. als AE cov*err-not-again
. br
. di
@@ -271,8 +284,9 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
. par@reset-env
. par@reset
. cov*print
+. \}
+. el .@error AE without AB
.\}
-.el .@error AE without AB
..
.de @div-end!cov*ab-div
.AE
@@ -289,6 +303,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
. bp 1
. als FS @FS
. als FE @FE
+. CHECK-FOOTER-AND-KEEP
. \}
. br
.\}
@@ -299,7 +314,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.cov*tl-au-print
.sp 3
.if d cov*ab-div \{\
-. nf
+. if !'\*(.T'html' . nf
. cov*ab-div
.\}
.sp 3
@@ -321,6 +336,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.\}
.als FS @FS
.als FE @FE
+.CHECK-FOOTER-AND-KEEP
.\" If anything was printed below where the footer line is normally printed,
.\" then that's an overflow.
.if -\\n[FM]/2+1v+\\n[cov*page-length]<\\n[nl] .@error cover sheet overflow
@@ -345,7 +361,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.rs
.sp 3
.ce 9999
-.cov*tl-div
+.if d cov*tl-div .cov*tl-div
.nr cov*i 1
.nr cov*sp 1v
.while \\n[cov*i]<=\\n[cov*n-au] \{\
@@ -461,6 +477,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
. nr pg*gutw \\n[LL]-(\\n[pg@ncols]*\\n[pg@colw])/(\\n[pg@ncols]-1)
. el .nr pg*gutw 0
.\}
+.HTML-TAG ".mc \\n[pg@ncols] \\n[pg@colw] \\n[pg*gutw]"
.mk pg*col-top
.ns
.nr pg*col-num 0
@@ -985,6 +1002,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.if !rHY .nr HY 14
.hy \\n[HY]
.TA
+.CHECK-FOOTER-AND-KEEP
..
.de par*vs
.\" If it's too big to be in points, treat it as units.
@@ -1206,6 +1224,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.\" start boxed text
.de B1
.br
+.HTML-IMAGE
.di par*box-div
.nr \\n[.ev]:li +1n
.nr \\n[.ev]:ri +1n
@@ -1242,6 +1261,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
. par*box-draw \\n[.i]u \\n[.l]u-(\\n[.H]u==1n*1n)
.\}
.el .@error B2 without B1
+.HTML-IMAGE-END
..
.de par*box-mark-top
.ie '\\n[.z]'' \{\
@@ -1280,6 +1300,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.ne 3v+\\n[\\n[.ev]:PD]u+\\n(.Vu
.sp 1
.ft B
+.HTML-TAG ".SH 1"
..
.\" TL, AU, and AI are aliased to these in cov*ab-init.
.de par@TL
@@ -1289,6 +1310,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.ps +2
.vs +3p
.ce 9999
+.HTML-TAG ".tl"
..
.de par@AU
.par@finish
@@ -1401,6 +1423,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.nr nh*hl 0
.\" numbered heading
.de @NH
+.HTML-TAG ".NH \\$1"
.ie '\\$1'S' \{\
. shift
. nr nh*hl 0
@@ -1868,5 +1891,36 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
.ds ? \(r?\" upside down ?
.ds ! \(r!\" upside down !
..
+.de CHECK-FOOTER-AND-KEEP
+.\" it might be better to als FS -> B1 and FE -> B2
+.\" however this produced wierd results, so I've moved back to a more reliable
+.\" but less interesting solution --fixme--
+. if '\*(.T'html' \{\
+. rm KF
+. als KF KS
+. rm FS
+. de FS
+. br
+. HTML-IMAGE
+\\..
+. rm FE
+. de FE
+. br
+. HTML-IMAGE-END
+\\..
+. \}
+. if r ps4html \{\
+. rm FS
+. de FS
+. br
+. HTML-IMAGE
+\\..
+. rm FE
+. de FE
+. br
+. HTML-IMAGE-END
+\\..
+. \}
+..
.par@load-init
.\" Make sure that no blank lines creep in at the end of this file.
diff --git a/tmac/troffrc b/tmac/troffrc
index 9f2a212a..9e71e774 100644
--- a/tmac/troffrc
+++ b/tmac/troffrc
@@ -16,11 +16,12 @@
.do ds troffrc!cp1047 tty.tmac
.do ds troffrc!lj4 lj4.tmac
.do ds troffrc!lbp lbp.tmac
-.do ds troffrc!html arkup.tmac
+.do ds troffrc!html www.tmac
+.do ds troffrc!html-old www.tmac
.do if d troffrc!\*[.T] \
. do mso \*[troffrc!\*[.T]]
.do rm troffrc!ps troffrc!Xps troffrc!dvi troffrc!X75 troffrc!X75-12 \
-troffrc!X100 troffrc!X100-12 troffrc!lj4 troff!lbp troffrc!html
+troffrc!X100 troffrc!X100-12 troffrc!lj4 troff!lbp troffrc!html troffrc!html-old
.ie '\*(.T'cp1047' .do tr \[char65]
.el .do tr \[char160]
.\" Set the hyphenation language to `us'.
diff --git a/tmac/troffrc-end b/tmac/troffrc-end
index 8f97605c..930e6afd 100644
--- a/tmac/troffrc-end
+++ b/tmac/troffrc-end
@@ -2,6 +2,19 @@
.\" final startup file for troff
.\" this file is parsed after all macro sets have been read
.\"
-.if '\*(.T'html' .mso html.tmac
-.if '\*(.T'html2' .mso html2.tmac
+.if '\*(.T'html' .mso html.tmac
+.if '\*(.T'html-old' .mso html-old.tmac
+.\" if we are running the postscript device for html images then load -mwww
+.\"
+.if r ps4html .mso www.tmac
+.\"
+.\" for all other devices blank out these macros
+.\"
+.if !d HTML-IMAGE-INLINE .ds HTML-IMAGE-INLINE
+.if !d HTML-IMAGE .ds HTML-IMAGE
+.if !d HTML-IMAGE-RIGHT .ds HTML-IMAGE-RIGHT
+.if !d HTML-IMAGE-LEFT .ds HTML-IMAGE-LEFT
+.if !d HTML-IMAGE-END .ds HTML-IMAGE-END
+.if !d HTML-TAG .ds HTML-TAG
+.if !d HTML-DO-IMAGE .ds HTML-DO-IMAGE
.\" Don't let blank lines creep in here.
diff --git a/tmac/www.tmac b/tmac/www.tmac
new file mode 100644
index 00000000..0297a265
--- /dev/null
+++ b/tmac/www.tmac
@@ -0,0 +1,213 @@
+.\" www.tmac
+.\"
+.\" A simple set of macros to provide HTML documents with basic
+.\" www functionality. It will work with any macro set.
+.\"
+.\" compute the value of '\*(.T'html-old':'\*(.T'html'
+.\" --fixme-- it would be nice to allow logical or with strings
+.nr html-or-html-old 0
+.if '\*(.T'html-old' .nr html-or-html-old 1
+.if '\*(.T'html' .nr html-or-html-old 1
+.\"
+.\"
+.\"
+.de HTML
+. if \\n[html-or-html-old] \{\
+.\" the following line makes the vertical mode leave, so to say
+\&
+\X^html:\\$*^
+. \}
+..
+.de HTMLINDEX
+. if \\n[html-or-html-old] \X^index:\\$*^
+..
+.\"
+.\" BODYCOLOR - $1 is foreground color
+.\" $2 is background color
+.\" $3 is the color of an active hypertext link
+.\" $4 is the color of a hypertext link not yet visited
+.\" $5 is the color of a visited hypertext link
+.\"
+.de BODYCOLOR
+. HTML <body text=\\$1 bgcolor=\\$2 link=\\$3 alink=\\$4 vlink=\\$5>
+..
+.\"
+.\" BACKGROUND - $1 is the background image file
+.\"
+.de BACKGROUND
+. HTML <body background=\\$1>
+..
+.\"
+.\" URL - $1 is the classical underlined blue text
+.\" $2 is the url
+.\" $3 is optional stuff printed immediately after $3
+.\"
+.de URL
+. ie \\n[html-or-html-old] \{\
+. HTML <a href="\\$2">\\$1</a>\\$3
+. \}
+. el \{\
+\\$1 \(la\fC\\$2\fP\(ra\\$3
+. \}
+..
+.\"
+.\" FTP - $1 is the classical underlined blue text
+.\" $2 is the ftp url
+.\" $3 is optional stuff printed immediately after $2
+.de FTP
+. ie \\n[html-or-html-old] \{\
+. HTML <a href=\\$2>\\$1</a>\\$3
+. \}
+. el \{\
+\\$1 \(la\fC\\$2\fP\(ra\\$3
+. \}
+..
+.\"
+.\" MAILTO - generate html email reference
+.\" $1 is the email address (without the `mailto:' prefix)
+.\" $2 is the optional name
+.\" $3 is optional stuff printed immediately after $2 (resp. $1)
+.\"
+.\" example:
+.\"
+.\" Foobar has been written by
+.\" .MAILTO fred@foo.bar "Fredrick Bloggs" .
+.\"
+.de MAILTO
+.\"
+.\" force reset after a potential heading by performing some motion..
+.\" how do we do this --fixme--
+.\" \h'\w' ''\h'-\w' '' doesn't work..
+. ie \\n[html-or-html-old] \{\
+. ie '\\$2'' \{\
+. HTML "<a href=mailto:\\$1>\\$1</a>\\$3"
+. \}
+. el \{\
+. HTML "<a href=mailto:\\$1>\\$2</a>\\$3"
+. \}
+. \}
+. el \{\
+. ie '\\$2'' \{\
+\fC\\$1\fP\\$3
+. \}
+. el \{\
+\\$2 \(la\fC\\$1\fP\(ra\\$3
+. \}
+. \}
+..
+.\"
+.\" TAG - generate an html name $1
+.\"
+.de TAG
+. HTML <a name="\\$1"></a>
+..
+.\"
+.\" IMAGE - reference an image
+.\" $1 is the image file
+.\" $2 is the x width (default if absent 400 pixels)
+.\" $3 is the y width (default if absent is the x value)
+.\"
+.de IMAGE
+. ie \\n[html-or-html-old] \{\
+. nr HTMLWIDTH 400
+. if !'\\$2'' \{\
+. nr HTMLWIDTH \\$2
+. \}
+. nr HTMLHEIGHT \\n[HTMLWIDTH]
+. if !'\\$3'' \{\
+. nr HTMLHEIGHT \\$3
+. \}
+. HTML-TAG ".centered-image"
+. HTML <img src="\\$1" width=\\n[HTMLWIDTH] height=\\n[HTMLHEIGHT]>
+. \}
+. el \{\
+. B1
+\(la\fC\\$1\fP\(ra
+. B2
+. \}
+..
+.\" HTML-TAG - emit a tag for the new grohtml
+.de HTML-TAG
+. if '\*(.T'html' \{\
+.\" the following line makes the vertical mode leave, so to say
+\&
+\X^html-tag:\\$*^
+. \}
+..
+.\" LINKS - emit the automatically collected links derived from section/numbered
+.\" headings at this position.
+.de LINKS
+. HTML-TAG ".links"
+..
+.\"
+.\" LINE - produce a horizontal line
+.\"
+.de LINE
+. HTML <hr>
+..
+.\"
+.\" supplimentary macros used by other macro sets
+.\"
+.\" here are some tags specially for -Tps or -Thtml when invoked by pre-html to
+.\" generate png images from postscript.
+.\"
+.\" HTML-DO-IMAGE - tells troff to issue an image marker which can be read back by pre-html
+.\"
+.de HTML-DO-IMAGE
+. if r ps4html .html-begin \{\
+. html-image \\$2 \\$1.png
+. bp
+. tl '''
+\O0\O1
+. \}
+. if '\*(.T'html' .html-begin \{
+. html-image \\$2 \\$1.png
+\O0
+. \}
+..
+.\"
+.\" HTML-IMAGE-END - terminates an image for html
+.\"
+.de HTML-IMAGE-END
+. if r ps4html .html-end \{\
+\O2\O1
+. \}
+. if '\*(.T'html' .html-end \{
+\O2\O1
+. \}
+..
+.nr png-no 0
+.\"
+.\" MAKE-UNIQUE-NAME - generates another unique name
+.\"
+.de MAKE-UNIQUE-NAME
+. nr png-no \\n[png-no]+1
+. ds HTML-UNIQUE-NAME \\n(.F-auto-\\n[png-no]
+..
+.\"
+.\" HTML-IMAGE - is the same name as a tag generated from eqn/tbl/pic.
+.\" Although the tags generated via the preprocessor
+.\" are given image names by pre-html and troff.
+.\" The macros below can only be invoked by *other macro sets*
+.\" not user troff input since the contents of macro sets are
+.\" not seen by pre-html.
+.\"
+.de HTML-IMAGE
+.\" generates a centered image
+. MAKE-UNIQUE-NAME
+. HTML-DO-IMAGE \\*[HTML-UNIQUE-NAME] c
+..
+.de HTML-IMAGE-RIGHT
+. MAKE-UNIQUE-NAME
+. HTML-DO-IMAGE \\*[HTML-UNIQUE-NAME] r
+..
+.de HTML-IMAGE-LEFT
+. MAKE-UNIQUE-NAME
+. HTML-DO-IMAGE \\*[HTML-UNIQUE-NAME] l
+..
+.de HTML-IMAGE-INLINE
+. MAKE-UNIQUE-NAME
+. HTML-DO-IMAGE \\*[HTML-UNIQUE-NAME] i
+..
+.nr HY 0
+.nh