1#! /bin/sh
2# -*- ksh -*-
3
4# psmandup --- produce a version of a PS file to print in manual Duplex.
5
6# Copyright (c) 1988, 89, 90, 91, 92, 93 Miguel Santana
7# Copyright (c) 1995, 96, 97, 98 Akim Demaille, Miguel Santana
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 2, or (at your option)
12# 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, you can either send email to this
21# program's maintainer or write to: The Free Software Foundation,
22# Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA.
23
24# Commentary:
25
26# Author: Akim Demaille <demaille@inf.enst.fr>
27
28# In the interest of general portability, some common bourne shell
29# constructs were avoided because they weren't guaranteed to be available
30# in some earlier implementations.  I've tried to make this program as
31# portable as possible.  Welcome to unix, where the lowest common
32# denominator is rapidly diminishing.
33#
34# Among the more interesting lossages I noticed with some bourne shells
35# are:
36#     * No shell functions.
37#     * No `unset' builtin.
38#     * `shift' cannot take a numeric argument, and signals an error if
39#       there are no arguments to shift.
40
41# Todo:
42# Maybe rewrite in perl.  It would help to handle (Begin|End)Document
43# which allows several Trailers etc.
44
45# Code:
46
47# Minimal path.  It must be able to see the psutils.
48PATH=/usr/local/bin:$PATH
49export PATH
50
51# Get the name of the program
52program=`echo $0 | sed 's#.*/##g'`
53
54# Local vars
55debug=
56file=
57output=
58psfix=${PSFIX:-psfix}
59tmpdir=/tmp/$program.$$
60verbose=echo
61
62
63# The version/usage strings
64version="psmandup 0.8 (a2ps 4.9.9k)
65
66Copyright (c) 1988, 89, 90, 91, 92, 93 Miguel Santana
67Copyright (c) 1995, 96, 97, 98 Akim Demaille, Miguel Santana
68This is free software; see the source for copying conditions.  There is NO
69warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
70
71Written by <Akim.Demaille@inf.enst.fr> and <Miguel.Santana@st.com>
72News, updates and documentation: visit http://www.inf.enst.fr/a2ps/"
73
74usage="\
75Usage: $program FILE
76Tries to produce a version of the PostScript FILE to print in manual
77Duplex.
78
79Options:
80 -h, --help           display this help and exit
81 -v, --version        display version information and exit
82 -q, --quiet          don't print informational messages
83 -o, --output=FILE    save result in FILE.  If FILE is \`-', send to stdout
84 -f, --no-fix         don't call psfix to fix PS problems in FILE
85
86Produced output is meant for PS level 2 printers which don't support
87Duplex printing, but support Manual Feed.  Once the first set of pages
88is printed (odd pages), manual feed is asked: introduce the odd pages
89to print the even pages on the other side.
90
91Report bugs to <a2ps-bugs@inf.enst.fr>"
92
93help="Try \`$program --help' for more information."
94
95# The PostScript line to ask manual feed
96# We go and pick up setpagedevice because the psutils (here psselect)
97# define an ineffective setpagedevice.
98# I hope setpagedevice is always in systemdict...
99psmanualfeed='% Pagedevice definitions:
100countdictstack [{
101%%BeginFeature: *ManualFeed True
102  (<<) cvx exec /ManualFeed true (>>) cvx exec
103  systemdict /setpagedevice get exec
104%%EndFeature
105} stopped
106cleartomark
107countdictstack exch sub dup 0 gt
108{
109  { end } repeat
110}{
111  pop
112} ifelse'
113
114# Don't leave really new lines in it
115psmanualfeed="`echo "$psmanualfeed" | tr '\n' '
116'`"
117
118# Parse our command line options once, thoroughly.
119while test $# -gt 0
120do
121  arg="$1"
122  shift
123
124  case "$arg" in
125    -*=*) optarg=`echo "$arg" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
126    *) optarg= ;;
127  esac
128
129  # If the previous option needs an argument, assign it.
130  if test -n "$prevopt"; then
131    optarg="$arg"
132    arg="$prevopt="
133    prevopt=
134  fi
135
136  # Have we seen a non-optional argument yet?
137  case "$arg" in
138    --help|-h)
139      echo "$usage"
140      exit 0
141      ;;
142
143    --version|-v)
144      echo "$version"
145      exit 0
146      ;;
147
148    -s|-q|--quiet|--silent) verbose=: ;;
149    # Delay debugging so that options parsing does not appear
150    -D|--debug) debug=: ;;
151
152    --output|-o) prevopt="--output" ;;
153    --output=*) output=$optarg ;;
154
155    -n|--no-fix) psfix= ;;
156
157    -) # We are working with stdin
158       nonopt="$nonopt $arg"
159       ;;
160
161    -*)
162      case "$arg" in
163        --*=* ) arg=`echo "$arg" | sed -e 's/=.*//'` ;;
164      esac
165      exec 1>&2
166      echo "$program: Unknown or ambiguous option \`$arg'."
167      echo "$program: Try \`--help' for more information."
168      exit 1
169      ;;
170
171    *)
172      nonopt="$nonopt $arg"
173    ;;
174  esac
175done
176
177if test -n "$prevopt"; then
178  echo "$program: option \`$prevopt' requires an argument" 1>&2
179  echo "$help" 1>&2
180  exit 1
181fi
182
183case `echo "$nonopt" | wc -w | sed -e 's/[\t ]//g'` in
184  0)  file=-;;
185  1)  file=$nonopt;;
186  *)  echo "$program: too many arguments" 1>&2
187      echo "$help"  1>&2
188      exit 1;;
189esac
190
191# Set -x now if debugging
192test $debug && set -x
193
194# Temp dir.  Get ready not to leave junk (if not debugging)
195test $debug || trap "/bin/rm -rf $tmpdir" 0 1 2 3 13 14 15
196mkdir $tmpdir
197
198# If printing from stdin, save into a tmp file
199if test $file = '-'; then
200  file=$tmpdir/stdin.ps
201  cat > $file
202fi
203
204# Fix the file
205if test -n "$psfix"; then
206  $psfix $file -o $tmpdir/fixed.ps `test $verbose = ":" && echo "-q"` \
207    || exit 1
208  file=$tmpdir/fixed.ps
209fi
210
211# Get the number of pages of the document
212pagenum=`grep '^%%Pages: ' $file | sed -e 's/%%Pages: \\([0-9]*\\).*$/\\1/g'`
213
214# Add padding to make sure to have an even number of pages
215# and fix the trailer of the file
216case $pagenum in
217  *0|*2|*4|*6|*8)
218    # No padding needed
219    ;;
220
221  *)
222    # One sheet needed
223    pagenum=`echo "$pagenum + 1" | bc`
224    # Put it before %%Trailer
225    sed -e "s/%%Trailer/%%Page: $pagenum
226showpage
227%%Trailer/g;\
228     s/%%Pages: .*/%%Pages: $pagenum/g" $file | tr '
229' '\n' \
230     > $tmpdir/padded.ps
231    file=$tmpdir/padded.ps
232    ;;
233esac
234
235psselectarg="1"
236i=3
237# Build the string to give to psselect
238while test $i -le $pagenum;
239do
240  psselectarg="$psselectarg,$i"
241  i=`echo "$i + 2" | bc`
242done
243
244i=$pagenum
245while test $i != 0;
246do
247  psselectarg="$psselectarg,$i"
248  i=`echo "$i - 2" | bc`
249done
250
251# Get odd pages in order, and then
252# even pages in reversed order
253psselect -q $psselectarg $file > $tmpdir/ordered.ps || exit 1
254
255# Insert the manual feed request at the first page of the second half
256# This page has as page num, half of $PAGENUM (which is odd, so no
257# worry)
258midpagenum=`echo "($pagenum / 2) + 1" | bc`
259
260# Insert the manual feed request at the first page of the second half
261# This page has as page num, $MIDPAGENUM.
262# Make sure to skip human readable page number.
263if test "$output" && test "$output" != '-'; then
264  sed -e "s#^%%Page:\(.* $midpagenum[ \t]*\)\$#%%Page:\1
265$psmanualfeed#g" \
266     $tmpdir/ordered.ps | tr '
267' '\n' > $output || exit 1
268else
269  sed -e "s#^%%Page:\(.* $midpagenum[ \t]*\)\$#%%Page:\1
270$psmanualfeed#g" \
271     $tmpdir/ordered.ps | tr '
272' '\n' || exit 1
273fi
274
275# Don't remove files if debugging
276test $debug || /bin/rm -rf $tmpdir
277
278$verbose "Once the first half of the file printed, insert the sheets" 1>&2
279$verbose "stack into the manual feed tray to print the second half." 1>&2
280exit 0
281
282