1#!/bin/sh -e
2# gendocs.sh -- generate a GNU manual in many formats.  This script is
3#   mentioned in maintain.texi.  See the help message below for usage details.
4
5scriptversion=2021-07-19.18
6
7# Copyright 2003-2021 Free Software Foundation, Inc.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program.  If not, see <https://www.gnu.org/licenses/>.
21#
22# Original author: Mohit Agarwal.
23# Send bug reports and any other correspondence to bug-gnulib@gnu.org.
24#
25# The latest version of this script, and the companion template, is
26# available from the Gnulib repository:
27#
28# https://git.savannah.gnu.org/cgit/gnulib.git/tree/build-aux/gendocs.sh
29# https://git.savannah.gnu.org/cgit/gnulib.git/tree/doc/gendocs_template
30
31# TODO:
32# - image importing was only implemented for HTML generated by
33#   makeinfo.  But it should be simple enough to adjust.
34# - images are not imported in the source tarball.  All the needed
35#   formats (PDF, PNG, etc.) should be included.
36
37prog=`basename "$0"`
38srcdir=`pwd`
39
40scripturl="https://git.savannah.gnu.org/cgit/gnulib.git/plain/build-aux/gendocs.sh"
41templateurl="https://git.savannah.gnu.org/cgit/gnulib.git/plain/doc/gendocs_template"
42
43: ${SETLANG="env LANG= LC_MESSAGES= LC_ALL= LANGUAGE="}
44: ${MAKEINFO="makeinfo"}
45: ${TEXI2DVI="texi2dvi"}
46: ${DOCBOOK2HTML="docbook2html"}
47: ${DOCBOOK2PDF="docbook2pdf"}
48: ${DOCBOOK2TXT="docbook2txt"}
49: ${GENDOCS_TEMPLATE_DIR="."}
50: ${PERL='perl'}
51: ${TEXI2HTML="texi2html"}
52unset CDPATH
53unset use_texi2html
54
55MANUAL_TITLE=
56PACKAGE=
57EMAIL=webmasters@gnu.org  # please override with --email
58commonarg= # passed to all makeinfo/texi2html invcations.
59dirargs=   # passed to all tools (-I dir).
60dirs=      # -I directories.
61htmlarg="--css-ref=https://www.gnu.org/software/gnulib/manual.css -c TOP_NODE_UP_URL=/manual"
62default_htmlarg=true
63infoarg=--no-split
64generate_ascii=true
65generate_html=true
66generate_info=true
67generate_tex=true
68outdir=manual
69source_extra=
70split=node
71srcfile=
72texarg="-t @finalout"
73
74version="gendocs.sh $scriptversion
75
76Copyright 2021 Free Software Foundation, Inc.
77There is NO warranty.  You may redistribute this software
78under the terms of the GNU General Public License.
79For more information about these matters, see the files named COPYING."
80
81usage="Usage: $prog [OPTION]... PACKAGE MANUAL-TITLE
82
83Generate output in various formats from PACKAGE.texinfo (or .texi or
84.txi) source.  See the GNU Maintainers document for a more extensive
85discussion:
86  https://www.gnu.org/prep/maintain_toc.html
87
88Options:
89  --email ADR use ADR as contact in generated web pages; always give this.
90
91  -s SRCFILE   read Texinfo from SRCFILE, instead of PACKAGE.{texinfo|texi|txi}
92  -o OUTDIR    write files into OUTDIR, instead of manual/.
93  -I DIR       append DIR to the Texinfo search path.
94  --common ARG pass ARG in all invocations.
95  --html ARG   pass ARG to makeinfo or texi2html for HTML targets,
96                 instead of '$htmlarg'.
97  --info ARG   pass ARG to makeinfo for Info, instead of --no-split.
98  --no-ascii   skip generating the plain text output.
99  --no-html    skip generating the html output.
100  --no-info    skip generating the info output.
101  --no-tex     skip generating the dvi and pdf output.
102  --source ARG include ARG in tar archive of sources.
103  --split HOW  make split HTML by node, section, chapter; default node.
104  --tex ARG    pass ARG to texi2dvi for DVI and PDF, instead of -t @finalout.
105
106  --texi2html  use texi2html to make HTML target, with all split versions.
107  --docbook    convert through DocBook too (xml, txt, html, pdf).
108
109  --help       display this help and exit successfully.
110  --version    display version information and exit successfully.
111
112Simple example: $prog --email bug-gnu-emacs@gnu.org emacs \"GNU Emacs Manual\"
113
114Typical sequence:
115  cd PACKAGESOURCE/doc
116  wget \"$scripturl\"
117  wget \"$templateurl\"
118  $prog --email BUGLIST MANUAL \"GNU MANUAL - One-line description\"
119
120Output will be in a new subdirectory \"manual\" (by default;
121use -o OUTDIR to override).  Move all the new files into your web CVS
122tree, as explained in the Web Pages node of maintain.texi.
123
124Please use the --email ADDRESS option so your own bug-reporting
125address will be used in the generated HTML pages.
126
127MANUAL-TITLE is included as part of the HTML <title> of the overall
128manual/index.html file.  It should include the name of the package being
129documented.  manual/index.html is created by substitution from the file
130$GENDOCS_TEMPLATE_DIR/gendocs_template.  (Feel free to modify the
131generic template for your own purposes.)
132
133If you have several manuals, you'll need to run this script several
134times with different MANUAL values, specifying a different output
135directory with -o each time.  Then write (by hand) an overall index.html
136with links to them all.
137
138If a manual's Texinfo sources are spread across several directories,
139first copy or symlink all Texinfo sources into a single directory.
140(Part of the script's work is to make a tar.gz of the sources.)
141
142As implied above, by default monolithic Info files are generated.
143If you want split Info, or other Info options, use --info to override.
144
145You can set the environment variables MAKEINFO, TEXI2DVI, TEXI2HTML,
146and PERL to control the programs that get executed, and
147GENDOCS_TEMPLATE_DIR to control where the gendocs_template file is
148looked for.  With --docbook, the environment variables DOCBOOK2HTML,
149DOCBOOK2PDF, and DOCBOOK2TXT are also consulted.
150
151By default, makeinfo and texi2dvi are run in the default (English)
152locale, since that's the language of most Texinfo manuals.  If you
153happen to have a non-English manual and non-English web site, see the
154SETLANG setting in the source.
155
156Email bug reports or enhancement requests to bug-gnulib@gnu.org.
157"
158
159while test $# -gt 0; do
160  case $1 in
161    -s)          shift; srcfile=$1;;
162    -o)          shift; outdir=$1;;
163    -I)          shift; dirargs="$dirargs -I '$1'"; dirs="$dirs $1";;
164    --common)    shift; commonarg=$1;;
165    --docbook)   docbook=yes;;
166    --email)     shift; EMAIL=$1;;
167    --html)      shift; default_htmlarg=false; htmlarg=$1;;
168    --info)      shift; infoarg=$1;;
169    --no-ascii)  generate_ascii=false;;
170    --no-html)   generate_ascii=false;;
171    --no-info)   generate_info=false;;
172    --no-tex)    generate_tex=false;;
173    --source)    shift; source_extra=$1;;
174    --split)     shift; split=$1;;
175    --tex)       shift; texarg=$1;;
176    --texi2html) use_texi2html=1;;
177
178    --help)      echo "$usage"; exit 0;;
179    --version)   echo "$version"; exit 0;;
180    -*)
181      echo "$0: Unknown option \`$1'." >&2
182      echo "$0: Try \`--help' for more information." >&2
183      exit 1;;
184    *)
185      if test -z "$PACKAGE"; then
186        PACKAGE=$1
187      elif test -z "$MANUAL_TITLE"; then
188        MANUAL_TITLE=$1
189      else
190        echo "$0: extra non-option argument \`$1'." >&2
191        exit 1
192      fi;;
193  esac
194  shift
195done
196
197# makeinfo uses the dirargs, but texi2dvi doesn't.
198commonarg=" $dirargs $commonarg"
199
200# For most of the following, the base name is just $PACKAGE
201base=$PACKAGE
202
203if $default_htmlarg && test -n "$use_texi2html"; then
204  # The legacy texi2html doesn't support TOP_NODE_UP_URL
205  htmlarg="--css-ref=https://www.gnu.org/software/gnulib/manual.css"
206fi
207
208if test -n "$srcfile"; then
209  # but here, we use the basename of $srcfile
210  base=`basename "$srcfile"`
211  case $base in
212    *.txi|*.texi|*.texinfo) base=`echo "$base"|sed 's/\.[texinfo]*$//'`;;
213  esac
214  PACKAGE=$base
215elif test -s "$srcdir/$PACKAGE.texinfo"; then
216  srcfile=$srcdir/$PACKAGE.texinfo
217elif test -s "$srcdir/$PACKAGE.texi"; then
218  srcfile=$srcdir/$PACKAGE.texi
219elif test -s "$srcdir/$PACKAGE.txi"; then
220  srcfile=$srcdir/$PACKAGE.txi
221else
222  echo "$0: cannot find .texinfo or .texi or .txi for $PACKAGE in $srcdir." >&2
223  exit 1
224fi
225
226if test ! -r $GENDOCS_TEMPLATE_DIR/gendocs_template; then
227  echo "$0: cannot read $GENDOCS_TEMPLATE_DIR/gendocs_template." >&2
228  echo "$0: it is available from $templateurl." >&2
229  exit 1
230fi
231
232# Function to return size of $1 in something resembling kilobytes.
233calcsize()
234{
235  size=`ls -ksl $1 | awk '{print $1}'`
236  echo $size
237}
238
239# copy_images OUTDIR HTML-FILE...
240# -------------------------------
241# Copy all the images needed by the HTML-FILEs into OUTDIR.
242# Look for them in . and the -I directories; this is simpler than what
243# makeinfo supports with -I, but hopefully it will suffice.
244copy_images()
245{
246  local odir
247  odir=$1
248  shift
249  $PERL -n -e "
250BEGIN {
251  \$me = '$prog';
252  \$odir = '$odir';
253  @dirs = qw(. $dirs);
254}
255" -e '
256/<img src="(.*?)"/g && ++$need{$1};
257
258END {
259  #print "$me: @{[keys %need]}\n";  # for debugging, show images found.
260  FILE: for my $f (keys %need) {
261    for my $d (@dirs) {
262      if (-f "$d/$f") {
263        use File::Basename;
264        my $dest = dirname ("$odir/$f");
265        #
266        use File::Path;
267        -d $dest || mkpath ($dest)
268          || die "$me: cannot mkdir $dest: $!\n";
269        #
270        use File::Copy;
271        copy ("$d/$f", $dest)
272          || die "$me: cannot copy $d/$f to $dest: $!\n";
273        next FILE;
274      }
275    }
276    die "$me: $ARGV: cannot find image $f\n";
277  }
278}
279' -- "$@" || exit 1
280}
281
282case $outdir in
283  /*) abs_outdir=$outdir;;
284  *)  abs_outdir=$srcdir/$outdir;;
285esac
286
287echo "Making output for $srcfile"
288echo " in `pwd`"
289mkdir -p "$outdir/"
290
291#
292if $generate_info; then
293  cmd="$SETLANG $MAKEINFO -o $PACKAGE.info $commonarg $infoarg \"$srcfile\""
294  echo "Generating info... ($cmd)"
295  rm -f $PACKAGE.info* # get rid of any strays
296  eval "$cmd"
297  tar czf "$outdir/$PACKAGE.info.tar.gz" $PACKAGE.info*
298  ls -l "$outdir/$PACKAGE.info.tar.gz"
299  info_tgz_size=`calcsize "$outdir/$PACKAGE.info.tar.gz"`
300  # do not mv the info files, there's no point in having them available
301  # separately on the web.
302fi  # end info
303
304#
305if $generate_tex; then
306  cmd="$SETLANG $TEXI2DVI $dirargs $texarg \"$srcfile\""
307  printf "\nGenerating dvi... ($cmd)\n"
308  eval "$cmd"
309  # compress/finish dvi:
310  gzip -f -9 $PACKAGE.dvi
311  dvi_gz_size=`calcsize $PACKAGE.dvi.gz`
312  mv $PACKAGE.dvi.gz "$outdir/"
313  ls -l "$outdir/$PACKAGE.dvi.gz"
314
315  cmd="$SETLANG $TEXI2DVI --pdf $dirargs $texarg \"$srcfile\""
316  printf "\nGenerating pdf... ($cmd)\n"
317  eval "$cmd"
318  pdf_size=`calcsize $PACKAGE.pdf`
319  mv $PACKAGE.pdf "$outdir/"
320  ls -l "$outdir/$PACKAGE.pdf"
321fi # end tex (dvi + pdf)
322
323#
324if $generate_ascii; then
325  opt="-o $PACKAGE.txt --no-split --no-headers $commonarg"
326  cmd="$SETLANG $MAKEINFO $opt \"$srcfile\""
327  printf "\nGenerating ascii... ($cmd)\n"
328  eval "$cmd"
329  ascii_size=`calcsize $PACKAGE.txt`
330  gzip -f -9 -c $PACKAGE.txt >"$outdir/$PACKAGE.txt.gz"
331  ascii_gz_size=`calcsize "$outdir/$PACKAGE.txt.gz"`
332  mv $PACKAGE.txt "$outdir/"
333  ls -l "$outdir/$PACKAGE.txt" "$outdir/$PACKAGE.txt.gz"
334fi
335
336#
337
338if $generate_html; then
339# Split HTML at level $1.  Used for texi2html.
340html_split()
341{
342  opt="--split=$1 --node-files $commonarg $htmlarg"
343  cmd="$SETLANG $TEXI2HTML --output $PACKAGE.html $opt \"$srcfile\""
344  printf "\nGenerating html by $1... ($cmd)\n"
345  eval "$cmd"
346  split_html_dir=$PACKAGE.html
347  (
348    cd ${split_html_dir} || exit 1
349    ln -sf ${PACKAGE}.html index.html
350    tar -czf "$abs_outdir/${PACKAGE}.html_$1.tar.gz" -- *.html
351  )
352  eval html_$1_tgz_size=`calcsize "$outdir/${PACKAGE}.html_$1.tar.gz"`
353  rm -f "$outdir"/html_$1/*.html
354  mkdir -p "$outdir/html_$1/"
355  mv ${split_html_dir}/*.html "$outdir/html_$1/"
356  rmdir ${split_html_dir}
357}
358
359if test -z "$use_texi2html"; then
360  opt="--no-split --html -o $PACKAGE.html $commonarg $htmlarg"
361  cmd="$SETLANG $MAKEINFO $opt \"$srcfile\""
362  printf "\nGenerating monolithic html... ($cmd)\n"
363  rm -rf $PACKAGE.html  # in case a directory is left over
364  eval "$cmd"
365  html_mono_size=`calcsize $PACKAGE.html`
366  gzip -f -9 -c $PACKAGE.html >"$outdir/$PACKAGE.html.gz"
367  html_mono_gz_size=`calcsize "$outdir/$PACKAGE.html.gz"`
368  copy_images "$outdir/" $PACKAGE.html
369  mv $PACKAGE.html "$outdir/"
370  ls -l "$outdir/$PACKAGE.html" "$outdir/$PACKAGE.html.gz"
371
372  # Before Texinfo 5.0, makeinfo did not accept a --split=HOW option,
373  # it just always split by node.  So if we're splitting by node anyway,
374  # leave it out.
375  if test "x$split" = xnode; then
376    split_arg=
377  else
378    split_arg=--split=$split
379  fi
380  #
381  opt="--html -o $PACKAGE.html $split_arg $commonarg $htmlarg"
382  cmd="$SETLANG $MAKEINFO $opt \"$srcfile\""
383  printf "\nGenerating html by $split... ($cmd)\n"
384  eval "$cmd"
385  split_html_dir=$PACKAGE.html
386  copy_images $split_html_dir/ $split_html_dir/*.html
387  (
388    cd $split_html_dir || exit 1
389    tar -czf "$abs_outdir/$PACKAGE.html_$split.tar.gz" -- *
390  )
391  eval \
392    html_${split}_tgz_size=`calcsize "$outdir/$PACKAGE.html_$split.tar.gz"`
393  rm -rf "$outdir/html_$split/"
394  mv $split_html_dir "$outdir/html_$split/"
395  du -s "$outdir/html_$split/"
396  ls -l "$outdir/$PACKAGE.html_$split.tar.gz"
397
398else # use texi2html:
399  opt="--output $PACKAGE.html $commonarg $htmlarg"
400  cmd="$SETLANG $TEXI2HTML $opt \"$srcfile\""
401  printf "\nGenerating monolithic html with texi2html... ($cmd)\n"
402  rm -rf $PACKAGE.html  # in case a directory is left over
403  eval "$cmd"
404  html_mono_size=`calcsize $PACKAGE.html`
405  gzip -f -9 -c $PACKAGE.html >"$outdir/$PACKAGE.html.gz"
406  html_mono_gz_size=`calcsize "$outdir/$PACKAGE.html.gz"`
407  mv $PACKAGE.html "$outdir/"
408
409  html_split node
410  html_split chapter
411  html_split section
412fi
413fi # end html
414
415#
416printf "\nMaking .tar.gz for sources...\n"
417d=`dirname $srcfile`
418(
419  cd "$d"
420  srcfiles=`ls -d *.texinfo *.texi *.txi *.eps $source_extra 2>/dev/null` || true
421  tar czfh "$abs_outdir/$PACKAGE.texi.tar.gz" $srcfiles
422  ls -l "$abs_outdir/$PACKAGE.texi.tar.gz"
423)
424texi_tgz_size=`calcsize "$outdir/$PACKAGE.texi.tar.gz"`
425
426#
427# Do everything again through docbook.
428if test -n "$docbook"; then
429  opt="-o - --docbook $commonarg"
430  cmd="$SETLANG $MAKEINFO $opt \"$srcfile\" >${srcdir}/$PACKAGE-db.xml"
431  printf "\nGenerating docbook XML... ($cmd)\n"
432  eval "$cmd"
433  docbook_xml_size=`calcsize $PACKAGE-db.xml`
434  gzip -f -9 -c $PACKAGE-db.xml >"$outdir/$PACKAGE-db.xml.gz"
435  docbook_xml_gz_size=`calcsize "$outdir/$PACKAGE-db.xml.gz"`
436  mv $PACKAGE-db.xml "$outdir/"
437
438  split_html_db_dir=html_node_db
439  opt="$commonarg -o $split_html_db_dir"
440  cmd="$DOCBOOK2HTML $opt \"${outdir}/$PACKAGE-db.xml\""
441  printf "\nGenerating docbook HTML... ($cmd)\n"
442  eval "$cmd"
443  (
444    cd ${split_html_db_dir} || exit 1
445    tar -czf "$abs_outdir/${PACKAGE}.html_node_db.tar.gz" -- *.html
446  )
447  html_node_db_tgz_size=`calcsize "$outdir/${PACKAGE}.html_node_db.tar.gz"`
448  rm -f "$outdir"/html_node_db/*.html
449  mkdir -p "$outdir/html_node_db"
450  mv ${split_html_db_dir}/*.html "$outdir/html_node_db/"
451  rmdir ${split_html_db_dir}
452
453  cmd="$DOCBOOK2TXT \"${outdir}/$PACKAGE-db.xml\""
454  printf "\nGenerating docbook ASCII... ($cmd)\n"
455  eval "$cmd"
456  docbook_ascii_size=`calcsize $PACKAGE-db.txt`
457  mv $PACKAGE-db.txt "$outdir/"
458
459  cmd="$DOCBOOK2PDF \"${outdir}/$PACKAGE-db.xml\""
460  printf "\nGenerating docbook PDF... ($cmd)\n"
461  eval "$cmd"
462  docbook_pdf_size=`calcsize $PACKAGE-db.pdf`
463  mv $PACKAGE-db.pdf "$outdir/"
464fi
465
466#
467printf "\nMaking index.html for $PACKAGE...\n"
468if test -z "$use_texi2html"; then
469  CONDS="/%%IF  *HTML_SECTION%%/,/%%ENDIF  *HTML_SECTION%%/d;\
470         /%%IF  *HTML_CHAPTER%%/,/%%ENDIF  *HTML_CHAPTER%%/d"
471else
472  # should take account of --split here.
473  CONDS="/%%ENDIF.*%%/d;/%%IF  *HTML_SECTION%%/d;/%%IF  *HTML_CHAPTER%%/d"
474fi
475
476curdate=`$SETLANG date '+%B %d, %Y'`
477sed \
478   -e "s!%%TITLE%%!$MANUAL_TITLE!g" \
479   -e "s!%%EMAIL%%!$EMAIL!g" \
480   -e "s!%%PACKAGE%%!$PACKAGE!g" \
481   -e "s!%%DATE%%!$curdate!g" \
482   -e "s!%%HTML_MONO_SIZE%%!$html_mono_size!g" \
483   -e "s!%%HTML_MONO_GZ_SIZE%%!$html_mono_gz_size!g" \
484   -e "s!%%HTML_NODE_TGZ_SIZE%%!$html_node_tgz_size!g" \
485   -e "s!%%HTML_SECTION_TGZ_SIZE%%!$html_section_tgz_size!g" \
486   -e "s!%%HTML_CHAPTER_TGZ_SIZE%%!$html_chapter_tgz_size!g" \
487   -e "s!%%INFO_TGZ_SIZE%%!$info_tgz_size!g" \
488   -e "s!%%DVI_GZ_SIZE%%!$dvi_gz_size!g" \
489   -e "s!%%PDF_SIZE%%!$pdf_size!g" \
490   -e "s!%%ASCII_SIZE%%!$ascii_size!g" \
491   -e "s!%%ASCII_GZ_SIZE%%!$ascii_gz_size!g" \
492   -e "s!%%TEXI_TGZ_SIZE%%!$texi_tgz_size!g" \
493   -e "s!%%DOCBOOK_HTML_NODE_TGZ_SIZE%%!$html_node_db_tgz_size!g" \
494   -e "s!%%DOCBOOK_ASCII_SIZE%%!$docbook_ascii_size!g" \
495   -e "s!%%DOCBOOK_PDF_SIZE%%!$docbook_pdf_size!g" \
496   -e "s!%%DOCBOOK_XML_SIZE%%!$docbook_xml_size!g" \
497   -e "s!%%DOCBOOK_XML_GZ_SIZE%%!$docbook_xml_gz_size!g" \
498   -e "s,%%SCRIPTURL%%,$scripturl,g" \
499   -e "s!%%SCRIPTNAME%%!$prog!g" \
500   -e "$CONDS" \
501$GENDOCS_TEMPLATE_DIR/gendocs_template >"$outdir/index.html"
502
503echo "Done, see $outdir/ subdirectory for new files."
504
505# Local variables:
506# eval: (add-hook 'before-save-hook 'time-stamp)
507# time-stamp-start: "scriptversion="
508# time-stamp-format: "%:y-%02m-%02d.%02H"
509# time-stamp-end: "$"
510# End:
511