#!/bin/sh
# Generate a book from man pages.

# Copyright (C) 2006 Marc Vertes

# This program 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.

# This program 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.

# release 1.5.6

man() {
	cat << \EOT
NAME
  bookman - Generate a book from man pages
SYNOPSIS
  bookman [-pPxn] [-o outfile] [-a author] [-d date] [-r release]
  [-t title] [-v volume] [-c coverfile] [manfile]
DESCRIPTION
  bookman compiles a set of man pages files specified by manfile
  arguments, or if no manfile is given, filenames are read from standard
  input.
OPTIONS
  -p		PDF output format.
  -P		Postscript output format.
  -x		X11 previewing, using gxditview(1).
  -n		no format, output is direct gtroff intermediate format.
  -o outfile    Output in file outfile. Default is standard output.
  -a author	Set the author, on the cover page.
  -d date	Set the date on the cover page.
  -r release	Set the book name and release on the cover page.
  -t title	Set the title on the cover page.
  -v volume	Specify the name of the volume.
  -c coverfile	Uses the file coverfile to generate the cover page,
		i.e. all pages preceding the table of content. coverfile
		must be in groff_ms(7) format.
ENVIRONMENT
  SOURCE_DATE_EPOCH  Unix timestamp that is used for date in header instead
                     of current date.

EXAMPLE
  To build a reference manual from section 2 man, do:

    $ cd /usr/share/man/man2
    $ bookman -p -t 'Unix Reference Manual' * >book.pdf

SEE ALSO
  man(1), mandoc(7), groff_ms(7), groff(1), troff(1), grops(1),
  gxditview(1), ps2pdf(1).
AUTHOR
  Marc Vertes <mvertes@free.fr>
EOT
}

post="grops"

while getopts :a:c:d:mno:pPr:t:v:x opt
do
	case $opt in
	(a) author=$OPTARG;;
	(c) cover=$OPTARG;;
	(d) date=$OPTARG;;
	(m) man; exit;;
	(n) post=cat;;
	(o) outfile=$OPTARG;;
	(p) post='grops | ps2pdf -';;
	(P) post=grops;;
	(x) post='gxditview -';;
	(r) release=$OPTARG;;
	(t) title=$OPTARG;;
	(v) volume=$OPTARG;;
	(*) man; exit;;
	esac
done
shift $(($OPTIND - 1))
if [ -n "$SOURCE_DATE_EPOCH" ]; then
  date=$(LC_ALL=C date -u -d "@$SOURCE_DATE_EPOCH" +'%d %B %Y')
fi
date=${date:-$(date +'%d %B %Y')}

[ $1 ] || set -- $(while read REPLY; do echo "$REPLY"; done)

[ $outfile ] && post="$post >$outfile"

{
	# Compute table of content from postscript output.
	# Generate output in gtroff intermediate format, so
	# it can be merged with content.
	{
		[ -f "$cover" ] && cat "$cover" || {
			printf ".af %% i\n.P1\n"
			printf ".OH ||%s||\n" "$volume"
			printf ".EH ||%s||\n" "$volume"
			printf ".OF |%s|%s|%%|\n" "$release" "$date"
			printf ".EF |%s|%s|%%|\n" "$release" "$date"
			printf ".TL\n%s\n" "$title"
			printf ".AU\n%s\n.AB no\n.AE\n" "$author"
		}
		for f
		do
			case $f in
			(*.Z|*.gz) zcat$f;;
			(*.bz2)    bzcat $f;;
			(*)        cat $f;;
			esac
		done | groff -man -rC1 -Tps | awk '
		$1 == "%%Page:" {page = $2}
		/%%EndPageSetup/ {
			getline l; getline; $0 = l $0
			# extract first word (disgard everything
			# outside braces).
			sub(/^[^\(]*\(/, "")
			gsub(/\)[^\(]*\(/, "")
			gsub(/\\214/, "fi")
			gsub(/\\215/, "fl")
			sub(/\)[^\(]*/, "")
			sub(/\\\(.*/, "")
			if (name != $0) {
				print (page == 1) ? ".XS 1" : ".XA " page
				print $0
			}
			name = $0
		}
		END {print ".XE"; print ".PX"}'
	} | groff -Z -ms | head --lines=-1

	# Output content, in gtroff intermediate format.
	for f
	do
		case $f in
		(*.Z|*.gz) zcat $f;;
		(*.bz2)    bzcat $f;;
		(*)        cat $f;;
		esac
	done | groff -Z -man -rC1 | awk 'NR >3'

} | eval $post
