9e19327db0fe62310cd70a8efb3f0de639019427
[platform/upstream/groff.git] / contrib / pdfmark / pdfroff.sh
1 #! /bin/sh
2 # ------------------------------------------------------------------------------
3 #
4 # Function: Format PDF Output from groff Markup
5 #
6 # Copyright (C) 2005-2014  Free Software Foundation, Inc.
7 # Written by Keith Marshall (keith.d.marshall@ntlworld.com)
8
9 # This file is part of groff.
10
11 # groff is free software; you can redistribute it and/or modify it under
12 # the terms of the GNU General Public License as published by the Free
13 # Software Foundation, either version 3 of the License, or
14 # (at your option) any later version.
15
16 # groff is distributed in the hope that it will be useful, but WITHOUT ANY
17 # WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 # for more details.
20
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #
24 # ------------------------------------------------------------------------------
25 #
26 # Set up an identifier for the NULL device.
27 # In most cases "/dev/null" will be correct, but some shells on
28 # MS-DOS/MS-Windows systems may require us to use "NUL".
29 #
30   NULLDEV="/dev/null"
31   test -c $NULLDEV || NULLDEV="NUL"
32 #
33 # Set up the command name to use in diagnostic messages.
34 # (We can't assume we have 'basename', so use the full path if required.
35 #  Also use the 'exec 2>...' workaround for a bug in Cygwin's 'ash').
36 #
37   CMD=`exec 2>$NULLDEV; basename $0` || CMD=$0
38 #
39 # To ensure that prerequisite helper programs are available, and are
40 # executable, a [fairly] portable method of detecting such programs is
41 # provided by function `searchpath'.
42 #
43   searchpath(){
44   #
45   # Usage:  searchpath progname path
46   #
47     IFS=${PATH_SEPARATOR-":"} prog=':'
48     for dir in $2
49     do
50       for ext in '' '.exe'
51       #
52       # try `progname' with all well known extensions
53       # (e.g. Win32 may require `progname.exe')
54       #
55       do
56         try="$dir/$1$ext"
57         test -f "$try" && test -x "$try" && prog="$try" && break
58       done
59       test "$prog" = ":" || break
60     done
61     echo "$prog"
62   }
63 # @PATH_SEARCH_SETUP@
64 #
65 # If the system maps '/bin/sh' to some 'zsh' implementation,
66 # then we may need this hack, adapted from autoconf code.
67 #
68   test x${ZSH_VERSION+"set"} = x"set" && NULLCMD=":" \
69     && (emulate sh) >$NULLDEV 2>&1 && emulate sh
70 #
71 # We need both 'grep' and 'sed' programs, to parse script options,
72 # and we also need 'cat', to display help and some error messages,
73 # so ensure they are all installed, before we continue.
74 #
75   CAT=`searchpath cat "$PATH"`
76   GREP=`searchpath grep "$PATH"`
77   SED=`searchpath sed "$PATH"`
78 #
79 # Another fundamental requirement is the 'groff' program itself;
80 # we MUST use a 'groff' program located in 'GROFF_BIN_DIR', if this
81 # is specified; if not, we will search 'GROFF_BIN_PATH', only falling
82 # back to a 'PATH' search, if neither of these is specified.
83 #
84   if test -n "$GROFF_BIN_DIR"
85   then
86     GPATH=GROFF_BIN_DIR
87     GROFF=`searchpath groff "$GROFF_BIN_DIR"`
88 #
89   elif test -n "$GROFF_BIN_PATH"
90   then
91     GPATH=GROFF_BIN_PATH
92     GROFF=`searchpath groff "$GROFF_BIN_PATH"`
93 #
94   else
95     GPATH=PATH
96     GROFF=`searchpath groff "$PATH"`
97   fi
98 #
99 # If one or more of these is missing, diagnose and bail out.
100 #
101   NO='' NOPROG="$CMD: installation problem: cannot find program"
102   test "$CAT" = ":" && echo >&2 "$NOPROG 'cat' in PATH" && NO="$NO 'cat'"
103   test "$GREP" = ":" && echo >&2 "$NOPROG 'grep' in PATH" && NO="$NO 'grep'"
104   test "$GROFF" = ":" && echo >&2 "$NOPROG 'groff' in $GPATH" && NO="$NO 'groff'"
105   test "$SED" = ":" && echo >&2 "$NOPROG 'sed' in PATH" && NO="$NO 'sed'"
106   if test -n "$NO"
107   then
108     set $NO
109     test $# -gt 1 && NO="s" IS="are" || NO='' IS="is"
110     while test $# -gt 0
111     do
112       test $# -gt 2 && NO="$NO $1,"
113       test $# -eq 2 && NO="$NO $1 and" && shift
114       test $# -lt 2 && NO="$NO $1"
115       shift
116     done
117     $CAT >&2 <<-ETX
118
119         *** FATAL INSTALLATION ERROR ***
120
121         The program$NO $IS required by '$CMD',
122         but cannot be found; '$CMD' is unable to continue.
123
124         ETX
125     exit 1
126   fi
127 #
128 # Identify the postprocessor command, for writing PDF output.
129 # (May be forced, by defining PDFROFF_POSTPROCESSOR_COMMAND in the environment;
130 #  if this is not set, leave blank to use the built in default).
131 #
132   if test -n "${PDFROFF_POSTPROCESSOR_COMMAND}"
133   then
134     GROFF_GHOSTSCRIPT_INTERPRETER=`set command ${PDFROFF_POSTPROCESSOR_COMMAND};
135       echo $2`
136   fi
137 #
138 # Set up temporary/intermediate file locations, with traps to
139 # clean them up on exit.  Note that, for greater portability, we
140 # prefer to refer to events by number, rather than by symbolic
141 # names; thus, the EXIT event is trapped as event zero.
142 #
143   export TMPDIR GROFF_TMPDIR
144   TMPDIR=${GROFF_TMPDIR=${TMPDIR-${TMP-${TEMP-"."}}}}
145   if GROFF_TMPDIR=`exec 2>${NULLDEV}; mktemp -dt pdfroff-XXXXXXXXXX`
146   then
147   #
148   # We successfully created a private temporary directory,
149   # so to clean up, we may simply purge it.
150   #
151     trap "rm -rf ${GROFF_TMPDIR}" 0
152   #
153   else
154   #
155   # Creation of a private temporary directory was unsuccessful;
156   # fall back to user nominated directory, (using current directory
157   # as default), and schedule removal of only the temporary files.
158   #
159     GROFF_TMPDIR=${TMPDIR}
160     trap "rm -f ${GROFF_TMPDIR}/pdf$$.*" 0
161   fi
162   #
163   # In the case of abnormal termination events, we force an exit
164   # (with status code '1'), leaving the normal exit trap to clean
165   # up the temporary files, as above.  Note that we again prefer
166   # to refer to events by number, rather than by symbolic names;
167   # here we trap SIGHUP, SIGINT, SIGQUIT, SIGPIPE and SIGTERM.
168   #
169   trap "exit 1" 1 2 3 13 15
170 #
171   WRKFILE=${GROFF_TMPDIR}/pdf$$.tmp
172 #
173   REFCOPY=${GROFF_TMPDIR}/pdf$$.cmp
174   REFFILE=${GROFF_TMPDIR}/pdf$$.ref
175 #
176   CS_DATA=""
177   TC_DATA=${GROFF_TMPDIR}/pdf$$.tc
178   BD_DATA=${GROFF_TMPDIR}/pdf$$.ps
179 #
180 # Initialise 'groff' format control settings,
181 # to discriminate table of contents and document body formatting passes.
182 #
183   TOC_FORMAT="-rPHASE=1"
184   BODY_FORMAT="-rPHASE=2"
185 #
186   LONGOPTS="
187     help        reference-dictionary    no-reference-dictionary
188     stylesheet  pdf-output              no-pdf-output
189     version     report-progress         no-toc-relocation
190     emit-ps     keep-temporary-files    no-kill-null-pages
191     "
192 # Parse the command line, to identify 'pdfroff' specific options.
193 # Collect all other parameters into new argument and file lists,
194 # to be passed on to 'groff', enforcing the '-Tps' option.
195 #
196   DIFF="" STREAM="" INPUT_FILES=""
197   SHOW_VERSION="" GROFF_STYLE="$GROFF -Tps"
198   while test $# -gt 0
199   do
200     case "$1" in
201 #
202 #     Long options must be processed locally ...
203 #
204       --*)
205 #
206 #          First identify, matching any abbreviation to its full form.
207 #
208            MATCH="" OPTNAME=`IFS==; set dummy $1; echo $2`
209            for OPT in $LONGOPTS
210            do
211              MATCH="$MATCH"`echo --$OPT | $GREP "^$OPTNAME"`
212            done
213 #
214 #          For options in the form --option=value
215 #          capture any specified value into $OPTARG.
216 #
217            OPTARG=`echo $1 | $SED -n s?"^${OPTNAME}="??p`
218 #
219 #          Perform case specific processing for matched option ...
220 #
221            case "$MATCH" in
222
223              --help)
224                $CAT <<-ETX
225                 Usage: $CMD [-option ...] [--long-option ...] [file ...]
226
227                 Options:
228                   -h
229                   --help
230                         Display this usage summary, and exit.
231
232                   -v
233                   --version
234                         Display a version identification message and exit.
235
236                   --report-progress
237                         Enable console messages, indicating the progress of the
238                         PDF document formatting process.
239
240                   --emit-ps
241                         Emit PostScript output instead of PDF; this may be useful
242                         when the ultimate PDF output is to be generated by a more
243                         specialised postprocessor, (e.g. gpresent), rather than
244                         the default GhostScript PDF writer.
245
246                   --pdf-output=name
247                         Write the PDF, (or PostScript), output stream to file
248                         'name'; if this option is unspecified, standard output
249                         is used for PDF, (or PostScript), output.
250
251                   --no-pdf-output
252                         Suppress the generation of PDF, (or PostScript), output
253                         entirely; use this with the --reference-dictionary option,
254                         if processing a document stream to produce only a
255                         reference dictionary.
256
257                   --no-reference-dictionary
258                         Suppress the generation of a '$CMD' reference dictionary
259                         for the PDF document.  Normally '$CMD' will create a
260                         reference dictionary, at the start of document processing;
261                         this option can accelerate processing, if it is known in
262                         advance, that no reference dictionary is required.
263
264                   --reference-dictionary=name
265                         Save the document reference dictionary in file 'name'.
266                         If 'name' already exists, when processing commences, it
267                         will be used as the base case, from which the updated
268                         dictionary will be derived.  If this option is not used,
269                         then the reference dictionary, created during the normal
270                         execution of '$CMD', will be deleted on completion of
271                         document processing.
272
273                   --stylesheet=name
274                         Use the file 'name' as a 'groff' style sheet, to control
275                         the appearance of the document's front cover section.  If
276                         this option is not specified, then no special formatting
277                         is applied, to create a front cover section.
278
279                   --no-toc-relocation
280                         Suppress the multiple pass 'groff' processing, which is
281                         normally required to position the table of contents at the
282                         start of a PDF document.
283
284                   --no-kill-null-pages
285                         Suppress the 'null page' elimination filter, which is used
286                         to remove the excess blank pages produced by the collation
287                         algorithm used for 'toc-relocation'.
288
289                   --keep-temporary-files
290                         Suppress the normal clean up of temporary files, which is
291                         scheduled when 'pdfroff' completes.
292
293                 ETX
294                exit 0
295                ;;
296
297              --version)
298                GROFF_STYLE="$GROFF_STYLE \"$1\""
299                SHOW_VERSION="GNU pdfroff (groff) version @VERSION@"
300                ;;
301
302              --report-progress)
303                SHOW_PROGRESS=echo
304                ;;
305
306              --keep-temporary-files)
307                trap "" 0
308                ;;
309
310              --emit-ps)
311                PDFROFF_POSTPROCESSOR_COMMAND="$CAT"
312                ;;
313
314              --pdf-output)
315                PDF_OUTPUT="$OPTARG"
316                ;;
317
318              --no-pdf-output)
319                PDF_OUTPUT="$NULLDEV"
320                ;;
321
322              --reference-dictionary)
323                REFFILE="$OPTARG"
324                ;;
325
326              --no-reference-dictionary)
327                AWK=":" DIFF=":" REFFILE="$NULLDEV" REFCOPY="$NULLDEV"
328                ;;
329
330              --stylesheet)
331                STYLESHEET="$OPTARG" CS_DATA=${GROFF_TMPDIR}/pdf$$.cs
332                ;;
333
334              --no-toc-relocation)
335                TC_DATA="" TOC_FORMAT="" BODY_FORMAT=""
336                ;;
337
338              --no-kill-null-pages)
339                PDFROFF_COLLATE="$CAT" PDFROFF_KILL_NULL_PAGES=""
340                ;;
341 #
342 #          any other non-null match must have matched more than one defined case,
343 #          so report the ambiguity, and bail out.
344 #
345              --*)
346                echo >&2 "$CMD: ambiguous abbreviation in option '$1'"
347                exit 1
348                ;;
349 #
350 #          while no match at all simply represents an undefined case.
351 #
352              *)
353                echo >&2 "$CMD: unknown option '$1'"
354                exit 1
355                ;;
356            esac
357            ;;
358 #
359 #     A solitary hyphen, as an argument, means "stream STDIN through groff",
360 #     while the "-i" option means "append STDIN stream to specified input files",
361 #     so set up a mechanism to achieve this, for ALL 'groff' passes.
362 #
363       - | -i*)
364            STREAM="$CAT ${GROFF_TMPDIR}/pdf$$.in |"
365            test "$1" = "-" && INPUT_FILES="$INPUT_FILES $1" \
366              || GROFF_STYLE="$GROFF_STYLE $1" 
367            ;;
368 #
369 #     Those standard options which expect an argument, but are specified with
370 #     an intervening space, between flag and argument, must be reparsed, so we
371 #     can trap invalid use of '-T dev', or missing input files.
372 #
373       -[dfFILmMnoPrTwW])
374            OPTNAME="$1"
375            shift; set reparse "$OPTNAME$@"
376            ;;
377 #
378 #     Among standard options, '-Tdev' is treated as a special case.
379 #     '-Tps' is automatically enforced, so if specified, is silently ignored.
380 #
381       -Tps) ;;
382 #
383 #     No other '-Tdev' option is permitted.
384 #
385       -T*) echo >&2 "$CMD: option '$1' is incompatible with PDF output"
386            exit 1
387            ;;
388 #
389 #     '-h' and '-v' options redirect to their equivalent long forms ...
390 #
391       -h*) set redirect --help
392            ;;
393 #
394       -v*) shift; set redirect --version "$@"
395            ;;
396 #
397 #     All other standard options are simply passed through to 'groff',
398 #     with no validation beforehand.
399 #
400       -*)  GROFF_STYLE="$GROFF_STYLE \"$1\""
401            ;;
402 #
403 #     All non-option arguments are considered as possible input file names,
404 #     and are passed on to 'groff', unaltered.
405 #
406       *)   INPUT_FILES="$INPUT_FILES \"$1\""
407            ;;
408     esac
409     shift
410   done
411 #
412 # If the '-v' or '--version' option was specified,
413 # then we simply emulate the behaviour of 'groff', with this option,
414 # and quit.
415 #
416   if test -n "$SHOW_VERSION"
417   then
418     echo >&2 "$SHOW_VERSION"
419     echo >&2; eval $GROFF_STYLE $INPUT_FILES
420     exit $?
421   fi
422 #
423 # Establish how to invoke 'echo', suppressing the terminating newline.
424 # (Adapted from 'autoconf' code, as found in 'configure' scripts).
425 #
426   case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
427     *c*,*-n*)  n=''   c=''   ;;
428     *c*)       n='-n' c=''   ;;
429     *)         n=''   c='\c' ;;
430   esac
431 #
432 # If STDIN is specified among the input files,
433 # or if no input files are specified, then we need to capture STDIN,
434 # so we can replay it into each 'groff' processing pass.
435 #
436   test -z "$INPUT_FILES" && STREAM="$CAT ${GROFF_TMPDIR}/pdf$$.in |"
437   test -n "$STREAM" && $CAT > ${GROFF_TMPDIR}/pdf$$.in
438 #
439 # Unless reference resolution is explicitly suppressed,
440 # we initiate it by touching the cross reference dictionary file,
441 # and initialise the comparator, to kickstart the reference resolver loop.
442 #
443   SAY=":"
444   if test -z "$DIFF"
445   then
446     >> $REFFILE
447     echo kickstart > $REFCOPY
448     test x${SHOW_PROGRESS+"set"} = x"set" && SAY=echo
449 #
450 #   In order to correctly resolve 'pdfmark' references,
451 #   we need to have both the 'awk' and 'diff' programs available.
452 #
453     NO=''
454     if test -n "$GROFF_AWK_INTERPRETER"
455     then
456       AWK="$GROFF_AWK_INTERPRETER"
457       test -f "$AWK" && test -x "$AWK" || AWK=":"
458     else
459       for prog in @GROFF_AWK_INTERPRETERS@
460       do
461         AWK=`searchpath $prog "$PATH"`
462         test "$AWK" = ":" || break
463       done
464     fi
465     DIFF=`searchpath diff "$PATH"`
466     test "$AWK" = ":" && echo >&2 "$NOPROG 'awk' in PATH" && NO="$NO 'awk'"
467     test "$DIFF" = ":" && echo >&2 "$NOPROG 'diff' in PATH" && NO="$NO 'diff'"
468     if test -n "$NO"
469     then
470       set $NO
471       SAY=":" AWK=":" DIFF=":"
472       test $# -gt 1 && NO="s $1 and $2 are" || NO=" $1 is"
473       $CAT >&2 <<-ETX
474
475         *** WARNING ***
476
477         The program$NO required, but cannot be found;
478         consequently, '$CMD' is unable to resolve 'pdfmark' references.
479
480         Document processing will continue, but no 'pdfmark' reference dictionary
481         will be compiled; if any 'pdfmark' reference appears in the resulting PDF
482         document, the formatting may not be correct.
483
484         ETX
485     fi
486   fi
487 #
488 # Run the multi-pass 'pdfmark' reference resolver loop ...
489 #
490   $SAY >&2 $n Resolving references ..$c
491   until $DIFF $REFCOPY $REFFILE 1>$NULLDEV 2>&1
492   do
493 #
494 #   until all references are resolved, to yield consistent values
495 #   in each of two consecutive passes, or until it seems that no consistent
496 #   resolution is achievable.
497 #
498     $SAY >&2 $n .$c
499     PASS_INDICATOR="${PASS_INDICATOR}."
500     if test "$PASS_INDICATOR" = "...."
501     then
502 #
503 #     More than three passes required indicates a probable inconsistency
504 #     in the source document; diagnose, and bail out.
505 #
506       $SAY >&2 " failed"
507       $CAT >&2 <<-ETX
508         $CMD: unable to resolve references consistently after three passes
509         $CMD: the source document may exhibit instability about the reference(s) ...
510         ETX
511 #
512 #     Report the unresolved references, as a diff between the two pass files,
513 #     preferring 'unified' or 'context' diffs, when available
514 #
515       DIFFOPT=''
516       $DIFF -c0 $NULLDEV $NULLDEV 1>$NULLDEV 2>&1 && DIFFOPT='-c0'
517       $DIFF -u0 $NULLDEV $NULLDEV 1>$NULLDEV 2>&1 && DIFFOPT='-u0'
518       $DIFF >&2 $DIFFOPT $REFCOPY $REFFILE
519       exit 1
520     fi
521 #
522 #   Replace the comparison file copy from any previous pass,
523 #   with the most recently updated copy of the reference dictionary.
524 #   (Some versions of 'mv' may not support overwriting of an existing file,
525 #    so remove the old comparison file first).
526 #
527     rm -f $REFCOPY
528     mv $REFFILE $REFCOPY
529 #
530 #   Run 'groff' and 'awk', to identify reference marks in the document source,
531 #   filtering them into the reference dictionary; discard incomplete 'groff' output
532 #   at this stage.
533 #
534     eval $STREAM $GROFF_STYLE -Z 1>$NULLDEV 2>$WRKFILE $REFCOPY $INPUT_FILES
535     $AWK '/^gropdf-info:href/ {$1 = ".pdfhref D -N"; print}' $WRKFILE > $REFFILE
536   done
537   $SAY >&2 " done"
538 #
539 # To get to here ...
540 # We MUST have resolved all 'pdfmark' references, such that the content of the
541 # updated reference dictionary file EXACTLY matches the last saved copy.
542 #
543 # If PDF output has been suppressed, then there is nothing more to do.
544 #
545   test "$PDF_OUTPUT" = "$NULLDEV" && exit 0
546 #
547 # We are now ready to start preparing the intermediate PostScript files,
548 # from which the PDF output will be compiled -- but before proceeding further ...
549 # let's make sure we have a GhostScript interpreter to convert them!
550 #
551   if test -n "$GROFF_GHOSTSCRIPT_INTERPRETER"
552   then
553     GS="$GROFF_GHOSTSCRIPT_INTERPRETER"
554     test -f "$GS" && test -x "$GS" || GS=":"
555   else
556     for prog in @GROFF_GHOSTSCRIPT_INTERPRETERS@
557     do
558       GS=`searchpath $prog "$PATH"`
559       test "$GS" = ":" || break
560     done
561   fi
562 #
563 # If we could not find a GhostScript interpreter, then we can do no more.
564 #
565   if test "$GS" = ":"
566   then
567     echo >&2 "$CMD: installation problem: cannot find GhostScript interpreter"
568     $CAT >&2 <<-ETX
569
570         *** FATAL INSTALLATION ERROR ***
571
572         '$CMD' requires a GhostScript interpreter to convert PostScript to PDF.
573         Since you do not appear to have one installed, '$CMD' connot continue.
574
575         ETX
576     exit 1
577   fi
578 #
579 # We now extend the local copy of the reference dictionary file,
580 # to create a full 'pdfmark' reference map for the document ...
581 #
582   $AWK '/^grohtml-info/ {print ".pdfhref Z", $2, $3, $4}' $WRKFILE >> $REFCOPY
583 #
584 # ... appending a dummy map reference, to ensure that at least
585 # one such is always present; (this is required, to suppress any
586 # further intermediate output to stderr during the "press-ready"
587 # runs of groff, for PDF output file production).
588 #
589   echo ".pdfhref Z 0 0 0" >> $REFCOPY
590 #
591 # Evaluate any processing options which may have been specified
592 # as a result of parsing the document source ...
593 #
594   eval `$SED -n '/^ *pdfroff-option:set */s///p' $WRKFILE`
595 #
596 # ... (which is currently supported to enable "toc-relocation",
597 # only when the document actually relies on it, and if it is not
598 # explicitly disabled from the command line) ...
599 #
600   if test x${toc_relocation-"auto"} != xenabled
601   then
602 #
603 #   ... thus we reproduce the effect of the "--no-toc-relocation"
604 #   option, when no enabling request is detected in the document
605 #   control stream.
606 #
607     TC_DATA="" TOC_FORMAT="" BODY_FORMAT=""
608   fi
609 #
610 # Re-enable progress reporting, if necessary ...
611 # (Missing 'awk' or 'diff' may have disabled it, to avoid display
612 #  of spurious messages associated with reference resolution).
613 #
614   test x${SHOW_PROGRESS+"set"} = x"set" && SAY=echo
615 #
616 # If a document cover style sheet is specified ...
617 # then we run a special formatting pass, to create a cover section file.
618 #
619   if test -n "$STYLESHEET"
620   then
621     DOT='^\.[   ]*'
622     CS_MACRO=${CS_MACRO-"CS"} CE_MACRO=${CE_MACRO-"CE"}
623     $SAY >&2 $n "Formatting document ... front cover section ..$c"
624     CS_FILTER="$STREAM $SED -n '/${DOT}${CS_MACRO}/,/${DOT}${CE_MACRO}/p'"
625     eval $CS_FILTER $INPUT_FILES | eval $GROFF_STYLE $STYLESHEET - > $CS_DATA
626     $SAY >&2 ". done"
627   fi
628 #
629 # If table of contents relocation is to be performed (it is, by default),
630 # then we run an extra 'groff' pass, to format a TOC intermediate file.
631 #
632   if test -n "$TC_DATA"
633   then
634     $SAY >&2 $n "Formatting document ... table of contents ..$c"
635     eval $STREAM $GROFF_STYLE $TOC_FORMAT $REFCOPY $INPUT_FILES > $TC_DATA
636     $SAY >&2 ". done"
637   fi
638 #
639 # In all cases, a final 'groff' pass is required, to format the document body.
640 #
641   $SAY >&2 $n "Formatting document ... body section ..$c"
642   eval $STREAM $GROFF_STYLE $BODY_FORMAT $REFCOPY $INPUT_FILES > $BD_DATA
643   $SAY >&2 ". done"
644 #
645 # Finally ...
646 # Invoke GhostScript as a PDF writer, to bind all of the generated
647 # PostScript intermediate files into a single PDF output file.
648 #
649   $SAY >&2 $n "Writing PDF output ..$c"
650   if test -z "$PDFROFF_POSTPROCESSOR_COMMAND"
651   then
652     PDFROFF_POSTPROCESSOR_COMMAND="$GS -dQUIET -dBATCH -dNOPAUSE -dSAFER
653       -sDEVICE=pdfwrite -sOutputFile="${PDF_OUTPUT-"-"}
654
655   elif test -n "$PDF_OUTPUT"
656   then
657     exec > $PDF_OUTPUT
658   fi
659 #
660 # (This 'sed' script is a hack, to eliminate redundant blank pages).
661 #
662   ${PDFROFF_COLLATE-"$SED"} ${PDFROFF_KILL_NULL_PAGES-'
663       /%%Page:/{
664         N
665         /%%BeginPageSetup/b again
666       }
667       b
668     :again
669       /%%EndPageSetup/b finish
670       /%%Page:/{
671         N
672         b again
673       }
674       b
675     :finish
676       N
677       /^%%Page:.*\n0 Cg EP$/d
678     '} $TC_DATA $BD_DATA | $PDFROFF_POSTPROCESSOR_COMMAND $CS_DATA -
679   $SAY >&2 ". done"
680 #
681 # ------------------------------------------------------------------------------
682 # $RCSfile$ $Revision$: end of file