From fe455f232653cc0752a0c1ae3724a6841f696f74 Mon Sep 17 00:00:00 2001 From: Werner LEMBERG Date: Mon, 28 Feb 2005 13:56:45 +0000 Subject: [PATCH] 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. --- contrib/pdfmark/ChangeLog | 26 +++ contrib/pdfmark/Makefile.sub | 120 +++++++++- contrib/pdfmark/TODO | 17 ++ contrib/pdfmark/pdfmark.tmac | 372 +++++++++++++++++------------- contrib/pdfmark/pdfroff.man | 522 ++++++++++++++++++++++++++++++++++++++++++ contrib/pdfmark/pdfroff.sh | 526 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 1414 insertions(+), 169 deletions(-) rewrite contrib/pdfmark/Makefile.sub (97%) create mode 100644 contrib/pdfmark/pdfroff.man create mode 100644 contrib/pdfmark/pdfroff.sh diff --git a/contrib/pdfmark/ChangeLog b/contrib/pdfmark/ChangeLog index 07c10f70..4f8dd4fa 100644 --- a/contrib/pdfmark/ChangeLog +++ b/contrib/pdfmark/ChangeLog @@ -1,3 +1,29 @@ +2005-02-28 Keith Marshall + + 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 * TODO: Updated. diff --git a/contrib/pdfmark/Makefile.sub b/contrib/pdfmark/Makefile.sub dissimilarity index 97% index 3f7212a3..62f9cfe8 100644 --- a/contrib/pdfmark/Makefile.sub +++ b/contrib/pdfmark/Makefile.sub @@ -1,10 +1,110 @@ -all: prepare_examples - -prepare_examples: - if test ! -f gnu.eps; then \ - if test -f $(top_srcdir)/doc/gnu.eps; then \ - cp $(top_srcdir)/doc/gnu.eps . ; \ - else \ - cp $(top_builddir)/doc/gnu.eps . ; \ - fi ; \ - fi +# Copyright (C) 2005, 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 2, or (at your option) any later +# version. +# +# groff is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with groff; see the file COPYING. If not, write to the Free Software +# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +MAN1=\ + pdfroff.n + +CMDFILES=\ + pdfroff + +TMACFILES=\ + pdfmark.tmac \ + spdf.tmac + +PDFDOCFILES=\ + pdfmark.pdf + +CLEANADD=\ + gnu.eps \ + $(PDFDOCFILES) \ + $(CMDFILES) + +GROFF_BIN_DIR=$(top_builddir)/src/roff/groff +GROFF_OTHER_BIN_DIRS=\ + $(top_builddir)/src/roff/troff \ + $(top_builddir)/src/devices/grops +GROFF_BIN_DIRS=$(GROFF_BIN_DIR) $(GROFF_OTHER_BIN_DIRS) +GROFF_BIN_PATH=`echo $(GROFF_BIN_DIRS) | sed -e 's| *|$(SH_SEP)|g'` + +FFLAG=-F$(top_builddir)/font -F$(top_srcdir)/font +MFLAG=-M$(srcdir) -M$(top_builddir)/tmac -M$(top_srcdir)/tmac +PFLAG=-dpaper=$(PAGE) -P-p$(PAGE) + +PDFROFF=\ + export GROFF_COMMAND_PREFIX; GROFF_COMMAND_PREFIX=''; \ + export GROFF_BIN_DIR; GROFF_BIN_DIR=$(GROFF_BIN_DIR); \ + export GROFF_BIN_PATH; GROFF_BIN_PATH=$(GROFF_BIN_PATH); \ + ./pdfroff $(FFLAG) $(MFLAG) $(PFLAG) + +.SUFFIXES: .ms .pdf +.ms.pdf: + $(RM) $@ + $(PDFROFF) -mspdf --style=$(srcdir)/cover.ms $< >$@ + +all: pdfroff $(make_pdfdoc) + +pdfdoc: gnu.eps $(PDFDOCFILES) + +gnu.eps: + if test -f $(top_srcdir)/doc/gnu.eps; then \ + cp $(top_srcdir)/doc/gnu.eps . ; \ + elif test -f $(top_builddir)/doc/gnu.eps; then \ + cp $(top_builddir)/doc/gnu.eps . ; \ + else \ + xpmtoppm $(top_srcdir)/doc/gnu.xpm | pnmdepth 15 | \ + $(pnmtops_nosetpage) -noturn -rle >$@ ; \ + fi + +pdfroff: pdfroff.sh + $(RM) $@ + sed -e "s|@VERSION@|$(version)$(revision)|" \ + -e "s|@GROFF_AWK_INTERPRETERS@|$(ALT_AWK_PROGS)|" \ + -e "s|@GROFF_GHOSTSCRIPT_INTERPRETERS@|$(ALT_GHOSTSCRIPT_PROGS)|" \ + -e "s|@GROFF_BIN_DIR@|$(bindir)|" $^ >$@ + chmod +x $@ + +install_data: $(make_install_pdfdoc) + -test -d $(bindir) || $(mkinstalldirs) $(bindir) + for f in $(CMDFILES); do \ + $(RM) $(bindir)/$$f; \ + $(INSTALL_DATA) $$f $(bindir)/$$f; \ + done + -test -d $(tmacdir) || $(mkinstalldirs) $(tmacdir) + for f in $(TMACFILES); do \ + $(RM) $(tmacdir)/$$f; \ + $(INSTALL_DATA) $(srcdir)/$$f $(tmacdir)/$$f; \ + done + +install_pdfdoc: + -test -d $(pdfdocdir) || $(mkinstalldirs) $(pdfdocdir) + for f in $(PDFDOCFILES); do \ + $(RM) $(pdfdocdir)/$$f; \ + $(INSTALL_DATA) $$f $(pdfdocdir)/$$f; \ + done + +uninstall_sub: + for f in $(CMDFILES); do \ + $(RM) $(bindir)/$$f; \ + done + for f in $(TMACFILES); do \ + $(RM) $(tmacdir)/$$f; \ + done + for f in $(PDFDOCFILES); do \ + $(RM) $(pdfdocdir)/$$f; \ + done diff --git a/contrib/pdfmark/TODO b/contrib/pdfmark/TODO index 8bd11e16..a63b14f9 100644 --- a/contrib/pdfmark/TODO +++ b/contrib/pdfmark/TODO @@ -23,14 +23,31 @@ recent changes. Make Makefile generic, so 'configure' can resolve target system dependencies. +* Comment added 2005-02-26 by Keith Marshall + +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 + +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 + +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/pdfmark.tmac b/contrib/pdfmark/pdfmark.tmac index 263d7e98..84f400cc 100644 --- a/contrib/pdfmark/pdfmark.tmac +++ b/contrib/pdfmark/pdfmark.tmac @@ -455,17 +455,23 @@ inspiration has come from discussion on the groff mailing list .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 glyphs, -.\" over which the hot spot will extend, while "PDFHREF.HEIGHT" sets -.\" the hot spot height, PER LINE of text occupied by the reference. -.\" -.\" 2.5 points is 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 2.5p +.\" "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 @@ -529,15 +535,13 @@ inspiration has come from discussion on the groff mailing list . nr pdf:href-X 0 . \" . \" Handle the case where subcommand is specified as "-class", -. \" setting up appropriate macro aliases for subcommand handlers, -. \" and adjusting "pdf:href.ok" to indicate where a reference -. \" file list is required +. \" 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 and "pdf:href.ok" setup +. \" Repeat macro alias setup . \" for the case where the subcommand is specified as "class", . \" (without a leading hyphen) . \" @@ -590,10 +594,14 @@ inspiration has come from discussion on the groff mailing list .\" 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 .. @@ -715,6 +723,8 @@ inspiration has come from discussion on the groff mailing list .. .\" .de pdf*href.set +.\" ---------------------------------------------------------------------- +.\" ---------------------------------------------------------------------- .pdf*href.map.init .ie \\n(.$ \{\ . \" @@ -760,6 +770,41 @@ inspiration has come from discussion on the groff mailing list .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 @@ -848,23 +893,29 @@ inspiration has come from discussion on the groff mailing list .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] .. @@ -1042,6 +1093,8 @@ inspiration has come from discussion on the groff mailing list .nop \&\\*[pdf:href-A] .. .de pdf*href.map.init +.\" ---------------------------------------------------------------------- +.\" ---------------------------------------------------------------------- .\" .if dpdf:href.map-1 \{\ . \" @@ -1056,6 +1109,32 @@ inspiration has come from discussion on the groff mailing list . \} .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): @@ -1092,118 +1171,65 @@ inspiration has come from discussion on the groff mailing list .\" .rr pdf:null .. -.\" -.\" The "pdf*href.mark" macro is called internally, by "pdf*href", to -.\" mark the start and end co-ordinates of the "link text" bounding box. -.\" These are then used as the basis for computing the bounding box(es) -.\" for the associated link "hot-spot". -.\" -.de pdf*href.mark(unused) +.de pdf*href.mark.begin .\" ---------------------------------------------------------------------- -.\" Usage: (internal use only): -.\" .pdf*href.mark 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" -.\" -.\" Note that this requires two pass processing in "groff" ... -.\" In pass 1, "pdf:href.map" is undefined; in pass 2, we source the -.\" filtered output from pass 1, which defines it, (in terms of a series -.\" of indexed sub-maps: "pdf:href.map-1" .. "pdf:href.map-N"). -.\" .pdf*href.map.init -.ie !dpdf:href.map \{\ -. \" -. \" In the first pass, we use the "grohtml" hook, to emit bounding -. \" box co-ordinates to "stderr"; (note that we use a zero width -. \" marker character, to obtain useful output -- we don't care that -. \" these may be visible, since this is effectively a "dummy run" -. \" through the formatter, and its PostScript output will be -. \" discarded). -. \" -. nop \O1|\h'-\w"|"u'\O2\c -. \} -.el \{\ +.ie dpdf:href.map \{\ . \" -. \" In the second pass, we harvest the bounding box co-ordinates, -. \" which we read back from the reprocessed "stderr" output from -. \" the first pass, and assign them to specified registers. -. \" First however, we will create an internal reference to the -. \" "pdf:href.map"; we will read co-ordinates via this internal -. \" reference, to ensure the "pdf:href.map" is not deleted from -. \" the string namespace, when its data is exhausted. +. \" 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.map.read \\$@ -. \} -.. -.de pdf*href.mark.begin -.pdf*href.map.init -.ie dpdf:href.map \{\ . pdf*href.mark.resolve \\$@ . rn pdf*href.mark.resolve pdf*href.mark.begin -. als pdf*href.mark.end pdf*href.mark.close +. 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 -. pdf*href.map.read spg llx ury epg +. 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.map.read urx lly -. ie \\n[pdf:ury]=\\n[pdf:lly] \{\ -. \" -. \" This link is entirely contained on a single output line; -. \" we may simply emit the "hot-spot" PDFMARK definition, as -. \" it has already been established. +. pdf*href.mark.emit 1 \\n[pdf:urx.end] +. if \\n[pdf:lly]<\\n[pdf:lly.end] \{\ . \" -. pdf*href.mark.emit 1 -. \} -. el \{\ . \" 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:urx.end \\n[pdf:urx] -. nr pdf:ury.end \\n[pdf:lly]-\\n[PDFHREF.LEADING] -. nr pdf:urx \\n(.o+\\n(.l -. pdf*href.mark.emit 1 -. \" -. \" Now, we adjust the initial "hot-spot" co-ordinates, to -. \" mark the beginning of its second line. -. \" -. nr pdf:llx \\n(.o+\\n[.in] . nr pdf:ury +1v -. if !\\n[pdf:ury.end]=\\n[pdf:ury] \{\ -. \" -. \" This link spans MORE than two lines, so we redefine -. \" its intermediate end point, in order to create a second -. \" "hot-spot", which spans all but the first and last lines -. \" of the "link text". -. \" -. nr pdf:lly \\n[pdf:ury.end]-1v+\\*[PDFHREF.HEIGHT] +. 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] . \} -. \" Finally, we adjust the "hot-spot" bounds once more, to -. \" create a final "hot-spot", which extends from the start of -. \" the last line of the "link text" to the originally computed -. \" "hot-spot" end point. -. \" -. nr pdf:urx \\n[pdf:urx.end] -. nr pdf:ury \\n[pdf:ury.end] -. rr pdf:urx.end pdf:ury.end -. pdf*href.mark.emit 0 +. pdf*href.mark.emit 0 \\n[pdf:urx.end] . \} +. pdf*href.mark.flush . \} . el \{\ . \" This link is split across a page break, so ... @@ -1214,15 +1240,7 @@ inspiration has come from discussion on the groff mailing list . \" First step: define the region from the start of the link, . \" to the end of its first line. . \" -. nr pdf:urx \\n(.o+\\n(.l -. pdf*href.mark.emit 1 -. \" -. \" Save the vertical trim distance, between the current text -. \" base line and the top of the actual "hot-spot" region, so we -. \" can make a similar adjustment at the top of the next page. -. \" -. mk pdf:ury.trim -. nr pdf:ury.trim \\n[pdf:ury]-\\n[pdf:ury.trim] +. pdf*href.mark.emit 1 \\n[pdf:urx] . \" . \" All additional regions MUST align with the left margin. . \" @@ -1248,7 +1266,6 @@ inspiration has come from discussion on the groff mailing list . \" termination handler, to deactivate it when done. . \" . als pdf*href.mark.hook pdf*href.mark.trap -. als pdf*href.mark.end pdf*href.mark.release . \" . \" Now we set up "pdf:epg" to count the number of page breaks . \" which this link will span, and emit the link text, leaving @@ -1263,7 +1280,6 @@ inspiration has come from discussion on the groff mailing list . \" we may discard the remaining map data for this link, . \" and issue a diagnostic. . \" -. pdf*href.map.read null null . pdf:error pdfhref: link dissociated at page break (trap not initialised) . if dPDFHREF.BROKEN.COLOR \{\ . \" @@ -1290,73 +1306,59 @@ inspiration has come from discussion on the groff mailing list .de pdf*href.mark.emit .\" ---------------------------------------------------------------------- .\" Usage: -.\" .pdf*href.mark.emit +.\" .pdf*href.mark.emit [] .\" == 0 --> normal operation -- link height = 1 line .\" == 1 --> start of link -- add leading above text .\" == 2 --> overtall link -- set intermediate baseline .\" == 3 --> split link -- break at bottom of page .\" ---------------------------------------------------------------------- .\" -.if \\$1=1 .nr pdf:ury -\\n[PDFHREF.LEADING] -.if \\$1<2 .nr pdf:lly \\n[pdf:ury]u+\\*[PDFHREF.HEIGHT] +.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 .pdfmark \\*[pdf:href.link] /Rect [\\*[pdf:bbox]] /ANN -.. -.de pdf*href.mark.release -.als pdf*href.mark.end pdf*href.mark.close -.als pdf*href.mark.hook pdf*href.mark.idle -.\" -.\" Before finalising this link, check if its active region -.\" extends beyond the first line of text on its last page. -.\" -.mk pdf:lly -.ie \\n[pdf:lly]>\\n[pdf:ury] \{\ -. \" -. \" When more than one line of link text overflows to a -. \" new page, then we need to compute an extra active region -. \" which will cover all but the last line of link text. -. \" -. nr pdf:lly +\\n[pdf:ury.trim]+\\n(.V-\\n[pdf:ury] -. nr pdf:lly \\n[pdf:lly]/1v*1v-1v+\\*[PDFHREF.HEIGHT]+\\n[pdf:ury] -. pdf*href.mark.emit 2 -. nr pdf:ury \\n[pdf:lly]-\\*[PDFHREF.HEIGHT]+1v -. \" -. \" Now, retrieve the page co-ordinates -. \" for the end of the link text -. \" -. pdf*href.map.read urx lly -. \} .el \{\ -. \" When the link text "overflow" occupies only a portion of -. \" the first line on its final page, then we need to compute -. \" the page co-ordinates for its upper right corner. +. \" Link region size and placement has been fully specified ... +. \" Emit it. . \" -. pdf*href.map.read urx ury -. nr pdf:ury -\\n[PDFHREF.LEADING] +. pdfmark \\*[pdf:href.link] /Rect [\\*[pdf:bbox]] /ANN . \} -.\" Finally, on the last line of the reference, -.\" define the "hot-spot" region to cover the portion of the -.\" link, from start of line to the end of the link text. -.\" -.pdf*href.mark.emit 0 -.pdf*href.mark.flush -.. -.de pdf*href.mark.flush -.rr pdf:spg pdf:llx pdf:lly pdf:urx pdf:ury pdf:ury.trim pdf:epg -.if dPDFHREF.COLOR .als PDFHREF.COLOUR PDFHREF.COLOR -.. -.de pdf*href.mark.close -.ie '\\n(.z'' .pdf*href.mark.flush -.el \!.pdf*href.mark.end -.. -.de pdf*href.mark.end -\O1|\h'-\w"|"u'\O2\c .. .\" .\" When "pdf*href" emits a link for which the "hot-spot" spans a @@ -1390,8 +1392,60 @@ inspiration has come from discussion on the groff mailing list .\" ---------------------------------------------------------------------- .\" .mk pdf:ury -.nr pdf:ury +\\n[pdf:ury.trim] -.if \\n-[pdf:epg] .pdf*href.mark.emit 3 +.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 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|\h'-\w"|"u'\O2\c .. .\" Macro "pdf*href-I" is used for one time initialisation of special .\" "pdfhref" features; (currently, only the above page trap hook is diff --git a/contrib/pdfmark/pdfroff.man b/contrib/pdfmark/pdfroff.man new file mode 100644 index 00000000..ce834f2e --- /dev/null +++ b/contrib/pdfmark/pdfroff.man @@ -0,0 +1,522 @@ +.TH PDFROFF @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +.\" -------------------------------------------------------------------- +.\" Legal Matters +.\" -------------------------------------------------------------------- +.ig +pdfroff.1 + +File position: /contrib/pdfmark/pdfroff.man + +Last update: + +This file is part of groff, the GNU roff type-setting system. + +Copyright (C) 2005 Free Software Foundation, Inc. +written by Keith Marshall + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 or +any later version published by the Free Software Foundation; with no +Front-Cover Texts, no Back-Cover Texts, and the following Invariant +Sections:-- + + a) This "Legal Matters" section, extending from the start of + the document, to the end of the enclosing ".ig" section. + + b) The entire section bearing the heading "AUTHOR", extending + from the ".SH AUTHOR" tag, to the end of the document. + +A copy of the Free Documentation License is included as a file called +FDL in the main directory of the groff source package. +.. +.\" -------------------------------------------------------------------- +. +.SH NAME +pdfroff \- create PDF documents using +.I groff +. +.hw pdfmark +.de Q +\&\\$3\*(lq\\$1\*(rq\\$2 +.. +.de nohy +.hy 0 +\&\\$* +.hy +.. +.\" -------------------------------------------------------------------- +. +.SH SYNOPSIS +.de cmd +. if r@i .in +. nr @i \\n(.i +. in +\w'\f[B]\\$1\0'u +. ti \\n(@iu +. B \\$1\0\c +.. +.de opt +. tr -\- +. RB [ -\\$1\c +. IR \&\\$2 ] +. tr -- +.. +.de opta +. ie \\n(.$>1 .opt \\$1 \0\\$2 +. el .opt \\$1 +.. +.de optx +. tr -\- +. RB [ --no\\$1 \0|\0\c +. B -\\$1\c +. IR \&\\$2 ] +. tr -- +.. +.ad l +.hy 0 +.ll -5 +.cmd pdfroff +.opt abcegilpstzCEGNRSUVXZ +.opta d cs +.opta f fam +.opta F dir +.opta I dir +.opta L arg +.opta m name +.opta M dir +.opta n num +.opta o list +.opta P arg +.opta r cn +.opta T dev +.opta w name +.opta W name +.opt -no-toc-relocation +.opt -stylesheet= name +.optx -pdf-output= name +.optx -reference-dictionary= name +.opt -report-progress +.B file +.I ... +.ll +.sp +.cmd pdfroff +.B -h +| +.B --help +.sp +.cmd pdfroff +.B -v +| +.B --version +.RI [ option +.IR ... ] +.rr @i +.in +.ad +.hy +.P +The command line is parsed in accordance with normal GNU conventions, +but with one exception \(em when 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 unambigous initial substring. +. +.\" -------------------------------------------------------------------- +. +.SH DESCRIPTION +.B pdfroff +is a wrapper program for the GNU text processing system, +.BR groff . +It transparently handles the mechanics of multiple pass +.B groff +processing, when applied to suitably marked up +.B 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 +.Q style\0sheet +capability is provided; +this allows for the definition of content which is required to preceed the +table of contents, in the published document. +.P +For each invocation of +.BR pdfroff , +the ultimate +.B groff +output stream is post\(hyprocessed by the GhostScript interpreter, +to produce a finished PDF document. +.P +.B pdfroff +makes no assumptions about, and imposes no restrictions on, +the use of any +.B 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 +.B pdfmark +macro package, should the user choose to employ it. +Specifically, if the +.I pdfhref +macro, defined in the +.B pdfmark.tmac +package, is used to define public reference marks, +or dynamic links to such reference marks, then +.B pdfroff +will perform as many preformatting +.B 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 +.B pdfroff +usage closely mirrors that of +.B groff +itself. +Indeed, +with the exception of the +.BR \-h , +.BR \-v , +and +.BI \-T \0dev +short form options, and +all long form options, +which are parsed internally by +.BR pdfroff , +all options and file name arguments specified on the command line are +passed on to +.BR groff , +to control the formatting of the PDF document. +Consequently, +.B pdfroff +accepts all options and arguments, as specified in +.BR groff (@MAN1EXT@), +which may also be considered as the definitive reference for all standard +.BR pdfroff +options and argument usage. +. +.\" -------------------------------------------------------------------- +. +.SH OPTIONS +.B pdfroff +accepts all of the short form options +(i.e., those introduced by a single hyphen), +which are available with +.B groff +itself. +In most cases, these are simply passed transparently to +.BR groff ; +the following, however, are handled specially by +.BR 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 +.BR groff , +but, if grouped with other options, it +.I must +be the first in the group. +Hiding it within a group will +break standard input processing, in the multiple pass +.B groff +processing context of +.BR pdfroff . +.TP +.BI \-T \0dev +Only +.BI \-T \0ps +is supported by +.BR pdfroff . +Attempting to specify any other device will cause +.B pdfroff +to abort. +.TP +.B \-v +Same as +.BR \-\-version ; +see below. +.P +See +.BR groff (@MAN1EXT@) +for a description of all other short form options, +which are transparently passed through +.BR pdfroff +to +.BR groff . +.P +All long form options +(i.e., those introduced by a double hyphen) +are interpreted locally by +.BR pdfroff ; +they are +.B not +passed on to +.BR groff , +unless otherwise stated below. +.TP +.B \-\-help +Causes +.B pdfroff +to display a summary of the its usage syntax, and supported options, +and then exit. +.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 +.B 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 will contain no public +references, created by the +.I pdfhref +macro. +.TP +.B \-\-no\-toc\-relocation +May be used to eliminate the extra +.B 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 +.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 +.B 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 +.B 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 +.B pdfroff +to display an informational message on standard error, +at the start of each +.B 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 +.B pdfroff +to display a version identification message. +The entire command line is then passed transparently to +.BR groff , +in a +.I one +pass operation +.IR only , +in order to display the associated +.B groff +version information, before exiting. +. +.\" -------------------------------------------------------------------- +. +.SH ENVIRONMENT +The following environment variables may be set, and exported, +to modify the behaviour of +.BR pdfroff . +.TP +.B GROFF_TMPDIR +Identifies the directory in which +.B pdfroff +should create temporary files. +If +.B GROFF_TMPDIR +is +.I not +specified, then the variables +.BR TMPDIR , +.B TMP +and +.B TEMP +are considered in turn, as possible temporary file repositories. +If none of these are set, then temporary files will be created +in the current directory. +.TP +.B GROFF_GHOSTSCRIPT_INTERPRETER +Specifies the program to be invoked, when +.B pdfroff +converts +.B groff +PostScript output to PDF. +If +.B GROFF_GHOSTSCRIPT_INTERPRETER +is not specified, then +.B pdfroff +will search the process +.BR PATH , +looking for a program with any of the well known names +for the GhostScript interpreter; +if no GhostScript interpreter can be found, +.B pdfroff +will abort. +.TP +.B GROFF_AWK_INTERPRETER +Specifies the program to be invoked, when +.B pdfroff +is extracting reference dictionary entries from a +.B groff +intermediate message stream. +If +.B GROFF_AWK_INTERPRETER +is not specified, then +.B pdfroff +will search the process +.BR PATH , +looking for any of the preferred programs, `gawk', `mawk', `nawk' +and `awk', in this order; +if none of these are found, +.B pdfroff +will issue a warning message, and continue processing; +however, in this case, no reference dictionary will be created. +.TP +.B SHOW_PROGRESS +If this is set to a non-empty value, then +.B pdfroff +will always behave as if the +.B \-\-report\-progress +option is specified, on the command line. +. +.\" -------------------------------------------------------------------- +. +.SH FILES +Input and output files for +.B 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 formatting macro package, e.g., +.IB file .ms +might be an input file for formatting using the +.B ms +macros +.RB ( s.tmac ); +normally, the final output file should be named +.IB file .pdf\c +\&. +.P +Temporary files, created by +.BR pdfroff , +are placed in the directory specified by environment variables (see +section +.BR ENVIRONMENT ), +and named according to the convention +.BI pdf $$ .*\c +\&, where +.I $$ +is the standard shell variable representing the process ID of the +.B pdfroff +process itself, and +.I * +represents any of a number of extensions used by +.B pdfroff +for temporary and intermediate files. +. +.\" -------------------------------------------------------------------- +. +.SH SEE ALSO +See +.BR groff (@MAN1EXT@) +for the definitive reference to document formatting with +.BR groff . +Since +.B pdfroff +provides a superset of all +.B groff +capabilities, +.BR groff (@MAN1EXT@) +may also be considered to be the definitive reference to all +.I standard +capabilities of +.BR pdfroff , +with this document providing the reference to +.BR pdfroff 's +extended features. +.P +While +.B pdfroff +imposes neither any restriction on, nor any requirement for, +the use of any specific +.B groff +macro package, a number of supplied macro packages, +and in particular those associated with the package +.BR pdfmark.tmac , +are best suited for use with +.BR pdfroff +as the preferred formatter. +Detailed documentation on the use of these packages may be found, +in PDF format, in the reference guide +.BR "\*(lqPortable Document Format Publishing with GNU Troff\*(rq" , +included in the installed documentation set as +.hy 0 +.BR @PDFDOCDIR@/pdfmark.pdf . +.hy +. +.\" -------------------------------------------------------------------- +. +.SH AUTHOR +Copyright \(co 2005, Free Software Foundation, Inc. +.LP +This man page is distributed under the terms of the +GNU Free Documentation License (FDL), version 1.1 or later, +and is part of the +.I GNU troff +software package. +It was originally written by Keith Marshall, +.nohy , +who also wrote the implementation of the +.I pdfroff +program, to which it relates. +.LP +You should have received a copy of the FDL as part of the +.I GNU troff +distribution; it is also available on\-line, at the GNU +.Q copyleft +site, +.nohy . +. +.\" -------------------------------------------------------------------- +.\" EOF / vim: ft=groff diff --git a/contrib/pdfmark/pdfroff.sh b/contrib/pdfmark/pdfroff.sh new file mode 100644 index 00000000..1313b7e3 --- /dev/null +++ b/contrib/pdfmark/pdfroff.sh @@ -0,0 +1,526 @@ +#!/bin/sh +# ------------------------------------------------------------------------------ +# +# Function: Format PDF Output from groff Markup +# +# Copyright (C) 2005, 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 2, or (at your option) any later +# version. +# +# groff is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with groff; see the file COPYING. If not, write to the Free Software +# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ------------------------------------------------------------------------------ +# +# 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 || NULDEV="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 +# +# 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=`exec 2>$NULLDEV ; set :\`type cat\` ; eval echo '$'$#` + GREP=`exec 2>$NULLDEV ; set :\`type grep\` ; eval echo '$'$#` + SED=`exec 2>$NULLDEV ; set :\`type sed\` ; eval echo '$'$#` +# +# Another fundamental requirement is the 'groff' program itself; +# we will prefer any version existing in a specified GROFF_BIN_DIR, +# or, if unspecified, the installed location of 'groff' programs; +# (we DO NOT use a PATH search, to locate 'groff'). +# + GBIN=${GROFF_BIN_DIR-"@GROFF_BIN_DIR@"} + GROFF=`exec 2>$NULLDEV ; set :\`type $GBIN/groff\` ; eval echo '$'$#` +# +# 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 $GBIN" && 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 +# +# Set up temporary/intermediate file locations. +# + WRKFILE=${GROFF_TMPDIR=${TMPDIR-${TMP-${TEMP-"."}}}}/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 +# +# Set a trap, to delete temporary files on exit. +# (FIXME: may want to include other signals, in released version). +# + trap "rm -f ${GROFF_TMPDIR}/pdf$$.*" 0 +# +# 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 + " +# 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="" ARGLIST="-Tps" 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 >&2 <<-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. + + --pdf-output=name + Write the PDF output stream to file 'name'; if this option + is unspecified, standard output is used for PDF output. + + --no-pdf-output + Suppress the generation of PDF 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. + + ETX + exit 0 + ;; + + --version) + ARGLIST="$ARGLIST \"$1\"" + SHOW_VERSION="GNU pdfroff (groff) version @VERSION@" + ;; + + --report-progress) + SHOW_PROGRESS=echo + ;; + + --pdf-output) + PDF_OUTPUT="$OPTARG" + ;; + + --no-pdf-output) + PDF_OUTPUT="$NULLDEV" + ;; + + --reference-dictionary) + REFFILE="$OPTARG" + ;; + + --no-reference-dictionary) + DIFF=":" REFFILE="$NULLDEV" REFCOPY="$NULLDEV" + ;; + + --stylesheet) + STYLESHEET="$OPTARG" CS_DATA=${GROFF_TMPDIR}/pdf$$.cs + ;; + + --no-toc-relocation) + TC_DATA="" TOC_FORMAT="" BODY_FORMAT="" + ;; +# +# 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 |" + ARGLIST="$ARGLIST $1" INPUT_FILES="$INPUT_FILES $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 illegal 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. +# + -*) ARGLIST="$ARGLIST \"$1\"" GROFF_STYLE="$GROFF_STYLE \"$1\"" + ;; +# +# All non-option arguments are considered as possible input file names, +# and are passed on to 'groff', unaltered. +# + *) ARGLIST="$ARGLIST \"$1\"" + test -f "$1" && 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 $ARGLIST + 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 "${SHOW_PROGRESS+"set"}" = "set" && SAY=echo +# +# In order to correctly resolve 'pdfmark' references, +# we need to have both the 'awk' and 'diff' programs available. +# + NO='' + set ${GROFF_AWK_INTERPRETER-"@GROFF_AWK_INTERPRETERS@"} + while test $# -gt 0 + do + AWK=`exec 2>$NULLDEV ; set :\`type $1\` ; eval echo '$'$#` + test "$AWK" = ":" || set "$AWK" + shift + done + DIFF=`exec 2>$NULLDEV ; set :\`type diff\` ; eval echo '$'$#` + 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 -Z 1>$NULLDEV 2>$WRKFILE $REFCOPY $ARGLIST + $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 proceding further ... +# let's make sure we have a GhostScript interpreter to convert them! +# + set ${GROFF_GHOSTSCRIPT_INTERPRETER-"@GROFF_GHOSTSCRIPT_INTERPRETERS@"} + while test $# -gt 0 + do + GS=`exec 2>$NULLDEV ; set :\`type $1\` ; eval echo '$'$#` + test "$GS" = ":" || set "$GS" + shift + done +# +# 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. + Since you do not appear to have one installed, '$CMD' connot 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 +# +# 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 "${SHOW_PROGRESS+"set"}" = "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='^\.[ ]*' + $SAY >&2 $n "Formatting document ... front cover section ..$c" + CS_FILTER="$STREAM $SED -n '/$DOT${CS_MACRO-"CS"}/,/$DOT${CE_MACRO-"CE"}/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 $TOC_FORMAT $REFCOPY $ARGLIST > $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 $BODY_FORMAT $REFCOPY $ARGLIST > $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" + PDFWRITE="$GS -dQUIET -dBATCH -dNOPAUSE -sDEVICE=pdfwrite" +# +# (This 'sed' script is a hack, to eliminate redundant blank pages). +# + $SED ' + :again + /%%EndPageSetup/b finish + /%%Page:/{ + N + b again + } + b + :finish + N + /^%%Page:.*0 *Cg *EP/d + ' $TC_DATA $BD_DATA | $PDFWRITE -sOutputFile=${PDF_OUTPUT-"-"} $CS_DATA - + $SAY >&2 ". done" +# +# ------------------------------------------------------------------------------ +# $Source: end of file -- 2.11.4.GIT