#!/usr/bin/env sh

# card --- smartly produce a printed reference card of a program

# Copyright 1998-2017 Free Software Foundation, Inc.

# 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 3, 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, see
# <https://www.gnu.org/licenses/gpl-3.0.html>.

# Author: Akim Demaille <Akim.Demaille@freefriends.org>

set -e

# Name by which this script was invoked.
program=`echo "$0" | sed -e 's/[^\/]*\///g'`
card_version='1.3'

# Initialize variables.
# Don't use `unset' since old bourne shells don't have this command.
# Instead, assign them an empty value.
# Some of these, like A2PS, may be inherited from the environment.
a2ps=${A2PS-a2ps}
a2ps_options=-Ecard
commands=
debug=
form_feed=
help="Try \`$program --help' for more information."
LC_ALL="${LC_ALL-C}" export LC_ALL
print_form_feeds=:
RM="/bin/rm -rf"
tmp_dir=`mktemp -d -t card.XXXXXX` || { echo "$program: Cannot create temporary dir!" >&2 ; exit 1; }
tmp_file=$tmp_dir/card
success=false
verbose=:
version_short="card $card_version (GNU a2ps 4.15.8)"

usage="Usage: $program [OPTION]... PROGRAM...
Print a reference card of the PROGRAMs thanks to their inline help.

Options:
 -h, --help           display this help and exit
 -v, --version        display version information and exit
 -o, --output=FILE    save the output in FILE
 -l, --language=LL    print the help in the language LL (default: English)
     --command=CMD    perform pretty-printing on the output of CMD
                      (e.g. --command='a2ps --help')

Options for a2ps are given after \`--', for instance

    $ card -lfr a2ps -- -Pdisplay -4

News, updates and documentation: https://www.gnu.org/software/a2ps/
Report bugs to <bug-a2ps@gnu.org>."

version="$version_short
Written by Akim Demaille.

Copyright (c) 1997-99 Akim Demaille, Miguel Santana
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

# List of the possible ways to get the on line help.
# -flags is used with Solaris' CC.
possible_options="--help -h -help -\? -flags"

# Parse command line arguments.
option_without_arguments='vhsqDf'

# As a first step, fetch all the options meant for a2ps, i.e.
# everything after `--'.
jam="$$card$$"
set dummy "${1+"$@"}" "$jam"
shift
while test "x$1" != "x$jam" && test "x$1" != "x--"; do
  set dummy "${1+"$@"}" "$1"
  shift
  shift
done

# If $[1] is `--', then from here to the JAM are a2ps arguments.
if test "x$1" = x--; then
  shift
  while test "x$1" != "x$jam"
  do
    a2ps_options="$a2ps_options $1"
    shift
  done
fi

# The current $1 is JAM.  Pop up the JAM, pop it up, pop it out.
shift

# Proceed to card's options parsing.
# Push a token among the arguments that will be used to notice when
# we ended options/arguments parsing.
arg_sep="$$--$$"
set dummy ${1+"$@"} "$arg_sep"
shift
while test "x$1" != "x$arg_sep"; do

  # Handle --option=value by splitting apart and putting back on argv.
  case "$1" in
    --*=*)
      opt=`echo "$1" | sed -e 's/=.*//'`
      val=`echo "$1" | sed -e 's/[^=]*=//'`
      shift
      set dummy "$opt" "$val" ${1+"$@"}
      shift
      ;;

    -[$option_without_arguments]?*)
      # Prefix $1 with x to avoid running `echo -na' for instance.
      opt=`echo "x$1" | sed -e 's/x-\(.\).*/-\1/'`
      rest=`echo "x$1" | sed -e 's/x-.\(.*\)/-\1/'`
      shift
      set dummy "$opt" "$rest" ${1+"$@"}
      shift
      ;;

    # This case needs to be protected so that the case `-??*' does
    # not split long options without arguments
    --*)
      ;;

    # This is an option with argument.  Split apart and put back on argv.
    -??*)
      opt=`echo "x$1" | sed -e 's/x-\(.\).*/-\1/'`
      arg=`echo "x$1" | sed -e 's/x-.\(.*\)/\1/'`
      shift
      set dummy "$opt" "$arg" ${1+"$@"}
      shift
      ;;
  esac

  # Now, handle the options.  $1 is the option *only*.  If it has an
  # argument, it is now necessarily in $2 etc.  Remember to shift
  # when fetching an argument.
  case "$1" in
    -v | --v*) echo "$version"; exit 0;;
    -h | --h*) echo "$usage"; exit 0;;
    -s|-q|--q*|--s*) verbose=: ;;
    -D | --debug) debug=: ;;
    -o|--output) shift
                 a2ps_options="$a2ps_options --output=$1" ;;
    --lan*|-l) shift; LC_ALL=$1                     ;;
    --com*|-c) shift; commands="$commands
