1#!/bin/sh 2# Generate a book from man pages. 3 4# Copyright (C) 2006 Marc Vertes 5 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2, or (at your option) 9# any later version. 10 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15 16# You should have received a copy of the GNU General Public License 17# along with this program; if not, write to the Free Software 18# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19# 02111-1307, USA. 20 21# release 1.7.1 22 23man() { 24 cat << \EOT 25NAME 26 bookman - Generate a book from man pages 27SYNOPSIS 28 bookman [-pPxn] [-o outfile] [-a author] [-d date] [-r release] 29 [-t title] [-v volume] [-c coverfile] [manfile] 30DESCRIPTION 31 bookman compiles a set of man pages files specified by manfile 32 arguments, or if no manfile is given, filenames are read from standard 33 input. 34OPTIONS 35 -p PDF output format. 36 -P Postscript output format. 37 -x X11 previewing, using gxditview(1). 38 -n no format, output is direct gtroff intermediate format. 39 -o outfile Output in file outfile. Default is standard output. 40 -a author Set the author, on the cover page. 41 -d date Set the date on the cover page. 42 -r release Set the book name and release on the cover page. 43 -t title Set the title on the cover page. 44 -v volume Specify the name of the volume. 45 -c coverfile Uses the file coverfile to generate the cover page, 46 i.e. all pages preceding the table of content. coverfile 47 must be in groff_ms(7) format. 48ENVIRONMENT 49 SOURCE_DATE_EPOCH Unix timestamp that is used for date in header instead 50 of current date. 51 52EXAMPLE 53 To build a reference manual from section 2 man, do: 54 55 $ cd /usr/share/man/man2 56 $ bookman -p -t 'Unix Reference Manual' * >book.pdf 57 58SEE ALSO 59 man(1), mandoc(7), groff_ms(7), groff(1), troff(1), grops(1), 60 gxditview(1), ps2pdf(1). 61AUTHOR 62 Marc Vertes <mvertes@free.fr> 63EOT 64} 65 66post="grops" 67 68while getopts :a:c:d:mno:pPr:t:v:x opt 69do 70 case $opt in 71 (a) author=$OPTARG;; 72 (c) cover=$OPTARG;; 73 (d) date=$OPTARG;; 74 (m) man; exit;; 75 (n) post=cat;; 76 (o) outfile=$OPTARG;; 77 (p) post='grops | ps2pdf -';; 78 (P) post=grops;; 79 (x) post='gxditview -';; 80 (r) release=$OPTARG;; 81 (t) title=$OPTARG;; 82 (v) volume=$OPTARG;; 83 (*) man; exit;; 84 esac 85done 86shift $(($OPTIND - 1)) 87 88# Check for dependencies 89 groff -ms /dev/null || { 90 printf "ERROR: You need install groff.\n" >&2 91 exit 1 92 } 93 94ps2pdf 2>&1 | grep -q Usage || { 95 printf "ERROR: You need install ghostscript.\n" >&2 96 exit 1 97 } 98 99# Compatibility wrapper for BSD/GNU date, for parsing dates 100if date -j >/dev/null 2>&1; then 101 pdate() { date -u -j -f '@%s' "$@"; } 102else 103 pdate() { date -u -d "$@"; } 104fi 105 106if [ -n "$SOURCE_DATE_EPOCH" ]; then 107 date=$(LC_ALL=C pdate "@$SOURCE_DATE_EPOCH" +'%d %B %Y') 108fi 109date=${date:-$(LC_ALL=C date -u +'%d %B %Y')} 110 111[ $1 ] || set -- $(while read REPLY; do echo "$REPLY"; done) 112 113[ $outfile ] && post="$post >$outfile" 114 115{ 116 # Compute table of content from postscript output. 117 # Generate output in gtroff intermediate format, so 118 # it can be merged with content. 119 { 120 [ -f "$cover" ] && cat "$cover" || { 121 printf ".af %% i\n.P1\n" 122 printf ".OH ||%s||\n" "$volume" 123 printf ".EH ||%s||\n" "$volume" 124 printf ".OF |%s|%s|%%|\n" "$release" "$date" 125 printf ".EF |%s|%s|%%|\n" "$release" "$date" 126 printf ".TL\n%s\n" "$title" 127 printf ".AU\n%s\n.AB no\n.AE\n" "$author" 128 } 129 for f 130 do 131 case $f in 132 (*.Z|*.gz) zcat $f;; 133 (*.bz2) bzcat $f;; 134 (*) cat $f;; 135 esac 136 done | groff -man -rC1 -Tps | gawk ' 137 $1 == "%%Page:" {page = $2} 138 /%%EndPageSetup/ { 139 getline l; getline; $0 = l $0 140 # extract first word (disgard everything 141 # outside braces). 142 sub(/^[^\(]*\(/, "") 143 gsub(/\)[^\(]*\(/, "") 144 gsub(/\\214/, "fi") 145 gsub(/\\215/, "fl") 146 sub(/\)[^\(]*/, "") 147 sub(/\\\(.*/, "") 148 if (name != $0) { 149 print (page == 1) ? ".XS 1" : ".XA " page 150 print $0 151 } 152 name = $0 153 } 154 END {print ".XE"; print ".PX"}' 155 } | groff -Z -ms | head --lines=-1 156 157 # Output content, in gtroff intermediate format. 158 for f 159 do 160 case $f in 161 (*.Z|*.gz) zcat $f;; 162 (*.bz2) bzcat $f;; 163 (*) cat $f;; 164 esac 165 done | groff -Z -man -rC1 | gawk 'NR >3' 166 167} | eval $post 168