#! /bin/sh
# -*- ksh -*-

# psmandup --- produce a version of a PS file to print in manual Duplex.

# Copyright (c) 1988, 89, 90, 91, 92, 93 Miguel Santana
# Copyright (c) 1995, 96, 97, 98 Akim Demaille, Miguel Santana

# 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, you can either send email to this
# program's maintainer or write to: The Free Software Foundation,
# Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.

# Commentary:

# Author: Akim Demaille <demaille@inf.enst.fr>

# In the interest of general portability, some common bourne shell
# constructs were avoided because they weren't guaranteed to be available
# in some earlier implementations.  I've tried to make this program as
# portable as possible.  Welcome to unix, where the lowest common
# denominator is rapidly diminishing.
#
# Among the more interesting lossages I noticed with some bourne shells
# are:
#     * No shell functions.
#     * No `unset' builtin.
#     * `shift' cannot take a numeric argument, and signals an error if
#       there are no arguments to shift.

# Todo:
# Maybe rewrite in perl.  It would help to handle (Begin|End)Document
# which allows several Trailers etc.

# Code:

# Minimal path.  It must be able to see the psutils.
PATH=/usr/local/bin:$PATH
export PATH

# Get the name of the program
program=`echo $0 | sed 's#.*/##g'`

# Local vars
debug=
file=
output=
psfix=${PSFIX:-psfix}
tmpdir=/tmp/$program.$$
verbose=echo


# The version/usage strings
version="psmandup 0.8 (a2ps 4.9.9k)

Copyright (c) 1988, 89, 90, 91, 92, 93 Miguel Santana
Copyright (c) 1995, 96, 97, 98 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.

Written by <Akim.Demaille@inf.enst.fr> and <Miguel.Santana@st.com>
News, updates and documentation: visit http://www.inf.enst.fr/a2ps/"

usage="\
Usage: $program FILE
Tries to produce a version of the PostScript FILE to print in manual
Duplex.

Options:
 -h, --help           display this help and exit
 -v, --version        display version information and exit
 -q, --quiet          don't print informational messages
 -o, --output=FILE    save result in FILE.  If FILE is \`-', send to stdout
 -f, --no-fix         don't call psfix to fix PS problems in FILE

Produced output is meant for PS level 2 printers which don't support
Duplex printing, but support Manual Feed.  Once the first set of pages
is printed (odd pages), manual feed is asked: introduce the odd pages
to print the even pages on the other side.

Report bugs to <a2ps-bugs@inf.enst.fr>"

help="Try \`$program --help' for more information."

# The PostScript line to ask manual feed
# We go and pick up setpagedevice because the psutils (here psselect)
# define an ineffective setpagedevice.
# I hope setpagedevice is always in systemdict...
psmanualfeed='% Pagedevice definitions:
countdictstack [{
%%BeginFeature: *ManualFeed True
  (<<) cvx exec /ManualFeed true (>>) cvx exec
  systemdict /setpagedevice get exec
%%EndFeature
} stopped
cleartomark
countdictstack exch sub dup 0 gt
{
  { end } repeat
}{
  pop
} ifelse'

# Don't leave really new lines in it
psmanualfeed="`echo "$psmanualfeed" | tr '\n' '
'`"