$optarg" ;;
    --no-*|-f) print_form_feeds=                    ;;

    --) # What remains are not options.
      shift
      while test "x$1" != "x$arg_sep"; do
        set dummy ${1+"$@"} "$1"
        shift
	shift
      done
      break;;

    -*)
      echo "$program: Unknown or ambiguous option \`$1'." >&2
      echo "$program: Try \`--help' for more information." >&2
      exit 1;;
    *) set dummy ${1+"$@"} "$1"
       shift
       ;;
   esac
   shift
done
# Pop the token
shift


# ARG now contains both options for a2ps and the true arguments.

if test $# = 0 && test "X$commands" = X; then
  exec 1>&2
  echo "$program: no program given"
  echo "$help"
  exit 1
fi

# Create a tmp dir and be ready to clean up
trap "$RM $tmp_dir" 0 1 2 15

case $LC_ALL in
  fr) footer="Engendré par $version_short" ;;
  *)  footer="Generated by $version_short" ;;
esac

# Set -x now if debugging
test -n "$debug" && set -x

# The files to process are in "$@"
for file
do
  success=false
  filename=`echo "$file" | sed -e 's/[^\/]*\///g'`
  $verbose "Working on \`$filename'"
  case $LC_ALL in
    fr) title="Carte de référence pour $filename" ;;
    *)  title="Reference card of $filename"       ;;
  esac

  # Try to find the help message
  for opt in $possible_options
  do
    $verbose "Trying \`$file $opt'"
    ($file $opt >$tmp_dir/foo 2>&1) >/dev/null 2>&1 && success=: && break
    # Netscape for example is stupid enough to `exit 255' when properly fed
    # with -help, as recommanded by -help itself...  If there are really
    # many lines, consider it is still a success.
    if test "$success" = false; then
      if test `wc -l <$tmp_dir/foo` -gt 10; then
        success=: && break
      fi
    fi
  done

  # If the help message has been found, process it with a2ps
  if $success; then
    $verbose "Success"
    if test -n "$form_feed"; then
       echo ""  >>$tmp_file
    fi
    cat <<EOF >>$tmp_file
				card_label($title)
card_title($title)
EOF
    cat $tmp_dir/foo >>$tmp_file
    # Be ready to insert a page break before next argument-program
    form_feed=$print_form_feeds
  else
    echo "$program: could not find help message for $file"
    exit 1
  fi
done

SAVED_IFS="$IFS"
IFS="
"
for command in $commands
do
  IFS="$SAVED_IFS"
  success=false
  case $LC_ALL in
    fr) title="Résultat de \`$command'" ;;
    *)  title="Result of \`$command'"   ;;
  esac

  (eval $command >$tmp_dir/foo 2>&1) >/dev/null 2>&1 && success=:
  # If the help message has been found, process it with a2ps
  if $success; then
    $verbose "Success"
    if test -n "$form_feed"; then
       echo ""  >>$tmp_file
    fi
    cat <<EOF >>$tmp_file
				card_label($title)
card_title($title)
EOF
    cat $tmp_dir/foo >>$tmp_file
    # Be ready to insert a page break before next argument-program
    form_feed=$print_form_feeds
  else
    echo "$program: command \"$command\" failed"
    exit 1
  fi
done
IFS="$SAVED_IFS"

# All the programs have been treated.  Call a2ps on the produced file
$a2ps $a2ps_options --footer="$footer" $tmp_file || exit 1

exit 0
