summaryrefslogtreecommitdiffstats
path: root/contrib/pdfmark
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--contrib/pdfmark/ChangeLog683
-rw-r--r--contrib/pdfmark/PROBLEMS32
-rw-r--r--contrib/pdfmark/README57
-rw-r--r--contrib/pdfmark/TODO60
-rw-r--r--contrib/pdfmark/cover.ms70
-rw-r--r--contrib/pdfmark/pdfmark.am99
-rw-r--r--contrib/pdfmark/pdfmark.ms2831
-rw-r--r--contrib/pdfmark/pdfmark.tmac1953
-rw-r--r--contrib/pdfmark/pdfroff.1.man981
-rw-r--r--contrib/pdfmark/pdfroff.sh682
-rw-r--r--contrib/pdfmark/sanitize.tmac170
-rw-r--r--contrib/pdfmark/spdf.tmac328
12 files changed, 7946 insertions, 0 deletions
diff --git a/contrib/pdfmark/ChangeLog b/contrib/pdfmark/ChangeLog
new file mode 100644
index 0000000..1c5a18f
--- /dev/null
+++ b/contrib/pdfmark/ChangeLog
@@ -0,0 +1,683 @@
+2023-02-18 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * pdfmark.am (uninstall-pdfmark-hook): Simplify uninstallation.
+ Try to remove the configured `pdfdocdir` in the event it is
+ empty, but do not fail if it isn't. (It can be a directory
+ shared with other groff components; we don't know in what order
+ the uninstall targets will serialize, but the last one run
+ should succeed.)
+
+2022-09-20 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * sanitize.tmac: Move comment to where escape sequences are
+ recognized. Problem arose in commit 058b63ce3d, 2021-09-04.
+
+ troff:.../contrib/pdfmark/sanitize.tmac:162: warning: macro '\"'
+ not defined
+
+2022-05-20 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * pdfmark.am: Rename `BUILD_PDFDOC` to `USE_GROPDF`.
+
+2022-03-30 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * pdfmark.am: Eliminate `PDFMARK_TFLAG` and `PDFMARK_PFLAG` Make
+ macros; they were expanded in only one place.
+ (PDFROFF): Track rename of Make macro `TFLAG` to `MFLAG`.
+
+2022-03-30 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * cover.ms: Die horribly if `PSPIC` call fails.
+
+2022-03-26 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * pdfmark.am (PDFDOCFILES): Replace hard-coded "gnu.eps"
+ file name with expansion of `DOC_GNU_EPS`.
+ (contrib/pdfmark/pdfmark.pdf): Pass `-I` option to pdfroff(1) to
+ enable location of "gnu.eps" file.
+
+2021-10-24 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Adapt to accommodate global XH and XN implementations.
+
+ cf. <https://savannah.gnu.org/bugs/?58946#comment13>
+
+ * spdf.tmac (XH-INIT, XN-INIT, XH-UPDATE-TOC): Delete definitions;
+ the defaults, provided by s.tmac, are now sufficient.
+ (XH-REPLACEMENT, XN-REPLACEMENT): Define these, rather than...
+ (XH, XN): ...these, respectively.
+
+2021-10-02 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Make a minor layout adjustment.
+
+ * pdfmark.ms (Section 2.4.3): Add a vertical space reservation, to
+ avoid a widow line at the end of the paragraph explaining use of...
+ (PDFHREF.Y): ...this computed register, in the definition of...
+ (PDFBOOKMARK.VIEW): ...this.
+
+2021-10-02 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Clarify references to use of the -Tpdf option.
+
+ * pdfmark.ms (Section 2, Section 3.1): Add footnotes, indicating that
+ only "-Tps" and "-Tpdf" output formats are supported, and that "-Tpdf"
+ may avoid a separate step, to convert from PostScript to PDF.
+
+2021-10-02 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Work around misplacement of link "hot-spots" in footnotes.
+
+ * pdfmark.ms (pdfhref-nobreak): New document-local macro; used instead
+ of "pdfhref", this forces paragraph adjustment before placement of any
+ unbreakable link text, for which line-wrap may be required. Currently
+ observed only within footnotes, without adjustment, the "hot-spot" for
+ the link may be placed 1v above its associated text.
+
+2021-10-02 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Link footnote reference marks to footnote text.
+
+ * pdfmark.ms (FP): Redefine locally; replace s.tmac default.
+ (FF): Do not redefine; our FP replacement macro does not use it.
+ [d FS-MARK] (FS-MARK): Redefine locally; map it to...
+ (pdf:fn.mark): ...this locally defined macro.
+ [!d FS-MARK] (@FS): Rename s.tmac implementation as...
+ (pdf:fn.record): ...this, then redefine @FS itself, to call...
+ (pdf:fn.mark, pdf:fn.record): ...these, in respective order.
+ (groff-1.19.1, GhostScript-8.14): Update footnote reference syntax.
+ (Ghostscript-8.14, MSYS): Emulate sentence space after footnote mark.
+ (*): Replace s.tmac string definition; make it equivalent to "\c",
+ after renaming its original implementation as...
+ (pdf:fn.index): ...this; synchronize references with changes to...
+ (pdf:fn.index.count): ...this new locally defined register; it is
+ auto-incremented by one, as each footnote is placed.
+
+2021-10-01 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Incorporate user-defined TOC leader style.
+
+ * pdfmark.ms: Make some comment tidy-up adjustments.
+ (TC-LEADER, TC-MARGIN): Define them, to take advantage of new
+ s.tmac features; cf. <https://savannah.gnu.org/bugs/?61157>.
+
+2021-09-18 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Factor a further unnecessary macro out of spdf.tmac
+
+ * spdf.tmac (XR): Remove it; relocate it to...
+ * pdfmark.ms (XR): ...here.
+
+2021-09-13 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Add comments to annotate locally-defined font change macros.
+
+ * pdfmark.ms (EM): Annotate this locally-defined emphasis macro...
+ (CWB, CWI, CWBI): ...these constant width font interpolation macros...
+ (=): ...and this locally-defined IP tag variant string.
+
+2021-09-13 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Update defunct internet URL references.
+
+ * pdfmark.ms (pdfmark-manual): Adobe moved the document (again);
+ update the document reference macro, to follow the URL relocation.
+ (www.mingw.org): The MinGW Project has relinquished this domain;
+ update the URL reference, to follow web-site relocation to...
+ (mingw.osdn.io): ...here.
+
+2021-09-13 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Factor document-specific bloat out of spdf.tmac
+
+ * spdf.tmac: Reorganize; add many comments.
+ (XN): Retained, but reimplemented, to serve as...
+ (XH, XN): ...both of these; add callback hooks for...
+ (XH-INIT, XN-INIT, XH-UPDATE-TOC): ...these; provide no-op stubs;
+ factor out TOC collection code, delegating to XH-UPDATE-TOC.
+ (opt*XN-N, opt*XN-S, opt*XN-X): Rename internal macros to...
+ (de spdf:XH-N, de spdf:XH-S, de spdf:XH-X): ...these, respectively.
+ (AN, @AN, IE, IS, LU, NN, PXREF, SAME-PAGE, XM): Delete; we do not
+ require these; if users do, they should define their own.
+ (pdf@toc): Delete internal macro; fold body into...
+ (TC): ...this.
+
+ * pdfmark.ms (XH-UPDATE-TOC): Implement callback; it is based on...
+ (XN): ...original implementation of this, factored out of spdf.tmac,
+ but with significant simplification, to remove unnecessary code.
+ (XNVS1, XNVS2, XNVS3): Tighten vertical spacing.
+
+2021-09-04 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Reduce potential for user-space exposure of "ms" internals.
+
+ * spdf.tmac (@NH): Append to s.tmac macro; assign...
+ (spdf:nh*hl): ...this new internal register; alias it to...
+ (.NH): ...this new public name, hence making it track...
+ (nh*hl): ...this s.tmac internal numeric register.
+ (XN): Use \n[.NH] instead of \n[nh*hl].
+
+2021-09-03 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Sanitize text for use in PDF document outlines.
+
+ * sanitize.tmac: New file; it implements...
+ (sanitize): ...this new macro; interprets its first argument as a
+ string name, and copies its remaining arguments to the named string,
+ discarding specific embedded troff escape sequences; currently...
+ (\F): ...only this is identified as "specifically discardable".
+
+ * pdfmark.am (TMACFILES): Add sanitize.tmac
+
+ * spdf.tmac (mso): Include sanitize.tmac
+ (xn*ref, xn*argc): Rename all occurrences...
+ (spdf:refname, spdf:argc): ...to these, respectively.
+ (XN): Stop inserting $* directly into PDF outlines; instead, use...
+ (spdf:bm.text): ...this new string; this is locally defined by...
+ (spdf:bm.define): ...this new macro; passed the original $* from
+ XN, this itself, is locally defined as a redirectable alias for...
+ (spdf:bm.basic): ...this new local macro; it simply copies $*,
+ passed from XN, to the string named by its first argument, (which is
+ always spdf:bm.text), so reproducing previous behaviour.
+ (opt*XN-S): New macro; defined for internal use only, it adds a "-S"
+ option to XN, such that, when specified, it temporarily redirects...
+ (spdf:bm.define): ...this macro mapping alias to...
+ (sanitize): ...this.
+
+ * pdfmark.ms (XN): Add "-S" option for all headings which include...
+ (\F[C]...\F[]): ...this escape sequence.
+
+2021-08-21 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Define, and use registered trade mark strings.
+
+ * pdfmark.ms (Adobe, Acrobat, Distiller, PostScript, Microsoft):
+ Define as strings. Each expands to its own name, followed by the
+ registered trademark symbol, as a superscript, and optional trailing
+ punctuation, below the superscript. Use each as required.
+
+2021-08-21 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Prefer "-ize" to "-ise" where etymology permits.
+
+ * pdfmark.ms: For all verbs, and their derivative nouns, for which
+ British English allows either "-ise" or "-ize" as ending, prefer the
+ "-ize" form of verb, and "-ization" form of noun, throughout.
+
+2021-08-20 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Correct a spelling error.
+
+ * pdfmark.ms (Section 2.5.3.1): Fix typo: s/exanple/example/.
+
+2021-08-20 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Space out section headings in pdfmark.ms source.
+
+ * pdfmark.ms (.NH): Precede each instance by one null request, to
+ improve readability.
+
+2021-08-18 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Refine pdfroff "missing ghostscript" diagnostic.
+
+ * pdfroff.sh [$GS = ":"]: Fix typo: s/connot/cannot/; refine text.
+
+2020-12-25 G. Branden Robinson <g.branden.robinson@gmail.com>
+
+ * pdfmark.am (PDFROFF): Call pdfroff without
+ `--keep-temporary-files` option. Temporary directories are
+ created with mktemp(1) and files with an embedded process
+ identifier, which frustrates reproducible builds.
+
+ See <https://savannah.gnu.org/bugs/?57218>.
+
+2018-02-28 Werner LEMBERG <wl@gnu.org>
+
+ * pdfmark.am (pdfmark.pdf): Use $(GROFF_V).
+
+2018-02-28 Werner LEMBERG <wl@gnu.org>
+
+ * pdfmark.am (pdfroff): Use $(AM_V_GEN) to silence file generation.
+
+2015-08-22 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * pdfroff.1.man: Rename `pdfroff.man'.
+
+ * pdfmark.am: Add `Last update'. Setup Emacs mode.
+
+2015-08-05 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * pdfmark.am: Add `Last update'. Setup Emacs mode.
+
+2015-04-03 Werner LEMBERG <wl@gnu.org>
+
+ * pdfroff.man: Make it work in compatibility mode.
+
+2014-10-14 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Deduce "--no-toc-relocation" from input stream (revisited).
+
+ * pdfroff.sh (WRKFILE): Correct malformed sed expression.
+
+ * spdf.tmac (TC): Prefer value of pdfroff's PHASE register to defined
+ state of pdf:href.map, when choosing to emit control record to...
+ (toc_relocation): ...enable this.
+
+2014-10-13 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Deduce "--no-toc-relocation" from input stream.
+
+ * pdfroff.sh (WRKFILE): Scan it for "pdfroff-option:set" records;
+ apply settings; check for equivalent of "--no-toc-relocation" option.
+
+ * spdf.tmac (TC): Emit "pdfroff-option:set toc-relocation=enabled".
+
+2014-10-12 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Avoid spurious user visible control messages on stderr.
+
+ * pdfroff.sh (REFCOPY): Ensure that at least one pdfhref mark of type
+ 'Z' will remain in the reference map, after all references have been
+ resolved; this is required, to suppress writing of reference control
+ records to stderr during the final PDF output processing phase.
+
+2014-09-04 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * all pdfmark source files: Copying (remove last updates and
+ replace years with package years) and Emacs setup.
+
+2014-03-30 Steffen Nurpmeso <sdaoden@yandex.com>
+
+ * Makefile.sub: Put straight error-prevention prefixes for `rm'.
+
+2014-03-29 Steffen Nurpmeso <sdaoden@yandex.com>
+
+ * Makefile.sub: Handle examples separately, controlled by
+ $(make{_,_install_,_uninstall_}examples).
+
+2013-01-28 Deri James <deri@chuzzlewit.myzen.co.uk>
+
+ * pdfmark.tmac (pdfmark, pdf:composed): Use `\!' instead of `\X'.
+
+ With the old pdfmark there are gaps between two of the lines, but
+ with the new version they disappear. The use of `.br' and `.in 0'
+ is arbitrary any request which causes an implicit break could be
+ used. Two breaks together only produce one line break, but if there
+ is an intervening `\X' then the second break finds the line buffer
+ not empty and generates another line break.
+
+ Using `\!' does alter the position of the pdfmark lines in the
+ intermediate file sent to grops (the pdfmark lines are output
+ immediately rather than being serialised through the output line
+ processing), but this has no effect since the contents of the
+ pdfmark line stay the same. It is the contents which determine
+ where bookmarks jump to not the position of the record in the input
+ stream to grops.
+
+ I initially used `.output', but hit a snag if a pdfbookmark occurs
+ before the document starts to output (message saying to insert an
+ explicit `.br'), this is quite likely for things like `.pdfinfo
+ /Author' which occur at the top of the document. So I'm using the
+ `\!' escape.
+
+2012-09-20 Werner LEMBERG <wl@gnu.org>
+
+ Simplify enviroment handling.
+
+ Suggested by Ivan Shmakov <oneingray@gmail.com>.
+
+ * Makefile.sub (PDFROFF): Don't use export.
+
+2011-12-26 Mike Frysinger <vapier@gentoo.org>
+
+ Fix parallel build race failure.
+
+ Sometimes building in parallel will fail in the pdfmark directory:
+
+ make[2]: Entering directory '.../contrib/pdfmark'
+ rm -f pdfroff
+ rm -f pdfmark.pdf
+ sed -f ... ./pdfroff.sh >pdfroff
+ ...; ./pdfroff ... pdfmark.ms >pdfmark.pdf
+ /bin/sh: ./pdfroff: Permission denied
+ chmod +x pdfroff
+ make[2]: *** [pdfmark.pdf] Error 126
+
+ This is because the generated pdf files use the local generated
+ pdfroff helper script, but they don't depend directly upon it, so
+ make tries to create the two in parallel and randomly falls over.
+
+ * Makefile.sub: Have all the .pdf files explicitly depend on the
+ `pdfroff' helper script.
+
+2010-12-23 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Update copyright notices; pdfmark.tmac bug-fix.
+
+ * pdfmark.tmac: Update copyright notices.
+ (pdf*href.mark.resolve): Avoid premature removal, by aliasing to...
+ (pdf*href.mark.begin): ...this, rather than renaming.
+
+ * pdfroff.sh, pdfroff.man: Update copyright notices.
+
+2010-12-14 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Clean up handling of temporary files directory.
+
+ * .cvsignore (pdfroff-*): Ignore sub-directories matching this.
+ * Makefile.sub (MOSTLCLEANDIRADD): Schedule them for removal.
+
+2010-12-02 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Address potential temporary file security vulnerabilities.
+
+ * pdfroff.sh (GROFF_TMPDIR): Use mktemp(1) to assign it, if possible;
+ fall back to ${TMPDIR}, ${TMP} or ${TEMP} if unsuccessful.
+ * pdfroff.man: Document it.
+
+2009-08-16 Colin Watson <cjwatson@debian.org>
+
+ Make pdfroff's GhostScript invocation safer.
+
+ * pdfroff.sh (PDFROFF_POSTPROCESSOR_COMMAND): Add `-dSAFER' option.
+ * pdfroff.man: Document it.
+
+2008-12-28 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Avoid phantom line wrapping in pdfhref hot-spots.
+
+ * pdfmark.tmac (pdf*href.mark.end): Emit hot-spot end markers within
+ scope of `\Z', to prevent possible output line length overflow which
+ may occur only in the layout computation passes, but not in the final
+ output pass. Problem observed and identified by Nick Stoughton; it
+ causes some hot-spots to be displaced from their proper locations.
+
+2007-04-11 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Avoid stray newlines in folded pdfmark literal content.
+
+ * pdfmark.tmac (pdf*pdfmark.dispatch.wrapped): New string; define it
+ when accumulating long literal content; make it undefined otherwise.
+ (PDFMARK.FOLDWIDTH, PDFMARK.FOLDWIDTH.MAX): Reserve space for two
+ extra characters, to accommodate a space and an escaped newline,
+ while accumulating literal content, in case folding is required.
+ (pdf*pdfmark.dispatch) [pdf*pdfmark.dispatch.wrapped]: Add them.
+
+2007-04-11 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ * pdfmark.tmac (pdfbookmark): Don't evaluate within diversions; defer
+ placement until diversion is copied out at top level.
+
+2007-02-06 Eric S. Raymond <esr@snark.thyrsus.com>
+
+ * pdfroff.man: Update .UR/.UE and .MT/.ME to latest changes in
+ an-ext.tmac.
+
+2007-01-30 Werner LEMBERG <wl@gnu.org>
+
+ * pdfroff.man: Updated.
+
+2007-01-21 Werner LEMBERG <wl@gnu.org>
+
+ * pdfroff.man: Revised, based on a patch from Eric Raymond. It now
+ uses the new macros from an-ext.tmac. This is the first of a series
+ of man patches which Eric has contributed.
+
+2006-07-30 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ * pdfroff.sh (PDFROFF_KILL_NULL_PAGES): Require `%%BeginPageSetup' on
+ PostScript output line immediately following `%%Page:'.
+
+2006-07-29 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ * pdfroff.sh (PDFROFF_KILL_NULL_PAGES): Require `sed' to match a more
+ explicit regular expression, for detection of redundant pages.
+
+2006-07-14 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ * pdfroff.sh (PDFWRITE): Local shell variable replaced...
+ (PDFROFF_POSTPROCESSOR_COMMAND): by this new environment variable...
+ (GROFF_GHOSTSCRIPT_INTERPRETER): with this bound to it.
+ (PDFROFF_COLLATE, PDFROFF_KILL_NULL_PAGES): New environment variables.
+ (--no-kill-null-pages): New command line option; implement it, and...
+ (--help): Add description for it.
+
+ * pdfroff.man (PDFROFF_POSTPROCESSOR_COMMAND): Document it.
+ (PDFROFF_COLLATE, PDFROFF_KILL_NULL_PAGES): Document them.
+ (--no-kill-null-pages): Document it.
+
+2006-07-14 Zvezdan Petkovic <zpetkovic@acm.org>
+
+ * pdfroff.sh (--emit-ps): New command line option; implement it.
+ (--help): Add description for it.
+
+ * pdfroff.man (--emit-ps): Document it.
+
+2006-06-11 Werner LEMBERG <wl@gnu.org>
+
+ * pdfroff.man: Add `.ig' block after NAME section to make mandb
+ happy.
+
+2006-03-31 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Split `pdfmark' output as required, to avoid excessively long
+ `ps:exec' intermediate output records.
+
+ * pdfmark.tmac (pdfmark): Macro extended to deploy ...
+ (pdf*pdfmark.limit): New macro; use it to define ...
+ (PDFMARK.FOLDWIDTH, PDFMARK.FOLDWIDTH.MAX): New registers.
+ (pdf*compose.first, pdf*compose.next, pdf*compose.literal): New
+ macros; each will be aliased as required to ...
+ (pdf*compose): ... this, to dynamically construct ...
+ (pdf:composed.line, pdf:composed.literal): ... these new strings.
+ (pdf:compose.test): New dynamically constructed string; use it to
+ detect parenthesised literals in pdfmark content, so folding can be
+ avoided within them, subject to honouring of `PDFMARK.FOLDWIDTH'.
+ (pdf*length.increment): New macro; it triggers output folding when ...
+ (pdf:length): ... this new register exceeds `PDFMARK.FOLDWIDTH.MAX'.
+ (pdf*pdfmark.post.first, pdf*pdfmark.post.next): New macros; each will
+ be aliased as required to ...
+ (pdf*pdfmark.post): ... this, and invoked by ...
+ (pdf*pdfmark.dispatch): ... this new macro; use it to define ...
+ (pdf:composed): ... this dynamically constructed macro; use ...
+ (pdf*end): ... this new macro to terminate it.
+
+2006-03-09 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Incorporate portability recommendations by Ralf Wildenhues
+ <ralf.wildenhues@gmx.de>
+
+ * pdfroff.sh: Avoid unsafe quoting in variable substitutions of
+ the form "${VAR+"set"}"; remove outer quotes everywhere; prefix
+ with `x' on each side of comparisons.
+ ($NULLCMD): Define when `$ZSH_VERSION' is set, i.e. when host
+ has `/bin/sh -> zsh'; also...
+ (emulate sh): Invoke, for this case.
+
+ Enhancement/bug fix requested by Werner LEMBERG <wl@gnu.org>
+
+ * pdfroff.sh (--help): Direct output to `stdout', not `stderr'.
+ (--keep-temporary-files): New option; implement it.
+
+ * pdfroff.man (OPTIONS): Document `--keep-temporary-files' option.
+ (FILES): Note names and purpose of files it affects.
+
+ * Makefile.sub (PDFROFF): Add `--keep-temporary-files' option;
+ retain them in `GROFF_TMPDIR=.'.
+ (CLEANADD): Include temporary files matching `pdf[0-9]*'.
+
+2006-03-08 Werner LEMBERG <wl@gnu.org>
+
+ * pdfmark.ms: Update URL for Adobe Reference Manual.
+
+2006-02-26 Claudio Fontana <claudio@gnu.org>
+
+ * Makefile.sub: Add DESTDIR to install and uninstall targets
+ to support staged installations.
+
+2006-02-25 Werner LEMBERG <wl@gnu.org>
+
+ * pdfmark.ms: Correct typo; reported by Thomas Klausner.
+
+2006-02-24 Werner LEMBERG <wl@gnu.org>
+
+ * pdfmark.ms, pdfroff.sh: Replace legal/illegal with valid/invalid.
+
+2005-06-22 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ pdfroff.sh portability enhancement.
+
+ * pdfroff.sh (ARGLIST): Variable removed.
+ (GROFF_STYLE): Use it for all groff invocations.
+ (INPUT_FILES): Pass to all groff invocations, instead of ARGLIST.
+ (CS_MACRO, CE_MACRO): Initialize independently.
+ (CS_FILTER): Simplify quoting; it used to confuse some shells.
+ (Source): CVS keyword removed; replaced by...
+ (RCSfile, Revision): these.
+
+2005-06-17 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ * pdfroff.sh (MATCH): Correct quoting.
+ (Source): Add terminating `$' on CVS keyword.
+
+2005-06-17 Zvezdan Petkovic <zpetkovic@acm.org>
+
+ * Makefile.sub: (RM): Define as `rm -f', for `make' programs
+ which don't predefine it.
+
+2005-06-16 Bernd Warken <groff-bernd.warken-72@web.de>
+
+ * pdfroff.sh (NULLDEV): Correct misspelled instance of NULDEV.
+
+2005-05-28 Werner LEMBERG <wl@gnu.org>
+
+ * Makefile.sub (.ms.pdf): Use `--stylesheet', not `--style'.
+
+2005-05-26 Werner LEMBERG <wl@gnu.org>
+
+ * Makefile.sub, pdfmark.tmac, pdfroff.sh, spdf.tmac: Update postal
+ address for Free Software Foundation.
+
+2005-05-17 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Improve portability of `pdfroff' shell script.
+
+ * pdfroff.sh: Add space in shebang, conforming to portability
+ guidelines in `autoconf' docs.
+ (searchpath): New shell function; use it instead of `type' command
+ to locate prerequisite helper programs.
+
+ * pdfroff.man: Document influence of `OSTYPE' and `PATH_SEPARATOR'
+ environment variables.
+
+ * Makefile.sub (pdfroff): Make it depend on SH_DEPS_SED_SCRIPT,
+ from arch/misc/shdeps.sh; use it to customize PATH_SEPARATOR
+ initialization code for `searchpath' function in pdfroff.sh.
+
+2005-05-16 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Interim documentation update.
+
+ * pdfmark.ms (GROFF-WEBSITE): New string; use it in references and
+ examples.
+ (Section 2.5): Add definitions of D and Z operators, for use with
+ pdfhref macro.
+ (Section 2.5.4): Complete description of pdfhref macro usage for
+ `Linking to Internet Resources'; provide examples.
+
+2005-05-14 Nick Stoughton <nick@usenix.org>
+
+ * pdfmark.tmac (LB): Renamed to ...
+ (PDFLB): This to avoid conflicts with mm's LB macro.
+
+2005-05-02 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Handle parsing anomalies in Cygwin's `ash', and similar, shells.
+
+ * pdfroff.sh ($CAT, $GREP, $SED, $GROFF, $DIFF): Avoid interpreting
+ misdirected error messages, which `type' sends to `stdout' in some
+ shells, as a successful program file match.
+
+ ($AWK, $GS): Likewise; also ensure that multiple choice match
+ prototypes are eval'ed as such, in case token splitting occurs
+ before variable expansion.
+
+2005-04-24 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Add support for folded outlines in PDF documents.
+
+ * pdfmark.tmac (PDFOUTLINE.FOLDLEVEL): New register.
+ (pdf:bm.emit): Use it.
+
+ * pdfmark.ms: Document it.
+
+2005-03-25 Werner LEMBERG <wl@gnu.org>
+
+ * Makefile.in: Removed.
+
+2005-03-24 Werner LEMBERG <wl@gnu.org>
+
+ * Makefile: Renamed to...
+ * Makefile.in: This.
+
+2005-03-22 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ * pdfroff.sh: Eliminate invalid program reference to $AWK, when
+ invoked with `--no-reference-dictionary' option.
+
+2005-03-02 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ * contrib/pdfmark/Makefile.sub (install_data): Use $(INSTALL_SCRIPT)
+ to install `pdfroff'.
+ * contrib/pdfmark/pdfroff.man (opte): New macro.
+ Use it to remove spurious equal signs from SYNOPSIS.
+
+2005-02-28 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ Provide `pdfroff' shell script, and manpage to document it;
+ runs multiple groff passes, to format PDF documents.
+
+ * pdfroff.sh: New shell script template;
+ * pdfroff.man: New man page to document it.
+
+ Integrate `pdfmark' into normal groff build system;
+ install macro `pdfmark' packages, build and install `pdfroff',
+ and PDF format documentation.
+
+ * Makefile.sub: Rewritten.
+ * pdfmark.tmac: Modified.
+ (pdfhref): New macro operators, `D' and `Z'.
+ (pdf*href-D, pdf*href-Z): New macros: implement them.
+ (pdf*href.mark.resolve, pdf*href.mark.emit, pdf*href.mark.flush):
+ Modified macro algorithm, to eliminate inconsistencies between
+ `grohtml' representations of `opminy' from differing groff versions.
+ (pdf*href.mark, pdf*href.mark.release, pdf*href.mark.close):
+ deleted (redundant macros).
+ (PDFHREF.LEADING): Default value changed (was 2.5p; now -1.0p).
+ Global comment updates.
+
+ * TODO: Updated.
+
+2004-12-10 Werner LEMBERG <wl@gnu.org>
+
+ * TODO: Updated.
+
+2004-12-08 Keith Marshall <keith.d.marshall@ntlworld.com>
+
+ First import of pdfmark files.
+
+________________________________________________________________________
+
+Copyright (C) 2004-2020 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
+
+Local Variables:
+fill-column: 72
+mode: change-log
+version-control: never
+End:
+vim:set autoindent textwidth=72:
diff --git a/contrib/pdfmark/PROBLEMS b/contrib/pdfmark/PROBLEMS
new file mode 100644
index 0000000..d31be4a
--- /dev/null
+++ b/contrib/pdfmark/PROBLEMS
@@ -0,0 +1,32 @@
+ -*- text -*-
+ Copyright (C) 2004-2020 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved.
+
+Known PROBLEMS in pdfmark.tmac
+==============================
+
+Bounding boxes for link hot-spots which straddle a page break
+are not computed correctly.
+
+*** Resolved: 06-Dec-2004 (KDM): pdfmark.tmac.patch-20041206 ***
+
+--------
+
+Documents including a large number of cross references may fail,
+with an 'input stack limit exceeded' error.
+
+*** Resolved: 27-Sep-2004 (KDM): pdfmark.tmac.patch-20040927 ***
+
+--------
+
+Links placed in diversions, such as footnotes or floating keeps,
+resolve to the wrong destinations; (mapping order becomes confused
+between links in diversion, and links in running text following
+the diversion).
+
+--------
+
+Annotations placed by .pdfnote cannot exceed about 200 chars.
diff --git a/contrib/pdfmark/README b/contrib/pdfmark/README
new file mode 100644
index 0000000..7440ffd
--- /dev/null
+++ b/contrib/pdfmark/README
@@ -0,0 +1,57 @@
+ -*- text -*-
+ Copyright (C) 2004-2020 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved.
+
+README for pdfmark.tmac
+=======================
+
+Copyright (C) 2004, 2009 Free Software Foundation Inc.
+Contributed by Keith Marshall (keith.d.marshall@ntlworld.com)
+
+This is free software. See file COPYING, for copying permissions,
+and warranty disclaimer.
+
+This is a preview release of a proposed pdfmark.tmac macro package,
+for use with GNU troff (groff). It is not yet complete, and should
+be considered as an alpha release; there are a few problems to be
+resolved (see file PROBLEMS).
+
+Partial documentation is provided, in groff-ms format. To convert
+this to PDF format, you will require a working groff installation,
+a working ghostscript installation, with the gs command in your PATH,
+and a GNU-compatible make. The tarball should be unpacked in the
+top directory of your groff source tree, then:
+
+ cd <groff-current>/contrib/pdfmark
+ make pdfmark
+
+where <groff-current> is the top directory of your current groff
+source tree.
+
+Included in this package, are:
+
+ pdfmark.tmac -- the core pdfmark macro set
+ spdf.tmac -- a rudimentary set of bindings for ms macros
+ pdfmark.ms -- preliminary documentation
+ cover.ms -- a template for the documentation cover sheet
+ gnu.eps -- the groff logo, copied from the groff distribution
+ Makefile -- makefile, for formatting the documentation
+ README -- this file
+ PROBLEMS -- a list of known problems
+ TODO -- a list of planned features, not yet implemented
+
+To make the pdfmark macros generally usable, copy pdfmark.tmac to the
+'site-tmac' directory appropriate to your groff installation; (ms users
+may also wish to copy spdf.tmac). The macros may then be accessed, by
+including the '-mpdfmark' option on the groff command line; (for ms
+users, '-mspdf' is equivalent to '-ms -mpdfmark', with some extra
+macros 'thrown in').
+
+Comments, and bug reports are welcomed. Please post to the groff
+mailing list, groff@gnu.org; (you must be subscribed to this list to
+post mails). To subscribe, visit
+
+ http://lists.gnu.org/mailman/listinfo/groff
diff --git a/contrib/pdfmark/TODO b/contrib/pdfmark/TODO
new file mode 100644
index 0000000..219b60e
--- /dev/null
+++ b/contrib/pdfmark/TODO
@@ -0,0 +1,60 @@
+ -*- text -*-
+ Copyright 2004-2020 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved.
+
+TODO items for pdfmark.tmac
+===========================
+
+Add copyright information to PDF documentation.
+
+--------
+
+Add acknowledgements and trade mark ownership notifications
+to PDF documentation.
+
+--------
+
+Provide documentation in man page and texinfo formats.
+
+--------
+
+Add comments in spdf.tmac, to clarify its operation.
+Also add commentary in pdfmark.tmac, to clarify operation of
+recent changes.
+
+--------
+
+Make Makefile generic, so 'configure' can resolve target
+system dependencies.
+
+* Comment added 2005-02-26 by Keith Marshall <keith.d.marshall@ntlworld.com>
+
+If this refers to contrib/pdfmark/Makefile, then it is addressed by the new
+'pdfroff' script; the original Makefile may be considered redundant. Local
+system dependencies are resolved by 'configure', and applied to 'pdfroff',
+when it is generated from 'pdfroff.sh'.
+
+--------
+
+Improve Makefile.sub, to integrate pdfmark.tmac installation
+into a regular groff build. Add it to groff's Makefile.in.
+
+* Comment added 2005-02-26 by Keith Marshall <keith.d.marshall@ntlworld.com>
+
+Completed.
+
+--------
+
+Provide a 'pdfmark' script (or call it 'groff2pdf'?) which
+actually converts a groff input file to pdf, and which
+takes care of the necessary intermediate steps to handle
+PDF marks.
+
+* Comment added 2005-02-26 by Keith Marshall <keith.d.marshall@ntlworld.com>
+
+This facility now provided by 'pdfroff' script; documented in 'pdfroff.man'.
+Man page still requires an additional section, to describe use of 'stylesheet'
+feature. Script also requires documentation in PDF and texinfo formats.
diff --git a/contrib/pdfmark/cover.ms b/contrib/pdfmark/cover.ms
new file mode 100644
index 0000000..b647a29
--- /dev/null
+++ b/contrib/pdfmark/cover.ms
@@ -0,0 +1,70 @@
+.\" Copyright (C) 2004-2020 Free Software Foundation, Inc.
+.\"
+.\" Copying and distribution of this file, with or without modification,
+.\" are permitted in any medium without royalty provided the copyright
+.\" notice and this notice are preserved.
+.\"
+.am pspic*error-hook
+. ab \\n[.F]:\\n[.c]: fatal error: PSPIC failed to include '\\$1'
+..
+.de CS
+.if !rCO .nr CO 0
+.if !rTL .nr TL 0
+.\".nr PO*SAVED \\n[PO]
+.nr LL*SAVED \\n[LL]
+.nr HM*SAVED \\n[HM]
+.nr HM 0
+.nr PO (2.1c+\\n[CO]u)
+.nr LL 17.1c
+\&
+.nr PS*SAVED \\n[PS]
+.nr VS*SAVED \\n[VS]
+.nr PS 24
+.nr VS 30
+.CD
+.fam T
+.sp |(5.9c+\\n[TL]u)
+.als AU au@first
+..
+.de au@first
+.sp 1.5v
+.als AU au@next
+.AU \\$@
+..
+.de au@next
+.DE
+.nr PS 18
+.nr VS 18
+.CD
+.sp 0.5v
+\\$*
+..
+.de AI
+\H'-4z'\\$*\H'0'
+..
+.de CE
+.DE
+.sp |17.5c
+.PSPIC gnu.eps
+.nr PS 19
+.CD
+.fam H
+.tkf HR 10z 2p 20z 4p
+\H'-4z'A GNU MANUAL\H'0'
+.DE
+.\".nr PO \\n[PO*SAVED]
+.nr LL \\n[LL*SAVED]
+.nr PS \\n[PS*SAVED]
+.nr VS \\n[VS*SAVED]
+.nr HM \\n[HM*SAVED]
+.\".rr PO*SAVED
+.rr LL*SAVED
+.rr PS*SAVED
+.rr VS*SAVED
+.rr HM*SAVED
+.fam
+..
+.\" Local Variables:
+.\" mode: nroff
+.\" End:
+.\" vim: filetype=groff:
diff --git a/contrib/pdfmark/pdfmark.am b/contrib/pdfmark/pdfmark.am
new file mode 100644
index 0000000..15eec8c
--- /dev/null
+++ b/contrib/pdfmark/pdfmark.am
@@ -0,0 +1,99 @@
+# Copyright (C) 2005-2021 Free Software Foundation, Inc.
+# Written by Keith Marshall (keith.d.marshall@ntlworld.com)
+# Automake migration by Bertrand Garrigues
+#
+# 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+pdfmark_srcdir = $(top_srcdir)/contrib/pdfmark
+pdfmark_builddir = $(top_builddir)/contrib/pdfmark
+
+man1_MANS += contrib/pdfmark/pdfroff.1
+
+bin_SCRIPTS += pdfroff
+
+# Files installed in $(tmacdir)
+TMACFILES = \
+ contrib/pdfmark/pdfmark.tmac \
+ contrib/pdfmark/sanitize.tmac \
+ contrib/pdfmark/spdf.tmac
+pdfmarktmacdir = $(tmacdir)
+dist_pdfmarktmac_DATA = $(TMACFILES)
+
+# Files installed in $(pdfdocdir)
+PDFDOCFILES = \
+ contrib/pdfmark/pdfmark.pdf
+if USE_PDFROFF
+pdfmarkpdfdocdir = $(pdfdocdir)
+nodist_pdfmarkpdfdoc_DATA = $(PDFDOCFILES)
+MOSTLYCLEANFILES += $(PDFDOCFILES)
+else
+EXTRA_DIST += $(PDFDOCFILES)
+endif
+
+EXTRA_DIST += \
+ contrib/pdfmark/cover.ms \
+ contrib/pdfmark/pdfmark.ms \
+ contrib/pdfmark/ChangeLog \
+ contrib/pdfmark/README \
+ contrib/pdfmark/PROBLEMS \
+ contrib/pdfmark/TODO \
+ contrib/pdfmark/pdfroff.1.man \
+ contrib/pdfmark/pdfroff.sh
+
+PDFROFF=\
+ GROFF_TMPDIR=. \
+ GROFF_COMMAND_PREFIX= \
+ GROFF_BIN_DIR="$(GROFF_BIN_DIR)" \
+ GROFF_BIN_PATH="$(GROFF_BIN_PATH)" \
+ ./pdfroff \
+ $(FFLAG) $(MFLAG) -dpaper=$(PAGE) -P-p$(PAGE) -M$(pdfmark_srcdir)
+
+contrib/pdfmark/pdfmark.pdf: contrib/pdfmark/pdfmark.ms
+ $(GROFF_V)$(MKDIR_P) `dirname $@` \
+ && $(PDFROFF) -I $(doc_builddir) -I $(doc_srcdir) -mspdf \
+ --stylesheet=$(pdfmark_srcdir)/cover.ms \
+ $(top_srcdir)/contrib/pdfmark/pdfmark.ms >$@
+
+# The pdf files use the local script to generate.
+$(PDFDOCFILES): pdfroff groff troff gropdf
+$(PDFDOCFILES): $(dist_devpsfont_DATA) $(nodist_devpsfont_DATA) \
+ $(DOC_GNU_EPS)
+
+pdfroff: contrib/pdfmark/pdfroff.sh $(SH_DEPS_SED_SCRIPT)
+ $(AM_V_GEN)sed -f $(SH_DEPS_SED_SCRIPT) \
+ -e "s|[@]VERSION[@]|$(VERSION)|" \
+ -e "s|[@]GROFF_AWK_INTERPRETERS[@]|$(ALT_AWK_PROGS)|" \
+ -e "s|[@]GROFF_GHOSTSCRIPT_INTERPRETERS[@]|$(ALT_GHOSTSCRIPT_PROGS)|" \
+ -e "s|[@]GROFF_BIN_DIR[@]|$(bindir)|" $(pdfmark_srcdir)/pdfroff.sh \
+ >$@ \
+ && chmod +x $@
+
+mostlyclean-local: mostlyclean_pdfmark
+mostlyclean_pdfmark:
+ rm -rf $(top_builddir)/pdfroff-*
+
+uninstall_groffdirs: uninstall-pdfmark-hook
+uninstall-pdfmark-hook:
+if USE_PDFROFF
+ -rmdir $(DESTDIR)$(pdfmarkpdfdocdir)
+endif
+
+
+# Local Variables:
+# mode: makefile-automake
+# fill-column: 72
+# End:
+# vim: set autoindent filetype=automake textwidth=72:
diff --git a/contrib/pdfmark/pdfmark.ms b/contrib/pdfmark/pdfmark.ms
new file mode 100644
index 0000000..0d7d28c
--- /dev/null
+++ b/contrib/pdfmark/pdfmark.ms
@@ -0,0 +1,2831 @@
+.ig
+pdfmark.ms
+
+This file is part of groff, the GNU roff type-setting system.
+
+Copyright (C) 2004-2021 Free Software Foundation, Inc.
+written by Keith Marshall <keith.d.marshall@ntlworld.com>
+
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+Texts.
+
+A copy of the Free Documentation License is included as a file called
+FDL in the main directory of the groff source package.
+..
+.
+.CS
+Portable Document Format
+Publishing with GNU Troff
+.AU Keith Marshall
+.AI <keith.d.marshall@ntlworld.com>
+.CE
+.
+.\" Specify the Internet address for the groff web site.
+.\"
+.ds GROFF-WEBSITE http://www.gnu.org/software/groff
+.
+.\" Set the PDF default document view attribute, to ensure that the document
+.\" outline is visible, each time the document is opened in Acrobat Reader.
+.\"
+.pdfview /PageMode /UseOutlines
+.\"
+.\" Initialize the outline view to show only three heading levels,
+.\" with additional subordinate level headings folded.
+.\"
+.nr PDFOUTLINE.FOLDLEVEL 3
+.
+.\" Add document identification meta-data
+.\"
+.pdfinfo /Title Portable Document Format Publishing with GNU Troff
+.pdfinfo /Author Keith Marshall
+.pdfinfo /Subject Tips and Techniques for Exploiting PDF Features with GNU Troff
+.pdfinfo /Keywords groff troff PDF pdfmark
+.
+.\" Set the default cross reference format to indicate section numbers,
+.\" rather than page numbers, when we insert a reference pointer.
+.\"
+.ds PDFHREF.INFO section \\*[SN-NO-DOT] \\$*
+.
+.\" Define a macro, to print reference links WITHOUT the usual "see" prefix.
+.\"
+.de XR-NO-PREFIX
+.rn PDFHREF.PREFIX xx
+.ds PDFHREF.PREFIX
+.XR \\$@
+.rn xx PDFHREF.PREFIX
+..
+.
+.\" Define a string, to insert a Registered Trade Mark symbol as
+.\" a superscript...
+.\"
+.ds rg \*{\(rg\*}
+.\"
+.\" ...and use it to define strings, representing frequently used
+.\" registered trade marks.
+.\"
+.ds Adobe "Adobe\Z'\\$1'\*(rg\"
+.ds Acrobat "Acrobat\Z'\\$1'\*(rg\"
+.ds Distiller "Distiller\Z'\\$1'\*(rg\"
+.ds PostScript "PostScript\Z'\\$1'\*(rg\"
+.\"
+.ds Microsoft "Microsoft\Z'\\$1'\*(rg\"
+.
+.\" Establish the page layout.
+.\"
+.nr PO 2.5c
+.nr LL 17.0c
+.nr LT 17.0c
+.nr DI 5n
+.nr HY 0
+.
+.\" Within the table of contents, the width of the right-hand margin,
+.\" in which space is reserved for the display of page numbers, and the
+.\" appearance of the leaders which precede it, are controlled by:-
+.\"
+.char \[TC-LEADER] \h'0.8n'.
+.nr TC-MARGIN \w'00000'
+.
+.\" Generate headers in larger point sizes, for NH levels < 4,
+.\" with point size increasing by 1.5p, for each lesser NH level.
+.\"
+.nr GROWPS 4
+.nr PSINCR 1.5p
+.
+.
+.\" Implement an interface with the FS macro (from s.tmac) to facilitate
+.\" placement of footnote reference marks, with each serving as an active
+.\" pdfhref link to the associated footnote itself.
+.\"
+.de pdf:fn.mark nr
+.\" Macro to replace original duty performed by "\**"; must be invoked
+.\" at point of footnote mark placement, e.g. by FS, BEFORE recording of
+.\" the associated text within the footnote diversion is commenced.
+.\"
+.ie \\n[.$] \{\
+. pdfhref L -D pdf:fn\\$1 -- \\$2
+. pdfhref M -N pdf:fn\\$1r
+. \}
+.\"
+.\" s.tmac does not publicly expose its auto-incrementing footnote index;
+.\" to avoid a dependency on an undocumented internal feature, we create
+.\" our own counter, while keeping the internal index synchronized, by
+.\" interpolating a renamed "\**", each time we increment our counter.
+.\"
+.el .\\$0 \\n+[pdf:fn.index.count] \\*[pdf:fn.index]
+.nr pdf:fn.index.count 0 1
+.rn * pdf:fn.index
+.ds * \c
+.
+.\" For versions of s.tmac which support the FS-MARK callback hook, it
+.\" is sufficient for us to answer the callback request.
+.\"
+.\" FIXME: in time, we may be able to unconditionally assume that this
+.\" callback hook will be supported...
+.\"
+.ie d FS-MARK .als FS-MARK pdf:fn.mark
+.el \{\
+.\" ...but in the interim, we may need to redefine s.tmac's FS macro,
+.\" (actually the @FS internal macro, rather than FS itself), to gain
+.\" an effect equivalent to taking control of FS-MARK, to achieve the
+.\" placement of a footnote mark as an active pdfhref link.
+.\"
+.rn @FS pdf:fn.record
+.de @FS
+.pdf:fn.mark
+.pdf:fn.record
+..
+.\}
+.\" Override s.tmac's (undocumented) footnote output hook; this emulates
+.\" the default output style for \n[FF] == 3 footnotes, with the footnote
+.\" number formatted as a pdfhref link back to the position at which the
+.\" footnote marker appears, within the document text.
+.\"
+.de FP
+.LP
+.nr pdf:fn.tag.width (u;2*\\n[FI])
+.ds pdf:fn.tag \s'-1.5p'\\$1.\s'+1.5p'
+.pdfhref M -N pdf:fn\\$1
+.in +\\n[pdf:fn.tag.width]u
+.ti -\\n[pdf:fn.tag.width]u
+.nr pdf:fn.tag.width -\\w'\\*[pdf:fn.tag]'u
+.pdfhref L -D pdf:fn\\$1r -A \\h'\\n[pdf:fn.tag.width]u'\c -- \\*[pdf:fn.tag]
+..
+.de pdfhref-nobreak
+.\" FIXME: I've only noticed this anomaly when planting pdfhref links
+.\" within footnotes; if the start of the link text is placed near the
+.\" line length limit, and all of it is moved to the start of the next
+.\" line, the "hot-spot" region is computed to be one line higher than
+.\" it should be; ending the preceding input line with "\c", and then
+.\" invoking pdfhref via this wrapper, works around this issue.
+.\"
+.ie \\n[.l]-\\n[.i]-\\n[.k]-\\w'\\$\\n[.$]' \&
+.el \p
+.pdfhref \\$*
+..
+.
+.\" Define a local macro to facilitate choice of style for emphasis;
+.\" by default, make it equivalent to the ms standard "I" macro.
+.\"
+.de EM
+.\".I "\s'+0.3'\\$1\s0" "\\$2" "\\$3"
+.I \\$@
+..
+.\" Also, define variations on the ms standard "CW" macro, to add
+.\" bold, italic, and both styles to constant width text; note that
+.\" each of these accept two additional arguments, in comparison to
+.\" standard "CW", such that \$1 specifies the text which is to be
+.\" styled, \$2 and \$3 specify inner after/before bracketting, to
+.\" set as regular "CW" text, while \$4 and \$5 become equivalent
+.\" to \$2 and \$3 of standard "CW", acting as outer bracketting.
+.\"
+.de CWB
+\\$5\fC\\$3\fP\f(CB\\$1\fP\fC\\$2\fP\\$4
+..
+.de CWI
+\\$5\fC\\$3\fP\f(CI\\$1\fP\fC\\$2\fP\\$4
+..
+.de CWBI
+\\$5\fC\\$3\fP\f[CBI]\\$1\fP\fC\\$2\fP\\$4
+..
+.\" Finally, augment this group with a variant string, which may be
+.\" used to set constant width tags on "IP" paragraphs, with \$1 set
+.\" as if by "CWB", followed by an optional suffix set as if by "CWBI",
+.\" and with the suffix bracketted by \$3 after and \$4 before, each
+.\" set in the regular "CW" style.
+.\"
+.ds = \f(CB\\$1\f(CR\\$4\f[CBI]\\$2\f(CR\\$3
+.
+.\" Additionally, add a cross-reference convenience macro, emulating
+.\" the style of the "ms" font change macros...
+.\"
+.\" .XR <dest-name> [<affixed> [<prefix>]]
+.\"
+.\" ...such that, when invoked with one, two, or three arguments, this
+.\" expands to the equivalent of:
+.\"
+.\" .pdfhref L -D <dest-name> [-A <affixed> [-P <prefix>]]
+.\"
+.\" to place a pdfhref reference link, to a named destination, within
+.\" the same document, using the reference text which is predefined in
+.\" the reference dictionary entry associated with the destination.
+.\"
+.de XR
+.if \\n(.$ \{\
+. if \\n[OPMODE] \{\
+. ds xr!argv -D "\\$1"
+. if \\n(.$>1 .as xr!argv " -A "\\$2"
+. if \\n(.$>2 .as xr!argv " -P "\\$3"
+. pdfhref L \\*[xr!argv]
+. rm xr!argv
+. \}
+. \}
+..
+.
+.NH 1
+.\" Conventionally, in "ms", NH precedes text which is to be set as a
+.\" numbered section heading, but it makes no provision for automatic
+.\" reference to that heading in a table of contents, or (in the case
+.\" of PDF document production) in a document outline. Both of these
+.\" limitations may be mitigated, by using the XN macro, (provided by
+.\" spdf.tmac), which sets its arguments, both as text to be included
+.\" in the section heading, as printed, and as an assocated document
+.\" outline reference; it will also make this same text available to
+.\" the user-specified callback macro, XH-UPDATE-TOC, whereby it may
+.\" be used, e.g. to construct a table of contents entry.
+.\"
+.\" Within the table of contents, structural layout will be achieved,
+.\" under the direction of the following spacing control constants:
+.\"
+.ds XNVS1 0.50v \" leading for top level
+.ds XNVS2 0.15v \" leading at nesting level increment
+.ds XNVS3 0.30v \" leading following nested group
+.\"
+.\" Note that one TOC related callback hook is shared by both XH and
+.\" XN; its is called XH-UPDATE-TOC, regardless of whether called by
+.\" XH or by XN; when called by XN, it is invoked with arguments:
+.\"
+.\" .XH-UPDATE-TOC <outline-level> <section-number> <text> ...
+.\"
+.de XH-UPDATE-TOC
+.\" This implementation of XH-UPDATE-TOC utilizes the rudimentary ms
+.\" mechanism for formatting a table of contents, using XS and XE to
+.\" bracket individual entries.
+. XS
+. \" A local register, tc*hl, is used to track the outline level
+. \" of each TOC entry, as it is added; it is not defined, until
+. \" the first entry is recorded...
+. \"
+. if r tc*hl \{\
+. \" ...after which, we use it to establish indentation,
+. \" to reflect changes in outline level.
+. \"
+. ie \\$1>1 \{\
+. \" When at any outline level greater than one,
+. \" any level increment will be offset by XNVS2
+. \" units of vertical space...
+. \"
+. ie \\$1>\\n[tc*hl] .sp \\*[XNVS2]
+.
+. \" ...whereas any decrement will be offset by
+. \" XNVS3 units.
+. \"
+. el .if \\n[tc*hl]>\\$1 .sp \\*[XNVS3]
+. \}
+.
+. \" ...but every top-level entry, after the first, is
+. \" offset by XNVS1 units.
+. \"
+. el .sp \\*[XNVS1]
+. \}
+.
+. \" \$1 becomes the effective outline level for the current table
+. \" of contents entry, but we must ensure that it is one or more.
+. \"
+. ie \\$1 .nr tc*hl \\$1
+. el .nr tc*hl 1
+.
+. \" The current outline level determines the indentation at which
+. \" we place the section number reference...
+. \"
+. nop \h'\\n[tc*hl]-1m'\\$2\c
+.
+. \" ...after which we discard \$1 and \$2, allowing us to append
+. \" all remaining arguments, ensuring that there is at least 0.5n
+. \" of following space, before the first leader dot.
+. \"
+. shift 2
+. nop \h'1.5n'\\$*\h'0.5n'
+. XE
+..
+.XN Introduction
+.\"
+.\" If using an old s.tmac, without the SN-NO-DOT extension, ensure
+.\" that we get SOMETHING in section number references.
+.\"
+.if !d SN-NO-DOT .als SN-NO-DOT SN
+.LP
+It might appear that it is a fairly simple matter to
+produce documents in \*[Adobe]\~\(lqPortable\~Document\~Format\(rq,
+commonly known as PDF, using
+.CW groff ) GNU\~Troff\~(
+as the document formatter.
+Indeed,
+.CW groff 's
+default output format is the native \*[Adobe]\~\*[PostScript] format,
+which PDF producers such as \*[Adobe] \*[Acrobat] \*[Distiller ,]
+or GhostScript, expect as their input format.
+Thus, the PDF production process would seem to entail simply
+formatting the document source with
+.CW groff ,
+to produce a \*[PostScript] version of the document,
+which can subsequently be processed by \*[Acrobat] \*[Distiller]
+or GhostScript, to generate the final PDF document.
+.LP
+For many PDF production requirements,
+the production cycle described above may be sufficient.
+However, this is a limited PDF production method,
+in which the resultant PDF document represents no more than
+an on screen image of the printed form of the document, if
+.CW groff 's
+\*[PostScript] output were printed directly.
+.LP
+The Portable Document Format provides a number of features,
+which significantly enhance the experience of reading a document on screen,
+but which are of little or no value to a document which is merely printed.
+It
+.EM is
+possible to exploit these PDF features, which are described in the \*[Adobe]
+.de pdfmark-manual pdfmark-manual
+.\" This is an example of a resource reference specified by URI ...
+.\" We may need to refer often to the Adobe pdfmark Reference Manual,
+.\" so we create the internet link definition using a macro, to make
+.\" it reusable.
+.\"
+.\" Note also, that we protect the description of the reference by
+.\" preceding it with "--", to avoid "invalid character in name" type
+.\" error messages from groff (caused by the use of "\~").
+.\"
+.pdfhref W -D https://www.adobe.com/go/acrobatsdk_pdfmark \
+ -P \(lq -A \(rq\\$1 -- pdfmark\~Reference\~Manual
+.pdfmark-manual ,
+with some refinement of the simple PDF production method, provided
+appropriate \(lqfeature implementing\(rq instructions can be embedded into
+.CW groff 's
+\*[PostScript] rendering of the document.
+This, of course, implies that the original document source, which
+.CW groff
+will process to generate the \*[PostScript] description of the document,
+must include appropriate markup to exploit the desired PDF features.
+It is this preparation of the
+.CW groff
+document source to exploit a number of these features,
+which provides the principal focus of this document.
+.LP
+The markup techniques to be described have been utilized in the production of
+the PDF version of this document itself.
+This has been formatted using
+.CW groff 's
+.CW ms
+macro package;
+thus, usage examples may be found in the document source file,
+.CW \n(.F ,
+to which comments have been added,
+to help identify appropriate markup examples for implementing PDF features,
+such as:\(en
+.QS
+.IP \(bu
+Selecting a default document view, which defines how the document will appear
+when opened in the reader application; for example, when this document is
+opened in \*[Acrobat]\~Reader, it should display the top of the cover sheet,
+in the document view pane, while a document outline should appear to the left,
+in the \(lqBookmarks\(rq pane.
+.IP \(bu
+Adding document identification \(lqmeta\(hydata\(rq,
+which can be accessed, in \*[Acrobat]\~Reader,
+by inspecting the \(lqFile\^/\^Document\~Properties\^/\^Summary\(rq.
+.IP \(bu
+Creating a document outline, which will be displayed in the \(lqBookmarks\(rq
+pane of \*[Acrobat]\~Reader, such that readers may quickly navigate to any
+section of the document, simply by clicking on the associated heading
+in the outline view.
+.IP \(bu
+Embedding active links in the body of the document, such that readers may
+quickly navigate to related material at another location within the same
+document, or in another PDF document, or even to a related Internet resource,
+specified by its URI.
+.IP \(bu
+Adding annotations, in the form of \(lqsticky notes\(rq, at strategic
+points within the PDF document.
+.QE
+.LP
+All of the techniques described have been tested on
+.EM both
+GNU/Linux, and on \*[Microsoft] Windows\(tm2000 operating platforms, using
+.CW groff
+.CW 1.19.1 ,\**
+.FS
+Later versions should, and some earlier versions may, be equally suitable.
+See\c
+.pdfhref-nobreak W \*[GROFF-WEBSITE]
+for information and availability of the latest version.
+.FE
+in association with
+.CW AFPL
+.CW GhostScript
+.CW 8.14 .\**
+.FS
+Again, other versions may be suitable.
+See\c
+.pdfhref-nobreak W http://ghostscript.com
+for information and availability.
+.FE
+\&
+Other tools employed, which should be readily available on
+.EM any
+Unix\(tm
+or GNU/Linux system, are
+.CW sed ,
+.CW awk
+and
+.CW make ,
+together with an appropriate text editor, for creating and marking up the
+.CW groff
+input files.
+These additional utilities are not provided, as standard,
+on the \*[Microsoft] Windows\(tm platform,
+but several third party implementations are available.
+Some worth considering include the MKS\*(rg\~Toolkit,\**
+.FS
+A commercial offering; see\c
+.pdfhref-nobreak W http://mkssoftware.com/products/tk/default.asp
+for information.
+.FE
+Cygwin,\**
+.FS
+A
+.EM free
+but comprehensive
+.SM
+POSIX
+.LG
+emulation environment and
+Unix\(tm
+toolkit for \%32\(hybit \*[Microsoft] Windows\(tm platforms; see\c
+.pdfhref-nobreak W http://cygwin.com
+for information and download.
+.FE
+or MSYS.\**
+.FS
+Another free, but minimal suite of common
+Unix\(tm
+tools for \%32\(hybit \*[Microsoft] Windows\(tm, available for download from\c
+.pdfhref-nobreak W -A ; https://mingw.osdn.io
+it
+.EM does
+include those tools listed above,
+and is the package which was actually used when performing the Windows\(tm2000
+platform tests referred to in the text.
+.FE
+\&
+This list is by no means exhaustive, and should in no way be construed as an
+endorsement of any of these packages, nor to imply that other similar packages,
+which may be available, are in any way inferior to them.
+.bp
+.
+.NH 1
+.\" We may wish a section heading to represent a named destination,
+.\" so that we can create a linked reference to it, from some other
+.\" part of the PDF document, (or even from another PDF document).
+.\"
+.\" Here we use the "-N" option of the "XN" macro, to create a named
+.\" PDF link destination, at the location of the heading. Notice that
+.\" we also use the "--" marker to separate the heading text from the
+.\" preceding option specification; it is not strictly necessary in
+.\" this case, but it does help to set off the heading text from the
+.\" option specification.
+.\"
+.XN -N pdf-features -- Exploiting PDF Document Features
+.LP
+To establish a consistent framework for adding PDF features, a
+.CW groff
+macro package, named
+.CW pdfmark.tmac ,
+has been provided.
+Thus, to incorporate PDF features in a document,
+the appropriate macro calls, as described below, may be placed in the
+.CW groff
+document source, which should then be processed with a
+.CW groff
+command of the form\**
+.FS
+.pdfhref M pdf-features-fn
+.nr pdf-features-fn \n[fn*text-num]
+Note that,
+if any
+.CW -T \^\c
+.CWI dev
+option is specified,
+it should be either
+.CW -T \^\c
+.CW ps ,
+or
+.CW -T \^\c
+.CW pdf ;
+any other explicit choice is unlikely to be compatible with
+.CW -m \|\|\c
+.CW pdfmark ,
+and will have an unpredictable
+(possibly erroneous)
+effect on the output.
+If no
+.CW -T \^\c
+.CWI dev
+option is specified,
+(in which case
+.CW -T \^\c
+.CW ps
+is implicitly assumed),
+or if
+.CW -T \^\c
+.CW ps
+is explicitly specified,
+then the output will be produced in \*[PostScript] format,
+and will require conversion to PDF,
+(e.g. by using GhostScript tools);
+explicit specification of
+.CW -T \^\c
+.CW pdf
+will result in direct output in PDF format,
+thus obviating the need for conversion.
+.FE
+.QP
+.fam C
+groff [-Tps\h'0.2p'|\h'0.2p'-Tpdf] [-m\F[]\|\|\FC\c
+.I name ]
+-m\F[]\|\|\FC\c
+.B pdfmark
+.I options \F[]\|\|\FC\c [-
+.I file \F[]\|\|\FC\c "...] "
+\&...
+.LP
+It may be noted that the
+.CW pdfmark
+macros have no dependencies on, and no known conflicts with,
+any other
+.CW groff
+macro package; thus, users are free to use any other macro package,
+of their choice, to format their documents, while also using the
+.CW pdfmark
+macros to add PDF features.
+.
+.NH 2
+.XN -S -N pdfmark-operator -- The \F[C]pdfmark\F[] Operator
+.LP
+All PDF features are implemented by embedding instances of the
+.B \F[C]pdfmark\F[]
+operator, as described in the \*[Adobe]
+.pdfmark-manual ,
+into
+.CW groff 's
+\*[PostScript] output stream.
+To facilitate the use of this operator, the
+.CW pdfmark
+macro package defines the primitive
+.CW pdfmark
+macro; it simply emits its argument list,
+as arguments to a
+.CW pdfmark
+operator, in the \*[PostScript] output stream.
+.LP
+.pdfhref M -N pdfmark-example
+To illustrate the use of the
+.CW pdfmark
+macro, the following is a much simplified example of how a bookmark
+may be added to a PDF document outline
+.QP
+.CW ".pdfmark \e"
+.RS 4
+.nf
+.fam C
+/Count 2 \e
+/Title (An Example of a Bookmark with Two Children) \e
+/View [/FitH \en[PDFPAGE.Y]] \e
+/OUT
+.RE
+.LP
+In general, users should rarely need to use the
+.CW pdfmark
+macro directly.
+In particular, the above example is too simple for general use; it
+.EM will
+create a bookmark, but it does
+.EM not
+address the issues of setting the proper value for the
+.CW /Count
+key, nor of computing the
+.CW PDFPAGE.Y
+value used in the
+.CW /View
+key. The
+.CW pdfmark
+macro package includes a more robust mechanism for creating bookmarks,
+.\"
+.\" Here is an example of how a local reference may be planted,
+.\" using the automatic formatting feature of the "pdfhref" macro.
+.\"
+.\" This is a forward reference to the named destination "add-outline",
+.\" which is defined below, using the "XN" wrapper macro, from the
+.\" "spdf.tmac" macro package. The automatically formatted reference
+.\" will be enclosed in parentheses, as specified by the use of
+.\" "-P" and "-A" options.
+.\"
+.pdfhref L -P ( -A ), -D add-outline
+.\"
+which addresses these issues automatically.
+Nevertheless, the
+.CW pdfmark
+macro may be useful to users wishing to implement more advanced PDF features,
+than those currently supported directly by the
+.CW pdfmark
+macro package.
+.
+.NH 2
+.XN -N docview -- Selecting an Initial Document View
+.LP
+By default,
+when a PDF document is opened,
+the first page will be displayed,
+at the default magnification set for the reader,
+and outline and thumbnail views will be hidden.
+When using a PDF reader,
+such as \*[Acrobat]\~Reader,
+which supports the
+.CW /DOCVIEW
+class of the
+.CW pdfmark
+operator,
+these default initial view settings may be overridden,
+using the
+.CW pdfview
+macro.
+For example
+.QP
+.CW ".pdfview /PageMode /UseOutlines"
+.LP
+will cause \*[Acrobat]\~Reader to open the document outline view,
+to the left of the normal page view,
+while
+.QP
+.CW ".pdfview /PageMode /UseThumbs"
+.LP
+will open the thumbnail view instead.
+.LP
+Note that the two
+.CW /PageMode
+examples, above, are mutually exclusive \(em it is not possible to have
+.EM both
+outline and thumbnail views open simultaneously.
+However, it
+.EM is
+permitted to add
+.CW /Page
+and
+.CW /View
+keys, to force the document to open at a page other than the first,
+or to change the magnification at which the document is initially displayed;
+see the
+.pdfmark-manual
+for more information.
+.LP
+It should be noted that the view controlling meta\(hydata, defined by the
+.CW pdfview
+macro, is not written immediately to the \*[PostScript] output stream,
+but is stored in an internal meta\(hydata \(lqcache\(rq,
+(simply implemented as a
+.CW groff
+diversion).
+This \(lqcached\(lq meta\(hydata must be written out later, by invoking the
+.CW pdfsync
+macro,
+.\"
+.\" Here is another example of how we may introduce a forward reference.
+.\" This time we are using the shorter notation afforded by the "XR" macro
+.\" provided by "spdf.tmac"; this example is equivalent to the native
+.\" "pdfmark.tmac" form
+.\" .pdfhref L -D pdfsync -P ( -A ).
+.\"
+.XR pdfsync ). (
+.
+.NH 2
+.XN -N docinfo -- Adding Document Identification Meta-Data
+.LP
+In addition to the
+.CW /DOCVIEW
+class of meta\(hydata described above,
+.XR docview ), (
+we may also wish to include document identification meta\(hydata,
+which belongs to the PDF
+.CW /DOCINFO
+class.
+.LP
+To do this, we use the
+.CW pdfinfo
+macro.
+As an example of how it is used,
+the identification meta\(hydata attached to this document
+was specified using a macro sequence similar to:\(en
+.DS I
+.CW
+\&.pdfinfo /Title PDF Document Publishing with GNU Troff
+\&.pdfinfo /Author Keith Marshall
+\&.pdfinfo /Subject How to Exploit PDF Features with GNU Troff
+\&.pdfinfo /Keywords groff troff PDF pdfmark
+.DE
+Notice that the
+.CW pdfinfo
+macro is repeated, once for each
+.CW /DOCINFO
+record to be placed in the document.
+In each case, the first argument is the name of the applicable
+.CW /DOCINFO
+key, which
+.EM must
+be named with an initial solidus character;
+all additional arguments are collected together,
+to define the value to be associated with the specified key.
+.LP
+As is the case with the
+.CW pdfview
+macro,
+.XR docview ), (
+the
+.CW /DOCINFO
+records specified with the
+.CW pdfinfo
+macro are not immediately written to the \*[PostScript] output stream;
+they are stored in the same meta\(hydata cache as
+.CW /DOCVIEW
+specifications, until this cache is explicitly flushed,
+by invoking the
+.CW pdfsync
+macro,
+.XR pdfsync ). (
+.
+.NH 2
+.XN -N add-outline -- Creating a Document Outline
+.LP
+A PDF document outline comprises a table of references,
+to \(lqbookmarked\(rq locations within the document.
+When the document is viewed in an \(lqoutline\~aware\(rq PDF document reader,
+such as \*[Adobe] \*[Acrobat] Reader,
+this table of \(lqbookmarks\(rq may be displayed in a document outline pane,
+or \(lqBookmarks\(rq pane, to the left of the main document view.
+Individual references in the outline view may then be selected,
+by clicking with the mouse,
+to jump directly to the associated marked location in the document view.
+.LP
+The document outline may be considered as a collection of \(lqhypertext\(rq
+references to \(lqbookmarked\(rq locations within the document.
+The
+.CW pdfmark
+macro package provides a single generalized macro,
+.CW pdfhref ,
+for creating and linking to \(lqhypertext\(rq reference marks.
+This macro will be described more comprehensively in a later section,
+.XR pdfhref ); (
+the description here is restricted to its use for defining document outline entries.
+.
+.NH 3
+.XN -N basic-outline -- A Basic Document Outline
+.LP
+In its most basic form, the document outline comprises a structured list of headings,
+each associated with a marked location, or \(lqbookmark\(rq, in the document text,
+and a specification for how that marked location should be displayed,
+when this bookmark is selected.
+.LP
+To create a PDF bookmark, the
+.CW pdfhref
+macro is used,
+at the point in the document where the bookmark is to be placed,
+in the form
+.QP
+.fam C
+.B ".pdfhref O"
+.I level > <
+.I "descriptive text ..."
+.LP
+in which the reference class
+.CWB O \& \& \(rq \(lq
+stipulates that this is an outline reference.
+.LP
+Alternatively, for those users who may prefer to think of a document outline
+simply as a collection of bookmarks, the
+.CW pdfbookmark
+macro is also provided \(em indeed,
+.CW pdfhref
+invokes it, when processing the
+.CWB O \& \& \(rq \(lq
+reference class operator.
+It may be invoked directly, in the form
+.QP
+.fam C
+.B .pdfbookmark
+.I level > <
+.I "descriptive text ..."
+.LP
+Irrespective of which of the above macro forms is employed, the
+.CWI level > <
+argument is required.
+It is a numeric argument, defining the nesting level of the \(lqbookmark\(rq
+in the outline hierarchy, with one being the topmost level.
+Its function may be considered analagous to the
+.EM "heading level"
+of the document's section headings,
+for example, as specified with the
+.CW NH
+macro, if using the
+.CW ms
+macros to format the document.
+.LP
+All further arguments, following the
+.CWI level > <
+argument, are collected together, to specify the heading text which will appear
+in the document's outline view.
+Thus, the outline entry for this section of this document,
+which has a level three heading,
+might be specified as
+.QP
+.CW
+\&.pdfhref O 3 \*(SN A Basic Document Outline
+.LP
+or, in the alternative form using the
+.CW pdfbookmark
+macro, as
+.QP
+.CW
+\&.pdfbookmark 3 \*(SN A Basic Document Outline
+.
+.NH 3
+.XN Hierarchical Structure in a Document Outline
+.LP
+When a document outline is created, using the
+.CW pdfhref
+macro as described in
+.\"
+.\" Here is an example of how we can temporarily modify the format of
+.\" a reference link, in this case to indicate only the section number
+.\" of the link target, in the form "section #", (or, if we define
+.\" "SECREF.BEGIN" before the call, its content followed by the
+.\" section number).
+.\"
+.\" We first define a macro, which will get the reference data from
+.\" pdfhref, as arguments, and will return the formatted output, as we
+.\" require it, the string "PDFHREF.TEXT".
+.\"
+.de SECREF
+.while \\n(.$ \{\
+. ie '\\$1'section' \{\
+. if !dSECREF.BEGIN .ds SECREF.BEGIN \\$1
+. ds PDFHREF.TEXT \\*[SECREF.BEGIN]\~\\$2
+. rm SECREF.BEGIN
+. shift \\n(.$
+. \}
+. el .shift
+. \}
+..
+.\" We now tell "pdfhref" to use our formatting macro, in place of
+.\" its builtin default formatter, before we specify the reference.
+.\"
+.pdfhref F SECREF
+.pdfhref L -A , -D basic-outline
+.\"
+.\" At this point, we would normally revert the "pdfhref" formatter
+.\" to use its default, built in macro. However, in this particular
+.\" case, we want to use our custom format one more time, before we
+.\" revert it, so we will omit the reversion step this time.
+.\"
+and any entry is added at a nesting level greater than one,
+then a hierarchical structure is automatically defined for the outline.
+However, as was noted in the simplified
+.pdfhref L -D pdfmark-example -- example
+in
+.pdfhref L -A , -D pdfmark-operator
+.\"
+.\" And now, we revert to default "pdfhref" formatting behaviour,
+.\" by completing the call we delayed above.
+.\"
+.pdfhref F
+.\"
+the data required by the
+.CW pdfmark
+operator to create the outline entry may not be fully defined,
+when the outline reference is defined in the
+.CW groff
+document source.
+Specifically, when the outline entry is created, its
+.CW /Count
+key must be assigned a value equal to the number of its subordinate entries,
+at the next inner level of the outline hierarchy;
+typically however,
+these subordinate entries will be defined
+.EM later
+in the document source, and the appropriate
+.CW /Count
+value will be unknown, when defining the parent entry.
+.LP
+To resolve this paradox, the
+.CW pdfhref
+macro creates the outline entry in two distinct phases \(em
+a destination marker is placed in the \*[PostScript] output stream immediately,
+when the outline reference is defined,
+but the actual outline entry is stored in an internal \(lqoutline cache\(rq,
+until its subordinate hierarchy has been fully defined;
+it can then be inserted in the output stream, with its
+.CW /Count
+value correctly assigned.
+Effectively, to ensure integrity of the document outline structure,
+this means that each top level outline entry, and
+.EM all
+of its subordinates, are retained in the cache, until the
+.EM next
+top level entry is defined.
+.LP
+One potential problem, which arises from the use of the \(lqoutline cache\(rq,
+is that, at the end of any document formatting run, the last top level outline entry,
+and any subordinates defined after it, will remain in the cache, and will
+.EM not
+be automatically written to the output stream.
+To avoid this problem, the user should follow the guidelines given in
+.\"
+.\" Here is a more conventional example of how to temporarily change
+.\" to the format used to display reference links. We will again use
+.\" the "SECREF" format, which we defined above, but on this occasion
+.\" we will immediately revert to the default format, after the link
+.\" has been placed.
+.\"
+.pdfhref F SECREF
+.pdfhref L -D pdfsync -A ,
+.pdfhref F
+.\"
+to synchronize the output state with the cache state,
+.XR pdfsync ), (
+at the end of the
+.CW groff
+formatting run.
+.
+.NH 3
+.XN -N outline-view -- Associating a Document View with an Outline Reference
+.LP
+Each \(lqbookmark\(rq entry, in a PDF document outline,
+is associated with a specific document view.
+When the reader selects any outline entry,
+the document view changes to display the document context
+associated with that entry.
+.LP
+The document view specification,
+to be associated with any document outline entry,
+is established at the time when the outline entry is created.
+However, rather than requiring that each individual use of the
+.CW pdhref
+macro, to create an outline entry,
+should include its own view specification,
+the actual specification assigned to each entry is derived from
+a generalized specification defined in the string
+.CW PDFBOOKMARK.VIEW ,
+together with the setting of the numeric register
+.CW PDFHREF.VIEW.LEADING ,
+which determine the effective view specification as follows:\(en
+.QS
+.IP \*[= PDFBOOKMARK.VIEW]
+Establishes the magnification at which the document will be viewed,
+at the location of the \(lqbookmark\(rq; by default, it is defined by
+.RS
+.QP
+.CW ".ds PDFBOOKMARK.VIEW /FitH \e\en[PDFPAGE.Y] u"
+.RE
+.IP
+which displays the associated document view,
+with the \(lqbookmark\(rq location positioned at the top of the display window,
+and with the magnification set to fit the page width to the width of the window.
+.IP \*[= PDFHREF.VIEW.LEADING]
+Specifies additional spacing,
+to be placed between the top of the display window
+and the actual location of the \(lqbookmark\(rq on the displayed page view.
+By default, it is set as
+.RS
+.QP
+.CW ".nr PDFHREF.VIEW.LEADING 5.0p"
+.RE
+.IP
+Note that
+.CW PDFHREF.VIEW.LEADING
+does not represent true \(lqleading\(rq, in the typographical sense,
+since any preceding text, set in the specified display space,
+will be visible at the top of the document viewing window,
+when the reference is selected.
+.IP
+Also note that the specification of
+.CW PDFHREF.VIEW.LEADING
+is shared by
+.EM all
+reference views defined by the
+.CW pdfhref
+macro; whereas
+.CW PDFBOOKMARK.VIEW
+is applied exclusively to outline references,
+there is no independent
+.CW PDFBOOKMARK.VIEW.LEADING
+specification.
+.QE
+.LP
+If desired, the view specification may be changed, by redefining the string
+.CW PDFBOOKMARK.VIEW ,
+and possibly also the numeric register
+.CW PDFHREF.VIEW.LEADING .
+Any alternative definition for
+.CW PDFBOOKMARK.VIEW
+.EM must
+be specified in terms of valid view specification parameters,
+as described in the \*[Adobe]
+.pdfmark-manual .
+.LP
+Note the use of the register
+.CW PDFPAGE.Y ,
+in the default definition of
+.CW PDFBOOKMARK.VIEW
+above.
+This register is computed by
+.CW pdfhref ,
+when creating an outline entry;
+it specifies the vertical position of the \(lqbookmark\(rq,
+in basic
+.CW groff
+units, relative to the
+.EM bottom
+edge of the document page on which it is defined,
+and is followed, in the
+.CW PDFBOOKMARK.VIEW
+definition, by the
+.CW grops
+.CW u \(rq \(lq
+operator, to convert it to \*[PostScript] units on output.
+It may be used in any redefined specification for
+.CW PDFBOOKMARK.VIEW ,
+(or in the analogous definition of
+.CW PDFHREF.VIEW ,
+described in
+'ne 2v
+.XR-NO-PREFIX pdfhref-view ),
+but
+.EM not
+in any other context,
+since its value is undefined outside the scope of the
+.CW pdfhref
+macro.
+.LP
+Since
+.CW PDFPAGE.Y
+is computed relative to the
+.EM bottom
+of the PDF output page,
+it is important to ensure that the page length specified to
+.CW troff
+correctly matches the size of the logical PDF page.
+This is most effectively ensured,
+by providing
+.EM identical
+page size specifications to
+.CW groff ,
+.CW grops
+and to the \*[PostScript] to PDF converter employed,
+and avoiding any page length changes within the document source.
+.LP
+Also note that
+.CW PDFPAGE.Y
+is the only automatically computed \(lqbookmark\(rq location parameter;
+if the user redefines
+.CW PDFBOOKMARK.VIEW ,
+and the modified view specification requires any other positional parameters,
+then the user
+.EM must
+ensure that these are computed
+.EM before
+invoking the
+.CW pdfhref
+macro.
+.
+.NH 3
+.XN -N outline-folding -- Folding the Outline to Conceal Less Significant Headings
+.LP
+When a document incorporates many subheadings,
+at deeply nested levels,
+it may be desirable to \(lqfold\(rq the outline
+such that only the major heading levels are initially visible,
+yet making the inferior subheadings accessible,
+by allowing the reader to expand the view of any heading branch on demand.
+.LP
+The
+.CW pdfmark
+macros support this capability,
+through the setting of the
+.CW PDFOUTLINE.FOLDLEVEL
+register.
+This register should be set to the number of heading levels
+which it is desired to show in expanded form, in the
+.EM initial
+document outline display;
+all subheadings at deeper levels will still be added to the outline,
+but will not become visible until the outline branch containing them is expanded.
+'ne 5
+For example, the setting used in this document:
+.QS
+.LD
+.fam C
+\&.\e" Initialize the outline view to show only three heading levels,
+\&.\e" with additional subordinate level headings folded.
+\&.\e"
+\&.nr PDFOUTLINE.FOLDLEVEL 3
+.DE
+.QE
+.LP
+results in only the first three levels of headings being displayed
+in the document outline,
+.EM until
+the reader chooses to expand the view,
+and so reveal the lower level headings in any outline branch.
+.LP
+The initial default setting of
+.CW PDFOUTLINE.FOLDLEVEL ,
+if the document author does not choose to change it,
+is 10,000.
+This is orders of magnitude greater than the maximum heading level
+which is likely to be used in any document;
+thus the default behaviour will be to show document outlines fully expanded,
+to display all headings defined,
+at all levels within each document.
+.LP
+The setting of
+.CW PDFOUTLINE.FOLDLEVEL
+may be changed at any time;
+however, the effect of each such change may be difficult to predict,
+since it is applied not only to outline entries which are defined
+.EM after
+the setting is changed,
+but also to any entries which remain in the outline cache,
+.EM at
+this time.
+Therefore, it is recommended that
+.CW PDFOUTLINE.FOLDLEVEL
+should be set
+.EM once ,
+at the start of each document;
+if it
+.EM is
+deemed necessary to change it at any other time,
+the outline cache should be flushed,
+.XR pdfsync ), (
+.EM immediately
+before the change,
+which should immediately preceed a level one heading.
+.
+.NH 3
+.XN -N multipart-outline -- Outlines for Multipart Documents
+.LP
+When a document outline is created, using the
+.CW pdfhref
+macro, each reference mark is automatically assigned a name,
+composed of a fixed stem followed by a serially generated numeric qualifier.
+This ensures that, for each single part document, every outline reference
+has a uniquely named destination.
+.LP
+As the overall size of the PDF document increases,
+it may become convenient to divide it into smaller,
+individually formatted \*[PostScript] components,
+which are then assembled, in the appropriate order,
+to create a composite PDF document.
+While this strategy may simplify the overall process of creating and
+editing larger documents, it does introduce a problem in creating
+an overall document outline,
+since each individual \*[PostScript] component will be assigned
+duplicated sequences of \(lqbookmark\(rq names,
+with each name ultimately referring to multiple locations in the composite document.
+To avoid such reference naming conflicts, the
+.CW pdfhref
+macro allows the user to specify a \(lqtag\(rq,
+which is appended to the automatically generated \(lqbookmark\(rq name;
+this may be used as a discriminating mark, to distinguish otherwise
+similarly named destinations, in different sections of the composite document.
+.LP
+To create a \(lqtagged\(rq document outline,
+the syntax for invocation of the
+.CW pdfhref
+macro is modified, by the inclusion of an optional \(lqtag\(rq specification,
+.EM before
+the nesting level argument, i.e.
+.QP
+.fam C
+.B ".pdfhref O"
+.B -T \& [
+.I tag >] <
+.I level > <
+.I "descriptive text ..."
+.LP
+The optional
+.CWI tag > <
+argument may be composed of any characters of the user's choice;
+however, its initial character
+.EM "must not"
+be any decimal digit, and ideally it should be kept short
+\(em one or two characters at most.
+.LP
+By employing a different tag in each section,
+the user can ensure that \(lqbookmark\(rq names remain unique,
+throughout all the sections of a composite document.
+For example, when using the
+.CW spdf.tmac
+macro package, which adds
+.CW pdfmark
+capabilities to the standard
+.CW ms
+package,
+.XR using-spdf ), (
+the table of contents is collected into a separate \*[PostScript] section
+from the main body of the document.
+In the \(lqbody\(rq section, the document outline is \(lquntagged\(rq,
+but in the \(lqTable\~of\~Contents\(rq section, a modified version of the
+.CW TC
+macro adds an outline entry for the start of the \(lqTable\~of\~Contents\(rq,
+invoking the
+.CW pdfhref
+macro as
+.QP
+.CW ".pdfhref O -T T 1 \e\e*[TOC]"
+.LP
+to tag the associated outline destination name with the single character suffix,
+.CW T \(rq. \(lq
+Alternatively, as in the case of the basic outline,
+.XR basic-outline ), (
+this may equally well be specified as
+.QP
+.CW ".pdfbookmark -T T 1 \e\e*[TOC]"
+.
+.NH 3
+.XN Delegation of the Outline Definition
+.LP
+Since the most common use of a document outline
+is to provide a quick method of navigating through a document,
+using active \(lqhypertext\(rq links to chapter and section headings,
+it may be convenient to delegate the responsibility of creating the outline
+to a higher level macro, which is itself used to
+define and format the section headings.
+This approach has been adopted in the
+.CW spdf.tmac
+package, to be described later,
+.XR using-spdf ). (
+.LP
+When such an approach is adopted,
+the user will rarely, if ever, invoke the
+.CW pdfhref
+macro directly, to create a document outline.
+For example, the structure and content of the outline for this document
+has been exclusively defined, using a combination of the
+.CW NH
+macro, from the
+.CW ms
+package, to establish the structure, and the
+.CW XN
+macro from
+.CW spdf.tmac ,
+to define the content.
+In this case,
+the responsibility for invoking the
+.CW pdfhref
+macro, to create the document outline,
+is delegated to the
+.CW XN
+macro.
+.
+.NH 2
+.XN -N pdfhref -- Adding Reference Marks and Links
+.LP
+.pdfhref F SECREF
+.ds SECREF.BEGIN Section
+.pdfhref L -D add-outline
+.pdfhref F
+has shown how the
+.CW pdfhref
+macro may be used to create a PDF document outline.
+While this is undoubtedly a powerful capability,
+it is by no means the only trick in the repertoire of this versatile macro.
+.LP
+The macro name,
+.CW pdfhref ,
+which is a contraction of \(lqPDF HyperText Reference\(rq,
+indicates that the general purpose of this macro is to define
+.EM any
+type of dynamic reference mark, within a PDF document.
+Its generalized usage syntax takes the form
+.QP
+.fam C
+.B .pdfhref
+.BI class > <
+.I "-options ...\&" ] [
+[--]
+.I "descriptive text ...\&" ] [
+.LP
+where
+.CW <\f(CIclass\fP>
+represents a required single character argument,
+which defines the specific reference operation to be performed,
+and may be selected from:\(en
+.QS
+.IP \*[= O]
+Add an entry to the document outline.
+This operation has been described earlier,
+.XR add-outline ). (
+.IP \*[= M]
+Place a \(lqnamed destination\(rq reference mark at the current output position,
+in the current PDF document,
+.XR mark-dest ). (
+.IP \*[= D]
+Specify the content of a PDF document reference dictionary entry;
+typically, such entries are generated automatically,
+by transformation of the intermediate output resulting from the use of
+.CW pdfhref
+.CWB M \& \& \(rq, \(lq
+with the
+.CWB -X \& \& \(rq \(lq
+modifier,
+.XR create-map ); (
+however, it is also possible to specify such entries manually,
+.XR user-format ). (
+.IP \*[= L]
+Insert an active link to a named destination,
+.XR link-named ), (
+at the current output position in the current PDF document,
+such that when the reader clicks on the link text,
+the document view changes to show the location of the named destination.
+.IP \*[= W]
+Insert an active link to a \(lqweb\(rq resource,
+.XR add-weblink ), (
+at the current output position in the current PDF document.
+This is effectively the same as using the
+.CWB L \& \& \(rq \(lq
+operator to establish a link to a named destination in another PDF document,
+.XR link-extern ), (
+except that in this case, the destination is specified by a
+\(lquniform resource identifier\(rq, or
+.CW URI ;
+this may represent any Internet or local resource
+which can be specified in this manner.
+.IP \*[= F]
+Specify a user defined macro, to be called by
+.CW pdfhref ,
+when formatting the text in the active region of a link,
+.XR set-format ). (
+.IP \*[= Z]
+Define the absolute position on the physical PDF output page,
+where the \(lqhot\(hyspot\(rq associated with an active link is to be placed.
+Invoked in pairs, marking the starting and ending PDF page co\(hyordinates
+for each link \(lqhot\(hyspot\(rq, this operator is rarely, if ever,
+specified directly by the user;
+rather, appropriate
+.CW pdfhref
+.CWB Z \& \& \(rq \(lq
+specifications are inserted automatically into the document reference map
+during the PDF document formatting process,
+.XR create-map ). (
+.IP \*[= I]
+Initialize support for
+.CW pdfhref
+features.
+The current
+.CW pdfhref
+implementation provides only one such feature which requires initialization
+\(em a helper macro which must be attached to a user supplied page trap handler,
+in order to support mapping of reference \(lqhot\(hyspots\(rq
+which extend through a page transition;
+.XR page-trap ). (
+.QE
+.
+.NH 3
+.XN -S -- Optional Features of the \F[C]pdfhref\F[] Macro
+.LP
+The behaviour of a number of the
+.CW pdfhref
+macro operations can be modified,
+by including
+.EM "option specifiers" \(rq \(lq
+after the operation specifying argument,
+but
+.EM before
+any other arguments normally associated with the operation.
+In
+.EM all
+cases, an option is specified by an
+.EM "option flag" \(rq, \(lq
+comprising an initial hyphen,
+followed by one or two option identifying characters.
+Additionally,
+.EM some
+options require
+.EM "exactly one"
+option argument;
+for these options, the argument
+.EM must
+be specified, and it
+.EM must
+be separated from the preceding option flag by one or more
+.EM spaces ,
+(tabs
+.EM "must not"
+be used).
+It may be noted that this paradigm for specifying options
+is reminiscent of most
+Unix\(tm
+shells; however, in the case of the
+.CW pdfhref
+macro, omission of the space separating an option flag from its argument is
+.EM never
+permitted.
+.LP
+A list of
+.EM all
+general purpose options supported by the
+.CW pdfhref
+macro is given below.
+Note that not all options are supported for all
+.CW pdfhref
+operations; the operations affected by each option are noted in the list.
+For
+.EM most
+operations, if an unsupported option is specified,
+it will be silently ignored; however, this behaviour should
+not be relied upon.
+.LP
+The general purpose options, supported by the
+.CW pdfhref
+macro, are:\(en
+.QS
+.IP \*[= -N\0 name > <]
+Allows the
+.CWI name > <
+associated with a PDF reference destination
+to be defined independently from the following text,
+which describes the reference.
+This option affects only the
+.CWB M \& \& \(rq \(lq
+operation of the
+.CW pdfhref
+macro,
+.XR mark-dest ). (
+.IP \*[= -E]
+Also used exclusively with the
+.CWB M \& \& \(rq \(lq
+operator, the
+.CWB -E
+option causes any specified
+.CWI descriptive \& \& \~\c
+.CWI text
+arguments,
+.XR mark-dest ), (
+to be copied, or
+.EM echoed ,
+in the body text of the document,
+at the point where the reference mark is defined;
+(without the
+.CWB -E
+option, such
+.CWI descriptive \& \& \~\c
+.CWI text
+will appear
+.EM only
+at points where links to the reference mark are placed,
+and where the standard reference display format,
+.XR set-format ), (
+is used).
+.IP \*[= -D\0 dest > <]
+Specifies the
+.CW URI ,
+or the destination name associated with a PDF active link,
+independently of the following text,
+which describes the link and demarcates the link \(lqhot\(hyspot\(rq.
+This option affects the behaviour of the
+.CW pdfhref
+macro's
+.CWB L \& \& \(rq \(lq
+and
+.CWB W \& \& \(rq \(lq
+operations.
+.IP
+When used with the
+.CWB L \& \& \(rq \(lq
+operator, the
+.CWI dest > <
+argument must specify a PDF \(lqnamed destination\(rq,
+as defined using
+.CW pdfhref
+with the
+.CWB M \& \& \(rq \(lq
+operator.
+.IP
+When used with the
+.CWB W \& \& \(rq \(lq
+operator,
+.CWI dest > <
+must specify a link destination in the form of a
+\(lquniform resource identifier\(rq, or
+.CW URI ,
+.XR add-weblink ). (
+.IP \*[= -F\0 file > <]
+When used with the
+.CWB L \& \& \(rq \(lq
+.CW pdfhref
+operator,
+.CWI file > <
+specifies an external PDF file in which the named destination
+for the link reference is defined.
+This option
+.EM must
+be specified with the
+.CWB L \& \& \(rq \(lq
+operator,
+to create a link to a destination in a different PDF document;
+when the
+.CWB L \& \& \(rq \(lq
+operator is used
+.EM without
+this option, the link destination is assumed to be defined
+within the same document.
+.IP \*[= -P\0 \(dqprefix\(hytext\(dq > <]
+Specifies
+.CWI \(dqprefix\(hytext\(dq > <
+to be attached to the
+.EM start
+of the text describing an active PDF document link,
+with no intervening space, but without itself being included in the
+active area of the link \(lqhot\(hyspot\(rq;
+it is effective with the
+.CWB L \& \& \(rq \(lq
+and
+.CWB W \& \& \(rq \(lq
+.CW pdfhref
+operators.
+.IP
+Typically, this option would be used to insert punctuation before
+the link \(lqhot\(hyspot\(rq.
+Thus, there is little reason for the inclusion of spaces in
+.CWI \(dqprefix\(hytext\(dq > < ;
+however, if such space is required, then the enclosing double quotes
+.EM must
+be specified, as indicated.
+.IP \*[= -A\0 \(dqaffixed\(hytext\(dq > <]
+Specifies
+.CWI \(dqaffixed\(hytext\(dq > <
+to be attached to the
+.EM end
+of the text describing an active PDF document link,
+with no intervening space, but without itself being included in the
+active area of the link \(lqhot\(hyspot\(rq;
+it is effective with the
+.CWB L \& \& \(rq \(lq
+and
+.CWB W \& \& \(rq \(lq
+.CW pdfhref
+operators.
+.IP
+Typically, this option would be used to insert punctuation after
+the link \(lqhot\(hyspot\(rq.
+Thus, there is little reason for the inclusion of spaces in
+.CWI \(dqaffixed\(hytext\(dq > < ;
+however, if such space is required, then the enclosing double quotes
+.EM must
+be specified, as indicated.
+.IP \*[= -T\0 tag > <]
+When specified with the
+.CWB O \& \& \(rq \(lq
+operator,
+.CWI tag > <
+is appended to the \(lqbookmark\(rq name assigned to the generated outline entry.
+This option is
+.EM required ,
+to distinguish between the series of \(lqbookmark\(rq names generated in
+individual passes of the
+.CW groff
+formatter, when the final PDF document is to be assembled
+from a number of separately formatted components;
+.XR multipart-outline ). (
+.IP \*[= -X]
+This
+.CW pdfhref
+option is used with either the
+.CWB M \& \& \(rq \(lq
+operator, or with the
+.CWB L \& \& \(rq \(lq
+operator.
+.IP
+When used with the
+.CWB M \& \& \(rq \(lq
+operator,
+.XR mark-dest ), (
+it ensures that a cross reference record for the marked destination
+will be included in the document reference map,
+.XR export-map ). (
+.IP
+When used with the
+.CWB L \& \& \(rq \(lq
+operator,
+.XR link-named ), (
+it causes the reference to be displayed in the standard cross reference format,
+.XR set-format ), (
+but substituting the
+.CWI descriptive \& \& \~\c
+.CWI text
+specified in the
+.CW pdfhref \& \(lq
+.CW L \(rq
+argument list,
+for the description specified in the document reference map.
+.IP \*[= --]
+Marks the end of the option specifiers.
+This may be used with all
+.CW pdfhref
+operations which accept options, to prevent
+.CW pdfhref
+from interpreting any following arguments as option specifiers,
+even if they would otherwise be interpreted as such.
+It is also useful when the argument list to
+.CW pdfhref
+contains special characters \(em any special character,
+which is not valid in a
+.CW groff
+macro name, will cause a parsing error, if
+.CW pdfhref
+attempts to match it as a possible option flag;
+using the
+.CW -- \(rq \(lq
+flag prevents this, so suppressing the
+.CW groff
+warning message, which would otherwise ensue.
+.IP
+Using this flag after
+.EM all
+sequences of macro options is recommended,
+even when it is not strictly necessary,
+if only for the entirely cosmetic benefit of visually separating
+the main argument list from the sequence of preceding options.
+.QE
+.LP
+In addition to the
+.CW pdfhref
+options listed above, a supplementary set of two character options are defined.
+These supplementary options, listed below, are intended for use with the
+.CWB L \& \& \(rq \(lq
+operator, in conjunction with the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option, to specify alternate file names,
+in formats compatible with the file naming conventions
+of alternate operating systems;
+they will be silently ignored, if used in any other context.
+.LP
+The supported alternate file name options,
+which are ignored if the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option is not specified, are:\(en
+.QS
+.IP \*[= -DF\0 dos\(hyfile > <]
+Specifies the name of the file in which a link destination is defined,
+using the file naming semantics of the
+.CW MS\(hyDOS \*(rg
+operating system.
+When the PDF document is read on a machine
+where the operating system uses the
+.CW MS\(hyDOS \*(rg
+file system, then
+.CWI dos\(hyfile > <
+is used as the name of the file containing the reference destination,
+overriding the
+.CWI file > <
+argument specified with the
+.CWB -F
+option.
+.IP \*[= -MF\0 mac\(hyfile > <]
+Specifies the name of the file in which a link destination is defined,
+using the file naming semantics of the
+.CW Apple \*(rg
+.CW Macintosh \*(rg
+operating system.
+When the PDF document is read on a machine
+where the operating system uses the
+.CW Macintosh \*(rg
+file system, then
+.CWI mac\(hyfile > <
+is used as the name of the file containing the reference destination,
+overriding the
+.CWI file > <
+argument specified with the
+.CWB -F
+option.
+.IP \*[= -UF\0 unix\(hyfile > <]
+Specifies the name of the file in which a link destination is defined,
+using the file naming semantics of the
+.CW Unix \(tm
+operating system.
+When the PDF document is read on a machine
+where the operating system uses
+.CW POSIX
+file naming semantics, then
+.CWI unix\(hyfile > <
+is used as the name of the file containing the reference destination,
+overriding the
+.CWI file > <
+argument specified with the
+.CWB -F
+option.
+.IP \*[= -WF\0 win\(hyfile > <]
+Specifies the name of the file in which a link destination is defined,
+using the file naming semantics of the
+.CW MS\(hyWindows \*(rg
+32\(hybit operating system.
+When the PDF document is read on a machine
+where the operating system uses any of the
+.CW MS\(hyWindows \*(rg
+file systems, with long file name support, then
+.CWI win\(hyfile > <
+is used as the name of the file containing the reference destination,
+overriding the
+.CWI file > <
+argument specified with the
+.CWB -F
+option.
+.QE
+.
+.NH 3
+.XN -N mark-dest -- Marking a Reference Destination
+.LP
+The
+.CW pdfhref
+macro may be used to create active links to any Internet resource,
+specified by its
+.CW URI ,
+or to any \(lqnamed destination\(rq,
+either within the same document, or in another PDF document.
+Although the PDF specification allows link destinations to be defined
+in terms of a page number, and an associated view specification,
+this style of reference is not currently supported by the
+.CW pdfhref
+macro, because it is not possible to adequately bind the specification
+for the destination with the intended reference context.
+.LP
+References to Internet resources are interpreted in accordance with the
+.CW W3C
+standard for defining a
+.CW URI ;
+hence the only prerequisite, for creating a link to any Internet resource,
+is that the
+.CW URI
+be properly specified, when declaring the reference;
+.XR add-weblink ). (
+In the case of references to \(lqnamed destinations\(rq in PDF documents,
+however, it is necessary to provide a mechanism for creating such
+\(lqnamed destinations\(rq.
+This may be accomplished, by invoking the
+.CW pdfhref
+macro in the form
+.QP
+.fam C
+.B ".pdfhref M"
+.B -N \& [
+.I name >] <
+.B -X ] [
+.B -E ] [
+.I "descriptive text ...\&" ] [
+.LP
+This creates a \(lqnamed destination\(rq reference mark, with its name specified by
+.CWI name > < ,
+or, if the
+.CWB -N
+option is not specified, by the first word of
+.CWI descriptive \& \& \~\c
+.CWI text \& \& ;
+(note that this imposes the restriction that,
+if the
+.CWB -N
+option is omitted, then
+.EM "at least"
+one word of
+.CWI descriptive \& \& \~\c
+.CWI text
+.EM must
+be specified).
+Additionally, a reference view will be automatically defined,
+and associated with the reference mark,
+.XR pdfhref-view ), (
+.\" and, if any
+.\" .CWI descriptive
+.\" .CWI text
+.\" is specified, or the
+and, if the
+.CWB -X
+option is specified, and no document cross reference map has been imported,
+.XR import-map ), (
+then a cross reference mapping record,
+.XR export-map ), (
+will be written to the
+.CW stdout
+stream;
+this may be captured, and subsequently used to generate a cross reference map
+for the document,
+.XR create-map ). (
+.LP
+When a \(lqnamed destination\(rq reference mark is created, using the
+.CW pdfhref
+macro's
+.CWB M \& \& \(rq \(lq
+operator, there is normally no visible effect in the formatted document; any
+.CWI descriptive \& \& \~\c
+.CWI text
+which is specified will simply be stored in the cross reference map,
+for use when a link to the reference mark is created.
+This default behaviour may be changed, by specifying the
+.CWB -E
+option, which causes any specified
+.CWI descriptive \& \& \~\c
+.CWI text
+to be \(lqechoed\(rq in the document text,
+at the point where the reference mark is placed,
+in addition to its inclusion in the cross reference map.
+.
+.NH 4
+.XN -N export-map -- Mapping a Destination for Cross Referencing
+.LP
+Effective cross referencing of
+.EM any
+document formatted by
+.CW groff
+requires multiple pass formatting.
+Details of how this multiple pass formatting may be accomplished,
+when working with the
+.CW pdfmark
+macros, will be discussed later,
+.XR do-xref ); (
+at this stage, the discussion will be restricted to the initial preparation,
+which is required at the time when the cross reference destinations are defined.
+.LP
+The first stage, in the process of cross referencing a document,
+is the generation of a cross reference map.
+Again, the details of
+.EM how
+the cross reference map is generated will be discussed in
+.pdfhref F SECREF L -D do-xref -A ;
+.pdfhref F
+however, it is important to recognize that
+.EM what
+content is included in the cross reference map is established
+when the reference destination is defined \(em it is derived
+from the reference data exported on the
+.CW stderr
+stream by the
+.CW pdfhref
+macro, when it is invoked with the
+.CWB M \& \& \(rq \(lq
+operator, and is controlled by whatever definition of the string
+.CW PDFHREF.INFO
+is in effect, when the
+.CW pdfhref
+macro is invoked.
+.LP
+The initial default setting of
+.CW PDFHREF.INFO
+is
+.QP
+.CW ".ds PDFHREF.INFO page \e\en% \e\e$*"
+.LP
+which ensures that the cross reference map will contain
+at least a page number reference, supplemented by any
+.CWI descriptive \& \& \~\c
+.CWI text
+which is specified for the reference mark, as defined by the
+.CW pdfhref
+macro, with its
+.CWB M \& \& \(rq \(lq
+operator; this may be redefined by the user,
+to export additional cross reference information,
+or to modify the default format for cross reference links,
+.XR set-format ). (
+.
+.NH 4
+.XN -N pdfhref-view -- Associating a Document View with a Reference Mark
+.LP
+In the same manner as each document outline reference, defined by the
+.CW pdfhref
+macro with the
+.CWB O \& \& \(rq \(lq
+operator,
+.XR add-outline ), (
+has a specific document view associated with it,
+each reference destination marked by
+.CW pdfhref
+with the
+.CWB M \& \& \(rq \(lq
+operator, requires an associated document view specification.
+.LP
+The mechanism whereby a document view is associated with a reference mark
+is entirely analogous to that employed for outline references,
+.XR outline-view ), (
+except that the
+.CW PDFHREF.VIEW
+string specification is used, in place of the
+.CW PDFBOOKMARK.VIEW
+specification.
+Thus, the reference view is defined in terms of:\(en
+.QS
+.IP \*[= PDFHREF.VIEW]
+A string,
+establishing the position of the reference mark within the viewing window,
+and the magnification at which the document will be viewed,
+at the location of the marked reference destination;
+by default, it is defined by
+.RS
+.QP
+.CW ".ds PDFHREF.VIEW /FitH \e\en[PDFPAGE.Y] u"
+.RE
+.IP
+which displays the reference destination at the top of the viewing window,
+with the magnification set to fit the page width to the width of the window.
+.IP \*[= PDFHREF.VIEW.LEADING]
+A numeric register,
+specifying additional spacing, to be placed between the top of the display
+window and the actual position at which the location of the reference
+destination appears within the window.
+This register is shared with the view specification for outline references,
+and thus has the same default initial setting,
+.RS
+.QP
+.CW ".nr PDFHREF.VIEW.LEADING 5.0p"
+.RE
+.IP
+as in the case of outline reference views.
+.IP
+Again, notice that
+.CW PDFHREF.VIEW.LEADING
+does not represent true typographic \(lqleading\(rq,
+since any preceding text, set in the specified display space,
+will be visible at the top of the viewing window,
+when the reference is selected.
+.QE
+.LP
+Just as the view associated with outline references may be changed,
+by redefining
+.CW PDFBOOKMARK.VIEW ,
+so the view associated with marked reference destinations may be changed,
+by redefining
+.CW PDFHREF.VIEW ,
+and, if desired,
+.CW PDFHREF.VIEW.LEADING ;
+such changes will become effective for all reference destinations marked
+.EM after
+these definitions are changed.
+(Notice that, since the specification of
+.CW PDFHREF.VIEW.LEADING
+is shared by both outline reference views and marked reference views,
+if it is changed, then the views for
+.EM both
+reference types are changed accordingly).
+.LP
+It may again be noted, that the
+.CW PDFPAGE.Y
+register is used in the definition of
+.CW PDFHREF.VIEW ,
+just as it is in the definition of
+.CW PDFBOOKMARK.VIEW ;
+all comments in
+.pdfhref F SECREF L -D outline-view
+.pdfhref F
+relating to its use, and indeed to page position computations in general,
+apply equally to marked reference views and to outline reference views.
+.
+.NH 3
+.XN -N link-named -- Linking to a Marked Reference Destination
+.LP
+Any named destination, such as those marked by the
+.CW pdfhref
+macro, using it's
+.CWB M \& \& \(rq \(lq
+operator, may be referred to from any point in
+.EM any
+PDF document, using an
+.EM "active link" ;
+such active links are created by again using the
+.CW pdfhref
+macro, but in this case, with the
+.CWB L \& \& \(rq \(lq
+operator.
+This operator provides support for two distinct cases,
+depending on whether the reference destination is defined in
+the same document as the link,
+.XR link-intern ), (
+or is defined as a named destination in a different PDF document,
+.XR link-extern ). (
+.
+.NH 4
+.XN -N link-intern -- References within a Single PDF Document
+.LP
+The general syntactic form for invoking the
+.CW pdfhref
+macro,
+when creating a link to a named destination within the same PDF document is
+.QP
+.fam C
+.B .pdfhref
+.B L
+.B -D \& [
+.BI dest-name >] <
+.B -P \& [
+.BI prefix-text >] <
+.B -A \& [
+.BI affixed-text >] <
+\e
+.br
+\0\0\0
+.B -X ] [
+.B -- ] [
+.I "descriptive text ...\&" ] [
+.LP
+where
+.CWI dest-name > <
+specifies the name of the link destination,
+as specified using the
+.CW pdfhref
+.CWB M \& \& \(rq \(lq
+operation; (it may be defined either earlier in the document,
+to create a backward reference, or later, to create a forward reference).
+.\"
+.\" Here's a example of how to add an iconic annotation.
+.\"
+.\".pdfnote -T "Internal Cross References" \
+.\" This description is rather terse, and could benefit from \
+.\" the inclusion of an example.
+.LP
+If any
+.CWI descriptive \& \& \~\c
+.CWI text
+arguments are specified, then they will be inserted into the
+.CW groff
+output stream, to define the text appearing in the \(lqhot\(hyspot\(rq
+region of the link;
+this will be printed in the link colour specified by the string,
+.CW PDFHREF.TEXT.COLOUR ,
+which is described in
+.XR-NO-PREFIX set-colour .
+If the
+.CWB -X
+option is also specified, then the
+.CWI descriptive \& \& \~\c
+.CWI text
+will be augmented, by prefacing it with page and section number indicators,
+in accordance with the reference formatting rules which are in effect,
+.XR set-format ); (
+such indicators will be included within the active link region,
+and will also be printed in the link colour.
+.LP
+Note that
+.EM either
+the
+.CWB -D \& \& \~\c
+.CWBI dest\(hyname > <
+option,
+.EM or
+the
+.CWI descriptive \& \& \~\c
+.CWI text
+arguments,
+.EM "but not both" ,
+may be omitted.
+If the
+.CWB -D \& \& \~\c
+.CWBI dest\(hyname > <
+option is omitted, then the first word of
+.CWI descriptive \& \& \~\c
+.CWI text \& \& ,
+i.e.\~all text up to but not including the first space,
+will be interpreted as the
+.CWBI dest\(hyname > <
+for the link; this text will also appear in the running text of the document,
+within the active region of the link.
+Alternatively, if the
+.CWB -D \& \& \~\c
+.CWBI dest\(hyname > <
+option
+.EM is
+specified, and
+.CWI descriptive \& \& \~\c
+.CWI text
+is not,
+then the running text which defines the reference,
+and its active region,
+will be derived from the reference description which is specified
+when the named destination is marked,
+.XR mark-dest ), (
+and will be formatted according to the reference formatting rules
+which are in effect, when the reference is placed,
+.XR set-format ); (
+in this case, it is not necessary to specify the
+.CWB -X
+option to activate automatic formatting of the reference \(em it is implied,
+by the omission of all
+.CWI descriptive \& \& \~\c
+.CWI text
+arguments.
+.LP
+The
+.CWB -P \& \& \~\c
+.CWBI prefix\(hytext > <
+and
+.CWB -A \& \& \~\c
+.CWBI affixed\(hytext > <
+options may be used to specify additional text
+which will be placed before and after the linked text respectively,
+with no intervening space.
+Such prefixed and affixed text will be printed in the normal text colour,
+and will not be included within the active region of the link.
+This feature is mostly useful for creating parenthetical references,
+or for placing punctuation adjacent to,
+but not included within,
+the text which defines the active region of the link.
+.LP
+The operation of the
+.CW pdfhref
+macro, when used with its
+.CWB L \& \& \(rq \(lq
+operator to place a link to a named PDF destination,
+may best be illustrated by an example.
+However, since the appearance of the link will be influenced by
+factors established when the named destination is marked,
+.XR mark-dest ), (
+and also by the formatting rules in effect when the link is placed,
+the presentation of a suitable example will be deferred,
+until the formatting mechanism has been explained,
+.XR set-format ). (
+.
+.NH 4
+.XN -N link-extern -- References to Destinations in Other PDF Documents
+.LP
+The
+.CW pdfhref
+macro's
+.CWB L \& \& \(rq \(lq
+operator is not restricted to creating reference links
+within a single PDF document.
+When the link destination is defined in a different document,
+then the syntactic form for invoking
+.CW pdfhref
+is modified, by the addition of options to specify the
+name and location of the PDF file in which the destination is defined.
+Thus, the extended
+.CW pdfhref
+syntactic form becomes
+.QP
+.fam C
+.B .pdfhref
+.B L
+.B -F
+.BI file > <
+.B -D \& [
+.BI dest-name >] <
+\e
+.br
+\0\0\0
+.B -DF \& [
+.BI dos-file >] <
+.B -MF \& [
+.BI mac-file >] <
+.B -UF \& [
+.BI unix-file >] <
+\e
+.br
+\0\0\0
+.B -WF \& [
+.BI win-file >] <
+.B -P \& [
+.BI prefix-text >] <
+.B -A \& [
+.BI affixed-text >] <
+\e
+.br
+\0\0\0
+.B -X ] [
+.B -- ] [
+.I "descriptive text ...\&" ] [
+.LP
+where the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option serves
+.EM two
+purposes: it both indicates to the
+.CW pdfhref
+macro that the specified reference destination
+is defined in an external PDF file,
+and it also specifies the normal path name,
+which is to be used to locate this file,
+when a user selects the reference.
+.LP
+In addition to the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option, which
+.EM must
+be specified when referring to a destination in an external PDF file,
+the
+.CWB -DF \& \& \~\c
+.CWBI dos\(hyfile > < ,
+.CWB -MF \& \& \~\c
+.CWBI mac\(hyfile > < ,
+.CWB -UF \& \& \~\c
+.CWBI unix\(hyfile > <
+and
+.CWB -WF \& \& \~\c
+.CWBI win\(hyfile > <
+options may be used to specify the location of the file
+containing the reference destination,
+in a variety of operating system dependent formats.
+These options assign their arguments to the
+.CW /DosFile ,
+.CW /MacFile ,
+.CW /UnixFile
+and
+.CW /WinFile
+keys of the generated
+.CW pdfmark
+respectively; thus when any of these options are specified,
+.EM "in addition to"
+the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option, and the document is read on the appropriate operating systems,
+then the path names specified by
+.CWBI dos\(hyfile > < ,
+.CWBI mac\(hyfile > < ,
+.CWBI unix\(hyfile > <
+and
+.CWBI win\(hyfile > <
+will be searched,
+.EM instead
+of the path name specified by
+.CWBI file > < ,
+for each of the
+.CW MS\(hyDOS \*(rg,
+.CW Apple \*(rg
+.CW Macintosh \*(rg,
+.CW Unix \(tm
+and
+.CW MS\(hyWindows \*(rg
+operating systems, respectively; see the
+.pdfmark-manual ,
+for further details.
+.LP
+Other than the use of these additional options,
+which specify that the reference destination is in an external PDF file,
+the behaviour of the
+.CW pdfhref
+.CWB L \& \& \(rq \(lq
+operator, with the
+.CWB -F \& \& \~\c
+.CWBI file > <
+option, remains identical to its behaviour
+.EM without
+this option,
+.XR link-intern ), (
+with respect to the interpretation of other options,
+the handling of the
+.CWI descriptive \& \& \~\c
+.CWI text
+arguments, and the formatting of the displayed reference.
+.LP
+Once again, since the appearance of the reference is determined by
+factors specified in the document reference map,
+and also by the formatting rules in effect when the reference is placed,
+the presentation of an example of the placing of
+a reference to an external destination will be deferred,
+until the formatting mechanism has been explained,
+.XR set-format ). (
+.
+.NH 3
+.XN -N add-weblink -- Linking to Internet Resources
+.LP
+In addition to supporting the creation of cross references
+to named destinations in PDF documents, the
+.CW pdfhref
+macro also has the capability to create active links to Internet resources,
+or indeed to
+.EM any
+resource which may be specified by a Uniform Resource Identifier,
+(which is usually abbreviated to the acronym \(lqURI\(rq,
+and sometimes also referred to as a Uniform Resource Locator,
+or \(lqURL\(rq).
+.LP
+Since the mechanism for creating a link to a URI differs somewhat
+from that for creating PDF references, the
+.CW pdfhref
+macro is invoked with the
+.CWB W \& \& \(rq \(lq
+(for \(lqweb\(hylink\(rq) operator, rather than the
+.CWB L \& \& \(rq \(lq
+operator; nevertheless, the invocation syntax is similar, having the form
+.QP
+.fam C
+.B .pdfhref
+.B W
+.B -D \& [
+.BI URI >] <
+.B -P \& [
+.BI prefix-text >] <
+.B -A \& [
+.BI affixed-text >] <
+\e
+.br
+\0\0\0
+.B -- ] [
+.I "descriptive text ...\&"
+.LP
+where the optional
+.CWB -D
+.CWBI URI > <
+modifier specifies the address for the target Internet resource,
+in any appropriate
+.EM "Uniform Resource Identifier"
+format, while the
+.CWI descriptive
+.CWI text
+argument specifies the text which is to appear in the \(lqhot\(hyspot\(rq
+region, and the
+.CWB -P
+.CWBI prefix\(hytext > <
+and
+.CWB -A
+.CWBI affixed\(hytext > <
+options have the same effect as in the case of local document links,
+.XR link-intern ). (
+.LP
+Notice that it is not mandatory to include the
+.CWB -D
+.CWBI URI > <
+in the link specification; if it
+.EM is
+specified, then it is not necessary for the URI to appear,
+in the running text of the document \(em the
+.CWI descriptive
+.CWI text
+argument exactly defines the text
+which will appear within the \(lqhot\(hyspot\(rq region,
+and this need not include the URI.
+However, if the
+.CWB -D \& \& \~\c
+.CWBI URI > <
+specification is omitted, then the
+.CWI descriptive
+.CWI text
+argument
+.EM must
+be an
+.EM exact
+representation of the URI, which
+.EM will ,
+therefore, appear as the entire content of the \(lqhot\(hyspot\(rq.
+For example, we could introduce a reference to
+.pdfhref W -D \*[GROFF-WEBSITE] -A , the groff web site
+in which the actual URI is concealed, by using mark up such as:\(en
+.DS I
+.CW
+For example, we could introduce a reference to
+\&.pdfhref W -D \*[GROFF-WEBSITE] -A , the groff web site
+in which the actual URI is concealed,
+.DE
+Alternatively,
+to refer the reader to the groff web site,
+making it obvious that the appropriate URI is
+.pdfhref W -A , \*[GROFF-WEBSITE]
+the requisite mark up might be:\(en
+.DS I
+.CW
+to refer the reader to the groff web site,
+making it obvious that the appropriate URI is
+\&.pdfhref W -A , \*[GROFF-WEBSITE]
+the requisite mark up might be:\e(en
+.DE
+.
+.NH 3
+.XN -N set-format -- Establishing a Format for References
+.LP
+There are two principal aspects to be addressed,
+when defining the format to be used when displaying references.
+Firstly, it is desirable to provide a visual cue,
+to indicate that the text describing the reference is imbued
+with special properties \(em it is dynamically linked to the reference
+destination \(em and secondly, the textual content should
+describe where the link leads, and ideally,
+it should also describe the content of the reference destination.
+.LP
+The visual cue,
+that a text region defines a dynamically linked reference,
+is most commonly provided by printing the text within the active
+region in a distinctive colour.
+This technique will be employed automatically by the
+.CW pdfhref
+macro \(em
+.XR set-colour
+\(em unless the user specifically chooses to adopt, and implement,
+some alternative strategy.
+.
+.NH 4
+.XN -N set-colour -- Using Colour to Demarcate Link Regions
+.LP
+Typically, when a PDF document contains
+.EM active
+references to other locations, either within the same document,
+or even in other documents, or on the World Wide Web,
+it is usually desirable to make the regions
+where these active links are placed stand out from the surrounding text.
+.
+.NH 4
+.XN -N user-format -- Specifying Reference Text Explicitly
+.
+.NH 4
+.XN -N auto-format -- Using Automatically Formatted Reference Text
+.
+.NH 4
+.XN -N custom-format -- Customizing Automatically Formatted Reference Text
+.LP
+It is incumbent on the user,
+if employing automatic formatting of the displayed reference,
+.XR set-format ), (
+to ensure that an appropriate reference definition
+is created for the reference destination,
+and is included in the reference map for the document
+in which the reference will appear;
+thus, it may be easiest to
+.EM always
+use manual formatting for external references.
+.
+.NH 3
+.XN Problematic Links
+.LP
+Irrespective of whether a
+.CW pdfhref
+reference is placed using the
+.CWB L \& \& \(rq \(lq
+operator, or the
+.CWB W \& \& \(rq \(lq
+operator, there may be occasions when the resulting link
+does function as expected.
+A number of scenarios, which are known to be troublesome,
+are described below.
+.
+.NH 4
+.XN -N page-trap -- Links with a Page Transition in the Active Region
+.LP
+When a link is placed near the bottom of a page,
+it is possible that its active region, or \(lqhot\(hyspot\(rq,
+may extend on to the next page.
+In this situation, a page trap macro is required
+to intercept the page transition, and to restart the mapping of
+the \(lqhot\(hyspot\(rq boundary on the new page.
+.LP
+The
+.CW pdfmark
+macro package includes a suitable page trap macro, to satisfy this requirement.
+However, to avoid pre\(hyempting any other requirement the user may have for
+a page transition trap, this is
+.EM not
+installed as an active page trap,
+unless explicitly requested by the user.
+.LP
+To enable proper handling of page transitions,
+which occur within the active regions of reference links,
+the user should:\(en
+.QS
+.nr ITEM 0 1
+.IP \n+[ITEM].
+Define a page transition macro, to provide whatever features may be required,
+when a page transition occurs \(em e.g.\& printing footnotes,
+adding page footers and headers, etc.
+This macro should end by setting the output position at the correct
+vertical page offset, where the printing of running text is to restart,
+following the page transition.
+.IP \n+[ITEM].
+Plant a trap to invoke this macro, at the appropriate vertical position
+marking the end of normal running text on each page.
+.KS
+.IP \n+[ITEM].
+Initialize the
+.CW pdfhref
+hook into this page transition trap, by invoking
+.RS
+.IP
+.fam C
+.B "pdfhref I -PT"
+.BI macro-name > <
+.LP
+where
+.CWBI macro-name > <
+is the name of the user supplied page trap macro,
+to ensure that
+.CW pdfhref
+will correctly restart mapping of active link regions,
+at the start of each new page.
+.KE
+.RE
+.QE
+.LP
+It may be observed that this initialization of the
+.CW pdfhref
+page transition hook is, typically, required only once
+.EM before
+document formatting begins.
+Users of document formatting macro packages may reasonably expect that
+this initialization should be performed by the macro package itself.
+Thus, writers of such macro packages which include
+.CW pdfmark
+bindings, should provide appropriate initialization,
+so relieving the end user of this responsibility.
+The following example, abstracted from the sample
+.CW ms
+binding package,
+.CW spdf.tmac ,
+illustrates how this may be accomplished:\(en
+.DS I
+.CW
+\&.\e" groff "ms" provides the "pg@bottom" macro, which has already
+\&.\e" been installed as a page transition trap. To ensure proper
+\&.\e" mapping of "pdfhref" links which overflow the bottom of any
+\&.\e" page, we need to install the "pdfhref" page transition hook,
+\&.\e" as an addendum to this macro.
+\&.
+\&.pdfhref I -PT pg@bottom
+.DE
+.
+.NH 2
+.XN -N add-note -- Annotating a PDF Document using Pop-Up Notes
+.
+.NH 2
+.XN -S -N pdfsync -- Synchronizing Output and \F[C]pdfmark\F[] Contexts
+.LP
+It has been noted previously, that the
+.CW pdfview
+macro,
+.XR docview ), (
+the
+.CW pdfinfo
+macro,
+.XR docinfo ), (
+and the
+.CW pdfhref
+macro, when used to create a document outline,
+.XR add-outline ), (
+do not immediately write their
+.CW pdfmark
+output to the \*[PostScript] data stream;
+instead, they cache their output, in a
+.CW groff
+diversion, in the case of the
+.CW pdfview
+and
+.CW pdfinfo
+macros, or in an ordered collection of strings and numeric registers,
+in the case of the document outline,
+until a more appropriate time for copying it out.
+In the case of
+.CW pdfview
+and
+.CW pdfinfo
+\(lqmeta\(hydata\(rq,
+this \(lqmore appropriate time\(rq is explicitly chosen by the user;
+in the case of document outline data,
+.EM some
+cached data may be implicitly written out as the document outline is compiled,
+but there will
+.EM always
+be some remaining data, which must be explicitly flushed out, before the
+.CW groff
+formatting process is allowed to complete.
+.LP
+To allow the user to choose when cached
+.CW pdfmark
+data is to be flushed to the output stream, the
+.CW pdfmark
+macro package provides the
+.CW pdfsync
+macro, (to synchronize the cache and output states).
+In its simplest form, it is invoked without arguments, i.e.
+.QP
+.fam C
+.B .pdfsync
+.LP
+This form of invocation ensures that
+.EM both
+the \(lqmeta\(hydata cache\(rq, containing
+.CW pdfview
+and
+.CW pdfinfo
+data,
+.EM and
+the \(lqoutline cache\(rq,
+containing any previously uncommitted document outline data,
+are flushed; ideally, this should be included in a
+.CW groff
+\(lqend macro\(rq, to ensure that
+.EM both
+caches are flushed, before
+.CW groff
+terminates.
+.LP
+Occasionally,
+it may be desirable to flush either the \(lqmeta\(hydata cache\(rq,
+without affecting the \(lqoutline cache\(rq, or vice\(hyversa,
+at a user specified time, prior to reaching the end of the document.
+This may be accomplished, by invoking the
+.CW pdfsync
+macro with an argument, i.e.
+.QP
+.fam C
+.B ".pdfsync M"
+.LP
+to flush only the \(lqmeta\(hydata cache\(rq, or
+.QP
+.fam C
+.B ".pdfsync O"
+.LP
+to flush only the \(lqoutline cache\(rq.
+.LP
+The \(lqmeta\(hydata cache\(rq can normally be safely flushed
+in this manner, at any time
+.EM after
+output of the first page has started;
+(it may cause formatting problems,
+most notably the appearance of unwanted white space, if flushed earlier,
+or indeed, if flushed immediately after a page transition,
+but before the output of the content on the new page has commenced).
+Caution is required, however, when explicitly flushing the
+\(lqoutline cache\(rq, since if the outline is to be
+subsequently extended, then the first outline entry after flushing
+.EM must
+be specified at level 1.
+Nevertheless, such explicit flushing may occasionally be necessary;
+for example, the
+.CW TC
+macro in the
+.CW spdf.tmac
+package,
+.XR using-spdf ), (
+invokes
+.CW ".pdfsync\ O" \(rq \(lq
+to ensure that the outline for the \(lqbody\(rq section of the document
+is terminated,
+.EM before
+it commences the formatting of the table of contents section.
+.bp
+.
+.NH 1
+.XN -N pdf-layout -- PDF Document Layout
+.LP
+The
+.CW pdfmark
+macros described in the preceding section,
+.XR pdf-features ), (
+provide no inherent document formatting capability of their own.
+However,
+they may be used in conjunction with any other
+.CW groff
+macro package of the user's choice,
+to add such capability.
+.LP
+In preparing this document, the standard
+.CW ms
+macro package, supplied as a component of the GNU Troff distribution,
+has been employed.
+To facilitate the use of the
+.CW pdfmark
+macros with the
+.CW ms
+macros,
+a binding macro package,
+.CW spdf.tmac ,
+has been created.
+The use of this binding macro package is described in the following section,
+.XR using-spdf ); (
+it may also serve as an example to users of other standard
+.CW groff
+macro packages,
+as to how the
+.CW pdfmark
+macros may be employed with their chosen primary macro package.
+.
+.NH 2
+.XN -S -N using-spdf -- Using \F[C]pdfmark\F[] Macros with the \F[C]ms\F[] Macro Package
+.LP
+The use of the binding macro package,
+.CW spdf.tmac ,
+allows for the use of the
+.CW pdfmark
+macros in conjunction with the
+.CW ms
+macros,
+simply by issuing a
+.CW groff
+command of the form\**
+.FS
+Once again,
+.pdfhref L -D pdf-features-fn -- as noted in footnote\*{\n[pdf-features-fn]\*}
+to
+.XR-NO-PREFIX pdf-features ,
+do not specify any
+.CW -T \^\c
+.CWI dev
+option,
+other than
+.CW -T \^\c
+.CW ps ,
+or
+.CW -T \^\c
+.CW pdf ;
+specify
+.CW -T \^\c
+.CW pdf ,
+if you wish to avoid the conversion of \*[PostScript] output to PDF,
+which will be required if you specify
+.CW -T \^\c
+.CW ps ,
+or if you omit the
+.CW -T \^\c
+.CWI dev
+option entirely.
+.FE
+.QP
+.fam C
+groff [-Tps\h'0.2p'|\h'0.2p'-Tpdf] [-m\F[]\|\|\FC\c
+.B spdf
+.I options \F[]\|\|\FC\c [-
+.I file \F[]\|\|\FC\c "...] "
+\&...
+.LP
+When using the
+.CW spdf.tmac
+package, the
+.CW groff
+input files may be marked up using any of the standard
+.CW ms
+macros to specify document formatting,
+while PDF features may be added,
+using any of the
+.CW pdfmark
+macros described previously,
+.XR pdf-features ). (
+Additionally,
+.CW spdf.tmac
+defines a number of convenient extensions to the
+.CW ms
+macro set, to better accomodate the use of PDF features within the
+.CW ms
+formatting framework,
+and to address a number of
+.CW ms
+document layout issues,
+which require special handling when producing PDF documents.
+These additional macros,
+and the issues they are intended to address,
+are described below.
+.
+.NH 3
+.XN -S -- \F[C]ms\F[] Section Headings in PDF Documents
+.LP
+Traditionally,
+.CW ms
+provides the
+.CW NH
+and
+.CW SH
+macros, to specify section headings.
+However,
+there is no standard mechanism for generating a
+table of contents entry based on the text of the section heading;
+neither is there any recognized standard method for establishing a
+cross reference link to the section.
+.LP
+To address this
+.CW ms
+limitation,
+.CW spdf.tmac
+defines the
+.CW XN
+macro,
+.XR xn-macro ), (
+to be used in conjunction with the
+.CW NH
+macro.
+.
+.NH 4
+.XN -S -N xn-macro -- The \F[C]XN\F[] Macro
+.bp
+.
+.NH 1
+.XN The PDF Publishing Process
+.
+.NH 2
+.XN -N do-xref -- Resolving Cross References
+.
+.NH 3
+.XN -N create-map -- Creating a Document Reference Map
+.
+.NH 3
+.XN -N import-map -- Deploying a Document Reference Map
+.TC
+.\" Local Variables:
+.\" mode: nroff
+.\" End:
+.\" vim: filetype=groff:
diff --git a/contrib/pdfmark/pdfmark.tmac b/contrib/pdfmark/pdfmark.tmac
new file mode 100644
index 0000000..5f664f2
--- /dev/null
+++ b/contrib/pdfmark/pdfmark.tmac
@@ -0,0 +1,1953 @@
+.ig
+
+pdfmark.tmac
+
+Copyright (C) 2004-2020 Free Software Foundation, Inc.
+ Written by Keith Marshall (keith.d.marshall@ntlworld.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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+Author's Note
+=============
+
+While I have written this macro package from scratch, much of my
+inspiration has come from discussion on the groff mailing list
+(mailto:groff@gnu.org). I am particularly indebted to:
+
+ Kees Zeelenberg, for an earlier macro package he posted,
+ a study of which helped me to get started.
+
+ Carlos J. G. Duarte and Werner Lemberg, whose discussion
+ on computation of the bounding boxes for link "hot-spots"
+ forms the basis of such computations in this package.
+..
+.if !\n(.g .ab These pdfmark macros require groff.
+.\"
+.\" Check if we have already been loaded -- do not reload
+.if d pdfmark .nx
+.\"
+.\" ======================================================================
+.\" Module PDFMARK: Insert Arbitrary PDFMARK Code in the Postscript Stream
+.\" ======================================================================
+.\"
+.\" PDFMARK output may be disabled, by zeroing the PDFOPMODE register,
+.\" ( which mimics a more generic OPMODE, if it is defined ).
+.\"
+.if rOPMODE .aln PDFOPMODE OPMODE
+.\"
+.\" but if OPMODE wasn't defined,
+.\" then make the default PDFMARK mode ENABLED.
+.\"
+.if !rPDFOPMODE .nr PDFOPMODE 1
+.\"
+.\" PDFMARK output must be constrained to a maximum line length limit,
+.\" for strict compliance with the Postscript DSC. This limit is defined
+.\" in register "PDFMARK.FOLDWIDTH.MAX". This is user definable, up to a
+.\" ceiling value of 255, which is also its default value; this limit
+.\" is enforced for each PDFMARK, by macro "pdf*pdfmark.limit".
+.\"
+.de pdf*pdfmark.limit
+.\" ----------------------------------------------------------------
+.\" Usage:
+.\" .pdf*pdfmark.limit REGISTER-NAME DEFAULT-MAXIMUM-VALUE
+.\" ----------------------------------------------------------------
+.\"
+.\" If a register named REGISTER-NAME has not been defined, then
+.\" define it now, with default value = DEFAULT-MAXIMUM-VALUE.
+.\"
+.if !r\\$1 .nr \\$1 \\$2
+.\"
+.\" But when it has already been defined, ensure that its value does
+.\" not exceed DEFAULT-MAXIMUM-VALUE; if value does exceed this ceiling,
+.\" then redefine it, to enforce the limit.
+.\"
+.if (\\n[\\$1] > \\$2) .nr \\$1 \\$2
+..
+.\" The "pdfmark" macro is responsible for emitting the appropriate
+.\" Postscript code.
+.\"
+.de pdfmark
+.\" ----------------------------------------------------------------
+.\" Usage:
+.\" .pdfmark text of pdfmark instruction
+.\" Macro supplies the required opening "[" and closing "pdfmark"
+.\" operator; DO NOT include them in the instruction text!
+.\" ----------------------------------------------------------------
+.\"
+.if \\n[PDFOPMODE] \{\
+.\"
+.\" Strict DSC compliance forbids emission of ps:exec lines which
+.\" exceed 255 characters in length. We will allow the user to specify
+.\" an alternative lesser limit ...
+.\"
+. pdf*pdfmark.limit PDFMARK.FOLDWIDTH.MAX 255
+.\"
+.\" ... and we will also support a second lesser limit, which will be
+.\" applied to literal text parenthetically embedded within the PDFMARK.
+.\"
+. pdf*pdfmark.limit PDFMARK.FOLDWIDTH \\n[PDFMARK.FOLDWIDTH.MAX]
+.\"
+.\" We will push out the entire PDFMARK in one chunk, provided it fits
+.\" within this limit.
+.\"
+. length pdf:length "[\\$* pdfmark\"
+. ie !(\\n[pdf:length] > \\n[PDFMARK.FOLDWIDTH]) \{\
+. \"
+. \" This PDFMARK is suitable for single chunk output ...
+. \"
+. nop \!x X ps:exec [\\$* pdfmark
+. \}
+. el \{\
+. \" ... but, when the limit would be violated, then we must
+. \" recompose the specified PDFMARK, spreading it over as many
+. \" continuation lines as are necessary.
+. \"
+. als pdf*compose pdf*compose.first
+. while \\n(.$ \{\
+. pdf*compose \\$1
+. shift
+. \}
+. \"
+. \" Complete the PDFMARK recomposition, by appending a
+. \" "pdfmark" operator, and push it out to the intermediate
+. \" output stream, (excluding its final line break).
+. \"
+. pdf*compose pdfmark
+. pdf*pdfmark.dispatch
+. \"
+. \" And clean up when done.
+. \"
+. rm pdf*compose pdf*pdfmark.post
+. rm pdf:compose.test pdf:composed.literal
+. \}
+. rr pdf:length
+. \}
+..
+.\" When a PDFMARK exceeds the specified output record length limit,
+.\" then we decompose it, subsequently using the dynamically overloaded
+.\" macro, "pdf*compose", to reassemble it into as many continuation
+.\" records as it may require.
+.\"
+.\" Each call to "pdf*compose" uses macro "pdf*length.increment" to
+.\" keep track of the current output record length, so ensuring that
+.\" the active maximum length limit is not violated.
+.\"
+.de pdf*length.increment
+.\" ----------------------------------------------------------------
+.\" Usage:
+.\" .pdf*length.increment NEXT-ADDITION
+.\" ----------------------------------------------------------------
+.\"
+.ie d pdf:composed.line \
+. length pdf:length "\\*[pdf:composed.line] \\$*\"
+.el .length pdf:length "\\$*\"
+..
+.\" The first call to "pdf*compose" for each PDFMARK is directed
+.\" to "pdf*compose.first"; this initialises the local strings
+.\" and macros used to compose the eventual PDFMARK output.
+.\"
+.de pdf*compose.first
+.\" ----------------------------------------------------------------
+.\" Usage:
+.\" .als pdf*compose pdf*compose.first
+.\" . pdf*compose TOKEN
+.\" ----------------------------------------------------------------
+.\"
+.\" Ensure that the output record accumulator will be initialised
+.\" on posting of the first composed PDFMARK record.
+.\"
+.als pdf*pdfmark.post pdf*pdfmark.post.first
+.\"
+.\" The first token passed to "pdf*compose" should not be a
+.\" literal, but be prepared to handle one, just in case.
+.\"
+.ds pdf:compose.test \\$1
+.substring pdf:compose.test 0 0
+.ie '('\\*[pdf:compose.test]' \{\
+.\"
+.\" We found a literal, even though we didn't expect it;
+.\" if it's a single element literal, we can just handle it
+.\" as if it is a regular token anyway.
+.\"
+. ds pdf:compose.test "\\$\\n(.$\"
+. substring pdf:compose.test -1
+. if !')'\\*[pdf:compose.test]' \{\
+. \"
+. \" But when it is the first of a literal sequence,
+. \" then we need to set up "pdf*compose" to handle it.
+. \"
+. ds pdf:composed.literal "[\\$*\"
+. als pdf*compose pdf*compose.literal
+. \}
+. \}
+.el .ds pdf:compose.test )
+.if ')'\\*[pdf:compose.test]' \{\
+.\"
+.\" In the normal case, we start each new PDFMARK with a
+.\" regular token; save it as the first in the composed output
+.\" line sequence, and set up "pdf*compose" to collect
+.\" the rest of the sequence.
+.\"
+. ds pdf:composed.line "[\\$*\"
+. als pdf*compose pdf*compose.next
+. \}
+..
+.\" Subsequent calls to "pdf*compose", while collecting
+.\" regular tokens, are then directed to "pdf*compose.next".
+.\"
+.de pdf*compose.next
+.\" ----------------------------------------------------------------
+.\" Usage:
+.\" .als pdf*compose pdf*compose.next
+.\" . pdf*compose TOKEN
+.\" ----------------------------------------------------------------
+.\"
+.\" This first checks to ensure that the supplied token really is
+.\" a regular token, and not the first element in a literal.
+.\"
+.ds pdf:compose.test \\$1
+.substring pdf:compose.test 0 0
+.ie '('\\*[pdf:compose.test]' \{\
+.\"
+.\" The supplied token represents the first element of a literal,
+.\" but it may be a single element literal, which we simply handle
+.\" as a regular token anyway.
+.\"
+. ds pdf:compose.test "\\$\\n(.$\"
+. substring pdf:compose.test -1
+. if !')'\\*[pdf:compose.test]' \{\
+. \"
+. \" The supplied token is the first of a sequence of elements
+. \" which collectively define a literal, so start collecting a
+. \" composite literal token, and change the "pdf*compose"
+. \" state, to collect and append the remaining elements.
+. \"
+. ds pdf:composed.literal "\\$*\"
+. als pdf*compose pdf*compose.literal
+. \}
+. \}
+.el .ds pdf:compose.test )
+.if ')'\\*[pdf:compose.test]' \{\
+.\"
+.\" The supplied token IS a regular token; add it, but ensure that
+.\" the active maximum record length limit is honoured.
+.\"
+. pdf*length.increment "\\$*\"
+. ie (\\n[pdf:length] > \\n[PDFMARK.FOLDWIDTH.MAX]) \{\
+. \"
+. \" Adding this token would cause the current PDFMARK record, in
+. \" groff's intermediate output file, to overflow the active record
+. \" length limit, so post the current record and start another.
+. \"
+. pdf*pdfmark.dispatch
+. ds pdf:composed.line "\\$*\"
+. \}
+. el \{\
+. \"
+. \" This token will fit in the current PDFMARK record, without
+. \" violating the active length limit, so simply add it.
+. \"
+. ie d pdf:composed.line .as pdf:composed.line " \\$*\"
+. el .ds pdf:composed.line "\\$*\"
+. \}
+. \}
+..
+.\" While assembling a multiple token literal sequence into a single
+.\" literal token, successive calls to "pdf*compose" are directed
+.\" to "pdf*compose.literal".
+.\"
+.de pdf*compose.literal
+.\" ----------------------------------------------------------------
+.\" Usage:
+.\" .als pdf*compose pdf*compose.literal
+.\" . pdf*compose TOKEN
+.\" ----------------------------------------------------------------
+.\"
+.\" First, check to ensure that the current token can be appended to
+.\" the accumulated literal, without extending it beyond the maximum
+.\" allowed literal token length.
+.\"
+.length pdf:length "\\*[pdf:composed.literal] \\$*\"
+.ie (\\n[pdf:length] > (\\n[PDFMARK.FOLDWIDTH] - 2)) \{\
+.\"
+.\" If it has grown too long, then it must be folded across two
+.\" physical PDFMARK output records, so check if we can accommodate
+.\" the portion collected so far within the current output record.
+.\"
+. pdf*length.increment "\\*[pdf:composed.literal]\"
+. if (\\n[pdf:length] > (\\n[PDFMARK.FOLDWIDTH.MAX] - 2)) \{\
+. \"
+. \" The current output record CAN'T accommodate the currently
+. \" composed portion of the literal, so flush out the current
+. \" record, to make way for the accumulated literal, and mark
+. \" the dispatch mode as "wrapped", for the fragments of the
+. \" folded literal string, which are to follow.
+. \"
+. pdf*pdfmark.dispatch
+. ds pdf*pdfmark.dispatch.wrapped
+. \}
+. ie d pdf:composed.line \{\
+. \"
+. \" If we DIDN'T need to flush the current output record,
+. \" then we can simply append the accumulated literal to it...
+. \"
+. as pdf:composed.line " \\*[pdf:composed.literal]\"
+. \}
+. el \{\
+. \"
+. \" otherwise, when the current record has been flushed, or is
+. \" empty, then we promote the accumulated literal, to make it
+. \" the next output record...
+. \"
+. rn pdf:composed.literal pdf:composed.line
+. \}
+.\"
+.\" Now, to complete the fold, flush out any accumulated partial
+.\" output record, and continue accumulating the literal, starting
+.\" with the current token.
+.\"
+. pdf*pdfmark.dispatch
+. ds pdf:composed.literal "\\$*\"
+. \}
+.el \{\
+.\"
+.\" Alternatively, when we HAVEN'T identified a need to fold the
+.\" current output record, then we simply append the current token
+.\" to the accumulated literal token buffer string.
+.\"
+. as pdf:composed.literal " \\$*\"
+. \}
+.\"
+.\" Having ensured that we have sufficient space, in which to
+.\" append the current token to the currently accumulated literal,
+.\" we check its rightmost character, to see if is the closing
+.\" parenthesis, which completes the literal.
+.\"
+.ds pdf:compose.test \\$\\n(.$
+.substring pdf:compose.test -1
+.if ')'\\*[pdf:compose.test]' \{\
+.\"
+.\" The literal has been completely collected, so we may now append
+.\" it to the current output record, as a single literal token, but
+.\" subject to the constraint that it must not extend the output
+.\" record beyond the maximum permitted length.
+.\"
+. pdf*length.increment "\\*[pdf:composed.literal]\"
+. ie (\\n[pdf:length] > \\n[PDFMARK.FOLDWIDTH.MAX]) \{\
+. \"
+. \" So, when the literal cannot be accommodated within the maximum
+. \" length constraint, then we flush the current record, and start
+. \" a new one, with the literal token as its first entry.
+. \"
+. pdf*pdfmark.dispatch
+. rn pdf:composed.literal pdf:composed.line
+. \}
+. el \{\
+. \"
+. \" When the literal CAN be accommodated within the maximum length
+. \" constraint, then ...
+. \"
+. ie d pdf:composed.line \{\
+. \"
+. \" When an output record has already been instantiated, we
+. \" append the literal token to it, and discard the accumulator
+. \" string, which is no longer required.
+. \"
+. as pdf:composed.line " \\*[pdf:composed.literal]\"
+. rm pdf:composed.literal
+. \}
+. el \{\
+. \"
+. \" But when no output record yet exists, then we simply
+. \" reassign the accumulated literal token, to instantiate a
+. \" new output record.
+. \"
+. rn pdf:composed.literal pdf:composed.line
+. \}
+. \}
+.\"
+.\" Finally, since we have completed the accumulation of the literal, we
+.\" revert to the "unwrapped" mode of operation for "pdf*pdfmark.dispatch",
+.\" and restore the normal "pdf*compose" action, for collection of the next
+.\" token (if any).
+.\"
+. rm pdf*pdfmark.dispatch.wrapped
+. als pdf*compose pdf*compose.next
+. \}
+..
+.\" While composing a multiple record PDFMARK, each composed record
+.\" must be added to the collection, whenever the partially composed
+.\" output record has been filled; this is handled when necessary,
+.\" by calling the "pdf*pdfmark.dispatch" macro.
+.\"
+.de pdf*pdfmark.dispatch
+.\" ----------------------------------------------------------------
+.\" Usage:
+.\" .pdf*pdfmark.dispatch
+.\" ----------------------------------------------------------------
+.\"
+.if d pdf:composed.line \{\
+.\"
+.\" This is simply a wrapper around the overloaded "pdf*pdfmark.post"
+.\" macro, ensuring that an output record has actually been collected
+.\" before attempting to post it; it then cleans up after posting, to
+.\" ensure that each collected record is posted only once.
+.\"
+. if d pdf*pdfmark.dispatch.wrapped \{\
+. \"
+. \" When dispatching an excessively long literal string, which
+. \" must be wrapped over multiple records, this mode is active
+. \" for all but the closing record; we must escape the newline
+. \" at the end of each such unclosed literal record.
+. \"
+. as pdf:composed.line " \\\\\\\\\"
+. \}
+. pdf*pdfmark.post
+. rm pdf:composed.line
+. \}
+..
+.\" For each PDFMARK, the first call of "pdf*pdfmark.post" is directed
+.\" to the "pdf*pdfmark.post.first" macro; this initialises the state
+.\" of the "pdf:composed" macro, for assembly of a new PDFMARK.
+.\"
+.de pdf*pdfmark.post.first
+. nop \!x X ps:exec \\*[pdf:composed.line]
+.\"
+.\" Subsequent calls to "pdf*pdfmark.post" are redirected to the
+.\" alternative "pdf*pdfmark.post.next" macro, which simply appends
+.\" additional PDFMARK records to the "pdf:composed" macro.
+.\"
+.als pdf*pdfmark.post pdf*pdfmark.post.next
+..
+.de pdf*pdfmark.post.next
+. nop \!+\\*[pdf:composed.line]
+..
+.\" "pdf*end" is a dummy macro. It is required to mark the end
+.\" of each individual fragment which is added to "pdf:composed";
+.\" other than this, it does nothing.
+.\"
+.de pdf*end
+..
+.\"
+.\" Some supporting macros defer actual pdfmark output until an
+.\" appropriate time for it to be written; the "pdfsync" macro
+.\" provides a mechanism for flushing such deferred output;
+.\" it should be called from an end macro, and at any other time
+.\" when it may be deemed necessary to flush pdfmark context.
+.\"
+.de pdfsync
+.\" ----------------------------------------------------------------
+.\" Usage:
+.\" .pdfsync buffer ...
+.\" Arguments indicate which "buffer(s)" to flush:
+.\" O -> bookmark (outline) cache
+.\" M -> document metadata diversion
+.\" If no argument, flush ALL buffers
+.\" ----------------------------------------------------------------
+.\"
+.ie \\n(.$ \{\
+. while \\n(.$ \{\
+. if '\\$1'O' .pdf:bm.sync 1
+. if '\\$1'M' \{\
+. if dpdf:metadata .pdf:metadata
+. rm pdf:metadata
+. \}
+. shift
+. \}
+. \}
+.el .pdfsync O M
+..
+.\"
+.\" some helper functions ...
+.\"
+.\" "pdf:warn" and "pdf:error" write diagnostic messages to stderr
+.\"
+.de pdf:warn
+.\" ----------------------------------------------------------
+.\" Usage:
+.\" .pdf:warn text of message
+.\" ----------------------------------------------------------
+.\"
+.tm \\n(.F:\\n(.c: macro warning: \\$*
+..
+.de pdf:error
+.\" ----------------------------------------------------------
+.\" Usage:
+.\" .pdf:error text of message
+.\" ----------------------------------------------------------
+.\"
+.tm \\n(.F:\\n(.c: macro error: \\$*
+..
+.\" "pdf:pop", assisted by "pdf*pop", allows us to retrieve register,
+.\" or string values, from a string masquerading as a data queue,
+.\" or as a stack.
+.\"
+.de pdf:pop
+.\" ----------------------------------------------------------------
+.\" Usage:
+.\" .pdf:pop <type> <to-name> <from-name>
+.\" $1 = nr for numeric register, ds for string
+.\" $2 = name of register or string to be assigned
+.\" $3 = name of string, from which data is to be retrieved
+.\" ----------------------------------------------------------------
+.\"
+.pdf*pop \\$* \\*[\\$3]
+..
+.de pdf*pop
+.ds pdf:stack \\$3
+.\\$1 \\$2 \\$4
+.shift 4
+.ie \\n(.$ .ds \\*[pdf:stack] \\$*
+.el .rm \\*[pdf:stack]
+.rm pdf:stack
+..
+.\"
+.\"
+.\" ===========================================================
+.\" Module PDFINFO: Insert MetaData Entries into a PDF Document
+.\" ===========================================================
+.\"
+.\" N.B.
+.\" Output from the macros in this module is deferred, until
+.\" subsequent invocation of .pdfsync, or .pdfexit
+.\"
+.\" ."pdfinfo" provides a general purpose form of metadata entry ...
+.\" it allows arbitrary text to be associated with any specified
+.\" metadata field name.
+.\"
+.de pdfinfo
+.\" -------------------------------------------------------------------
+.\" Usage:
+.\" .pdfinfo /FieldName field content ...
+.\" Examples:
+.\" .pdfinfo /Title A PDF Document
+.\" .pdfinfo /Author Keith Marshall
+.\" -------------------------------------------------------------------
+.\"
+.ds pdf:meta.field \\$1
+.shift
+.da pdf:metadata
+\!.pdfmark \\*[pdf:meta.field] (\\$*) /DOCINFO
+.di
+.rm pdf:meta.field
+..
+.\"
+.\" Macro "pdfview" defines a special form of metadata entry ...
+.\" it uses the /DOCVIEW pdfmark, to specify the initial (default) view,
+.\" when the document is opened.
+.\"
+.de pdfview
+.\" -------------------------------------------------------------------
+.\" Usage:
+.\" .pdfview view parameters ...
+.\" Examples:
+.\" .pdfview /PageMode /UseOutlines
+.\" .pdfview /Page 2 /View [/FitH \n(.p u]
+.\" -------------------------------------------------------------------
+.\"
+.da pdf:metadata
+\!.pdfmark \\$* /DOCVIEW
+.di
+..
+.\"
+.\"
+.\" =====================================================================
+.\" Module PDFNOTE: Insert "Sticky Note" Style Comments in a PDF Document
+.\" =====================================================================
+.\"
+.\" "PDFNOTE.WIDTH" and "PDFNOTE.HEIGHT" set the preferred size for
+.\" display of the "sticky note" pane, when opened. Acrobat Reader
+.\" seems not to honour these -- perhaps GhostScript doesn't encode
+.\" them correctly! Anyway, let's set some suitable default values,
+.\" in case the user has a set up which does work as advertised.
+.\"
+.nr PDFNOTE.WIDTH 3.5i
+.nr PDFNOTE.HEIGHT 2.0i
+.\"
+.\" "pdf:bbox" defines the expression used to set the size and location
+.\" of the bounding rectangle for display of notes and link "hot-spots".
+.\" This is defined, such that a note is placed at troff's current text
+.\" position on the current page, with its displayed image size defined
+.\" by the "PDFNOTE.WIDTH" and "PDFNOTE.HEIGHT" registers, while the
+.\" bounds for a link "hot-spot" are matched to the text region which
+.\" defines the "hot-spot".
+.\"
+.ds pdf:bbox \\n[pdf:llx] u \\n[pdf:lly] u \\n[pdf:urx] u \\n[pdf:ury] u
+.\"
+.\" Getting line breaks into the text of a PDFNOTE is tricky -- we need
+.\" to get a "\n" into the Postscript stream, but three levels of "\" are
+.\" swallowed, when we invoke "pdfnote". The following definition of "PDFLB",
+.\" (for LineBreak), is rather ugly, but does allow us to use
+.\"
+.\" .pdfnote Some text.\*[PDFLB]Some more text, on a new line.
+.\"
+.ds PDFLB \\\\\\\\\\\\\\\\n
+.\"
+.de pdfnote
+.\" ----------------------------------------------------------------------
+.\" Usage:
+.\" .pdfnote [-T "Text for Title"] Text of note ...
+.\" ----------------------------------------------------------------------
+.\"
+.if \\n[PDFOPMODE] \{\
+.\"
+.\" First, compute the bounding rectangle,
+.\" for this PDFNOTE instance
+.\"
+. mk pdf:ury
+. nr pdf:llx \\n(.k+\\n(.o+\\n[.in]
+. nr pdf:lly \\n[pdf:ury]-\\n[PDFNOTE.HEIGHT]
+. nr pdf:urx \\n[pdf:llx]+\\n[PDFNOTE.WIDTH]
+. ds pdf:note.instance /Rect [\\*[pdf:bbox]]
+.\"
+.\" Parse any specified (recognisable) PDFNOTE options
+.\"
+. while dpdf:note\\$1 \{\
+. pdf:note\\$1 \\$@
+. shift \\n[pdf:note.argc]
+. \}
+.\"
+.\" Emit the note, and clean up
+.\"
+. pdfmark \\*[pdf:note.instance] /Contents (\\$*) /ANN
+. rm pdf:note.instance
+. rr pdf:note.argc
+. \}
+..
+.de pdf:note-T
+.nr pdf:note.argc 2
+.as pdf:note.instance " /Title (\\$2)
+..
+.\"
+.\"
+.\" =====================================================================
+.\" Module PDFBOOKMARK: Add an Outline Reference in the PDF Bookmark Pane
+.\" =====================================================================
+.\"
+.\" "PDFBOOKMARK.VIEW" controls how the document will be displayed,
+.\" when the user selects a bookmark. This default setting will fit
+.\" the page width to the viewing window, with the bookmarked entry
+.\" located at the top of the viewable area.
+.\"
+.ds PDFBOOKMARK.VIEW /FitH \\n[PDFPAGE.Y] u
+.\"
+.\" "PDFOUTLINE.FOLDLEVEL" controls how the document outline will be
+.\" displayed. It is a number, defining the maximum heading level
+.\" which will be visible, without outline expansion by the user, in
+.\" the initial view of the document outline. Assuming that no sane
+.\" document will ever extend to 10,000 levels of nested headings,
+.\" this initial default value causes outlines to be fully expanded.
+.\"
+.nr PDFOUTLINE.FOLDLEVEL 10000
+.\"
+.\" The actual job of creating an outline reference
+.\" is performed by the "pdfbookmark" macro.
+.\"
+.de pdfbookmark
+.\" ------------------------------------------------------------------
+.\" Usage:
+.\" .pdfbookmark [-T tag] level "Text of Outline Entry"
+.\"
+.\" $1 = nesting level for bookmark (1 is top level)
+.\" $2 = text for bookmark, (in PDF viewer bookmarks list)
+.\" $3 = suffix for PDF internal bookmark name (optional)
+.\" ------------------------------------------------------------------
+.\"
+.ie '\\n(.z'' \{\
+.\"
+.\" When we are at the top diversion level, i.e. actually emitting text
+.\" to the output device stream, then we compute the location of, and
+.\" plant this bookmark immediately.
+.\"
+. if \\n[PDFOPMODE] \{\
+. \"
+. \" Make the bookmark name "untagged" by default,
+. \" then parse any specified options, to set a "tag", if required
+. \"
+. ds pdf:href-T
+. while dpdf:href.opt\\$1 \{\
+. pdf:href.opt\\$1 \\$@
+. shift \\n[pdf:href.argc]
+. \}
+. rr pdf:href.argc
+. \"
+. \" If we found "--" to mark the end of the options, discard it
+. \"
+. if '\\$1'--' .shift
+. \"
+. \" Synchronise the bookmark cache
+. \" to the requested bookmark nesting level
+. \"
+. pdf:bm.sync \\$1
+. shift
+. \"
+. \" Increment the bookmark serialisation index
+. \" in order to generate a uniquely serialised bookmark name,
+. \" ( which we return in the string "PDFBOOKMARK.NAME" ),
+. \" and insert this bookmark into the cache
+. \"
+. pdf:href.sety
+. nr pdf:bm.nr +1
+. ds PDFBOOKMARK.NAME pdf:bm\\n[pdf:bm.nr]\\*[pdf:href-T]
+. ds pdf:bm\\n[pdf:bm.nr] /Dest /\\*[PDFBOOKMARK.NAME]
+. pdfmark \\*[pdf:bm\\n[pdf:bm.nr]] /View [\\*[PDFBOOKMARK.VIEW]] /DEST
+. as pdf:bm\\n[pdf:bm.nr] " /Title (\\$*)
+. pdf:href.options.clear
+. rr PDFPAGE.Y
+. \}
+. \}
+.el \{\
+.\"
+.\" But when we are collecting a diversion which will be written out later,
+.\" then we must defer bookmark placement, until we emit the diversion.
+.\" (don't rely on $0 == pdfbookmark here; it may be a volatile alias).
+.\"
+. nop \!.pdfbookmark \\$@
+. \}
+..
+.\"
+.\" Macro "pdf:bm.sync" is called for each bookmark created,
+.\" to establish a cache entry at the appropriate nesting level.
+.\" It will flush ALL previous cache content, when called to
+.\" add a new bookmark at level 1, or if simply called at
+.\" level 1, without adding any bookmark.
+.\"
+.de pdf:bm.sync
+.\" ------------------------------------------------------------------
+.\" Usage:
+.\" .pdf:bm.sync level
+.\" $1 = nesting level of current bookmark, or 1 to flush cache
+.\" ------------------------------------------------------------------
+.\"
+.\" First validate the bookmark nesting level
+.\" adjusting it if required
+.\"
+.if \\$1>\\n[pdf:bm.nl] .nr pdf:bm.nl +1
+.ie \\$1>\\n[pdf:bm.nl] \{\
+. pdf:warn adjusted level \\$1 bookmark; should be <= \\n[pdf:bm.nl]
+. \}
+.el .nr pdf:bm.nl \\$1
+.if \\n[pdf:bm.nl]<1 \{\
+. pdf:warn bad arg (\\$1) in \\$0 \\$1; \\$0 1 forced
+. nr pdf:bm.nl 1
+. \}
+.\"
+.\" If reverting from a higher to a lower nesting level,
+.\" cyclicly adjust cache counts for each pending higher level
+.\"
+.if \\n[pdf:bm.lc]>=\\n[pdf:bm.nl] \{\
+. nr pdf:bm.lc +1
+. if !rpdf:bm.c\\n[pdf:bm.lc].c .nr pdf:bm.c\\n[pdf:bm.lc].c 0
+. while \\n[pdf:bm.lc]>\\n[pdf:bm.nl] \{\
+. as pdf:bm.c\\n[pdf:bm.lc] " \\n[pdf:bm.c\\n[pdf:bm.lc].c]
+. rr pdf:bm.c\\n[pdf:bm.lc].c
+. nr pdf:bm.lc -1
+. \}
+. \}
+.\"
+.\" Update the cache level,
+.\" flushing when we are at level 1
+.\"
+.nr pdf:bm.lc \\n[pdf:bm.nl]
+.ie \\n[pdf:bm.nl]=1 \{\
+. while \\n[pdf:bm.ic]<\\n[pdf:bm.nr] .pdf:bm.emit 0
+. rr pdf:bm.rc
+. \}
+.el .nr pdf:bm.c\\n[pdf:bm.nl].c +1
+..
+.\" Macro "pdf:bm.emit" is called, when the cache is at level 1.
+.\" This flushes ALL pending bookmarks from the cache, i.e. the
+.\" preceding level 1 bookmark, and any nested dependents,
+.\" which it may have.
+.\"
+.de pdf:bm.emit
+.\" ------------------------------------------------------------------
+.\" Usage:
+.\" .pdf:bm.emit flag
+.\" $1 = reference counting flag, used to control recursion
+.\" ------------------------------------------------------------------
+.\"
+.\" First check for nested dependents,
+.\" and append the "dependent count" to the bookmark, as required.
+.\"
+.nr pdf:bm.ic +1
+.nr pdf:bm.lc +1
+.pdf:pop nr pdf:bm.rc pdf:bm.c\\n[pdf:bm.lc]
+.if \\n[pdf:bm.rc] \{\
+. ds pdf:bm.fold
+. if \\n[pdf:bm.lc]>\\n[PDFOUTLINE.FOLDLEVEL] .ds pdf:bm.fold -
+. as pdf:bm\\n[pdf:bm.ic] " /Count \\*[pdf:bm.fold]\\n[pdf:bm.rc]
+. rm pdf:bm.fold
+. \}
+.pdfmark \\*[pdf:bm\\n[pdf:bm.ic]] /OUT
+.rm pdf:bm\\n[pdf:bm.ic]
+.\"
+.\" For ALL dependents, if any,
+.\" recursively flush out any higher level dependents,
+.\" which they themselves may have
+.\"
+.while \\n[pdf:bm.rc] \{\
+. nr pdf:bm.rc -1
+. pdf:bm.emit \\n[pdf:bm.rc]
+. \}
+.\"
+.\" Finally,
+.\" unwind the recursive call stack, until we return to the top level.
+.\"
+.nr pdf:bm.rc \\$1
+.nr pdf:bm.lc -1
+..
+.nr pdf:bm.nr 0
+.nr pdf:bm.nl 1
+.nr pdf:bm.lc 0
+.nr pdf:bm.ic 0
+.\"
+.\"
+.\" =============================================================
+.\" Module PDFHREF: Create Hypertext References in a PDF Document
+.\" =============================================================
+.\"
+.\" "PDFHREF.VIEW" controls how the document will be displayed,
+.\" when the user follows a link to a named reference.
+.\"
+.ds PDFHREF.VIEW /FitH \\n[PDFPAGE.Y] u
+.\"
+.\" This default setting will fit the page width to the viewing
+.\" window, with the bookmarked entry located close to the top
+.\" of the viewable area. "PDFHREF.VIEW.LEADING" controls the
+.\" actual distance below the top of the viewing window, where
+.\" the reference will be positioned; 5 points is a reasonable
+.\" default offset.
+.\"
+.nr PDFHREF.VIEW.LEADING 5.0p
+.\"
+.\" Yuk!!!
+.\" PDF view co-ordinates are mapped from the bottom left corner,
+.\" of the page, whereas page printing co-ordinates are mapped
+.\" conventionally, from top left.
+.\"
+.\" Macro "pdf:href.sety" transforms the vertical position of the
+.\" last printed baseline, from the printing co-ordinate domain to
+.\" the PDF view domain.
+.\"
+.de pdf:href.sety
+.\" ----------------------------------------------------------------
+.\" Usage:
+.\" .pdf:href.sety
+.\" ----------------------------------------------------------------
+.\"
+.\" This computation yields the vertical view co-ordinate
+.\" in groff's basic units; don't forget to append grops' "u"
+.\" conversion operator, when writing the pdfmark!
+.\"
+.nr PDFPAGE.Y \\n(.p-\\n(nl+\\n[PDFHREF.VIEW.LEADING]
+..
+.\" When we create a link "hot-spot" ...
+.\" "PDFHREF.LEADING" sets the distance above the top of the glyph
+.\" bounding boxes, in each line of link text, over which the link
+.\" hot-spot will extend, while "PDFHREF.HEIGHT" sets the hot-spot
+.\" height, PER LINE of text occupied by the reference.
+.\"
+.\" Since most fonts specify some leading space within the bounding
+.\" boxes of their glyphs, a better appearance may be achieved when
+.\" NEGATIVE leading is specified for link hot-spots; indeed, when
+.\" the default 10pt Times font is used, -1.0 point seems to be a
+.\" reasonable default value for "PDFHREF.LEADING" -- it may be
+.\" changed, if desired.
+.\"
+.\" "PDFHREF.HEIGHT" is initially set as one vertical spacing unit;
+.\" note that it is defined as a string, so it will adapt to changes
+.\" in the vertical spacing. Changing it is NOT RECOMMENDED.
+.\"
+.nr PDFHREF.LEADING -1.0p
+.ds PDFHREF.HEIGHT 1.0v
+.\"
+.\" PDF readers generally place a rectangular border around link
+.\" "hot-spots". Within text, this looks rather ugly, so we set
+.\" "PDFHREF.BORDER" to suppress it -- the three zeroes represent
+.\" the border parameters in the "/Border [0 0 0]" PDFMARK string,
+.\" and may be changed to any valid form, as defined in Adobe's
+.\" PDFMARK Reference Manual.
+.\"
+.ds PDFHREF.BORDER 0 0 0
+.\"
+.\" "PDFHREF.COLOUR" (note British spelling) defines the colour to
+.\" be used for display of link "hot-spots". This will apply both
+.\" to borders, if used, and, by default to text; however, actual
+.\" text colour is set by "PDFHREF.TEXT.COLOUR", which may be reset
+.\" independently of "PDFHREF.COLOUR", to achieve contrasting text
+.\" and border colours.
+.\"
+.\" "PDFHREF.COLOUR" must be set to a sequence of three values,
+.\" each in the range 0.0 .. 1.0, representing the red, green, and
+.\" blue components of the colour specification in the RGB colour
+.\" domain, which is shared by "groff" and the PDF readers.
+.\"
+.ds PDFHREF.COLOUR 0.35 0.00 0.60
+.defcolor pdf:href.colour rgb \*[PDFHREF.COLOUR]
+.\"
+.\" "PDFHREF.TEXT.COLOUR", on the other hand, is simply defined
+.\" using any "groff" colour name -- this default maps it to the
+.\" same colour value as "PDFHREF.COLOUR".
+.\"
+.ds PDFHREF.TEXT.COLOUR pdf:href.colour
+.\"
+.\" Accommodate users who prefer the American spelling, COLOR, to
+.\" the British spelling, COLOUR.
+.\"
+.als PDFHREF.COLOR PDFHREF.COLOUR
+.als PDFHREF.TEXT.COLOR PDFHREF.TEXT.COLOUR
+.\"
+.\" All PDF "Hypertext" reference capabilities are accessed
+.\" through the "pdfhref" macro
+.\"
+.de pdfhref
+.\" -----------------------------------------------------------------
+.\" Usage:
+.\" .pdfhref <subcommand [options ...] [parameters ...]> ...
+.\" -----------------------------------------------------------------
+.\"
+.if \\n[PDFOPMODE] \{\
+.\"
+.\" Loop over all subcommands specified in the argument list
+.\"
+. while \\n(.$ \{\
+. \"
+. \" Initially, assume each subcommand will complete successfully
+. \"
+. nr pdf:href.ok 1
+. \"
+. \" Initialise -E and -X flags in the OFF state
+. \"
+. nr pdf:href-E 0
+. nr pdf:href-X 0
+. \"
+. \" Handle the case where subcommand is specified as "-class",
+. \" setting up appropriate macro aliases for subcommand handlers.
+. \"
+. if dpdf*href\\$1 .als pdf*href pdf*href\\$1
+. if dpdf*href\\$1.link .als pdf*href.link pdf*href\\$1.link
+. if dpdf*href\\$1.file .als pdf*href.file pdf*href\\$1.file
+. \"
+. \" Repeat macro alias setup
+. \" for the case where the subcommand is specified as "class",
+. \" (without a leading hyphen)
+. \"
+. if dpdf*href-\\$1 .als pdf*href pdf*href-\\$1
+. if dpdf*href-\\$1.link .als pdf*href.link pdf*href-\\$1.link
+. if dpdf*href-\\$1.file .als pdf*href.file pdf*href-\\$1.file
+. \"
+. \" Process one subcommand ...
+. \"
+. ie dpdf*href \{\
+. \"
+. \" Subcommand "class" is recognised ...
+. \" discard the "class" code from the argument list,
+. \" set the initial argument count to swallow all arguments,
+. \" and invoke the selected subcommand handler.
+. \"
+. shift
+. nr pdf:argc \\n(.$
+. pdf*href \\$@
+. \"
+. \" When done,
+. \" discard all arguments actually consumed by the handler,
+. \" before proceeding to the next subcommand (if any).
+. \"
+. shift \\n[pdf:argc]
+. \}
+. el \{\
+. \"
+. \" Subcommand "class" is not recognised ...
+. \" issue a warning, and discard the entire argument list,
+. \" so aborting this "pdfhref" invocation
+. \"
+. pdf:warn \\$0: undefined reference class '\\$1' ignored
+. shift \\n(.$
+. \}
+. \"
+. \" Clean up temporary reference data,
+. \" to ensure it doesn't propagate to any future reference
+. \"
+. rm pdf*href pdf:href.link pdf:href.files
+. rr pdf:href-E pdf:href-X
+. pdf:href.options.clear
+. \}
+. rr pdf:href.ok
+. \}
+..
+.\"
+.\" Macros "pdf:href.flag" and "pdf:href.option"
+.\" provide a generic mechanism for switching on flag type options,
+.\" and for decoding options with arguments, respectively
+.\"
+.de pdf:href.flag
+.\" ----------------------------------------------------------------------
+.\" ----------------------------------------------------------------------
+.nr pdf:href\\$1 1
+.nr pdf:href.argc 1
+..
+.de pdf:href.option
+.\" ----------------------------------------------------------------------
+.\" ----------------------------------------------------------------------
+.ds pdf:href\\$1 \\$2
+.nr pdf:href.argc 2
+..
+.\"
+.\" Valid PDFHREF options are simply declared
+.\" by aliasing option handlers to "pdf:href.option",
+.\" or to "pdf:href.flag", as appropriate
+.\"
+.als pdf:href.opt-A pdf:href.option \" affixed text
+.als pdf:href.opt-D pdf:href.option \" destination name
+.als pdf:href.opt-E pdf:href.flag \" echo link descriptor
+.als pdf:href.opt-F pdf:href.option \" remote file specifier
+.als pdf:href.opt-N pdf:href.option \" reference name
+.als pdf:href.opt-P pdf:href.option \" prefixed text
+.als pdf:href.opt-T pdf:href.option \" bookmark "tag"
+.als pdf:href.opt-X pdf:href.flag \" cross reference
+.\"
+.\" For references to another document file
+.\" we also need to support OS dependent file name specifiers
+.\"
+.als pdf:href.opt-DF pdf:href.option \" /DOSFile specifier
+.als pdf:href.opt-MF pdf:href.option \" /MacFile specifier
+.als pdf:href.opt-UF pdf:href.option \" /UnixFile specifier
+.als pdf:href.opt-WF pdf:href.option \" /WinFile specifier
+.\"
+.\" Macro "pdf:href.options.clear" ensures that ALL option
+.\" argument strings are deleted, after "pdfhref" has completed
+.\" all processing which depends on them
+.\"
+.de pdf:href.options.clear
+.\" -----------------------------------------------------------------
+.\" Usage:
+.\" .pdf:href.options.clear [option ...]
+.\" -----------------------------------------------------------------
+.\"
+.\" When an option list is specified ...
+.\"
+.ie \\n(.$ \{\
+. \"
+. \" then loop through the list,
+. \" deleting each specified option argument string in turn
+. \"
+. while \\n(.$ \{\
+. if dpdf:href-\\$1 .rm pdf:href-\\$1
+. shift
+. \}
+. \}
+.\"
+.\" ... but when no list is specified,
+.\" then recurse, to clear all known option argument strings
+.\"
+.el .pdf:href.options.clear A D F N P T DF MF UF WF
+..
+.\"
+.\" "PDFHREF.INFO" establishes the content of the cross reference
+.\" data record, which is exported via the "stderr" stream, when a
+.\" cross reference anchor is created using a "pdfhref" macro request
+.\" of the form
+.\"
+.\" .pdfhref M -N name -X text ...
+.\"
+.\" .ds PDFHREF.INFO \\*[PDFHREF.NAME] reference data ...
+.\"
+.ds PDFHREF.INFO page \\n% \\$*
+.\"
+.\" Macro "pdf*href-M" is the handler invoked by "pdfhref", when
+.\" called with the "M" reference class specifier, to create a
+.\" named cross reference mark, and to emit a cross reference
+.\" data record, as specified by "PDFHREF.INFO".
+.\"
+.de pdf*href-M
+.\" -----------------------------------------------------------------
+.\" Usage:
+.\" .pdfhref M [-X] [-N name | -D name] [-E] descriptive text ...
+.\" -----------------------------------------------------------------
+.\"
+.\" Initially, declare the -D and -N string options as empty,
+.\" so we avoid warning messages when we try to use them, and find
+.\" that they are undefined.
+.\"
+.ds pdf:href-D
+.ds pdf:href-N
+.\"
+.\" Parse, interpret, and strip any specified options from the
+.\" argument list. (Note that only options with a declared handler
+.\" will be processed; there is no provision for detecting invalid
+.\" options -- anything which is not recognised is assumed to start
+.\" the "descriptive text" component of the argument list).
+.\"
+.while dpdf:href.opt\\$1 \{\
+. pdf:href.opt\\$1 \\$@
+. shift \\n[pdf:href.argc]
+. \}
+.\"
+.\" If we found "--", to mark the end of the options,
+.\" then we should discard it.
+.\"
+.if '\\$1'--' .shift
+.\"
+.\" All PDF reference markers MUST be named. The name may have been
+.\" supplied using the "-N Name" option, (or the "-D Name" option);
+.\" if not, deduce it from the first "word" in the "descriptive text",
+.\" if any, and set the marker -- if we still can't identify the name
+.\" for the destination, then this marker will not be created.
+.\"
+.pdf*href.set \\*[pdf:href-N] \\*[pdf:href-D] \\$1
+.\"
+.\" If we specified a cross reference, with the "-X" option, and the
+.\" reference mark has been successfully created, then we now need to
+.\" write the cross reference info to the STDERR stream
+.\"
+.if \\n[pdf:href-X] .pdf*href.export \\*[PDFHREF.INFO]
+.\"
+.\" Irrespective of whether this marker is created, or not,
+.\" the descriptive text will be copied to the groff output stream,
+.\" provided the "-E" option was specified
+.\"
+.if \\n[pdf:href-E] \&\\$*
+..
+.\"
+.de pdf*href.set
+.\" ----------------------------------------------------------------------
+.\" ----------------------------------------------------------------------
+.pdf*href.map.init
+.ie \\n(.$ \{\
+. \"
+. \" a marker name has been supplied ...
+. \" if we are formatting for immediate output,
+. \" emit PDFMARK code to establish the associated view
+. \"
+. ie '\\n(.z'' \{\
+. pdf:href.sety
+. pdfmark /Dest /\\$1 /View [\\*[PDFHREF.VIEW]] /DEST
+. ds PDFHREF.NAME \\$1
+. rr PDFPAGE.Y
+. \}
+. \"
+. \" but, when formatting a diversion ...
+. \" delay output of the PDFMARK code, until the diversion
+. \" is eventually written out
+. \"
+. el \!.\\$0 \\$@
+. \"
+. \" check if we also need to emit cross reference data
+. \" (caller will do this if "pdf:href-X" is set, but it is
+. \" not necessary, when "pdf:href.map" already exists)
+. \"
+. if dpdf:href.map .nr pdf:href-X 0
+. \}
+.el \{\
+. \" marker is unnamed ...
+. \" issue error message; do not emit reference data
+. \"
+. pdf:warn pdfhref destination marker must be named
+. nr pdf:href-X 0
+. \}
+..
+.de pdf*href.export
+.\"
+.\" Called ONLY by "pdf*href-M",
+.\" this macro ensures that the emission of exported reference data
+.\" is synchronised with the placement of the reference mark,
+.\" especially when the mark is defined within a diversion.
+.\"
+.ie '\\n(.z'' .tm gropdf-info:href \\*[PDFHREF.NAME] \\$*
+.el \!.\\$0 \\$@
+..
+.\"
+.\" Macro "pdf*href-D" is invoked when "pdfhref" is called
+.\" with the "D" reference class specifier; it provides a
+.\" standardised mechanism for interpreting reference data
+.\" exported by the "M" reference class, and may be used
+.\" to directly define external reference data, without the
+.\" use of "M" reference class designators in the source
+.\" document.
+.\"
+.de pdf*href-D
+.ds pdf:href-N
+.\"
+.\" Parse, interpret, and strip any specified options from the
+.\" argument list. (Note that only options with a declared handler
+.\" will be processed; there is no provision for detecting invalid
+.\" options -- anything which is not recognised is assumed to start
+.\" the "descriptive text" component of the argument list).
+.\"
+.while dpdf:href.opt\\$1 \{\
+. pdf:href.opt\\$1 \\$@
+. shift \\n[pdf:href.argc]
+. \}
+.\"
+.\" If we found "--", to mark the end of the options,
+.\" then we should discard it.
+.\"
+.if '\\$1'--' .shift
+.\"
+.ie '\\*[pdf:href-N]'' \{\
+. pdf:warn pdfhref defined reference requires a name
+. \}
+.el \{\
+. ds pdf:href(\\*[pdf:href-N]).info \\$*
+. \}
+..
+.\"
+.\" Macro "pdf*href-F" is invoked when "pdfhref" is called
+.\" with the "F" reference class specifier; it allows the user
+.\" to provide an alternative interpreter macro, which will be
+.\" called when a "PDFHREF.INFO" record is retrieved to define
+.\" the text of a cross reference link "hot spot".
+.\"
+.de pdf*href-F
+.\" ----------------------------------------------------------------
+.\" Usage:
+.\" .pdfhref F [macro-name]
+.\" ----------------------------------------------------------------
+.\"
+.\" Set macro specified by "macro-name" as the format interpreter
+.\" for parsing "PDFHREF.INFO" records; if "macro-name" is omitted,
+.\" or is specified as the reserved name "default", then use the
+.\" default format parser, "pdf*href.format", defined below.
+.\"
+.if '\\$1'default' .shift \\n(.$
+.ie \\n(.$ .als pdf*href.format \\$1
+.el .als pdf*href.format pdf*href.default
+.nr pdf:argc 1
+..
+.\" The default reference formatting macro is defined below.
+.\" It parses the "PDFHREF.INFO" record specific to each reference,
+.\" recognising the keywords "file", "page" and "section", when they
+.\" appear in initial key/value pairs, replacing the key/value pair
+.\" with "PDFHREF.FILEREF", "PDFHREF.PAGEREF" or "PDFHREF.SECTREF"
+.\" respectively; any additional data in the "PDFHREF.INFO" record
+.\" is enclosed in typographic double quotes, and the parsed record
+.\" is appended to "PDFHREF.PREFIX", to be returned as the formatted
+.\" reference text.
+.\"
+.\" Default definitions for the reference strings "PDFHREF.PREFIX",
+.\" "PDFHREF.FILEREF", "PDFHREF.PAGEREF" and "PDFHREF.SECTREF" are
+.\" provided, in the English language. Users may substitute any
+.\" desired alternative definitions, for example, when formatting
+.\" documents in other languages. In each case, "\\$1" may be used
+.\" in the substitution, to represent the "value" component of the
+.\" respective key/value pair specified in the "PDFHREF.INFO" record.
+.\"
+.ds PDFHREF.PREFIX see
+.ds PDFHREF.PAGEREF page \\$1,
+.ds PDFHREF.SECTREF section \\$1,
+.ds PDFHREF.FILEREF \\$1
+.\"
+.de pdf*href.format
+.\" -----------------------------------------------------------------
+.\" Usage: (to be called ONLY by "pdfhref")
+.\" .pdf*href.format cross reference data ...
+.\" -----------------------------------------------------------------
+.\"
+.\" This macro is responsible for defining the strings "PDFHREF.TEXT"
+.\" and "PDFHREF.DESC", which are used by the "pdfhref" macro, as the
+.\" basis for generating the text content of a link "hot spot"; (any
+.\" user specified alternate formatter MUST do likewise).
+.\"
+.\" Note that "PDFHREF.TEXT" defines the overall format for the "link
+.\" text", while "PDFHREF.DESC" is the descriptive component thereof.
+.\"
+.\" This default implementation, subject to user customisation of the
+.\" "internationalisation" strings defined above, formats "hot spots"
+.\" of the style
+.\"
+.\" see page N, section S, "descriptive text ..."
+.\"
+.ds PDFHREF.TEXT \\*[PDFHREF.PREFIX]
+.while d\\$0.\\$1 \{\
+. \\$0.\\$1 "\\$2"
+. shift 2
+. \}
+.\"
+.\" Retrieve the descriptive text from the cross reference data,
+.\" ONLY IF no overriding description has been set by the calling
+.\" "pdfhref" macro invocation.
+.\"
+.if \\n(.$ .if !dPDFHREF.DESC .ds PDFHREF.DESC \\$*
+.\"
+.\" Augment "PDFHREF.TEXT" so the descriptive text will be included
+.\" in the text of the formatted reference
+.\"
+.if dPDFHREF.DESC .as PDFHREF.TEXT " \(lq\\\\*[PDFHREF.DESC]\(rq
+.\"
+.\" Finally, suppress any leading spaces,
+.\" which may have been included in the PDFHREF.TEXT definition.
+.\"
+.ds PDFHREF.TEXT \\*[PDFHREF.TEXT]
+..
+.de pdf*href.format.file
+.\" ----------------------------------------------------------------------
+.\" Include a file identifier in a formatted reference.
+.\" This is invoked ONLY by "pdf*href.format", and ONLY IF the
+.\" reference data includes an initial file identifier tuple.
+.\" ----------------------------------------------------------------------
+.\"
+.as PDFHREF.TEXT " \\*[PDFHREF.FILEREF]
+..
+.de pdf*href.format.page
+.\" ----------------------------------------------------------------------
+.\" Include a page number in a formatted reference.
+.\" This is invoked ONLY by "pdf*href.format", and ONLY IF the
+.\" reference data includes an initial page number tuple.
+.\" ----------------------------------------------------------------------
+.\"
+.as PDFHREF.TEXT " \\*[PDFHREF.PAGEREF]
+..
+.de pdf*href.format.section
+.\" ----------------------------------------------------------------------
+.\" Include a section number in a formatted reference.
+.\" This is invoked ONLY by "pdf*href.format", and ONLY IF the
+.\" reference data includes an initial section number tuple.
+.\" ----------------------------------------------------------------------
+.\"
+.as PDFHREF.TEXT " \\*[PDFHREF.SECTREF]
+..
+.\"
+.\" Make "pdf*href.format" the default cross reference formatter
+.\"
+.als pdf*href.default pdf*href.format
+.\"
+.\"
+.\" Macro "pdf*href" provides a generic mechanism for placing link
+.\" "hot-spots" in a PDF document. ALL "pdfhref" class macros which
+.\" create "hot-spots" are aliased to this macro; each must also have
+.\" an appropriately aliased definition for "pdf*href.template".
+.\"
+.de pdf*href
+.\" ------------------------------------------------------------------
+.\" Usage:
+.\" .pdf*href class [options ...] [link text ...]
+.\" ------------------------------------------------------------------
+.\"
+.\" First, we initialise an empty string, which will be affixed to
+.\" the end of the "link text". (This is needed to cancel the effect
+.\" of a "\c" escape, which is placed at the end of the "link text"
+.\" to support the "-A" option -- any text supplied by the user, when
+.\" the "-A" option is specified, will replace this empty string).
+.\"
+.ds pdf:href-A
+.\"
+.\" Now we interpret, and remove any specified options from the
+.\" argument list. (Note that only options with a declared handler
+.\" will be processed; there is no provision for detecting invalid
+.\" options -- anything which is not recognised is assumed to start
+.\" the "link text" component of the argument list).
+.\"
+.while dpdf:href.opt\\$1 \{\
+. pdf:href.opt\\$1 \\$@
+. shift \\n[pdf:href.argc]
+. \}
+.\"
+.\" If we found "--", to mark the end of the options, then we should
+.\" discard it.
+.\"
+.if '\\$1'--' .shift
+.\"
+.\" All PDF link classes REQUIRE a named destination. This may have
+.\" been supplied using the "-D Name" option, but, if not, deduce it
+.\" from the first "word" in the "link text", if any -- if we still
+.\" can't identify the destination, then set "pdf:href.ok" to zero,
+.\" so this link will not be created.
+.\"
+.if !dpdf:href-D .pdf:href.option -D \\$1
+.if '\\*[pdf:href-D]'' \{\
+. pdf:error pdfhref has no destination
+. nr pdf:href.ok 0
+. \}
+.\"
+.\" Some PDF link classes support a "/File (FilePathName)" argument.
+.\"
+.if dpdf*href.file \{\
+. \"
+. \" When this is supported, it may be specified by supplying
+. \" the "-F FileName" option, which is captured in "pdf:href-F".
+. \"
+. if dpdf:href-F \{\
+. \"
+. \" the /File key is present, so set up the link specification
+. \" to establish the reference to the specified file
+. \"
+. als pdf*href.link pdf*href.file
+. ds pdf:href.files /File (\\*[pdf:href-F])
+. \"
+. \" in addition to the /File key,
+. \" there may also be platform dependent alternate file names
+. \"
+. if dpdf:href-DF .as pdf:href.files " /DOSFile (\\*[pdf:href-DF])
+. if dpdf:href-MF .as pdf:href.files " /MacFile (\\*[pdf:href-MF])
+. if dpdf:href-UF .as pdf:href.files " /UnixFile (\\*[pdf:href-UF])
+. if dpdf:href-WF .as pdf:href.files " /WinFile (\\*[pdf:href-WF])
+. \}
+. \" In some cases, the "/File" key is REQUIRED.
+. \" We will know it is missing, if "pdf*href.link" is not defined.
+. \"
+. if !dpdf*href.link \{\
+. \"
+. \" When a REQUIRED "/File" key specification is not supplied,
+. \" then complain, and set "pdf:href.ok" to abort the creation
+. \" of the current reference.
+. \"
+. pdf:error pdfhref: required -F specification omitted
+. nr pdf:href.ok 0
+. \}
+. \" Now, we have no further use for "pdf*href.file".
+. \"
+. rm pdf*href.file
+. \}
+.\"
+.\" Now, initialise a string, defining the PDFMARK code sequence
+.\" to create the reference, using the appropriate type indicators.
+.\"
+.ds pdf:href.link /Subtype /Link \\*[pdf*href.link]
+.\"
+.\" And now, we have no further use for "pdf*href.link".
+.\"
+.rm pdf*href.link
+.\"
+.\" If the user specified any "link prefix" text, (using the "-P text"
+.\" option), then emit it BEFORE processing the "link text" itself.
+.\"
+.if dpdf:href-P \&\\*[pdf:href-P]\c
+.ie \\n[pdf:href.ok] \{\
+. \"
+. \" This link is VALID (so far as we can determine) ...
+. \" Modify the "link text" argument specification, as required,
+. \" to include any pre-formatted cross reference information
+. \"
+. ie \\n(.$ \{\
+. \"
+. \" One or more "link text" argument(s) are present,
+. \" so, set the link description from the argument(s) ...
+. \"
+. ds PDFHREF.DESC \\\\$*
+. ie \\n[pdf:href-X] \{\
+. \"
+. \" ... and, when the "-X" flag is set,
+. \" also include formatted location information,
+. \" derived from the cross reference record.
+. \"
+. pdf*href.format \\*[pdf:href(\\*[pdf:href-D]).info]
+. \}
+. el \{\
+. \" ... but, when the "-X" flag is NOT set,
+. \" use only the argument(s) as the entire content
+. \" of the "link text"
+. \"
+. rn PDFHREF.DESC PDFHREF.TEXT
+. \}
+. \}
+. el \{\
+. \" No "link text" arguments are present,
+. \" so, format the cross reference record to define
+. \" the content of the "link text".
+. \"
+. pdf*href.format \\*[pdf:href(\\*[pdf:href-D]).info]
+. \}
+. \" Apply border and colour specifications to the PDFMARK string
+. \" definition, as required.
+. \"
+. if dPDFHREF.BORDER .as pdf:href.link " /Border [\\*[PDFHREF.BORDER]]
+. if dPDFHREF.COLOUR .as pdf:href.link " /Color [\\*[PDFHREF.COLOUR]]
+. \"
+. \" Emit the "link text", in its appropriate colour, marking the
+. \" limits of its bounding box(es), as the before and after output
+. \" text positions.
+. \"
+. pdf*href.mark.begin "\\*[pdf:href.link]"
+. if dPDFHREF.COLOUR .defcolor pdf:href.colour rgb \\*[PDFHREF.COLOUR]
+. nop \&\m[\\*[PDFHREF.TEXT.COLOUR]]\\*[PDFHREF.TEXT]\m[]\c
+. pdf*href.mark.end
+. \"
+. \" Clean up the temporary registers and strings, used to
+. \" compute the "hot-spot" bounds, and format the reference,
+. \"
+. rm PDFHREF.DESC PDFHREF.TEXT
+. \}
+.\"
+.\" But when we identify an INVALID link ...
+.\" We simply emit the "link text", with no colour change, no border,
+.\" and no associated "hot-spot".
+.\"
+.el \&\\$*\c
+.\"
+.\" And then, if the user specified any affixed text, (using the
+.\" "-A text" option), we tack it on at the end.
+.\"
+.nop \&\\*[pdf:href-A]
+..
+.de pdf*href.map.init
+.\" ----------------------------------------------------------------------
+.\" ----------------------------------------------------------------------
+.\"
+.if dpdf:href.map-1 \{\
+. \"
+. \" We have a reference map, but we haven't started to parse it yet.
+. \" This must be the first map reference in pass 2, so we need to
+. \" "kick-start" the parsing process, by loading the first indexed
+. \" sub-map into the global map.
+. \"
+. rn pdf:href.map-1 pdf:href.map
+. als pdf:href.map.internal pdf:href.map
+. nr pdf:href.map.index 1 1
+. \}
+.als pdf*href.map.init pdf*href.mark.idle
+..
+.\"
+.\" "pdf*href-Z" is used to add link co-ordinate entries to the
+.\" "pdf:href.map". Primarily, it is used by the "pdfroff" formatter,
+.\" to pass link co-ordinate data from one "groff" formatting pass to
+.\" the next, and is not generally useful to the end user.
+.\"
+.de pdf*href-Z
+.\" ----------------------------------------------------------------------
+.\" Usage:
+.\" .pdfhref Z page-index x-displacement y-displacement
+.\" Where:
+.\" page-index is the reference mark's page number
+.\" x-displacement is its offset from the left edge of the page
+.\" y-displacement is its offset from the top edge of the page
+.\" ( both displacement values are expressed in basic groff units, )
+.\" ( and measured perpendicular to their respective page edges. )
+.\" ----------------------------------------------------------------------
+.\"
+.ie \\n(.$=3 .ds pdf:href.map-\\n+[pdf*href-Z.index] \\$*
+.el .pdf:error pdfhref Z operator expects exactly three arguments
+..
+.\" Initialise the auto-incrementing "pdf*href-Z.index" register,
+.\" to ensure that sub-map numbering starts at 1.
+.\"
+.nr pdf*href-Z.index 0 1
+.\"
+.de pdf*href.map.read
+.\" ----------------------------------------------------------------------
+.\" Usage: (internal use only):
+.\" .pdf*href.map.read co-ordinate name list ...
+.\" ----------------------------------------------------------------------
+.\"
+.\" Reads values from "pdf:href.map" to each named register, in turn
+.\" Reading to "null" discards the corresponding value in "pdf:href.map"
+.\"
+.while \\n(.$ \{\
+. \"
+. \" Loop over all registers named in the argument list,
+. \" assigning values from "pdf:href.map" to each in turn.
+. \"
+. pdf:pop nr pdf:\\$1 pdf:href.map.internal
+. if !dpdf:href.map.internal \{\
+. \"
+. \" We ran out of map references in the current sub-map,
+. \" so move on to the next indexed sub-map, if any.
+. \"
+. if dpdf:href.map-\\n+[pdf:href.map.index] \{\
+. rn pdf:href.map-\\n[pdf:href.map.index] pdf:href.map
+. als pdf:href.map.internal pdf:href.map
+. \}
+. \}
+. \"
+. \" Proceed to the next named co-ordinate, (if any), specified
+. \" in the argument list.
+. \"
+. shift
+. \}
+.\"
+.\" Discard any assignments to a register named "null"
+.\"
+.rr pdf:null
+..
+.de pdf*href.mark.begin
+.\" ----------------------------------------------------------------------
+.\" ----------------------------------------------------------------------
+.pdf*href.map.init
+.ie dpdf:href.map \{\
+. \"
+. \" Once we have established a document reference map,
+. \" then this, and all subsequent calls to "pdf*href.mark.begin",
+. \" may be redirected to the reference mark resolver, and the
+. \" "pdf*href.mark.end" macro has nothing further to do.
+. \"
+. pdf*href.mark.resolve \\$@
+. als pdf*href.mark.begin pdf*href.mark.resolve
+. als pdf*href.mark.end pdf*href.mark.idle
+. \}
+.el \{\
+. \" Since we don't yet have a document reference map, the
+. \" reference mark resolver will not work, in this pass of the
+. \" formatter; this, and all subsequent calls to "pdf*href.mark.begin",
+. \" may be redirected to "pdf*href.mark.end", which is responsible
+. \" for emitting the reference mark data to be incorporated into
+. \" the reference map in a subsequent formatting pass.
+. \"
+. pdf*href.mark.end
+. als pdf*href.mark.begin pdf*href.mark.end
+. \}
+..
+.de pdf*href.mark.resolve
+.\" ----------------------------------------------------------------------
+.\" ----------------------------------------------------------------------
+.ie '\\n(.z'' \{\
+. ds pdf:href.link \\$1
+. nr pdf:urx \\n(.o+\\n(.l
+. pdf*href.map.read spg llx ury epg urx.end lly.end
+. ie \\n[pdf:spg]=\\n[pdf:epg] \{\
+. \"
+. \" This link is entirely contained on a single page ...
+. \" emit the text, which defines the content of the link region,
+. \" then make it active.
+. \"
+. pdf*href.mark.emit 1 \\n[pdf:urx.end]
+. if \\n[pdf:lly]<\\n[pdf:lly.end] \{\
+. \"
+. \" This link spans multiple output lines; we must save its
+. \" original end co-ordinates, then define a new intermediate
+. \" end point, to create a PDFMARK "hot-spot" extending from
+. \" the start of the link to the end if its first line.
+. \"
+. nr pdf:ury +1v
+. nr pdf:llx \\n(.o+\\n[.in]
+. nr pdf:lly \\n[pdf:lly.end]-\\*[PDFHREF.HEIGHT]
+. if \\n[pdf:ury]<\\n[pdf:lly] \{\
+. nr pdf:lly +\\*[PDFHREF.HEIGHT]-1v
+. pdf*href.mark.emit 2
+. nr pdf:ury \\n[pdf:lly.end]-\\*[PDFHREF.HEIGHT]
+. \}
+. pdf*href.mark.emit 0 \\n[pdf:urx.end]
+. \}
+. pdf*href.mark.flush
+. \}
+. el \{\
+. \" This link is split across a page break, so ...
+. \" We must mark the "hot-spot" region on the current page,
+. \" BEFORE we emit the link text, as we will have moved off
+. \" this page, by the time the text has been output.
+. \"
+. \" First step: define the region from the start of the link,
+. \" to the end of its first line.
+. \"
+. pdf*href.mark.emit 1 \\n[pdf:urx]
+. \"
+. \" All additional regions MUST align with the left margin.
+. \"
+. nr pdf:llx \\n(.o+\\n[.in]
+. \"
+. \" If the current page can accommodate more than the current line,
+. \" then it will include a second active region for this link; this
+. \" will extend from just below the current line to the end of page
+. \" trap, if any, or the bottom of the page otherwise, and occupy
+. \" the full width of the page, between the margins.
+. \"
+. nr pdf:ury +1v
+. pdf*href.mark.emit 3
+. \"
+. \" We now need a page transition trap, to map the active link
+. \" region(s), which overflow on to the following page(s); (the
+. \" handler for this trap MUST have been previously installed).
+. \"
+. ie dpdf*href.mark.hook \{\
+. \"
+. \" The page transition trap handler has been installed,
+. \" so we may activate both it, and also the appropriate
+. \" termination handler, to deactivate it when done.
+. \"
+. als pdf*href.mark.hook pdf*href.mark.trap
+. \"
+. \" Now we set up "pdf:epg" to count the number of page breaks
+. \" which this link will span, and emit the link text, leaving
+. \" the page trap macro to map active regions on intervening
+. \" pages, which are included in the link.
+. \"
+. nr pdf:epg -\\n[pdf:spg] 1
+. \}
+. el \{\
+. \" There was no handler initialised for the page trap,
+. \" so we are unable to map the active regions for this link;
+. \" we may discard the remaining map data for this link,
+. \" and issue a diagnostic.
+. \"
+. pdf:error pdfhref: link dissociated at page break (trap not initialised)
+. if dPDFHREF.BROKEN.COLOR \{\
+. \"
+. \" The user may opt to have such broken links highlighted.
+. \" We use "PDFHREF.BROKEN.COLOUR" to specify this requirement,
+. \" but the user may prefer the American spelling, so we will
+. \" handle both as equivalent.
+. \"
+. als PDFHREF.BROKEN.COLOUR PDFHREF.BROKEN.COLOR
+. \}
+. if dPDFHREF.BROKEN.COLOUR \{\
+. if dPDFHREF.COLOUR .als PDFHREF.COLOUR PDFHREF.BROKEN.COLOUR
+. \}
+. \}
+. \}
+. \}
+.el \!.\\$0 \\$@
+..
+.\"
+.\" Macro "pdf*href.mark.emit" is called only by "pdf*href". It is
+.\" responsible for emitting the PDFMARK code, to establish the
+.\" "hot-spot" region associated with a document or resource link.
+.\"
+.de pdf*href.mark.emit
+.\" ----------------------------------------------------------------------
+.\" Usage:
+.\" .pdf*href.mark.emit <action> [<end-urx>]
+.\" <action> == 0 --> normal operation -- link height = 1 line
+.\" <action> == 1 --> start of link -- add leading above text
+.\" <action> == 2 --> overtall link -- set intermediate baseline
+.\" <action> == 3 --> split link -- break at bottom of page
+.\" ----------------------------------------------------------------------
+.\"
+.if \\$1=1 \{\
+. \"
+. \" Initialising a new link region ...
+. \" Some different versions of "groff" disagree about the vertical
+. \" displacement of "opminy", as emitted by "\O1|\h'-\w"|"u'\O2\c",
+. \" relative to the current text baseline. Therefore, recompute
+. \" the link displacement, independently of "opminy".
+. \"
+. mk pdf:ury.base
+. while \\n[pdf:ury.base]<\\n[pdf:ury] .nr pdf:ury.base +1v
+. nr pdf:ury.base -1m+\\n[PDFHREF.LEADING]
+. \"
+. \" adjust the end-point vertical displacement by the same offset,
+. \" and then relocate the link starting point to its new displacement,
+. \" as established by this base line relative computation.
+. \"
+. nr pdf:lly.end +\\n[pdf:ury.base]-\\n[pdf:ury]+\\*[PDFHREF.HEIGHT]
+. rnn pdf:ury.base pdf:ury
+. \}
+.if \\$1<2 \{\
+. \"
+. \" Link segment fits on a single line ...
+. \" Set its height and end-point horizontal displacement accordingly.
+. \"
+. nr pdf:lly \\n[pdf:ury]+\\*[PDFHREF.HEIGHT]
+. if \\n[pdf:lly]>=\\n[pdf:lly.end] .nr pdf:urx \\$2
+. \}
+.ie \\$1=3 \{\
+. \"
+. \" Link segment extends beyond the next page break ...
+. \" Recompute truncated height, to just fit portion on current page,
+. \" recursing to emit it, and leaving page trap mechanism to place
+. \" continuation region(s) on following page(s).
+. \"
+. nr pdf:lly (\\n[.t]u-\\n[.V]u)/1v
+. if \\n[pdf:lly]>0 \{\
+. nr pdf:lly \\n[pdf:ury]+\\n[pdf:lly]v-1v+\\*[PDFHREF.HEIGHT]
+. pdf*href.mark.emit 2
+. \}
+. \}
+.el \{\
+. \" Link region size and placement has been fully specified ...
+. \" Emit it.
+. \"
+. pdfmark \\*[pdf:href.link] /Rect [\\*[pdf:bbox]] /ANN
+. \}
+..
+.\"
+.\" When "pdf*href" emits a link for which the "hot-spot" spans a
+.\" page break, then we need to provide a "hook" in to the page break
+.\" trap, so we can map the "hot-spot" regions which are to be placed
+.\" on either side of the page break.
+.\"
+.\" Macro "pdf*href.mark.idle" is a dummy macro, which provide this
+.\" "hook" for normal page breaks, where there is no link "hot-spot"
+.\" crossing the break.
+.\"
+.de pdf*href.mark.idle
+.\" ----------------------------------------------------------------------
+.\" Usage:
+.\" Called only as an internal hook, by a page trap macro.
+.\" Expects no arguments, and does nothing.
+.\" ----------------------------------------------------------------------
+..
+.\"
+.\" Macro "pdf*href.mark.trap" is the active "hook", which is substituted
+.\" for "pdf*href,mark.idle" at those page breaks which are crossed by
+.\" a link "hot-spot".
+.\"
+.de pdf*href.mark.trap
+.\" ----------------------------------------------------------------------
+.\" Usage:
+.\" Called only as an internal hook, by a page trap macro.
+.\" Expects no arguments. Maps residual link "hot-spot" regions,
+.\" which spill beyond any page break. Not to be invoked directly
+.\" by the user, nor by any user supplied macro.
+.\" ----------------------------------------------------------------------
+.\"
+.mk pdf:ury
+.nr pdf:ury +1v-1m-\\n[PDFHREF.LEADING]
+.ie \\n-[pdf:epg] \{\
+. \"
+. \" The link "hot-spot" extends across more than one page break,
+. \" so, for each page which is completely contained within the
+. \" extent of the link, simply mark the entire text area on the
+. \" page as a "hot-spot".
+. \"
+. pdf*href.mark.emit 3
+. \}
+.el \{\
+. \" The link "hot-spot" ends on the page which immediately follows
+. \" the current page transition, so we may now finalise this link.
+. \"
+. nr pdf:lly \\n[pdf:ury]+\\*[PDFHREF.HEIGHT]
+. if \\n[pdf:lly.end]>\\n[pdf:lly] \{\
+. \"
+. \" The "hot-spot" extends beyond the first line of text,
+. \" on its final page; compute and emit "hot-spot" region to cover
+. \" the full with of the text area, including all but the last
+. \" line of the link text.
+. \"
+. while \\n[pdf:lly.end]>\\n[pdf:lly] .nr pdf:lly +1v
+. nr pdf:lly -1v
+. pdf*href.mark.emit 2
+. \"
+. \" Now, adjust the vertical "hot-spot" mapping reference,
+. \" to identify the correct position for the last line of
+. \" text, over which the "hot-spot" extends.
+. \"
+. nr pdf:ury \\n[pdf:lly.end]-\\*[PDFHREF.HEIGHT]
+. \}
+. \"
+. \" We now have exactly one final line of text, over which we must
+. \" emit a "hot-spot" region; map it, terminate page trap processing
+. \" for this "hot-spot", and clean up the "hot-spot" mapping context.
+. \"
+. pdf*href.mark.emit 0 \\n[pdf:urx.end]
+. als pdf*href.mark.hook pdf*href.mark.idle
+. pdf*href.mark.flush
+. \}
+..
+.de pdf*href.mark.flush
+.\" ----------------------------------------------------------------------
+.\" ----------------------------------------------------------------------
+.rr pdf:spg pdf:epg
+.rr pdf:llx pdf:lly pdf:urx pdf:ury
+.if dPDFHREF.COLOR .als PDFHREF.COLOUR PDFHREF.COLOR
+.rr pdf:urx.end pdf:lly.end
+..
+.de pdf*href.mark.end
+.\" ----------------------------------------------------------------------
+.\" ----------------------------------------------------------------------
+\O1\Z'|'\O2\c
+..
+.\" Macro "pdf*href-I" is used for one time initialisation of special
+.\" "pdfhref" features; (currently, only the above page trap hook is
+.\" supported, but it is implemented with one level of indirection, to
+.\" accommodate possible future expansion).
+.
+.de pdf*href-I
+.\" ----------------------------------------------------------------------
+.\" Usage:
+.\" .pdfhref I -<option> <optarg> [-<option> <optarg>] ...
+.\" ----------------------------------------------------------------------
+.\"
+.\" Loop over all arguments, in pairs ...
+.
+.while \\n(.$ \{\
+. \"
+. \" handing them off to their respective initialisers,
+. \" when suitable initialisers exist, or complaining otherwise.
+. \"
+. ie dpdf*href\\$1.init .pdf*href\\$1.init \\$2
+. el .pdf*error pdfhref:init: unknown feature '\\$1'
+. shift 2
+. \}
+..
+.\" Before we can use the page break "hook", we need to initialise it
+.\" as an addendum to a regular page break trap. To ensure that we don't
+.\" compromise the user's page trap setup, we leave the onus for this
+.\" initialisation with the user, but we provide the "pdf*href-PT.init"
+.\" macro, (invoked by ".pdfhref I -PT <macro-name>"), to implement a
+.\" suitable initialisation action.
+.
+.de pdf*href-PT.init
+.\" ----------------------------------------------------------------------
+.\" Usage:
+.\" .pdfhref I -PT <macro-name>
+.\" <macro-name> == name of user's page break trap macro
+.\" ----------------------------------------------------------------------
+.\"
+.\" Initially, map the page break hook to its default, do nothing helper.
+.
+.als pdf*href.mark.hook pdf*href.mark.idle
+.ie !\\n(.$ \{\
+. \"
+. \" Don't have enough arguments to specify a page trap macro name,
+. \" so simply plant "pdf*href.mark.hook" as a top of page trap.
+. \"
+. wh 0 pdf*href.mark.hook
+. \}
+.el \{\
+. \" Page trap macro name is specified in "\\$1" ...
+. \"
+. ie d\\$1 \{\
+. \"
+. \" When this page trap macro already exists, then we simply
+. \" append a call to "pdf*href.mark.hook" to it.
+. \"
+. am \\$1 pdf*href.mark.idle
+. pdf*href.mark.hook
+. pdf*href.mark.idle
+. \}
+. el \{\
+. \" However, when the specified page trap macro does not yet
+. \" exist, then we create it, and plant it as a top of page
+. \" trap.
+. \"
+. de \\$1 pdf*href.mark.idle
+. pdf*href.mark.hook
+. pdf*href.mark.idle
+. wh 0 \\$1
+. \}
+. \}
+..
+.
+.\" "pdf*href-L" is the generic handler for creating references to
+.\" named destinations in PDF documents. It supports both local
+.\" references, to locations within the same document, through its
+.\" "pdf*href-L.link" attribute, and also references to locations
+.\" in any other PDF document, through "pdf*href-L.file".
+.\"
+.als pdf*href-L pdf*href
+.ds pdf*href-L.link /Dest /\\\\*[pdf:href-D]
+.ds pdf*href-L.file /Action /GoToR \\\\*[pdf:href.files] \\*[pdf*href-L.link]
+.\"
+.\" "pdf*href-O" is the "official" handler for creating PDF
+.\" document outlines. It is simply an alias to "pdfbookmark",
+.\" which may also be invoked directly, if preferred. Neither
+.\" a "pdf*href-O.link" nor a "pdf*href-O.file" attribute is
+.\" required.
+.\"
+.als pdf*href-O pdfbookmark
+.\"
+.\" "pdf*href-W" is the generic handler for creating references to
+.\" web resources, (or any resource specified by a uniform resource
+.\" identifier). Such resource links are fully specified by the
+.\" "pdf*href-W.link" attribute.
+.\"
+.als pdf*href-W pdf*href
+.ds pdf*href-W.link /Action << /Subtype /URI /URI (\\\\*[pdf:href-D]) >>
+.\"
+.\" Local Variables:
+.\" mode: nroff
+.\" End:
+.\" vim: filetype=groff:
+.\" pdfmark.tmac: end of file
diff --git a/contrib/pdfmark/pdfroff.1.man b/contrib/pdfmark/pdfroff.1.man
new file mode 100644
index 0000000..029a1f4
--- /dev/null
+++ b/contrib/pdfmark/pdfroff.1.man
@@ -0,0 +1,981 @@
+.TH pdfroff @MAN1EXT@ "@MDATE@" "groff @VERSION@"
+.SH Name
+pdfroff \- construct files in Portable Document Format using
+.I groff
+.
+.
+.\" ====================================================================
+.\" Legal Terms
+.\" ====================================================================
+.\"
+.\" Copyright (C) 2005-2020 Free Software Foundation, Inc.
+.\"
+.\" This file is part of groff, the GNU roff type-setting system.
+.\"
+.\" Permission is granted to copy, distribute and/or modify this
+.\" document under the terms of the GNU Free Documentation License,
+.\" Version 1.3 or any later version published by the Free Software
+.\" Foundation; with no Invariant Sections, with no Front-Cover Texts,
+.\" and with no Back-Cover Texts.
+.\"
+.\" A copy of the Free Documentation License is included as a file
+.\" called FDL in the main directory of the groff source package.
+.
+.
+.\" Save and disable compatibility mode (for, e.g., Solaris 10/11).
+.do nr *groff_pdfroff_1_man_C \n[.cp]
+.cp 0
+.
+.\" Define fallback for groff 1.23's MR macro if the system lacks it.
+.nr do-fallback 0
+.if !\n(.f .nr do-fallback 1 \" mandoc
+.if \n(.g .if !d MR .nr do-fallback 1 \" older groff
+.if !\n(.g .nr do-fallback 1 \" non-groff *roff
+.if \n[do-fallback] \{\
+. de MR
+. ie \\n(.$=1 \
+. I \%\\$1
+. el \
+. IR \%\\$1 (\\$2)\\$3
+. .
+.\}
+.rr do-fallback
+.
+.
+.\" ====================================================================
+.SH Synopsis
+.\" ====================================================================
+.
+.SY pdfroff
+.RI [ groff-option ]
+.RB [ \-\-emit\-ps ]
+.RB [ \-\-no\-toc\-relocation ]
+.RB [ \-\-no\-kill\-null\-pages ]
+.RB [ \-\-stylesheet=\c
+.IR name ]
+.RB [ \-\-no\-pdf\-output ]
+.RB [ \-\-pdf\-output=\c
+.IR name ]
+.RB [ \-\-no\-reference\-dictionary ]
+.RB [ \-\-reference\-dictionary=\c
+.IR name ]
+.RB [ \-\-report\-progress ]
+.RB [ \-\-keep\-temporary\-files ]
+.RI [ file\~ .\|.\|.]
+.YS
+.
+.
+.SY pdfroff
+.B \-h
+.
+.SY pdfroff
+.B \-\-help
+.YS
+.
+.
+.SY pdfroff
+.B \-v
+.RI [ groff-option
+\&.\|.\|.\&]
+.
+.SY pdfroff
+.B \-\-version
+.RI [ groff-option
+\&.\|.\|.\&]
+.YS
+.
+.
+.P
+.I groff-option
+is any short option supported by
+.MR groff @MAN1EXT@
+except for
+.BR \-h ,
+.BR \-T ,
+and
+.BR \-v ;
+see section \[lq]Usage\[rq] below.
+.
+.
+.\" ====================================================================
+.SH Description
+.\" ====================================================================
+.
+.I pdfroff
+is a wrapper program for the GNU text processing system,
+.IR groff .
+.
+It transparently handles the mechanics of multiple pass
+.I groff
+processing,
+when applied to suitably marked up
+.I groff
+source files,
+such that tables of contents and body text are formatted separately,
+and are subsequently combined in the correct order,
+for final publication as a single PDF document.
+.
+A further optional \[lq]style sheet\[rq] capability is provided;
+this allows for the definition of content which is required to precede
+the table of contents,
+in the published document.
+.
+.
+.P
+For each invocation of
+.IR pdfroff ,
+the ultimate
+.I groff
+output stream is post-processed by the Ghostscript
+.MR gs 1
+interpreter to produce a finished PDF document.
+.
+.
+.P
+.I pdfroff
+makes no assumptions about,
+and imposes no restrictions on,
+the use of any
+.I groff
+macro packages which the user may choose to employ,
+in order to achieve a desired document format;
+however,
+it
+.I does
+include specific built in support for the
+.I \%pdfmark
+macro package,
+should the user choose to employ it.
+.
+Specifically,
+if the
+.I pdfhref
+macro,
+defined in the
+.I \%pdfmark.tmac
+package,
+is used to define public reference marks,
+or dynamic links to such reference marks,
+then
+.I pdfroff
+performs as many preformatting
+.I groff
+passes as required,
+up to a maximum limit of
+.IR four ,
+in order to compile a document reference dictionary,
+to resolve
+references,
+and to expand the dynamically defined content of links.
+.
+.
+.\" ====================================================================
+.SH Usage
+.\" ====================================================================
+.
+The command line is parsed in accordance with normal GNU conventions,
+but with one exception\(emwhen specifying any short form option
+(i.e.,
+a single character option introduced by a single hyphen),
+and if that option expects an argument,
+then it
+.I must
+be specified independently
+(i.e.,
+it may
+.I not
+be appended to any group of other single character short form options).
+.
+.
+.P
+Long form option names
+(i.e.,
+those introduced by a double hyphen)
+may
+be abbreviated to their minimum length unambiguous initial substring.
+.
+.
+.P
+Otherwise,
+.I pdfroff
+usage closely mirrors that of
+.I groff
+itself.
+.
+Indeed,
+with the exception of the
+.BR \-h ,
+.BR \-v ,
+and
+.BI \-T \ dev
+short form options,
+and all long form options,
+which are parsed
+internally by
+.IR pdfroff ,
+all options and file name arguments specified on the command line are
+passed on to
+.IR groff ,
+to control the formatting of the PDF document.
+.
+Consequently,
+.I pdfroff
+accepts all options and arguments,
+as specified in
+.MR groff @MAN1EXT@ ,
+which may also be considered as the definitive reference for all
+standard
+.I pdfroff
+options and argument usage.
+.
+.
+.\" ====================================================================
+.SH Options
+.\" ====================================================================
+.
+.I pdfroff
+accepts all of the short form options
+(i.e.,
+those introduced by a
+single hyphen),
+which are available with
+.I groff
+itself.
+.
+In most cases,
+these are simply passed transparently to
+.IR groff ;
+the following,
+however,
+are handled specially by
+.IR pdfroff .
+.
+.
+.TP
+.B \-h
+Same as
+.BR \-\-help ;
+see below.
+.
+.
+.TP
+.B \-i
+Process standard input,
+after all other specified input files.
+.
+This is passed transparently to
+.IR groff ,
+but,
+if grouped with other options,
+it
+.I must
+be the first in the group.
+.
+Hiding it within a group breaks standard input processing,
+in the multiple-pass
+.I groff
+processing context of
+.IR pdfroff .
+.
+.
+.TP
+.BI \-T \ dev
+Only
+.B \-T\ ps
+is supported by
+.IR pdfroff .
+.
+Attempting to specify any other device causes
+.I pdfroff
+to abort.
+.
+.
+.TP
+.B \-v
+Same as
+.BR \-\-version ;
+see below.
+.
+.
+.P
+See
+.MR groff @MAN1EXT@
+for a description of all other short form options,
+which are
+transparently passed through
+.I pdfroff
+to
+.IR groff .
+.
+.
+.P
+All long form options
+(i.e.,
+those introduced by a double hyphen)
+are interpreted locally by
+.IR pdfroff ;
+they are
+.I not
+passed on to
+.IR groff ,
+unless otherwise stated below.
+.
+.
+.TP
+.B \-\-help
+Causes
+.I pdfroff
+to display a summary of the its usage syntax,
+and supported options,
+and then exit.
+.
+.
+.TP
+.B \-\-emit\-ps
+Suppresses the final output conversion step,
+causing
+.I pdfroff
+to emit PostScript output instead of PDF.
+.
+This may be useful to capture intermediate PostScript output when using
+a specialised postprocessor,
+such as
+.I gpresent
+for example,
+in place of the default Ghostscript PDF writer.
+.
+.
+.TP
+.B \-\-keep\-temporary\-files
+Suppresses the deletion of temporary files,
+which normally occurs
+after
+.I pdfroff
+has completed PDF document formatting;
+this may be useful when debugging formatting problems.
+.
+.
+.IP
+See section \[lq]Files\[rq] below for a description of the temporary
+files used by
+.IR pdfroff .
+.
+.
+.TP
+.B \-\-no\-pdf\-output
+May be used with the
+.BI \%\-\-reference\-dictionary= name
+option
+(described below)
+to eliminate the overhead of PDF formatting when running
+.I pdfroff
+to create a reference dictionary for use in a different document.
+.
+.
+.TP
+.B \-\-no\-reference\-dictionary
+May be used to eliminate the overhead of creating a reference
+dictionary,
+when it is known that the target PDF document contains no public
+references,
+created by the
+.B pdfhref
+macro.
+.
+.
+.TP
+.B \-\-no\-toc\-relocation
+May be used to eliminate the extra
+.I groff
+processing pass,
+which is required to generate a table of contents,
+and relocate it to the start of the PDF document,
+when processing any document which lacks an automatically
+generated table of contents.
+.
+.
+.TP
+.B \-\-no\-kill\-null\-pages
+While preparing for simulation of the manual collation step,
+which is traditionally required to relocate a
+.I "table of contents"
+to the start of a document,
+.I pdfroff
+accumulates a number of empty page descriptions
+into the intermediate PostScript output stream.
+.
+During the final collation step,
+these empty pages are normally discarded from the finished document;
+this option forces
+.I pdfroff
+to leave them in place.
+.
+.
+.TP
+.BI \-\-pdf\-output= name
+Specifies the name to be used for the resultant PDF document;
+if unspecified,
+the PDF output is written to standard output.
+.
+A future version of
+.I pdfroff
+may use this option,
+to encode the document name in a generated reference dictionary.
+.
+.
+.TP
+.BI \-\-reference\-dictionary= name
+Specifies the name to be used for the generated reference dictionary
+file;
+if unspecified,
+the reference dictionary is created in a temporary file,
+which is deleted when
+.I pdfroff
+completes processing of the current document.
+.
+This option
+.I must
+be specified,
+if it is desired to save the reference dictionary,
+for use in references placed in other PDF documents.
+.
+.
+.TP
+.B \-\-report\-progress
+Causes
+.I pdfroff
+to display an informational message on standard error,
+at the start of each
+.I groff
+processing pass.
+.
+.
+.TP
+.BI \-\-stylesheet= name
+Specifies the name of an
+.IR "input file" ,
+to be used as a style sheet for formatting of content,
+which is to be placed
+.I before
+the table of contents,
+in the formatted PDF document.
+.
+.
+.TP
+.B \-\-version
+Causes
+.I pdfroff
+to display a version identification message.
+.
+The entire command line is then passed transparently to
+.IR groff ,
+in a
+.I one
+pass operation
+.IR only ,
+in order to display the associated
+.I groff
+version information,
+before exiting.
+.
+.
+.\" ====================================================================
+.SH Environment
+.\" ====================================================================
+.
+The following environment variables may be set,
+and exported,
+to modify the behaviour of
+.IR pdfroff .
+.
+.
+.TP
+.I PDFROFF_COLLATE
+Specifies the program to be used
+for collation of the finished PDF document.
+.
+.
+.IP
+This collation step may be required to move
+.I tables of contents
+to the start of the finished PDF document,
+when formatting with traditional macro packages,
+which print them at the end.
+.
+However,
+users should not normally need to specify
+.IR \%PDFROFF_COLLATE ,
+(and indeed,
+are not encouraged to do so).
+.
+If unspecified,
+.I pdfroff
+uses
+.MR sed @MAN1EXT@
+by default,
+which normally suffices.
+.
+.
+.IP
+If
+.I \%PDFROFF_COLLATE
+.I is
+specified,
+then it must act as a filter,
+accepting a list of file name arguments,
+and write its output to the standard output stream,
+whence it is piped to the
+.IR \%PDFROFF_POSTPROCESSOR_COMMAND ,
+to produce the finished PDF output.
+.
+.
+.IP
+When specifying
+.IR \%PDFROFF_COLLATE ,
+it is normally necessary to also specify
+.IR \%PDFROFF_KILL_NULL_PAGES .
+.
+.
+.IP
+.I \%PDFROFF_COLLATE
+is ignored,
+if
+.I pdfroff
+is invoked with the
+.B \%\-\-no\-kill\-null\-pages
+option.
+.
+.
+.TP
+.I PDFROFF_KILL_NULL_PAGES
+Specifies options to be passed to the
+.I \%PDFROFF_COLLATE
+program.
+.
+.
+.IP
+It should not normally be necessary to specify
+.IR \%PDFROFF_KILL_NULL_PAGES .
+.
+The internal default is a
+.MR sed @MAN1EXT@
+script,
+which is intended to remove completely blank pages
+from the collated output stream,
+and which should be appropriate in most applications of
+.IR pdfroff .
+.
+However,
+if any alternative to
+.MR sed @MAN1EXT@
+is specified for
+.IR \%PDFROFF_COLLATE ,
+then it is likely that a corresponding alternative specification for
+.I \%PDFROFF_KILL_NULL_PAGES
+is required.
+.
+.
+.IP
+As in the case of
+.IR \%PDFROFF_COLLATE ,
+.I \%PDFROFF_KILL_NULL_PAGES
+is ignored,
+if
+.I pdfroff
+is invoked with the
+.B \%\-\-no\-kill\-null\-pages
+option.
+.
+.
+.TP
+.I PDFROFF_POSTPROCESSOR_COMMAND
+Specifies the command to be used for the final document conversion
+from PostScript intermediate output to PDF.
+.
+It must behave as a filter,
+writing its output to the standard output stream,
+and must accept an arbitrary number of
+.I files .\|.\|.\&
+arguments,
+with the special case of
+.RB \[lq] \- \[rq]
+representing the standard input stream.
+.
+.
+.IP
+If unspecified,
+.I \%PDFROFF_POSTPROCESSOR_COMMAND
+defaults to
+.
+.RS 12n
+.EX
+gs \-dBATCH \-dQUIET \-dNOPAUSE \-dSAFER \-sDEVICE=pdfwrite \e
+ \-sOutputFile=\-
+.EE
+.RE
+.
+.
+.TP
+.I GROFF_TMPDIR
+Identifies the directory in which
+.I pdfroff
+should create temporary files.
+.
+If
+.I \%GROFF_TMPDIR
+is
+.I not
+specified,
+then the variables
+.IR TMPDIR ,
+.I TMP
+and
+.I TEMP
+are considered in turn as possible temporary file repositories.
+.
+If none of these are set,
+then temporary files are created
+in the current directory.
+.
+.
+.TP
+.I GROFF_GHOSTSCRIPT_INTERPRETER
+Specifies the program to be invoked when
+.I pdfroff
+converts
+.I groff
+PostScript output to PDF.
+.
+If
+.I \%PDFROFF_POSTPROCESSOR_COMMAND
+is specified,
+then the command name it specifies is
+.I implicitly
+assigned to
+.IR \%GROFF_GHOSTSCRIPT_INTERPRETER ,
+overriding any explicit setting specified in the environment.
+.
+If
+.I \%GROFF_GHOSTSCRIPT_INTERPRETER
+is not specified,
+then
+.I pdfroff
+searches the process
+.IR PATH ,
+looking for a program with any of the well known names
+for the Ghostscript interpreter;
+if no Ghostscript interpreter can be found,
+.I pdfroff
+aborts.
+.
+.
+.TP
+.I GROFF_AWK_INTERPRETER
+Specifies the program to be invoked when
+.I pdfroff
+is extracting reference dictionary entries from a
+.I groff
+intermediate message stream.
+.
+If
+.I \%GROFF_AWK_INTERPRETER
+is not specified,
+then
+.I pdfroff
+searches the process
+.IR PATH ,
+looking for any of the preferred programs,
+.IR gawk ,
+.IR mawk ,
+.IR nawk ,
+and
+.IR awk ,
+in that order;
+if none of these are found,
+.I pdfroff
+issues a warning message,
+and continue processing;
+however,
+in this case,
+no reference dictionary is created.
+.
+.
+.TP
+.I OSTYPE
+Typically defined automatically by the operating system,
+.I \%OSTYPE
+is used on Microsoft Win32/MS-DOS platforms
+.IR only ,
+to infer the default
+.I \%PATH_SEPARATOR
+character,
+which is used when parsing the process
+.I PATH
+to search for external helper programs.
+.
+.
+.TP
+.I PATH_SEPARATOR
+If set,
+.I \%PATH_SEPARATOR
+overrides the default separator character,
+(\[oq]:\[cq] on POSIX/Unix systems,
+inferred from
+.I \%OSTYPE
+on Microsoft Win32/MS-DOS),
+which is used when parsing the process
+.I PATH
+to search for external helper programs.
+.
+.
+.TP
+.I SHOW_PROGRESS
+If this is set to a non-empty value,
+then
+.I pdfroff
+always behaves as if the
+.B \%\-\-report\-progress
+option is specified on the command line.
+.
+.
+.\" ====================================================================
+.SH Files
+.\" ====================================================================
+.
+Input and output files for
+.I pdfroff
+may be named according to any convention of the user's choice.
+.
+Typically,
+input files may be named according to the choice of the principal
+normatting macro package,
+e.g.,
+.RI file .ms
+might be an input file for formatting using the
+.I ms
+macros
+.RI ( s.tmac );
+normally,
+the final output file should be named
+.RI file .pdf .
+.
+.
+.P
+Temporary files created by
+.I pdfroff
+are placed in the file system hierarchy,
+in or below the directory specified by environment variables
+(see section \[lq]Environment\[rq] above).
+.
+If
+.MR mktemp @MAN1EXT@
+is available,
+it is invoked to create a private subdirectory of
+the nominated temporary files directory,
+(with subdirectory name derived from the template
+.IR pdfroff\-XXXXXXXXXX );
+if this subdirectory is successfully created,
+the temporary files will be placed within it,
+otherwise they will be placed directly in the directory
+nominated in the environment.
+.
+.
+.P
+All temporary files themselves
+are named according to the convention
+.IR pdf $$ . *,
+where
+.I $$
+is the standard shell variable representing the process identifier of
+the
+.I pdfroff
+process itself,
+and
+.I *
+represents any of the extensions used by
+.I pdfroff
+to identify the following temporary and intermediate files.
+.
+.
+.TP
+.IR pdf $$ .tmp
+A scratch pad file,
+used to capture reference data emitted by
+.IR groff ,
+during the
+.I reference dictionary
+compilation phase.
+.
+.
+.TP
+.IR pdf $$ .ref
+The
+.IR "reference dictionary" ,
+as compiled in the last but one pass of the
+.I reference dictionary
+compilation phase;
+(at the start of the first pass,
+this file is created empty;
+in successive passes,
+it contains the
+.I reference dictionary
+entries,
+as collected in the preceding pass).
+.
+.
+.IP
+If the
+.BR \%\-\-reference\-dictionary =\c
+.I name
+option is specified,
+this intermediate file becomes permanent,
+and is named
+.IR name ,
+rather than
+.IR pdf $$ .ref .
+.
+.
+.TP
+.IR pdf $$ .cmp
+Used to collect
+.I reference dictionary
+entries during the active pass of the
+.I reference dictionary
+compilation phase.
+.
+At the end of any pass,
+when the content of
+.IR pdf $$ .cmp
+compares as identical to
+.IR pdf $$ .ref ,
+(or the corresponding file named by the
+.BR \%\-\-reference\-dictionary =\c
+.I name
+option),
+then
+.I reference dictionary
+compilation is terminated,
+and the
+.I document reference map
+is appended to this intermediate file,
+for inclusion in the final formatting passes.
+.
+.
+.TP
+.IR pdf $$ .tc
+An intermediate
+.I PostScript
+file,
+in which \[lq]Table of Contents\[rq] entries are collected,
+to facilitate relocation before the body text,
+on ultimate output to the
+.I Ghostscript
+postprocessor.
+.
+.
+.TP
+.IR pdf $$ .ps
+An intermediate
+.I PostScript
+file,
+in which the body text is collected prior to ultimate output to the
+.I Ghostscript
+postprocessor,
+in the proper sequence,
+.I after
+.IR pdf $$ .tc .
+.
+.
+.\" ====================================================================
+.SH Authors
+.\" ====================================================================
+.
+.I pdfroff
+was written by
+.MT keith\:.d\:.marshall@\:ntlworld\:.com
+Keith Marshall
+.ME ,
+who maintains it at
+.UR https://\:osdn\:.net/\:users/\:keith/\:pf/\:\%groff-pdfmark/\
+\:wiki/\:\%FrontPage
+his
+.I groff-pdfmark
+OSDN site
+.UE .
+.
+.IR groff 's
+version may be withdrawn in a future release.
+.
+.
+.\" ====================================================================
+.SH "See also"
+.\" ====================================================================
+.
+.IR "Groff: The GNU Implementation of troff" ,
+by Trent A.\& Fisher and Werner Lemberg,
+is the primary
+.I groff
+manual.
+.
+You can browse it interactively with \[lq]info groff\[rq].
+.
+.
+.P
+Since
+.I pdfroff
+provides a superset of all
+.I groff
+capabilities,
+the above manual,
+or its terser reference page,
+.MR groff @MAN7EXT@
+may also be considered definitive references to all
+.I standard
+capabilities of
+.IR pdfroff ,
+with this document providing the reference to
+.IR pdfroff 's
+extended features.
+.
+.
+.P
+While
+.I pdfroff
+imposes neither any restriction on,
+nor any requirement for,
+the use of any specific
+.I groff
+macro package,
+a number of supplied macro packages,
+and in particular those associated with the package
+.IR \%pdfmark.tmac ,
+are best suited for use with
+.I pdfroff
+as the preferred formatter.
+.
+.
+.TP
+.I @PDFDOCDIR@/\:\%pdfmark.pdf
+\[lq]Portable Document Format Publishing with GNU
+.IR Troff \[rq],
+by Keith Marshall,
+offers detailed documentation on the use of these packages.
+.
+This file,
+together with its source,
+.IR \%pdfmark.ms ,
+is part of the
+.I groff
+distribution.
+.
+.
+.\" Restore compatibility mode (for, e.g., Solaris 10/11).
+.cp \n[*groff_pdfroff_1_man_C]
+.do rr *groff_pdfroff_1_man_C
+.
+.
+.\" Local Variables:
+.\" fill-column: 72
+.\" mode: nroff
+.\" End:
+.\" vim: set filetype=groff textwidth=72:
diff --git a/contrib/pdfmark/pdfroff.sh b/contrib/pdfmark/pdfroff.sh
new file mode 100644
index 0000000..f34c841
--- /dev/null
+++ b/contrib/pdfmark/pdfroff.sh
@@ -0,0 +1,682 @@
+#! /bin/sh
+# ------------------------------------------------------------------------------
+#
+# Function: Format PDF Output from groff Markup
+#
+# Copyright (C) 2005-2021 Free Software Foundation, Inc.
+# Written by Keith Marshall (keith.d.marshall@ntlworld.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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# ------------------------------------------------------------------------------
+#
+# Set up an identifier for the NULL device.
+# In most cases "/dev/null" will be correct, but some shells on
+# MS-DOS/MS-Windows systems may require us to use "NUL".
+#
+ NULLDEV="/dev/null"
+ test -c $NULLDEV || NULLDEV="NUL"
+#
+# Set up the command name to use in diagnostic messages.
+# (We can't assume we have 'basename', so use the full path if required.
+# Also use the 'exec 2>...' workaround for a bug in Cygwin's 'ash').
+#
+ CMD=`exec 2>$NULLDEV; basename $0` || CMD=$0
+#
+# To ensure that prerequisite helper programs are available, and are
+# executable, a [fairly] portable method of detecting such programs is
+# provided by function 'searchpath'.
+#
+ searchpath(){
+ #
+ # Usage: searchpath progname path
+ #
+ IFS=${PATH_SEPARATOR-":"} prog=':'
+ for dir in $2
+ do
+ for ext in '' '.exe'
+ #
+ # try 'progname' with all well known extensions
+ # (e.g. Win32 may require 'progname.exe')
+ #
+ do
+ try="$dir/$1$ext"
+ test -f "$try" && test -x "$try" && prog="$try" && break
+ done
+ test "$prog" = ":" || break
+ done
+ echo "$prog"
+ }
+# @PATH_SEARCH_SETUP@
+#
+# If the system maps '/bin/sh' to some 'zsh' implementation,
+# then we may need this hack, adapted from autoconf code.
+#
+ test x${ZSH_VERSION+"set"} = x"set" && NULLCMD=":" \
+ && (emulate sh) >$NULLDEV 2>&1 && emulate sh
+#
+# We need both 'grep' and 'sed' programs, to parse script options,
+# and we also need 'cat', to display help and some error messages,
+# so ensure they are all installed, before we continue.
+#
+ CAT=`searchpath cat "$PATH"`
+ GREP=`searchpath grep "$PATH"`
+ SED=`searchpath sed "$PATH"`
+#
+# Another fundamental requirement is the 'groff' program itself;
+# we MUST use a 'groff' program located in 'GROFF_BIN_DIR', if this
+# is specified; if not, we will search 'GROFF_BIN_PATH', only falling
+# back to a 'PATH' search, if neither of these is specified.
+#
+ if test -n "$GROFF_BIN_DIR"
+ then
+ GPATH=GROFF_BIN_DIR
+ GROFF=`searchpath groff "$GROFF_BIN_DIR"`
+#
+ elif test -n "$GROFF_BIN_PATH"
+ then
+ GPATH=GROFF_BIN_PATH
+ GROFF=`searchpath groff "$GROFF_BIN_PATH"`
+#
+ else
+ GPATH=PATH
+ GROFF=`searchpath groff "$PATH"`
+ fi
+#
+# If one or more of these is missing, diagnose and bail out.
+#
+ NO='' NOPROG="$CMD: installation problem: cannot find program"
+ test "$CAT" = ":" && echo >&2 "$NOPROG 'cat' in PATH" && NO="$NO 'cat'"
+ test "$GREP" = ":" && echo >&2 "$NOPROG 'grep' in PATH" && NO="$NO 'grep'"
+ test "$GROFF" = ":" && echo >&2 "$NOPROG 'groff' in $GPATH" && NO="$NO 'groff'"
+ test "$SED" = ":" && echo >&2 "$NOPROG 'sed' in PATH" && NO="$NO 'sed'"
+ if test -n "$NO"
+ then
+ set $NO
+ test $# -gt 1 && NO="s" IS="are" || NO='' IS="is"
+ while test $# -gt 0
+ do
+ test $# -gt 2 && NO="$NO $1,"
+ test $# -eq 2 && NO="$NO $1 and" && shift
+ test $# -lt 2 && NO="$NO $1"
+ shift
+ done
+ $CAT >&2 <<-ETX
+
+ *** FATAL INSTALLATION ERROR ***
+
+ The program$NO $IS required by '$CMD',
+ but cannot be found; '$CMD' is unable to continue.
+
+ ETX
+ exit 1
+ fi
+#
+# Identify the postprocessor command, for writing PDF output.
+# (May be forced, by defining PDFROFF_POSTPROCESSOR_COMMAND in the environment;
+# if this is not set, leave blank to use the built in default).
+#
+ if test -n "${PDFROFF_POSTPROCESSOR_COMMAND}"
+ then
+ GROFF_GHOSTSCRIPT_INTERPRETER=`set command ${PDFROFF_POSTPROCESSOR_COMMAND};
+ echo $2`
+ fi
+#
+# Set up temporary/intermediate file locations, with traps to
+# clean them up on exit. Note that, for greater portability, we
+# prefer to refer to events by number, rather than by symbolic
+# names; thus, the EXIT event is trapped as event zero.
+#
+ export TMPDIR GROFF_TMPDIR
+ TMPDIR=${GROFF_TMPDIR=${TMPDIR-${TMP-${TEMP-"."}}}}
+ if GROFF_TMPDIR=`exec 2>${NULLDEV}; mktemp -dt pdfroff-XXXXXXXXXX`
+ then
+ #
+ # We successfully created a private temporary directory,
+ # so to clean up, we may simply purge it.
+ #
+ trap "rm -rf ${GROFF_TMPDIR}" 0
+ #
+ else
+ #
+ # Creation of a private temporary directory was unsuccessful;
+ # fall back to user nominated directory, (using current directory
+ # as default), and schedule removal of only the temporary files.
+ #
+ GROFF_TMPDIR=${TMPDIR}
+ trap "rm -f ${GROFF_TMPDIR}/pdf$$.*" 0
+ fi
+ #
+ # In the case of abnormal termination events, we force an exit
+ # (with status code '1'), leaving the normal exit trap to clean
+ # up the temporary files, as above. Note that we again prefer
+ # to refer to events by number, rather than by symbolic names;
+ # here we trap SIGHUP, SIGINT, SIGQUIT, SIGPIPE and SIGTERM.
+ #
+ trap "exit 1" 1 2 3 13 15
+#
+ WRKFILE=${GROFF_TMPDIR}/pdf$$.tmp
+#
+ REFCOPY=${GROFF_TMPDIR}/pdf$$.cmp
+ REFFILE=${GROFF_TMPDIR}/pdf$$.ref
+#
+ CS_DATA=""
+ TC_DATA=${GROFF_TMPDIR}/pdf$$.tc
+ BD_DATA=${GROFF_TMPDIR}/pdf$$.ps
+#
+# Initialise 'groff' format control settings,
+# to discriminate table of contents and document body formatting passes.
+#
+ TOC_FORMAT="-rPHASE=1"
+ BODY_FORMAT="-rPHASE=2"
+#
+ LONGOPTS="
+ help reference-dictionary no-reference-dictionary
+ stylesheet pdf-output no-pdf-output
+ version report-progress no-toc-relocation
+ emit-ps keep-temporary-files no-kill-null-pages
+ "
+# Parse the command line, to identify 'pdfroff' specific options.
+# Collect all other parameters into new argument and file lists,
+# to be passed on to 'groff', enforcing the '-Tps' option.
+#
+ DIFF="" STREAM="" INPUT_FILES=""
+ SHOW_VERSION="" GROFF_STYLE="$GROFF -Tps"
+ while test $# -gt 0
+ do
+ case "$1" in
+#
+# Long options must be processed locally ...
+#
+ --*)
+#
+# First identify, matching any abbreviation to its full form.
+#
+ MATCH="" OPTNAME=`IFS==; set dummy $1; echo $2`
+ for OPT in $LONGOPTS
+ do
+ MATCH="$MATCH"`echo --$OPT | $GREP "^$OPTNAME"`
+ done
+#
+# For options in the form --option=value
+# capture any specified value into $OPTARG.
+#
+ OPTARG=`echo $1 | $SED -n s?"^${OPTNAME}="??p`
+#
+# Perform case specific processing for matched option ...
+#
+ case "$MATCH" in
+
+ --help)
+ $CAT <<-ETX
+ Usage: $CMD [-option ...] [--long-option ...] [file ...]
+
+ Options:
+ -h
+ --help
+ Display this usage summary, and exit.
+
+ -v
+ --version
+ Display a version identification message and exit.
+
+ --report-progress
+ Enable console messages, indicating the progress of the
+ PDF document formatting process.
+
+ --emit-ps
+ Emit PostScript output instead of PDF; this may be useful
+ when the ultimate PDF output is to be generated by a more
+ specialised postprocessor, (e.g. gpresent), rather than
+ the default GhostScript PDF writer.
+
+ --pdf-output=name
+ Write the PDF, (or PostScript), output stream to file
+ 'name'; if this option is unspecified, standard output
+ is used for PDF, (or PostScript), output.
+
+ --no-pdf-output
+ Suppress the generation of PDF, (or PostScript), output
+ entirely; use this with the --reference-dictionary option,
+ if processing a document stream to produce only a
+ reference dictionary.
+
+ --no-reference-dictionary
+ Suppress the generation of a '$CMD' reference dictionary
+ for the PDF document. Normally '$CMD' will create a
+ reference dictionary, at the start of document processing;
+ this option can accelerate processing, if it is known in
+ advance, that no reference dictionary is required.
+
+ --reference-dictionary=name
+ Save the document reference dictionary in file 'name'.
+ If 'name' already exists, when processing commences, it
+ will be used as the base case, from which the updated
+ dictionary will be derived. If this option is not used,
+ then the reference dictionary, created during the normal
+ execution of '$CMD', will be deleted on completion of
+ document processing.
+
+ --stylesheet=name
+ Use the file 'name' as a 'groff' style sheet, to control
+ the appearance of the document's front cover section. If
+ this option is not specified, then no special formatting
+ is applied, to create a front cover section.
+
+ --no-toc-relocation
+ Suppress the multiple pass 'groff' processing, which is
+ normally required to position the table of contents at the
+ start of a PDF document.
+
+ --no-kill-null-pages
+ Suppress the 'null page' elimination filter, which is used
+ to remove the excess blank pages produced by the collation
+ algorithm used for 'toc-relocation'.
+
+ --keep-temporary-files
+ Suppress the normal clean up of temporary files, which is
+ scheduled when 'pdfroff' completes.
+
+ ETX
+ exit 0
+ ;;
+
+ --version)
+ GROFF_STYLE="$GROFF_STYLE \"$1\""
+ SHOW_VERSION="GNU pdfroff (groff) version @VERSION@"
+ ;;
+
+ --report-progress)
+ SHOW_PROGRESS=echo
+ ;;
+
+ --keep-temporary-files)
+ trap "" 0
+ ;;
+
+ --emit-ps)
+ PDFROFF_POSTPROCESSOR_COMMAND="$CAT"
+ ;;
+
+ --pdf-output)
+ PDF_OUTPUT="$OPTARG"
+ ;;
+
+ --no-pdf-output)
+ PDF_OUTPUT="$NULLDEV"
+ ;;
+
+ --reference-dictionary)
+ REFFILE="$OPTARG"
+ ;;
+
+ --no-reference-dictionary)
+ AWK=":" DIFF=":" REFFILE="$NULLDEV" REFCOPY="$NULLDEV"
+ ;;
+
+ --stylesheet)
+ STYLESHEET="$OPTARG" CS_DATA=${GROFF_TMPDIR}/pdf$$.cs
+ ;;
+
+ --no-toc-relocation)
+ TC_DATA="" TOC_FORMAT="" BODY_FORMAT=""
+ ;;
+
+ --no-kill-null-pages)
+ PDFROFF_COLLATE="$CAT" PDFROFF_KILL_NULL_PAGES=""
+ ;;
+#
+# any other non-null match must have matched more than one defined case,
+# so report the ambiguity, and bail out.
+#
+ --*)
+ echo >&2 "$CMD: ambiguous abbreviation in option '$1'"
+ exit 1
+ ;;
+#
+# while no match at all simply represents an undefined case.
+#
+ *)
+ echo >&2 "$CMD: unknown option '$1'"
+ exit 1
+ ;;
+ esac
+ ;;
+#
+# A solitary hyphen, as an argument, means "stream STDIN through groff",
+# while the "-i" option means "append STDIN stream to specified input files",
+# so set up a mechanism to achieve this, for ALL 'groff' passes.
+#
+ - | -i*)
+ STREAM="$CAT ${GROFF_TMPDIR}/pdf$$.in |"
+ test "$1" = "-" && INPUT_FILES="$INPUT_FILES $1" \
+ || GROFF_STYLE="$GROFF_STYLE $1"
+ ;;
+#
+# Those standard options which expect an argument, but are specified with
+# an intervening space, between flag and argument, must be reparsed, so we
+# can trap invalid use of '-T dev', or missing input files.
+#
+ -[dfFILmMnoPrTwW])
+ OPTNAME="$1"
+ shift; set reparse "$OPTNAME$@"
+ ;;
+#
+# Among standard options, '-Tdev' is treated as a special case.
+# '-Tps' is automatically enforced, so if specified, is silently ignored.
+#
+ -Tps) ;;
+#
+# No other '-Tdev' option is permitted.
+#
+ -T*) echo >&2 "$CMD: option '$1' is incompatible with PDF output"
+ exit 1
+ ;;
+#
+# '-h' and '-v' options redirect to their equivalent long forms ...
+#
+ -h*) set redirect --help
+ ;;
+#
+ -v*) shift; set redirect --version "$@"
+ ;;
+#
+# All other standard options are simply passed through to 'groff',
+# with no validation beforehand.
+#
+ -*) GROFF_STYLE="$GROFF_STYLE \"$1\""
+ ;;
+#
+# All non-option arguments are considered as possible input file names,
+# and are passed on to 'groff', unaltered.
+#
+ *) INPUT_FILES="$INPUT_FILES \"$1\""
+ ;;
+ esac
+ shift
+ done
+#
+# If the '-v' or '--version' option was specified,
+# then we simply emulate the behaviour of 'groff', with this option,
+# and quit.
+#
+ if test -n "$SHOW_VERSION"
+ then
+ echo >&2 "$SHOW_VERSION"
+ echo >&2; eval $GROFF_STYLE $INPUT_FILES
+ exit $?
+ fi
+#
+# Establish how to invoke 'echo', suppressing the terminating newline.
+# (Adapted from 'autoconf' code, as found in 'configure' scripts).
+#
+ case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,*-n*) n='' c='' ;;
+ *c*) n='-n' c='' ;;
+ *) n='' c='\c' ;;
+ esac
+#
+# If STDIN is specified among the input files,
+# or if no input files are specified, then we need to capture STDIN,
+# so we can replay it into each 'groff' processing pass.
+#
+ test -z "$INPUT_FILES" && STREAM="$CAT ${GROFF_TMPDIR}/pdf$$.in |"
+ test -n "$STREAM" && $CAT > ${GROFF_TMPDIR}/pdf$$.in
+#
+# Unless reference resolution is explicitly suppressed,
+# we initiate it by touching the cross reference dictionary file,
+# and initialise the comparator, to kickstart the reference resolver loop.
+#
+ SAY=":"
+ if test -z "$DIFF"
+ then
+ >> $REFFILE
+ echo kickstart > $REFCOPY
+ test x${SHOW_PROGRESS+"set"} = x"set" && SAY=echo
+#
+# In order to correctly resolve 'pdfmark' references,
+# we need to have both the 'awk' and 'diff' programs available.
+#
+ NO=''
+ if test -n "$GROFF_AWK_INTERPRETER"
+ then
+ AWK="$GROFF_AWK_INTERPRETER"
+ test -f "$AWK" && test -x "$AWK" || AWK=":"
+ else
+ for prog in @GROFF_AWK_INTERPRETERS@
+ do
+ AWK=`searchpath $prog "$PATH"`
+ test "$AWK" = ":" || break
+ done
+ fi
+ DIFF=`searchpath diff "$PATH"`
+ test "$AWK" = ":" && echo >&2 "$NOPROG 'awk' in PATH" && NO="$NO 'awk'"
+ test "$DIFF" = ":" && echo >&2 "$NOPROG 'diff' in PATH" && NO="$NO 'diff'"
+ if test -n "$NO"
+ then
+ set $NO
+ SAY=":" AWK=":" DIFF=":"
+ test $# -gt 1 && NO="s $1 and $2 are" || NO=" $1 is"
+ $CAT >&2 <<-ETX
+
+ *** WARNING ***
+
+ The program$NO required, but cannot be found;
+ consequently, '$CMD' is unable to resolve 'pdfmark' references.
+
+ Document processing will continue, but no 'pdfmark' reference dictionary
+ will be compiled; if any 'pdfmark' reference appears in the resulting PDF
+ document, the formatting may not be correct.
+
+ ETX
+ fi
+ fi
+#
+# Run the multi-pass 'pdfmark' reference resolver loop ...
+#
+ $SAY >&2 $n Resolving references ..$c
+ until $DIFF $REFCOPY $REFFILE 1>$NULLDEV 2>&1
+ do
+#
+# until all references are resolved, to yield consistent values
+# in each of two consecutive passes, or until it seems that no consistent
+# resolution is achievable.
+#
+ $SAY >&2 $n .$c
+ PASS_INDICATOR="${PASS_INDICATOR}."
+ if test "$PASS_INDICATOR" = "...."
+ then
+#
+# More than three passes required indicates a probable inconsistency
+# in the source document; diagnose, and bail out.
+#
+ $SAY >&2 " failed"
+ $CAT >&2 <<-ETX
+ $CMD: unable to resolve references consistently after three passes
+ $CMD: the source document may exhibit instability about the reference(s) ...
+ ETX
+#
+# Report the unresolved references, as a diff between the two pass files,
+# preferring 'unified' or 'context' diffs, when available
+#
+ DIFFOPT=''
+ $DIFF -c0 $NULLDEV $NULLDEV 1>$NULLDEV 2>&1 && DIFFOPT='-c0'
+ $DIFF -u0 $NULLDEV $NULLDEV 1>$NULLDEV 2>&1 && DIFFOPT='-u0'
+ $DIFF >&2 $DIFFOPT $REFCOPY $REFFILE
+ exit 1
+ fi
+#
+# Replace the comparison file copy from any previous pass,
+# with the most recently updated copy of the reference dictionary.
+# (Some versions of 'mv' may not support overwriting of an existing file,
+# so remove the old comparison file first).
+#
+ rm -f $REFCOPY
+ mv $REFFILE $REFCOPY
+#
+# Run 'groff' and 'awk', to identify reference marks in the document source,
+# filtering them into the reference dictionary; discard incomplete 'groff' output
+# at this stage.
+#
+ eval $STREAM $GROFF_STYLE -Z 1>$NULLDEV 2>$WRKFILE $REFCOPY $INPUT_FILES
+ $AWK '/^gropdf-info:href/ {$1 = ".pdfhref D -N"; print}' $WRKFILE > $REFFILE
+ done
+ $SAY >&2 " done"
+#
+# To get to here ...
+# We MUST have resolved all 'pdfmark' references, such that the content of the
+# updated reference dictionary file EXACTLY matches the last saved copy.
+#
+# If PDF output has been suppressed, then there is nothing more to do.
+#
+ test "$PDF_OUTPUT" = "$NULLDEV" && exit 0
+#
+# We are now ready to start preparing the intermediate PostScript files,
+# from which the PDF output will be compiled -- but before proceeding further ...
+# let's make sure we have a GhostScript interpreter to convert them!
+#
+ if test -n "$GROFF_GHOSTSCRIPT_INTERPRETER"
+ then
+ GS="$GROFF_GHOSTSCRIPT_INTERPRETER"
+ test -f "$GS" && test -x "$GS" || GS=":"
+ else
+ for prog in @GROFF_GHOSTSCRIPT_INTERPRETERS@
+ do
+ GS=`searchpath $prog "$PATH"`
+ test "$GS" = ":" || break
+ done
+ fi
+#
+# If we could not find a GhostScript interpreter, then we can do no more.
+#
+ if test "$GS" = ":"
+ then
+ echo >&2 "$CMD: installation problem: cannot find GhostScript interpreter"
+ $CAT >&2 <<-ETX
+
+ *** FATAL INSTALLATION ERROR ***
+
+ '$CMD' requires a GhostScript interpreter to convert PostScript to PDF.
+ You do not appear to have one installed; thus, '$CMD' cannot continue.
+
+ ETX
+ exit 1
+ fi
+#
+# We now extend the local copy of the reference dictionary file,
+# to create a full 'pdfmark' reference map for the document ...
+#
+ $AWK '/^grohtml-info/ {print ".pdfhref Z", $2, $3, $4}' $WRKFILE >> $REFCOPY
+#
+# ... appending a dummy map reference, to ensure that at least
+# one such is always present; (this is required, to suppress any
+# further intermediate output to stderr during the "press-ready"
+# runs of groff, for PDF output file production).
+#
+ echo ".pdfhref Z 0 0 0" >> $REFCOPY
+#
+# Evaluate any processing options which may have been specified
+# as a result of parsing the document source ...
+#
+ eval `$SED -n '/^ *pdfroff-option:set */s///p' $WRKFILE`
+#
+# ... (which is currently supported to enable "toc-relocation",
+# only when the document actually relies on it, and if it is not
+# explicitly disabled from the command line) ...
+#
+ if test x${toc_relocation-"auto"} != xenabled
+ then
+#
+# ... thus we reproduce the effect of the "--no-toc-relocation"
+# option, when no enabling request is detected in the document
+# control stream.
+#
+ TC_DATA="" TOC_FORMAT="" BODY_FORMAT=""
+ fi
+#
+# Re-enable progress reporting, if necessary ...
+# (Missing 'awk' or 'diff' may have disabled it, to avoid display
+# of spurious messages associated with reference resolution).
+#
+ test x${SHOW_PROGRESS+"set"} = x"set" && SAY=echo
+#
+# If a document cover style sheet is specified ...
+# then we run a special formatting pass, to create a cover section file.
+#
+ if test -n "$STYLESHEET"
+ then
+ DOT='^\.[ ]*'
+ CS_MACRO=${CS_MACRO-"CS"} CE_MACRO=${CE_MACRO-"CE"}
+ $SAY >&2 $n "Formatting document ... front cover section ..$c"
+ CS_FILTER="$STREAM $SED -n '/${DOT}${CS_MACRO}/,/${DOT}${CE_MACRO}/p'"
+ eval $CS_FILTER $INPUT_FILES | eval $GROFF_STYLE $STYLESHEET - > $CS_DATA
+ $SAY >&2 ". done"
+ fi
+#
+# If table of contents relocation is to be performed (it is, by default),
+# then we run an extra 'groff' pass, to format a TOC intermediate file.
+#
+ if test -n "$TC_DATA"
+ then
+ $SAY >&2 $n "Formatting document ... table of contents ..$c"
+ eval $STREAM $GROFF_STYLE $TOC_FORMAT $REFCOPY $INPUT_FILES > $TC_DATA
+ $SAY >&2 ". done"
+ fi
+#
+# In all cases, a final 'groff' pass is required, to format the document body.
+#
+ $SAY >&2 $n "Formatting document ... body section ..$c"
+ eval $STREAM $GROFF_STYLE $BODY_FORMAT $REFCOPY $INPUT_FILES > $BD_DATA
+ $SAY >&2 ". done"
+#
+# Finally ...
+# Invoke GhostScript as a PDF writer, to bind all of the generated
+# PostScript intermediate files into a single PDF output file.
+#
+ $SAY >&2 $n "Writing PDF output ..$c"
+ if test -z "$PDFROFF_POSTPROCESSOR_COMMAND"
+ then
+ PDFROFF_POSTPROCESSOR_COMMAND="$GS -dQUIET -dBATCH -dNOPAUSE -dSAFER
+ -sDEVICE=pdfwrite -sOutputFile="${PDF_OUTPUT-"-"}
+
+ elif test -n "$PDF_OUTPUT"
+ then
+ exec > $PDF_OUTPUT
+ fi
+#
+# (This 'sed' script is a hack, to eliminate redundant blank pages).
+#
+ ${PDFROFF_COLLATE-"$SED"} ${PDFROFF_KILL_NULL_PAGES-'
+ /%%Page:/{
+ N
+ /%%BeginPageSetup/b again
+ }
+ b
+ :again
+ /%%EndPageSetup/b finish
+ /%%Page:/{
+ N
+ b again
+ }
+ b
+ :finish
+ N
+ /^%%Page:.*\n0 Cg EP$/d
+ '} $TC_DATA $BD_DATA | $PDFROFF_POSTPROCESSOR_COMMAND $CS_DATA -
+ $SAY >&2 ". done"
+#
+# ------------------------------------------------------------------------------
+# $RCSfile$ $Revision$: end of file
diff --git a/contrib/pdfmark/sanitize.tmac b/contrib/pdfmark/sanitize.tmac
new file mode 100644
index 0000000..49feaa9
--- /dev/null
+++ b/contrib/pdfmark/sanitize.tmac
@@ -0,0 +1,170 @@
+.ig
+
+sanitize.tmac
+
+Copyright (C) 2021 Free Software Foundation, Inc.
+ Written by Keith Marshall (keith.d.marshall@ntlworld.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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+..
+.eo
+.de sanitize
+.\" Usage: .sanitize name text ...
+.\"
+.\" Remove designated formatting escape sequences from "text ..."; return
+.\" the sanitized text in a string register, identified by "name".
+.\"
+.\" Begin by initializing the named result as an empty string, bind it to
+.\" an internal reference name, and discard the "name" argument, to leave
+.\" only the text which is to be sanitized, as residual arguments.
+.\"
+. ds \$1
+. als sanitize:result \$1
+. shift
+.
+.\" Initialize a working string register, which we will cyclically reduce
+.\" until it becomes empty, after starting with all of the text passed as
+.\" the residual arguments, and establish its initial length.
+.\"
+. ds sanitize:residual "\$*\"
+. length sanitize:residual.length "\$*\"
+.
+.\" Begin the cyclic reduction loop...
+.\"
+. while \n[sanitize:residual.length] \{\
+. \"
+. \" ...assuming, at the start of each cycle, that the next character
+. \" will not be skipped, and that it will be moved from the residual,
+. \" to the result, as the character-by-character scan proceeds.
+. \"
+. nr sanitize:skip.count 0
+. sanitize:scan.execute
+.
+. \" For each character scanned, we need to check if it matches the
+. \" normal escape character; the check is most readily performed, if
+. \" an alternative escape character is introduced, and when a match
+. \" is found, we prepare to skip an escape sequence.
+. \"
+. ec !
+. if '!*[sanitize:scan.char]'\' .nr sanitize:skip.count 1
+. ec
+. ie \n[sanitize:skip.count] \{\
+. \"
+. \" When a possible escape sequence has been detected, we back it
+. \" up, (in case it isn't recognized, and we need to reinstate its
+. \" content into the result string), then scan ahead to check for
+. \" an identifiable escape sequence...
+. \"
+. rn sanitize:scan.char sanitize:hold
+. sanitize:scan.execute
+. ie d sanitize:esc-\*[sanitize:scan.char] \
+. \"
+. \" ...which we delegate to its appropriate handler, to skip...
+. \"
+. sanitize:esc-\*[sanitize:scan.char]
+.
+. \" ...but, in the case of an unrecognized escape sequence, we copy
+. \" its backed-up content, followed by the character retrieved from
+. \" the current scan cycle, to the result string.
+. \"
+. el .as sanitize:result "\*[sanitize:hold]\*[sanitize:scan.char]\"
+. \}
+.
+. \" When the current scan cycle has retrieved a character, which isn't
+. \" part of any possible escape sequence, we simply copy that character
+. \" to the result string.
+. \"
+. el .as sanitize:result "\*[sanitize:scan.char]\"
+. \}
+.
+.\" Clean up the register space, by deleting all of the string registers,
+.\" and numeric registers, which are designated as temporary, for private
+.\" use within this macro only.
+.\"
+. rm sanitize:hold sanitize:scan.char sanitize:residual sanitize:result
+. rr sanitize:residual.length sanitize:skip.count
+..
+.de sanitize:scan.execute
+.\" Usage (internal): .sanitize:scan.execute
+.\"
+.\" Perform a single-character reduction of sanitize:residual, by copying
+.\" its initial character to sanitize:scan.char, and then deleting it from
+.\" sanitize:residual itself. (Note that we use arithmetic decrementation
+.\" of sanitize:residual.length, rather than repeating the length request
+.\" on sanitize:residual, because reduction WILL fail when there is only
+.\" one character remaining).
+.\"
+. nr sanitize:residual.length -1
+. ds sanitize:scan.char "\*[sanitize:residual]\"
+. substring sanitize:scan.char 0 0
+. substring sanitize:residual 1
+..
+.de sanitize:skip-(
+.\" Usage (internal): .sanitize:skip-(
+.\"
+.\" For any identified escape sequence, with a two-character property name,
+.\" simply skip over the next two characters in the residual string.
+.\"
+. nr sanitize:residual.length -2
+. substring sanitize:residual 2
+..
+.de sanitize:skip-[
+.\" Usage (internal): .sanitize:skip-[
+.\"
+.\" For any identified escape sequence, with an arbitrary-length property
+.\" name, skip following characters in the residual string, until we find
+.\" a terminal "]" character, or we exhaust the residual.
+.\"
+. while \n[sanitize:skip.count] \{\
+. sanitize:scan.execute
+. ie \n[sanitize:residual.length] \{\
+. \" We haven't yet exhausted the residual; if we find a nested "["
+. \" character, increment the nesting level, otherwise decrement it
+. \" for each "]"; it will become zero at the terminal "]".
+. \"
+. ie '\*[sanitize:scan.char]'[' .nr sanitize:skip.count +1
+. el .if '\*[sanitize:scan.char]']' .nr sanitize:skip.count -1
+. \}
+. \" Stop unconditionally, if we do exhaust the residual.
+. \"
+. el .nr sanitize:skip.count 0
+. \}
+..
+.de sanitize:esc-generic
+.\" Usage: .sanitize:esc-X
+.\"
+.\" (X represents any legitimate single-character escape sequence id).
+.\"
+.\" Handler for skipping "\X" sequences, in text which is to be sanitized;
+.\" this will automatically detect sequences conforming to any of the forms
+.\" "\Xc", "\X(cc", or "\X[...]", and will handle each appropriately. The
+.\" implementation is generic, and may be aliased to handle any specific
+.\" escape sequences, which exhibit similar semantics.
+.\"
+. sanitize:scan.execute
+. if d sanitize:skip-\*[sanitize:scan.char] \
+. sanitize:skip-\*[sanitize:scan.char]
+..
+.ec
+.\" Map the generic handler to specific escape sequences, as required.
+.\"
+.als sanitize:esc-F sanitize:esc-generic
+.\" Local Variables:
+.\" mode: nroff
+.\" End:
+.\" vim: filetype=groff:
+.\" sanitize.tmac: end of file
diff --git a/contrib/pdfmark/spdf.tmac b/contrib/pdfmark/spdf.tmac
new file mode 100644
index 0000000..130d8bd
--- /dev/null
+++ b/contrib/pdfmark/spdf.tmac
@@ -0,0 +1,328 @@
+.ig
+
+spdf.tmac
+
+Binding macros for use of "-m pdfmark" in conjunction with "-ms".
+
+
+Copyright (C) 2004-2021 Free Software Foundation, Inc.
+ Written by Keith Marshall (keith.d.marshall@ntlworld.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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+..
+.\" Bindings
+.\" ========
+.\"
+.\" Generic output mode control flag; pdfmark.tmac will bind this to
+.\" its own internal PDFOPMODE flag.
+.\"
+.if !r OPMODE .nr OPMODE 1
+.\"
+.mso s.tmac
+.mso sanitize.tmac
+.mso pdfmark.tmac
+.
+.\" Establish a handler to clean up output context, at end of document.
+.\"
+.de pdf@exit em
+. if \\n[OPMODE] .pdfsync
+. pg@end-text
+.em pdf@exit
+.
+.
+.\" Omitted Sections
+.\" ================
+.\"
+.\" Define section markers, for special document sections,
+.\" which are to be omitted from regular document processing.
+.\"
+.\" .OMIT <name1> <name2>
+.\"
+.\" Defines a pair of macros, <name1> and <name2>, such that execution
+.\" of .<name1> marks the start of a block of troff input which should
+.\" be ignored; this block ends, on execution of .<name2>
+.\"
+.de OMIT OMIT
+. de \\$1
+. omit@begin \\$1 \\$2
+. .
+. de \\$2
+. omit@end \\$1 \\$2
+. .
+.\" Definition of the OMIT macro itself, ends when it is first used,
+.\" to identify an omitted section marker macro pair.
+.\"
+.OMIT CS CE \" front cover text, processed independently
+.OMIT MS ME \" menu definitions, for info documents only
+.
+.\" Actual omission is initiated by recording the name of the block
+.\" start macro, followed by injection of an "ig" request...
+.\"
+.de omit@begin
+. ds omit@section \\$1
+\. ig \\$2
+..
+.\" ...and terminates with verification that the end macro matches
+.\" the start macro, and removal of the start macro record; (error
+.\" reporting uses the "@error" macro, from s.tmac).
+.\"
+.de omit@end
+. if !'\\*[omit@section]'\\$1' .@error \\$2 without \\$1
+. rm omit@section
+..
+.
+.\" Document Outlines, and Section Headings
+.\" =======================================
+.\"
+.\" .XH [-N <name>] [-S] [-X] <outline-level> <heading-text> ...
+.\" .XN [-N <name>] [-S] [-X] <heading-text> ...
+.\"
+.\" Use after SH, and XN <n> respectively, to define text to be set
+.\" within the section heading, as a PDF document ouline entry, and
+.\" optionally, as a table of contents entry.
+.\"
+.\" Options:
+.\" -N <name> Assigns <name> as a pdfhref destination,
+.\" and associates it with the heading.
+.\"
+.\" -S Strip troff font-change escapes from the
+.\" text copied to the document outline.
+.\"
+.\" -X Force pdfhref destination assignment; if
+.\" -N <name> is unspecified, use first word
+.\" of <heading-text> as <name>.
+.\"
+.\" Arguments:
+.\" <outline-level> The nesting level of the heading, within
+.\" the document outline, and TOC. Required
+.\" for XH; inferred from NH <n>, for XN.
+.\"
+.\" <heading-text> Text (required) to appear within each of
+.\" the section heading, document outline,
+.\" and (optionally) TOC.
+.\"
+.\" Hooks:
+.\" XH-INIT User-defined macro, called on entry to XH;
+.\" used to specify initialization state which
+.\" may be needed after using SH; e.g. specify
+.\" a PDFHREF.INFO state without incorporation
+.\" of any "section" references.
+.\"
+.\" XN-INIT User-defined macro, called on entry to XN;
+.\" used to specify initialization state which
+.\" may be needed after using NH; e.g. specify
+.\" a PDFHREF.INFO state which may incorporate
+.\" "section" references.
+.\"
+.\" XH-UPDATE-TOC User-defined macro, called by both XH, and
+.\" XN; (there is no XN-UPDATE-TOC). Must be
+.\" defined, if a TOC entry is to be generated
+.\" by either XH, or XN; the format of such a
+.\" TOC entry is determined by the definition
+.\" of this macro.
+.\"
+.\" Our replacements for both XH, and XN macros share a common entry
+.\" point; we map both to their respective replacement hooks, so that
+.\" we may continue to take advantage of setup logic in s.tmac. When
+.\" these are eventually invoked, they will have been renamed so that
+.\" they replace XH, and XH respectively.
+.\"
+.de XH-REPLACEMENT als
+.als XN-REPLACEMENT XH-REPLACEMENT
+.\" FIXME: within s.tmac, the heading level established by the most
+.\" recent prior invocation of the NH macro is tracked by the "nh*hl"
+.\" private register; perhaps s.tmac could expose this more publicly,
+.\" as by this ostensibly read-only alias, since we need it to keep
+.\" PDF document outlines in synchronization with NH level...
+.\"
+.\" .aln .NH nh*hl
+.\"
+.\" ...but maybe a local "belt and braces" approach is better anyway,
+.\" to insulate "nh*hl" from possible abuse of our ".NH" register, by
+.\" any users who may be determined to shoot themselves in the foot!
+.\"
+.ie r nh*hl .nr spdf:nh*hl \n[nh*hl]
+.el .nr spdf:nh*hl 0
+.am @NH
+. nr spdf:nh*hl \\n[nh*hl]
+..
+.aln .NH spdf:nh*hl
+.
+.\" The common entry point for both XH, and XN, handles initialization,
+.\" and interpretation of any specified options, before handing over to
+.\" one of two distinct formatting helper macros, which are specific to
+.\" the XH, and XN implementations respectively.
+.\"
+.am XH-REPLACEMENT \" thus serving as implementation for both XH and XN
+.\"
+.\" The user is expected to furnish the XH-INIT, XH-UPDATE-TOC, and
+.\" XN-INIT handlers. (Note that the XH-UPDATE-TOC hook serves both
+.\" XH and XN; there is no separate XN-UPDATE-TOC). A suitable stub
+.\" for each is provided by s.tmac; we have no need to replace them.
+.\"
+. \\$0-INIT
+. rm spdf:refname
+. als spdf:bm.define spdf:bm.basic
+. while d spdf:XH\\$1 \{\
+. spdf:XH\\$1 \\$*
+. shift \\n[spdf:argc]
+. \}
+. rr spdf:argc
+. if '\\$1'--' .shift
+. spdf:\\$0.format \\$@
+..
+.\" Interpret the "-N <name>" option...
+.\"
+.de spdf:XH-N
+. ds spdf:refname \\$2
+. nr spdf:argc 2
+..
+.\" ...the "-X" option, and...
+.\"
+.de spdf:XH-X
+. if !d spdf:refname .ds spdf:refname \\\\$1
+. nr spdf:argc 1
+..
+.\" ...the "-S" option.
+.\"
+.de spdf:XH-S
+. als spdf:bm.define sanitize
+. nr spdf:argc 1
+..
+.\" By default, when the "-S" option is not specified, the text
+.\" incorporated into the PDF document outline will be a simple
+.\" verbatim copy of the arguments.
+.\"
+.de spdf:bm.basic
+. shift \" ignore \$1; it should always be "spdf:bm.text"
+. ds spdf:bm.text "\\$*\"
+..
+.\" After initialization, and interpretation of options, the XH
+.\" and XN implementations diverge, into this helper macro, which
+.\" is specific to the XH implementation...
+.\"
+.de spdf:XH.format
+. XH-UPDATE-TOC \\$@
+. ds spdf:bm.argv \\$1
+. shift \" finalization doesn't want the outline level in \$1
+. spdf:XH.finalize \\$@
+..
+.\" ...and this, which is specific to XN...
+.\"
+.de spdf:XN.format
+. ds spdf:bm.argv \\n[.NH] \\*[SN]
+. XH-UPDATE-TOC \\n[.NH] \\*[SN] \\$@
+. spdf:XH.finalize \\$@
+..
+.\" ...before ultimately converging back into this finalization
+.\" macro, which is once again common to both XH and XN.
+.\"
+.de spdf:XH.finalize
+. spdf:bm.define spdf:bm.text "\\$*"
+. if d spdf:refname .pdfhref M -X -N \\*[spdf:refname] -- \\$@
+. pdfhref O \\*[spdf:bm.argv] \\*[spdf:bm.text]
+. rm spdf:refname spdf:bm.argv spdf:bm.text
+. nop \\$*
+..
+.
+.\" Cross-Reference Marshalling
+.\" ===========================
+.\"
+.\" s.tmac provides the "pg@bottom" macro, which has already
+.\" been installed as a page transition trap. To ensure proper
+.\" mapping of "pdfhref" links which overflow the bottom of any
+.\" page, we need to install the "pdfhref" page transition hook,
+.\" as an addendum to this macro.
+.
+.pdfhref I -PT pg@bottom
+.
+.
+.\" Phased Output Control
+.\" =====================
+.\"
+.\" Segregate output of table of contents, and document body text,
+.\" into two distinct output phases, to facilitate assembly of the
+.\" aggregate document in the correct order, particularly when the
+.\" TOC is generated at the end, by the default "ms" mechanism.
+.\"
+.nr PDF-TOC-ONLY 1
+.nr PDF-BODY-TEXT 2
+.\"
+.\" .OP [<output-phase>]
+.\"
+.\" If the user-specified PHASE numeric register has been defined,
+.\" and its value matches the <output-phase> argument value, (or if
+.\" no <output-phase> argument is specified), then set the OPMODE
+.\" control flag to one, and activate groff's "pen-down" mode.
+.\"
+.\" Otherwise, if <output-phase> is specified, but does NOT match
+.\" PHASE, set OPMODE to zero, and select "pen-up" mode.
+.\"
+.\" Alternatively, if PHASE has not been defined, unconditionally
+.\" set OPMODE to one, and leave groff's pen state unchanged.
+.\"
+.de OP
+.ie r PHASE \{\
+. ie \\n(.$ \{\
+. nr op:request 0
+. while \\n(.$ \{\
+. if \\$1=\\n[PHASE] .nr op:request 1
+. shift
+. \}
+. \}
+. el .nr op:request 1
+. if !\\n[op:request]=\\n[OPMODE] \{\
+. nr OPMODE \\n[op:request]
+. nop \O[\\n[OPMODE]]\c
+. \}
+. \}
+.el .nr OPMODE 1
+..
+.
+.\" Table of Contents Generation
+.\" ============================
+.\"
+.\" .TC [no]
+.\"
+.\" Replaces (and emulates) the TC macro, from s.tmac, to ensure
+.\" that the pdfmark document outline cache is flushed, before TOC
+.\" generation commences, that an outline reference is added for the
+.\" TOC itself, and that pdfroff TOC relocation mode is enabled, for
+.\" the TOC output phase of document production.
+.\"
+.de TC
+. pdfsync O
+. P1
+. OP \n[PDF-TOC-ONLY]
+. pg@begin 1 i
+. if !\\n[PHASE] .tm pdfroff-option:set toc_relocation=enabled
+. if \\n[OPMODE] \{\
+. pdfhref O -T T 1 "\\*[TOC]"
+. pdfsync O
+. \}
+. PX \\$1
+..
+.
+.\" Initialize the default output state, for production of "body-text".
+.\"
+.OP \n[PDF-BODY-TEXT]
+.
+.\" Local Variables:
+.\" mode: nroff
+.\" End:
+.\" vim: filetype=groff:
+.\" spdf.tmac: end of file