# Parse our command line options once, thoroughly.
while test $# -gt 0
do
  arg="$1"
  shift
  
  case "$arg" in
    -*=*) optarg=`echo "$arg" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
    *) optarg= ;;
  esac
  
  # If the previous option needs an argument, assign it.
  if test -n "$prevopt"; then
    optarg="$arg"
    arg="$prevopt="
    prevopt=
  fi
  
  # Have we seen a non-optional argument yet?
  case "$arg" in
    --help|-h)
      echo "$usage"
      exit 0
      ;;
    
    --version|-v)
      echo "$version"
      exit 0
      ;;
    
    -s|-q|--quiet|--silent) verbose=: ;;
    # Delay debugging so that options parsing does not appear
    -D|--debug) debug=: ;;
    
    --output|-o) prevopt="--output" ;;
    --output=*) output=$optarg ;;
    
    -n|--no-fix) psfix= ;;

    -) # We are working with stdin
       nonopt="$nonopt $arg"
       ;;

    -*)
      case "$arg" in
        --*=* ) arg=`echo "$arg" | sed -e 's/=.*//'` ;;
      esac
      exec 1>&2
      echo "$program: Unknown or ambiguous option \`$arg'."
      echo "$program: Try \`--help' for more information."
      exit 1
      ;;
    
    *)
      nonopt="$nonopt $arg"
    ;;
  esac
done

if test -n "$prevopt"; then
  echo "$program: option \`$prevopt' requires an argument" 1>&2
  echo "$help" 1>&2
  exit 1
fi

case `echo "$nonopt" | wc -w | sed -e 's/[\t ]//g'` in
  0)  file=-;;
  1)  file=$nonopt;;
  *)  echo "$program: too many arguments" 1>&2
      echo "$help"  1>&2
      exit 1;;
esac

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

# Temp dir.  Get ready not to leave junk (if not debugging)
test $debug || trap "/bin/rm -rf $tmpdir" 0 1 2 3 13 14 15
mkdir $tmpdir

# If printing from stdin, save into a tmp file
if test $file = '-'; then
  file=$tmpdir/stdin.ps
  cat > $file
fi

# Fix the file
if test -n "$psfix"; then
  $psfix $file -o $tmpdir/fixed.ps `test $verbose = ":" && echo "-q"` \
    || exit 1
  file=$tmpdir/fixed.ps
fi

# Get the number of pages of the document
pagenum=`grep '^%%Pages: ' $file | sed -e 's/%%Pages: \\([0-9]*\\).*$/\\1/g'`

# Add padding to make sure to have an even number of pages
# and fix the trailer of the file
case $pagenum in
  *0|*2|*4|*6|*8)
    # No padding needed
    ;;

  *)
    # One sheet needed
    pagenum=`echo "$pagenum + 1" | bc`
    # Put it before %%Trailer
    sed -e "s/%%Trailer/%%Page: $pagenum
showpage
%%Trailer/g;\
     s/%%Pages: .*/%%Pages: $pagenum/g" $file | tr '
' '\n' \
     > $tmpdir/padded.ps
    file=$tmpdir/padded.ps
    ;;
esac

psselectarg="1"
i=3
# Build the string to give to psselect
while test $i -le $pagenum;
do
  psselectarg="$psselectarg,$i"
  i=`echo "$i + 2" | bc`
done

i=$pagenum
while test $i != 0;
do
  psselectarg="$psselectarg,$i"
  i=`echo "$i - 2" | bc`
done

# Get odd pages in order, and then
# even pages in reversed order
psselect -q $psselectarg $file > $tmpdir/ordered.ps || exit 1

# Insert the manual feed request at the first page of the second half
# This page has as page num, half of $PAGENUM (which is odd, so no
# worry)
midpagenum=`echo "($pagenum / 2) + 1" | bc`

# Insert the manual feed request at the first page of the second half
# This page has as page num, $MIDPAGENUM.  
# Make sure to skip human readable page number.
if test "$output" && test "$output" != '-'; then
  sed -e "s#^%%Page:\(.* $midpagenum[ \t]*\)\$#%%Page:\1
$psmanualfeed#g" \
     $tmpdir/ordered.ps | tr '
' '\n' > $output || exit 1
else
  sed -e "s#^%%Page:\(.* $midpagenum[ \t]*\)\$#%%Page:\1
$psmanualfeed#g" \
     $tmpdir/ordered.ps | tr '
' '\n' || exit 1
fi

# Don't remove files if debugging
test $debug || /bin/rm -rf $tmpdir

$verbose "Once the first half of the file printed, insert the sheets" 1>&2
$verbose "stack into the manual feed tray to print the second half." 1>&2
exit 0

