chou@oahu.cs.ucla.edu (Ching-Tsun Chou) (11/28/90)
I asked some time ago about how to print 2 pages on 1 page of physical paper. Here are the replies that I got. I've edited them a bit to save space and post only those that contain actual codes. My sincere thanks to all who responded to my query. By the way, many people mentioned Rockiki's dvidvi. Does anyone know where to get it? Please send your reply to: <chou@cs.ucla.edu> - Ching Tsun From: mernst@theory.lcs.mit.edu (Michael Ernst) You can use Rockiki's dvidvi to rearrange .dvi files. You can also use the following hack, which loses some resolution since it uses fonts at a smaller-than-usual size instead of substituting for other fonts; but the result is readable nonetheless. I got this shell script from Michelangelo Grigni; I don't know whether he's the original author. -Michael Ernst mernst@theory.lcs.mit.edu =========================================================================== : # multi.sh # print files with several pages per sheet. Defaults: nup=-2 dividers=true printer=-P${PRINTER-ps} dviheaders=/a/aviary/psfig/lib/tex.ps # /a/aviary/psfig/lib/mac.MDII.pro case "$1" in ""|-h*) exec cat << END_USAGE usage: multi [-1|-2|-4|-8] [-d] [-Pprinter] [-Jjobname] file ... Print files (postscript, plain text, or dvi) with N virtual pages per real sheet of paper, where N=1, 2, 4, or 8 (default -N is "$nup"). DVI files are piped through dvi2ps, text files are piped through enscript. The -d option turns off black dividing lines between the virtual pages. The default printer job name is "multi:" plus the first file name, this can be changed with the -J option. The default printer is "$printer". END_USAGE ;; esac # parse the arguments files= for arg do case "$arg" in -[1248]) nup=$arg ;; -d*) dividers=false ;; -P*) printer="$arg" ;; -J*) job="$arg" ;; *) : ${job="-Jmulti:$arg"} if test ! -f "$arg" then echo "$0: cannot find file $arg" 1>&2 exit 1 fi files="$files $arg" ;; esac done case "$nup" in -1) landscape=false; rows=1; cols=1; dividers=false;; -2) landscape=true; rows=1; cols=2;; -4) landscape=false; rows=2; cols=2;; -8) landscape=true; rows=2; cols=4;; *) echo "$0: internal error" 1>&2; exit 2;; esac case "$files" in "") echo "$0: no files specified!" 1>&2; exit 1;; esac echo "Sending output via 'lpr $printer $job'" 1>&2 ( echo "First sending multi.ps preamble" 1>&2 cat << 'END_MULTI' %!PS-Adobe-1.0 %%Creator: Ross Cartlidge <rossc@extro.ucc.su.oz> %%Title: Multiple pages on one page %%CreationDate: Tuesday July 25 18:00:00 1989 %%Pages: 0 %%DocumentFonts: %%BoundingBox: 0 0 0 0 %%EndComments % % Uncomment the next line if you wish to load multi into the "exitserver" % state of the PostScript device % serverdict begin 0 exitserver % % % make each operator to overlay a procedure so a bind in % a prolog will not stop the overlaying by "multi" % [ /gsave /grestore /grestoreall /initgraphics /initmatrix /currentmatrix /setmatrix % Path construction operators /initclip % Virtual memory operators /save % ones which needed special overloading /showpage /erasepage /copypage /restore % ignore these /letter /legal /a4 /b5 /lettersmall /note ] { % if exists check if operator else define {} dup where { pop % If operator then make into procedure dup load type /operatortype eq { 1 array cvx dup 0 3 index cvx % /n -> n put % {}[0] -> n bind def } { pop } ifelse } { {} def } ifelse } forall % % Initialise endmulti to execute an error % /endmulti { count array astore /ostack exch def 250 array execstack /estack exch def 20 array dictstack /dstack exch def $error /newerror true put $error /errorname (No matching multi) cvn put $error /command (endmulti) put $error /ostack ostack put $error /estack estack put $error /dstack dstack put stop } bind def % % Put multiple logical pages on one physical page % until "endmulti" called % % landscape nrows ncols dividers multi - % % landscape boolean, if true divide page in landscape orientation % nrows integer, number of logical pages down physical page % ncols integer, number of logical pages across physical page % dividers boolean, if true divide logical pages by lines % /multi { currentdict 64 dict begin /initdict exch def % store initial dict for backward reference /dividers exch def /cols exch def /rows exch def % % get size of current page % initgraphics clippath pathbbox /Y exch def % Max Y /X exch def % Max X /y exch def % Min Y /x exch def % Min X /W X x add def % Width of Page /H Y y add def % Height of page % if landscape { % % Note: x and y are reversed % /w Y y sub def % Width of imageable region /h X x sub def % Height of imageable region /L % Map to landscape -90 matrix rotate 0 H matrix translate matrix concatmatrix def /O y x matrix translate def % Move to origin } { /w X x sub def /h Y y sub def /L matrix def /O x y matrix translate def } ifelse % % CTM (multi) = C x T x M x L x I % CTM (normal) = C x I % CTM (normal) = CTM (multi) x (T x M x L x I)-1 x I % M = (Scale rows/cols) x (Scale logical to physical) x % (Translate to physical clip origin % T = (Convert logical page to spot and physical) % L = (Convert to landscape) % I = Initial Physical CTM % C = Random transform on logical page /I matrix currentmatrix def /I_inv I matrix invertmatrix def /M w W div cols div h H div rows div matrix scale %TMP O matrix concatmatrix def % matrix T <current T> /T { page# cols mod W mul rows page# cols idiv sub 1 sub H mul 3 -1 roll translate } def % % Utility functions % NB: *_t1 are temporary variables % % matrix fromcanon <I-1 x T x M x L x I> /From_t1 matrix def /From_t2 matrix def /From_t3 matrix def /From_t4 matrix def /fromcanon { I_inv From_t1 T M L I From_t2 concatmatrix From_t3 concatmatrix From_t4 concatmatrix 3 -1 roll concatmatrix } def % /n {} mkmulti - % makes a new function called "n" in previous dict with:- % {}[0] = /n % {}[1] = currentdict % currentdict.n = prevdict.n % /mkmulti { 1 index dup load def %define old val in current dict 5 array cvx dup 3 4 -1 roll put % A[3] = {} dup 0 3 index put % A[0] = /n dup 1 currentdict put % A[1] = currentdict dup 2 /begin cvx put % A[2] = begin dup 4 /exec cvx put % A[4] = exec initdict 3 1 roll put % define initdict.n to multi function } def % % path_to_proc {} % make proc represenation of current path % /path_to_proc { { [ /newpath cvx { /moveto cvx} { /lineto cvx} { /curveto cvx} { /closepath cvx } pathforall ] cvx exch pop } stopped { $error /errorname get /invalidaccess eq { cleartomark $error /newerror false put (%%Warning%% charpath in path - path nulled) = cvx exec } { stop } ifelse } if } def /path_def { { currentpoint } stopped { $error /newerror false put { newpath } } { /newpath cvx 3 1 roll /moveto cvx 4 array astore cvx } ifelse } cvlit def % % Draw lines round logical pages % /draw_dividers { initgraphics L concat M concat 1 1 cols 1 sub { W mul dup 0 moveto rows H mul lineto } for 1 1 rows 1 sub { H mul dup 0 exch moveto cols W mul exch lineto } for stroke } def % % for each graphics operator which affects absolute state % /M1 matrix def /M3 matrix def /M2 matrix def [ /gsave /grestore /grestoreall /initgraphics /initmatrix /currentmatrix /setmatrix % Path construction operators /initclip % Virtual memory operators /save ] { { % Save paths path_def path_to_proc clippath { {} } path_to_proc % % CTM <- CTM x Tocano (canon mode) % M1 currentmatrix Tocanon M2 concatmatrix setmatrix % Restore paths initclip exec clip exec load exec % Save paths path_def path_to_proc clippath { {} } path_to_proc % % CTM <- CTM x Fromcanon (Non canon mode) % M1 currentmatrix Fromcanon M2 concatmatrix setmatrix % Restore paths initclip exec clip exec end } mkmulti } forall % % Define the operators which can't use the standard template % /showpage { /page# page# 1 add def % Update the transform matrices page# npages eq { dividers { draw_dividers } if load exec % the previous showpage /page# 0 def } { pop } ifelse /Fromcanon Fromcanon fromcanon def /Tocanon Fromcanon Tocanon invertmatrix def end initgraphics % the new initgraphics } mkmulti /copypage { pop end gsave showpage grestore } mkmulti /erasepage { pop end gsave initclip clippath 1 setgray fill grestore } mkmulti [ /letter /legal /a4 /b5 /lettersmall /note ] { { pop end (%%Warning%% Device change ignored) = } mkmulti } forall % % Define restore separately as it affects the value of page#, etc % /restore { pop % Push the values to restore after restore mark exch % put mark under -save- page# Fromcanon aload pop Tocanon aload pop counttomark -1 roll % get -save- to the top restore % Restore popped values Tocanon astore pop Fromcanon astore pop /page# exch def pop % mark % Save paths path_def path_to_proc clippath { { } } path_to_proc % % CTM <- CTM x Fromcanon (Non canon mode) % M1 currentmatrix Fromcanon M2 concatmatrix setmatrix % Restore paths initclip exec clip exec end } mkmulti % % procedure to undo the effect of multi % /endmulti { pop % don't need /endmulti [ /gsave /grestore /grestoreall /initgraphics /initmatrix /currentmatrix /setmatrix % Path construction operators /initclip % Virtual memory operators /save % ones which needed special overloading /showpage /erasepage /copypage /restore % ignore these /letter /legal /a4 /b5 /lettersmall /note % /endmulti ] { initdict exch dup load % get old value put % restore old value } forall page# 0 ne % if not at new page show uncomplete page { dividers { draw_dividers } if showpage } if end } mkmulti % % Set up in multi(non canon) mode % /page# 0 def /npages rows cols mul def /Fromcanon matrix fromcanon def /Tocanon Fromcanon matrix invertmatrix def end initgraphics } bind def END_MULTI echo "Using landscape=$landscape rows=$rows cols=$cols dividers=$dividers" 1>&2 echo "$landscape $rows $cols $dividers multi" # Now send all the files, special handling for dvi and text files: dvisent=no echo "Printing files:" 1>&2 for file in $files do case "$file" in *.ps) echo "$file: assumed PostScript" 1>&2 cat $file ;; *.dvi) case $dvisent in no) echo "Sending dvi2ps header files" 1>&2 cat $dviheaders dvisent=yes ;; esac echo "$file: piping via dvi2ps" 1>&2 dvi2ps -r -h $file ;; # 2> /dev/null *) case "`file -L $file`" in *"PostScript document") echo "$file: assumed PostScript" 1>&2 cat $file ;; *) echo "$file: assumed ascii, piping via enscript" 1>&2 enscript -1RB -p - $file ;; # 2> /dev/null esac ;; esac echo '' done echo "endmulti" echo "Done." 1>&2 ) | lpr $printer $job From: dwilkins@MATHS.TCD.IE Here are my own macros for doing this, by inserting the relevant command (e.g. \twopageafour) at or near the head of the TeX document (before any text or other material to be printed). Unfortunately for you, it is set up for A4 paper (297mm * 210mm). You would have to hack the \fullhsize, \voffset and \hoffset to get it to work with US letter or legal paper. Also the macros use the landscape \special command for the dvitops dvi -> postscript translator. If you use printer driver (e.g. dvips, dvi2ps, dvi3ps), you would have to use whatever landscape mode \special command is available ---------------------Cut------------------------------------- % \twopageoutput is a macro to output on A4 paper, two % pages at a time. The user specifies the \vsize and \hsize % parameters for the individual pages, together with the % width of the outside margins. The macro \twopageafour % calls \twopageoutput with these values set to % 160 true mm, 125 true mm and 10 true mm respectively \newdimen\fullhsize \newbox\leftpage \def\twopageoutput#1#2#3{\vsize=#1\hsize=#2\relax \fullhsize=#3\multiply\fullhsize by -2 \advance \fullhsize by 297 true mm \voffset=79.6 true mm \advance\voffset by -0.5\vsize \hoffset=#3\advance \hoffset by -25.4 true mm \let\lr=L \tenpointstyle \output={\if L\lr \global\setbox\leftpage=\line{\vbox{\makeheadline \pagebody\makefootline}\hss}% \advancepageno\global\let\lr=R \else \shipout\vbox{\hbox to \fullhsize{\box\leftpage\hfil \line{\vbox{\makeheadline\pagebody\makefootline}\hss}}% \special{dvitops: landscape}}% \advancepageno\global\let\lr=L \fi \ifnum\outputpenalty>-20000 \else \dosupereject \fi}} \def\twopageafour{\twopageoutput{160 true mm}{125 true mm}{10 true mm}} ---------------------Cut------------------------------------- I don't know whether this is of any use to you. You will probably get something more suitable from somebody else. David Wilkins (dwilkins@maths.tcd.ie) School of Mathematics, Trinity College, Dublin 2, Ireland From: kai@nada.kth.se (Kai-Mikael J{{-Aro) Subject: This is multi Article 73 of comp.text.tex: Path: draken!kth.se!sunic!uupsi!rpi!zaphod.mps.ohio-state.edu!uakari!ames!apple!uokmax!munnari.oz.au!cluster!metro!news From: rossc@extro.ucc.su.oz.au (Ross Cartlidge) Newsgroups: comp.text.tex Subject: Multi.ps - 2 up printing (and more) Message-ID: <1990Feb24.005958.29506@metro.ucc.su.oz.au> Date: 24 Feb 90 00:59:58 GMT Reply-To: rossc@extro.ucc.su.oz.au (Ross Cartlidge) Organization: University Computing Service, Uni. of Sydney, Australia. Lines: 719 To everyone who asked for this:- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # multi.ps # eg.sh # README.multi # This archive created: Wed Feb 21 20:47:57 1990 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'multi.ps' then echo shar: "will not over-write existing file 'multi.ps'" else cat << \SHAR_EOF > 'multi.ps' %!PS-Adobe-1.0 %%Creator: Ross Cartlidge <rossc@extro.ucc.su.oz> %%Title: Multiple pages on one page %%CreationDate: Tuesday July 25 18:00:00 1989 %%Pages: 0 %%DocumentFonts: %%BoundingBox: 0 0 0 0 %%EndComments % % Uncomment the next line if you wish to load multi into the "exitserver" % state of the PostScript device % serverdict begin 0 exitserver % % % make each operator to overlay a procedure so a bind in % a prolog will not stop the overlaying by "multi" % [ /gsave /grestore /grestoreall /initgraphics /initmatrix /currentmatrix /setmatrix % Path construction operators /initclip % Virtual memory operators /save % ones which needed special overloading /showpage /erasepage /copypage /restore % ignore these /letter /legal /a4 /b5 /lettersmall /note ] { % if exists check if operator else define {} dup where { pop % If operator then make into procedure dup load type /operatortype eq { 1 array cvx dup 0 3 index cvx % /n -> n put % {}[0] -> n bind def } { pop } ifelse } { {} def } ifelse } forall % % Initialise endmulti to execute an error % /endmulti { count array astore /ostack exch def 250 array execstack /estack exch def 20 array dictstack /dstack exch def $error /newerror true put $error /errorname (No matching multi) cvn put $error /command (endmulti) put $error /ostack ostack put $error /estack estack put $error /dstack dstack put stop } bind def % % Put multiple logical pages on one physical page % until "endmulti" called % % landscape nrows ncols dividers multi - % % landscape boolean, if true divide page in landscape orientation % nrows integer, number of logical pages down physical page % ncols integer, number of logical pages across physical page % dividers boolean, if true divide logical pages by lines % /multi { currentdict 64 dict begin /initdict exch def % store initial dict for backward reference /dividers exch def /cols exch def /rows exch def % % get size of current page % initgraphics clippath pathbbox /Y exch def % Max Y /X exch def % Max X /y exch def % Min Y /x exch def % Min X /W X x add def % Width of Page /H Y y add def % Height of page % if landscape { % % Note: x and y are reversed % /w Y y sub def % Width of imageable region /h X x sub def % Height of imageable region /L % Map to landscape -90 matrix rotate 0 H matrix translate matrix concatmatrix def /O y x matrix translate def % Move to origin } { /w X x sub def /h Y y sub def /L matrix def /O x y matrix translate def } ifelse % % CTM (multi) = C x T x M x L x I % CTM (normal) = C x I % CTM (normal) = CTM (multi) x (T x M x L x I)-1 x I % M = (Scale rows/cols) x (Scale logical to physical) x % (Translate to physical clip origin % T = (Convert logical page to spot and physical) % L = (Convert to landscape) % I = Initial Physical CTM % C = Random transform on logical page /I matrix currentmatrix def /I_inv I matrix invertmatrix def /M w W div cols div h H div rows div matrix scale %TMP O matrix concatmatrix def % matrix T <current T> /T { page# cols mod W mul rows page# cols idiv sub 1 sub H mul 3 -1 roll translate } def % % Utility functions % NB: *_t1 are temporary variables % % matrix fromcanon <I-1 x T x M x L x I> /From_t1 matrix def /From_t2 matrix def /From_t3 matrix def /From_t4 matrix def /fromcanon { I_inv From_t1 T M L I From_t2 concatmatrix From_t3 concatmatrix From_t4 concatmatrix 3 -1 roll concatmatrix } def % /n {} mkmulti - % makes a new function called "n" in previous dict with:- % {}[0] = /n % {}[1] = currentdict % currentdict.n = prevdict.n % /mkmulti { 1 index dup load def %define old val in current dict 5 array cvx dup 3 4 -1 roll put % A[3] = {} dup 0 3 index put % A[0] = /n dup 1 currentdict put % A[1] = currentdict dup 2 /begin cvx put % A[2] = begin dup 4 /exec cvx put % A[4] = exec initdict 3 1 roll put % define initdict.n to multi function } def % % path_to_proc {} % make proc represenation of current path % /path_to_proc { { [ /newpath cvx { /moveto cvx} { /lineto cvx} { /curveto cvx} { /closepath cvx } pathforall ] cvx exch pop } stopped { $error /errorname get /invalidaccess eq { cleartomark $error /newerror false put (%%Warning%% charpath in path - path nulled) = cvx exec } { stop } ifelse } if } def /path_def { { currentpoint } stopped { $error /newerror false put { newpath } } { /newpath cvx 3 1 roll /moveto cvx 4 array astore cvx } ifelse } cvlit def % % Draw lines round logical pages % /draw_dividers { initgraphics L concat M concat 1 1 cols 1 sub { W mul dup 0 moveto rows H mul lineto } for 1 1 rows 1 sub { H mul dup 0 exch moveto cols W mul exch lineto } for stroke } def % % for each graphics operator which affects absolute state % /M1 matrix def /M3 matrix def /M2 matrix def [ /gsave /grestore /grestoreall /initgraphics /initmatrix /currentmatrix /setmatrix % Path construction operators /initclip % Virtual memory operators /save ] { { % Save paths path_def path_to_proc clippath { {} } path_to_proc % % CTM <- CTM x Tocano (canon mode) % M1 currentmatrix Tocanon M2 concatmatrix setmatrix % Restore paths initclip exec clip exec load exec % Save paths path_def path_to_proc clippath { {} } path_to_proc % % CTM <- CTM x Fromcanon (Non canon mode) % M1 currentmatrix Fromcanon M2 concatmatrix setmatrix % Restore paths initclip exec clip exec end } mkmulti } forall % % Define the operators which can't use the standard template % /showpage { /page# page# 1 add def % Update the transform matrices page# npages eq { dividers { draw_dividers } if load exec % the previous showpage /page# 0 def } { pop } ifelse /Fromcanon Fromcanon fromcanon def /Tocanon Fromcanon Tocanon invertmatrix def end initgraphics % the new initgraphics } mkmulti /copypage { pop end gsave showpage grestore } mkmulti /erasepage { pop end gsave initclip clippath 1 setgray fill grestore } mkmulti [ /letter /legal /a4 /b5 /lettersmall /note ] { { pop end (%%Warning%% Device change ignored) = } mkmulti } forall % % Define restore separately as it affects the value of page#, etc % /restore { pop % Push the values to restore after restore mark exch % put mark under -save- page# Fromcanon aload pop Tocanon aload pop counttomark -1 roll % get -save- to the top restore % Restore popped values Tocanon astore pop Fromcanon astore pop /page# exch def pop % mark % Save paths path_def path_to_proc clippath { { } } path_to_proc % % CTM <- CTM x Fromcanon (Non canon mode) % M1 currentmatrix Fromcanon M2 concatmatrix setmatrix % Restore paths initclip exec clip exec end } mkmulti % % procedure to undo the effect of multi % /endmulti { pop % don't need /endmulti [ /gsave /grestore /grestoreall /initgraphics /initmatrix /currentmatrix /setmatrix % Path construction operators /initclip % Virtual memory operators /save % ones which needed special overloading /showpage /erasepage /copypage /restore % ignore these /letter /legal /a4 /b5 /lettersmall /note % /endmulti ] { initdict exch dup load % get old value put % restore old value } forall page# 0 ne % if not at new page show uncomplete page { dividers { draw_dividers } if showpage } if end } mkmulti % % Set up in multi(non canon) mode % /page# 0 def /npages rows cols mul def /Fromcanon matrix fromcanon def /Tocanon Fromcanon matrix invertmatrix def end initgraphics } bind def SHAR_EOF fi if test -f 'eg.sh' then echo shar: "will not over-write existing file 'eg.sh'" else cat << \SHAR_EOF > 'eg.sh' #!/bin/sh cat multi.ps - <<-'!' % landscape mode, 1 row, 2 cols, no dividers true 1 2 true multi % /Helvetica findfont 12 scalefont setfont 100 100 moveto save (This is Page One) show showpage restore save (This is Page Two) show showpage restore % endmulti ! SHAR_EOF chmod +x 'eg.sh' fi if test -f 'README.multi' then echo shar: "will not over-write existing file 'README.multi'" else cat << \SHAR_EOF > 'README.multi' This package is a PostScript prolog which when used with almost any valid PostScript will output it with multiple logical pages on each physical page. Each logical page will be identical (but smaller) to the original result of each showpage. Written By: Ross Cartlidge University Computing Service Building H08, Sydney University NSW, 2006, Australia rossc@extro.ucc.su.oz Email +61 2 692 3495 Phone +61 2 660 6557 Fax It works by overlaying each PostScript Operator which is affected by or affects the absolute graphics state with a procedure which first goes back to normal full page graphics state, does the operator, and then restores the multiple page graphics state. Thus when "initgraphics", eg, is executed its transformation of CTM, path and clippath is mapped onto the multiple page representation. Also when a "save" is done the full page version is saved, thus when "restore" is done - possibly many logical pages into the future - the graphics state saved is transformed into the new multi page. All its local variables are stored in private (unnamed) directories and the only "pollution" of the current directory is with the entry and exit points "multi" and "endmulti". It is written to be able to be included in the "exitserver" state of the the server, thus it can be loaded before any other permanent prologs which may use absolute graphics commands (like "showpage"). It works recursively so a "multi" can be called inside another "multi" to any level (VM permitting). It tries to use as little VM as possible but some is consumed in restoring paths between multi and single page graphics states so large documents may cause VMerror earlier than in normal representation unless "save-restore" is used appropriately. USAGE: "multi.ps" defines 2 procedures:- (i) landscape nrows ncols dividers multi - Go into multi page representation landscape boolean, if true divide page in landscape orientation nrows integer, number of logical pages down physical page ncols integer, number of logical pages across physical page dividers boolean, if true divide logical pages by lines (ii) endmulti - End multi page representation EXAMPLES: Display pages in "side by side" form % landscape mode, 1 row, 2 cols, dividers true 1 2 true multi % /Helvetica findfont 12 scalefont setfont 100 100 moveto save (This is Page One) show showpage restore save (This is Page Two) show showpage restore % endmulti To run this example type:- sh eg.sh | <your PostScript print command> It's not a bad idea to load multi.ps in to the "exitserver" state of your LaserWriter as then it will work with any prologs you may be using. Make sure you load it first! To load it into the "exitserver" state see the comments at the start of multi.ps. You then only need the :- true 1 2 false multi line in code sent to the LaserWriter. CAVEATS: If you have a proprietary font in you path or your clippath then the path will be lost when one of the overlayed operators is used. If you need the font in the path then either stop the overloading of that operator and assume its effect won't be used across logical page boundaries or change the postscript you are "multi-ing" to refer to the systemdict version of the operators where the effect is not used across page boundaries. EG: CHANGE (FRED true charpath gsave fill grestore stroke TO (FRED) true charpath systemdict begin gsave end fill systemdict begin grestore end stroke OR remove the overloading of gsave/grestore from multi.ps More memory is consumed than normal output Direct references to operators through "systemdict" will circumvent overlays Programs which rely on the overlayed named being operators and not procedures will fail. For example:- /showpage { showpage } bind def will create an infinite loop when showpage is called. Also procedures directly on the stack do not execute unlike operators so the program:- /s [ /showpage load ] cvx def s will not work ( an "exec" is required after the "load") Device changing operators such as "letter", etc are mapped to null procedures SHAR_EOF fi exit 0 # End of shell archive -- ________________________________________________________________________ Ross Rodney Cartlidge | rossc@extro.ucc.su.oz.au University Computing Service, H08 | Phone: +61 2 6923497 University of Sydney, NSW 2006, Australia | FAX: +61 2 6606557 From: kai@nada.kth.se (Kai-Mikael J{{-Aro) Subject: This is mpage : This is a shar archive. Extract with sh, not csh. : This archive ends with exit, so do not worry about trailing junk. echo 'Extracting CHANGES' sed 's/^X//' > CHANGES << '+ END-OF-FILE CHANGES' XMany changes have been made between Version 1 and Version 2: X X- *BIGGIE* Printing of backspaces, overwrites, formfeeds and other Xtext is greatly improved. I changed the whole way text was processed Xand the code went from 3 unreadable pages to one very readable page. XIt is amazing what the right approch can do. X X- *ANOTHER BIGGIE* PostScript documents can now be printed. Most Xconforming will be properly printed, multple pages per sheet. There Xis still clean up to do here, but it seems to work. I think that when XI hit upon the right paradigm for this, it will clean up just like the Xtext processing code did. (XRef: TODO) X X- Outlines are now optional. If you like to see them (as I do) put the X"-o" option in your MPAGE environment variable. X X- Added recognition of the PRINTER and MPAGE environment variables. X X- Added the beginnings of support the European A4 paper. (The method Xshould be extended to legal sized paper.) Credit goes to Michael XFingerhut, System Manager, IRCAM Paris (France), (...!uunet!ircam!mf) Xfor the inspiration for the proper way to do this. X X- MPage now prints a message stating how many pages (sheets) were Xcreated and to which printer it was spooled. X X- Stuffed the sources under RCS to keep track of changes. X + END-OF-FILE CHANGES chmod 'u=rw,g=rw,o=r' 'CHANGES' echo ' -rw-rw-r-- 1 kai 1249 Jan 1 1990 CHANGES (as sent)' echo -n ' ' /bin/ls -l CHANGES echo 'Extracting MANIFEST' sed 's/^X//' > MANIFEST << '+ END-OF-FILE MANIFEST' X File Name Archive # Description X---------------------------------------------------------- X README 1 Notes and descriptions X MANIFEST 1 This shipping list X CHANGES 1 Changes since Version 1 X Makefile.mpage 2 The Makefile X TODO 2 Wish List for changes X mp_args.c 2 Command line and options processing X mp_file.c 1 Generic file handeling X mp_glob.c 1 Global variable setup X mp_head.h 1 Definitions X mp_main.c 2 Main Control X mp_page.c 2 Page layout routines X mp_post.c 1 PostScript file processing X mp_sample.c 2 Prints sample page layout pages X mp_text.c 1 Text file processing X mpage.1 2 Manual page X + END-OF-FILE MANIFEST chmod 'u=rw,g=rw,o=r' 'MANIFEST' echo ' -rw-rw-r-- 1 kai 867 Jan 1 1990 MANIFEST (as sent)' echo -n ' ' /bin/ls -l MANIFEST echo 'Extracting Makefile.mpage' sed 's/^X//' > Makefile.mpage << '+ END-OF-FILE Makefile.mpage' X# X# $Header: Makefile,v 1.3 89/05/25 09:06:55 mark Exp $ X# XHEAD = mp_head.h XSRCS = mp_main.c mp_glob.c mp_text.c mp_post.c mp_file.c mp_page.c mp_args.c XMOBJ = mp_main.o mp_glob.o mp_text.o mp_post.o mp_file.o mp_page.o mp_args.o XSMPL = mp_sample.c mp_page.c mp_glob.c mp_args.c XSOBJ = mp_sample.o mp_page.o mp_glob.o mp_args.o X X X#CFLAGS = -gx -DDEBUG XCFLAGS = -gx X X.SUFFIXES: .c,v X Xdefault: mpage msample Makefile.mpage X @echo Done! X Xmpage: $(MOBJ) X $(CC) $(CFLAGS) -o mpage $(MOBJ) X Xmsample: $(SOBJ) X $(CC) $(CFLAGS) -o msample $(SOBJ) X XMakefile.mpage: Makefile X Xclean: X rm -rf $(MOBJ) mpage mpage.ps X Xmp_main.o: $(HEAD) mp_main.c X $(CC) -c $(CFLAGS) mp_main.c X Xmp_glob.o: $(HEAD) mp_glob.c X $(CC) -c $(CFLAGS) mp_glob.c X Xmp_text.o: $(HEAD) mp_text.c X $(CC) -c $(CFLAGS) mp_text.c X Xmp_post.o: $(HEAD) mp_post.c X $(CC) -c $(CFLAGS) mp_post.c X Xmp_file.o: $(HEAD) mp_file.c X $(CC) -c $(CFLAGS) mp_file.c X Xmp_page.o: $(HEAD) mp_page.c X $(CC) -c $(CFLAGS) mp_page.c X Xmp_args.o: $(HEAD) mp_args.c X $(CC) -c $(CFLAGS) mp_args.c X Xmp_sample.o: $(HEAD) X $(CC) -c $(CFLAGS) $*.c X Xmpage.ps: mpage.1 X psroff -t -man mpage.1 > mpage.ps X X X# add your proper install stuff Xinstall: X + END-OF-FILE Makefile.mpage chmod 'u=rw,g=rw,o=r' 'Makefile.mpage' echo ' -rw-rw-r-- 1 kai 1173 Jan 1 1990 Makefile.mpage (as sent)' echo -n ' ' /bin/ls -l Makefile.mpage echo 'Extracting README' sed 's/^X//' > README << '+ END-OF-FILE README' X XCOPYRIGHT: X XMpage and all the files distributed with mpage are covered by copyright: X X Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia X X Permission is granted to anyone to make or distribute verbatim X copies of this document as received, in any medium, provided X that this copyright notice notice is preserved, and that the X distributor grants the recipient permission for further X redistribution as permitted by this notice. X XMpage was written by: X ...!uunet!\ Mark Hahn, Sr Systems Engineer X >pyrdc!mark Pyramid Technology Corporation X ...!pyramid!/ Vienna, Va (703)848-2050 X X X X******************** Important Notice **************************** X XI am moving to Seoul, Korea in about 2 days. As such any claims Xthat I might have a couple minutes to spare to work on improvments Xor repairs should be reduced accordingly. While there are still Xa number of changes I would like to make, I just don't have the Xtime. They will have to wait. However, I still solicit your input Xso that if I have time, I will do what I can. I don't know my Xnew net address or postal address, but mail sent to the above will Xbe forwarded on an irregular schedule. X X**************** End Of Important Notice ************************* X XDESCRIPTION: X XMpage is a program to reduce and print multiple pages of text per Xsheet on a PostScript compatible printer. X XThe following are the files you should have for mpage. X X MANIFEST The shipping list X README Notes and descriptions X CHANGES Changes since Version 1 X Makefile.mpage The Makefile X TODO Wish List for changes X mp_args.c Command line and options processing X mp_file.c Generic file handeling X mp_glob.c Global variable setup X mp_head.h Definitions X mp_main.c Main Control X mp_page.c Page layout routines X mp_post.c PostScript file processing X mp_sample.c Prints sample page layout pages X mp_text.c Text file processing X mpage.1 Manual page X X X XINSTRUCTIONS: X XAll you should need to do is copy Makefile.mpage to Makefile and run Xmake. This will create mpage and a program called msample. Mpage is Xthe program to print n-up pages. Msample prints a sample outline. I Xused it for debugging the placement of the layout. It is also handy Xfor other layout purposes. It accepts all the arguments that mpage Xdoes, but does not print files. X XAs a quick sample try: X X "mpage -p mp_args.c" Xor X "mpage -p8 mp_post.c" Xor X "psroff -t -man mpage.1 | mpage -2" X XThe manual page, mpage.1, formats with UCB or ATT manual macros. X XThe spooler interface in mpage only submits to a UCB style spooler. It Xshouldn't take too much work to convert to submission to a ATT style Xspooler. X X X XUSING MPAGE: X XYou will find that it takes a while on an Apple LW or Apple LW+ to Xprint 4 pages per sheet, It takes "a good long time" for 8 pages. XReduced PostScript documents take a while too. (A rule of thumb might Xbe 4 times as long for 4-pages-per-sheet reduction :-) On a QMS 8ppm Xprinter 4 pages per sheet is about the same speed and other forms of X"1-up" output. mpage prints some timing information back from the Xprinter so you can measure the time required for full jobs. X X X XADMINSITRATORS: X XAs a printer administrator you should see the wish list for caveats Xand information about future versions. I still have work to do to Xmake mpage more "administrator friendly", but figured that I'd better Xget what's been done out the door. The alternative is to constanly Xmake changes and never release anything. X X X XBUG REPORTS: X XMpage is not a supported program. I do not have the time or resources Xto maintain mpage. I am interested in receiving reports of problems Xso that which I get spare time I can try to fix them. If you have a Xproblem please send me a complete, succinct description of the Xsymptoms. Please include the brand name of your printer, a copy of Xthe input file (especially if it is with PostScript input), and a Xdescription of what to look for on the output. If your printer has an Xerror log, please include as much of it as is revalant. In general, Xthe more clearly organized information I have, the easier it will be Xfor me. X X X XMAKING CHANGES: X XPlease, if you make any improvements, send them back to me so that I Xcan include them in future versions. Also I would solicit comments as Xto the usefulness, and effectiveness of mpage. Let me know what you Xlike or dislike and feel free to ask any questions you have concerning Xthis mpage distribution. Thank you, Mark Hahn. X + END-OF-FILE README chmod 'u=rw,g=rw,o=r' 'README' echo ' -rw-rw-r-- 1 kai 4768 Jan 1 1990 README (as sent)' echo -n ' ' /bin/ls -l README echo 'Extracting TODO' sed 's/^X//' > TODO << '+ END-OF-FILE TODO' XCurrent Wish List: X X X- Should print a help string when invoked as "mpage". However, like Xcat(1), I chose to default to processing standard input when no files Xare specified. I will change this so that the file "-" refers to Xstandard input and hence you will have to type something like: X ls -Rl | mpage -8 - XMore thought is required here. (you comments solicited) X X X- Add support for handeling ATT style spoolers. Or any type spooler. XShouldn't be that difficult. X X X- Support for reducing mpage output. I.E. if I do: X mpage -8P file.txt | mpage -8 XI should get 64-up output. Problems are that the PostScript code Xproduced is not "recursive". The end-of-page macro in particular Xsuffers under re-definition, you get blank pages. Another problems is Xresolution of the printer. See the next Wish item. X X X- Better handeling of PostScript input. The current stuff works, but Xit is not general enough. I am currently learning more here, thanks Xto the "Green Book" and will work on a cleaner parser for Version 3. X(Oh-my-goodness, a pre-announcement ;-) X XPerhaps I should convert the whole PostScript processing routing to be Xa "Finite Automata". Each line will represent a "token" parsed by its Xcomment, output will be based upon transitions from state to state. XThe automata should allow states and transitions to be added dynamicly Xso that we can adapt to differening structure conventions, and Xdiffering PostScript code generators (psdit, dvi2ps, etc ...) X X X- Fix A4 paper handeling. X X X- Add better timing information, possible adding command line Xarguments to control the amount of timing information added to the Xfile. (Eyuk, more arguments:-( X X X- Lots more, I'm sure. X + END-OF-FILE TODO chmod 'u=rw,g=rw,o=r' 'TODO' echo ' -rw-rw-r-- 1 kai 1685 Jan 1 1990 TODO (as sent)' echo -n ' ' /bin/ls -l TODO echo 'Extracting mp_args.c' sed 's/^X//' > mp_args.c << '+ END-OF-FILE mp_args.c' X# include <stdio.h> X# include <sys/types.h> X X# ifndef lint Xstatic char *rcs_id = X "@(#) $Header: mp_args.c,v 2.6 89/05/25 15:43:07 mark Exp $"; X# endif X X# include "mp_head.h" X X/* X * mpage: a program to reduce pages of print so that several pages X * of output appear on one printed page. X * X * Written by: X * ...!uunet!\ Mark Hahn, Sr Systems Engineer X * >pyrdc!mark Pyramid Technology Corporation X * ...!pyramid!/ Vienna, Va (703)848-2050 X * X * X * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia X * X * Permission is granted to anyone to make or distribute verbatim X * copies of this document as received, in any medium, provided X * that this copyright notice notice is preserved, and that the X * distributor grants the recipient permission for further X * redistribution as permitted by this notice. X * X */ X X/* $Log: mp_args.c,v $ X * Revision 2.6 89/05/25 15:43:07 mark X * added the -b options as a converse to the -o option. X * X * Revision 2.5 89/05/25 10:42:39 mark X * changes to print a page count on stderr after the print job is queued. X * X * Revision 2.4 89/05/25 08:57:47 mark X * rearranged the rcs header keywords for better readability. X * X * Revision 2.3 89/05/22 14:41:03 mark X * Fixed the type-o in the rcs identification string X * X * Revision 2.2 89/05/22 14:38:06 mark X * Added rcs identification usable with the "what" program X * X * Revision 2.1 89/05/22 14:31:29 mark X * New Major Revision X * X * Revision 1.1 89/05/22 14:25:29 mark X * Initial revision X * */ X Xdo_args(argc, argv, envflag) X int argc; X char **argv; X int envflag; X{ X char *optstr; X int consumed; X int currarg; X int opterrors; X X opterrors = 0; X for (currarg = 1; currarg < argc; currarg++) { X if (*argv[currarg] != '-') { X if (envflag) { X opterrors++; X } X break; X } X optstr = argv[currarg]; X consumed = 0; X while (*++optstr && ! consumed) { X switch (*optstr) { X default: X fprintf(stderr,"%s: unknown option -%c\n", X MPAGE, *optstr); X opterrors++; X break; X case '1': X sheetindex = 0; X break; X case '2': X sheetindex = 1; X break; X case '4': X sheetindex = 2; X break; X case '8': X sheetindex = 3; X break; X case 'A': /* A4 sized, european paper */ X opt_a4 = 1; X set_page(); X break; X case 'a': /* across */ X sheetorder = LEFTRIGHT; X break; X case 'h': X ++optstr; X opt_doheader = 1; X (void)strcpy(opt_header, optstr); X consumed = 1; X break; X case 'L': X ++optstr; X opt_lines = atoi(optstr); X consumed = 1; X break; X case 'l': /* landscape */ X sheetaspect = LANDSCAPE; X break; X case 'n': /* normal */ X sheetaspect = NORMAL; X break; X case 'o': /* print outlines */ X opt_outline = 1; X break; X case 'b': /* don't print outlines */ X opt_outline = 0; X break; X case 'P': /* Printer */ X ++optstr; X (void) strcpy(printer, optstr); X consumed = 1; X break; X case 'p': /* pr */ X opt_pr++; X break; X case 's': /* silent (don't print page count) */ X opt_verbose = 0; X break; X case 'u': /* updown */ X sheetorder = UPDOWN; X break; X case 'v': /* verbose (print page count) */ X opt_verbose = 1; X break; X case 'W': X ++optstr; X opt_width = atoi(optstr); X consumed = 1; X break; X } X } X } X if (opterrors) { X return -1; X } X return currarg; X} X Xdo_env() X{ X int argc; X char **argv, **slice(); X char copy[LINESIZE]; X char *env, *getenv(); X X env = getenv("PRINTER"); X if (env) { X strcpy(printer, env); X } X X env = getenv("MPAGE"); X if (env) { X strcpy(copy, env); X argv = slice(copy, &argc); X if (do_args(argc, argv, 1) < 0) { X fprintf(stderr, "%s: error in envronment \"%s\"\n", X MPAGE, env); X return 0; X } X } X return 1; X} X Xchar *slc_argv[20]; X Xchar **slice(string, cntp) X char *string; X int *cntp; X{ X int count; X X /* X * mimic the shell for conformity X */ X slc_argv[0] = MPAGE; X count = 1; X /* X * while there are still characters to be processed X */ X while (*string) { X /* X * skip any leading or leftover white space X */ X while (*string == ' ') { X string++; X } X /* X * make sure we had more than just white space before X * we believe we actually have an argument X */ X if (*string) { X /* X * point the next slot in argv to this string X */ X slc_argv[count] = string; X count += 1; X /* X * and go looking for the end of this string X * which is delienated by a space or NULL X */ X while (*string && *string != ' ') { X string++; X } X /* X * if this not the end of the string, then convert X * the space into a NULL and move forward one byte. X * if this is the end of the string, we already have X * a suitable NULL byte for the string and it also X * drops us out of all the loops X */ X if (*string) { X *string = 0; X string++; X } X } X } X /* X * return the count via the integer pointer we were given X * and put a null pointer into the argv array for conformity X */ X slc_argv[count] = 0; X *cntp = count; X return slc_argv; X} X + END-OF-FILE mp_args.c chmod 'u=rw,g=rw,o=r' 'mp_args.c' echo ' -rw-rw-r-- 1 kai 5081 Jan 1 1990 mp_args.c (as sent)' echo -n ' ' /bin/ls -l mp_args.c echo 'Extracting mp_file.c' sed 's/^X//' > mp_file.c << '+ END-OF-FILE mp_file.c' X# include <stdio.h> X# include <sys/types.h> X X# ifndef lint Xstatic char *rcs_id = X "@(#) $Header: mp_file.c,v 2.4 89/05/25 08:58:18 mark Exp $"; X# endif X X# include "mp_head.h" X X/* X * mpage: a program to reduce pages of print so that several pages X * of output appear on one printed page. X * X * Written by: X * ...!uunet!\ Mark Hahn, Sr Systems Engineer X * >pyrdc!mark Pyramid Technology Corporation X * ...!pyramid!/ Vienna, Va (703)848-2050 X * X * X * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia X * X * Permission is granted to anyone to make or distribute verbatim X * copies of this document as received, in any medium, provided X * that this copyright notice notice is preserved, and that the X * distributor grants the recipient permission for further X * redistribution as permitted by this notice. X * X */ X X/* $Log: mp_file.c,v $ X * Revision 2.4 89/05/25 08:58:18 mark X * rearranged the rcs header keywords for better readability. X * X * Revision 2.3 89/05/22 14:40:59 mark X * Fixed the type-o in the rcs identification string X * X * Revision 2.2 89/05/22 14:38:02 mark X * Added rcs identification usable with the "what" program X * X * Revision 2.1 89/05/22 14:31:24 mark X * New Major Revision X * X * Revision 1.1 89/05/22 14:23:34 mark X * Initial revision X * */ X X/* X * do_file converts one file into postscript for output. The file type is X * determined then the proper conversion routine is selected. X */ Xdo_file(fname, asheet, outfd) X char *fname; X struct sheet *asheet; X FILE *outfd; X{ X FILE *fd; X int firstchr; X X /* X * if we have the pr option, then we have to assume it's a text file X */ X if (opt_pr) { X do_pr_file(fname, asheet, outfd); X return; X } X /* X * if not using pr(1), open fname and try to figure out what type of X * file it is X */ X if ((fd = fopen(fname, "r")) == NULL) { X fprintf(stderr, "%s: cannot open %s\n", X MPAGE, fname); X perror(MPAGE); X return; X } X /* X * check for the cutomary characters that flag a postscript file X */ X if (ps_check(fd)) { X /* X * found the flag signaling PS input X */ X do_ps_doc(fd, asheet, outfd); X } else { X /* X * no postscript flag, print the ascii text X */ X do_text_doc(fd, asheet, outfd); X } X (void)fclose(fd); X} X X/* X * do_file processes one text file into postscript, but first runs the file X * through pr(1). X */ Xdo_pr_file(fname, asheet, outfd) X char *fname; X struct sheet *asheet; X FILE *outfd; X{ X FILE *fd; X char command[LINESIZE]; X X /* X * build the proper command based upon a specified X * header or not X */ X if (opt_doheader) { X (void)sprintf(command, "pr -l%d -w%d -h \"%s\" %s", X asheet->sh_plength, asheet->sh_cwidth, X opt_header, fname); X } else { X (void)sprintf(command, "pr -l%d -w%d %s", X asheet->sh_plength, asheet->sh_cwidth, X fname); X } X /* X * open a pipe to the proper pr(1) command, and pr provides X * us with the input X */ X if ((fd = popen(command, "r")) == NULL) { X fprintf(stderr, "%s: cannot create pipe for '%s'\n", X command); X perror(MPAGE); X } else { X do_text_doc(fd, asheet, outfd); X (void)pclose(fd); X } X} X X/* X * do_stdin uses do_????_doc to process the standard input X */ Xdo_stdin(asheet, outfd) X struct sheet *asheet; X FILE *outfd; X{ X FILE *fd; X char command[LINESIZE]; X char tmpfile[LINESIZE]; X char buffer[LINESIZE]; X int incnt, outcnt; X X if (opt_pr) { X Debug(DB_STDIN, "%%do_stdin: pr option selects text\n", 0); X /* X * if pr(1) is to be used we need to read the input X * and pass it to a pr(1) command which will write X * a temporary file; this temporary file will then X * be used as input to the do_doc routine X */ X (void)strcpy(tmpfile, "/usr/tmp/mpageXXXXXX"); X (void)mktemp(tmpfile); X if (opt_doheader) { X (void)sprintf(command, "pr -l%d -w%d -h \"%s\"> %s", X asheet->sh_plength, asheet->sh_cwidth, X opt_header, tmpfile); X } else { X (void)sprintf(command, "pr -l%d -w%d > %s", X asheet->sh_plength, asheet->sh_cwidth, X tmpfile); X } X /* X * open a pipe to the pr(1) command which will create a X * temporary file for convertin into PS X */ X if ((fd = popen(command, "w")) == NULL) { X fprintf(stderr, "%s: cannot create pipe for '%s'\n", X command); X perror(MPAGE); X return; X } X#ifdef DEBUG X errno = 0; X Debug(DB_STDIN, "%% sizeof buffer == %d\n", sizeof buffer); X#endif X /* X * read input to mpage and pass it onto the pr(1) command X */ X do { X incnt = fread(buffer, 1, sizeof buffer, stdin); X outcnt = fwrite(buffer, 1, incnt, fd); X Debug(DB_STDIN, "%% incnt == %d,", incnt); X Debug(DB_STDIN, " outcnt == %d,", outcnt); X Debug(DB_STDIN, " errno == %d\n", errno); X } while (incnt && outcnt); X Debug(DB_STDIN, "%% Done with while\n", 0); X (void)pclose(fd); X Debug(DB_STDIN, "%% closed pipe, looking for tmpfile\n", 0); X /* X * now open the temporary file and use do_doc to X * convert it to PS X */ X if ((fd = fopen(tmpfile, "r")) == NULL) { X fprintf(stderr, "%s: cannot open %s\n", X MPAGE, tmpfile); X perror(MPAGE); X } else { X Debug(DB_STDIN, "%% got tmpfile, now do_doc\n", 0); X do_text_doc(fd, asheet, outfd); X (void)fclose(fd); X } X /* X * tidy up by removing our temp file X */ X Debug(DB_STDIN, "%% now remove '%s'\n", tmpfile); X (void)unlink(tmpfile); X } else { X /* X * check for the cutomary flag at the start of postscript files X */ X if (ps_check(stdin)) { X /* X * found the flag signaling PS input X */ X Debug(DB_STDIN, "%%do_stdin: is postscript\n", 0); X do_ps_doc(stdin, asheet, outfd); X } else { X /* X * no postscript flag, print the ascii text X */ X Debug(DB_STDIN, "%%do_stdin: not postscript\n", 0); X do_text_doc(stdin, asheet, outfd); X } X } X} X X X + END-OF-FILE mp_file.c chmod 'u=rw,g=rw,o=r' 'mp_file.c' echo ' -rw-rw-r-- 1 kai 5779 Jan 1 1990 mp_file.c (as sent)' echo -n ' ' /bin/ls -l mp_file.c echo 'Extracting mp_glob.c' sed 's/^X//' > mp_glob.c << '+ END-OF-FILE mp_glob.c' X# include <stdio.h> X# include <sys/types.h> X X# ifndef lint Xstatic char *rcs_id = X "@(#) $Header: mp_glob.c,v 2.7 89/08/09 11:44:01 mark Exp $"; X# endif X X# include "mp_head.h" X X/* X * mpage: a program to reduce pages of print so that several pages X * of output appear on one printed page. X * X * Written by: X * ...!uunet!\ Mark Hahn, Sr Systems Engineer X * >pyrdc!mark Pyramid Technology Corporation X * ...!pyramid!/ Vienna, Va (703)848-2050 X * X * X * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia X * X * Permission is granted to anyone to make or distribute verbatim X * copies of this document as received, in any medium, provided X * that this copyright notice notice is preserved, and that the X * distributor grants the recipient permission for further X * redistribution as permitted by this notice. X * X */ X X/* $Log: mp_glob.c,v $ X * Revision 2.7 89/08/09 11:44:01 mark X * change the defaults so that outlines are normally printed X * X * Revision 2.6 89/05/25 10:42:37 mark X * changes to print a page count on stderr after the print job is queued. X * X * Revision 2.5 89/05/25 09:50:29 mark X * turned off all debugging. X * X * Revision 2.4 89/05/25 08:58:21 mark X * rearranged the rcs header keywords for better readability. X * X * Revision 2.3 89/05/22 14:40:49 mark X * Fixed the type-o in the rcs identification string X * X * Revision 2.2 89/05/22 14:37:51 mark X * Added rcs identification usable with the "what" program X * X * Revision 2.1 89/05/22 14:31:18 mark X * New Major Revision X * X * Revision 1.1 89/05/22 14:21:16 mark X * Initial revision X * */ X X/* X * to turn on debugging, define the preprocessor macro DEBUG and set X * the variable Debug_flag to the sum of the sections to debug. X */ X# ifdef DEBUG Xint Debug_flag = DB_PSMPAGE; X# endif DEBUG X X/* X * some basic PS parameters X */ Xint ps_width = 612; /* number of points in the X direction (8.5 inches) */ Xint ps_height = 792; /* number of points in the Y direction (11 inches) */ X X/* X * outlines for various page orientations and number of output pages to X * put on printed pages X */ Xint outline_1(); Xint outline_2(); Xint outline_4(); Xint outline_8(); X X/* X * the structures describe where to put the reduced pages of output on the X * printed page. X */ X/* base point for one page, normal aspect */ Xstruct pagepoints one_normal[] = { X { xbase1, ybase1 }, X { 0, 0 } X}; X/* base points for two pages, normal aspect */ Xstruct pagepoints two_normal[] = { X { xbase1, ytop4 }, { xbase1 , ytop2 }, X { 0, 0 } X}; X/* base points for four pages, normal aspect, running reduced pages X * read from left to right */ Xstruct pagepoints lr_four_normal[] = { X { xbase1, ybase3 }, { xbase2, ybase3 }, X { xbase1, ybase1 }, { xbase2, ybase1 }, X { 0, 0 } X}; X/* base points for four pages, normal aspect, running reduced pages X * read from top to bottom (up/down) */ Xstruct pagepoints ud_four_normal[] = { X { xbase1, ybase3 }, { xbase1, ybase1 }, X { xbase2, ybase3 }, { xbase2, ybase1 }, X { 0, 0 } X}; X/* base points for eight pages, normal aspect, running reduced pages X * read from left to right */ Xstruct pagepoints lr_eight_normal[] = { X { xbase2, ytop4 }, { xbase2, ytop3 }, X { xbase2, ytop2 }, { xbase2, ytop1 }, X { xbase1, ytop4 }, { xbase1, ytop3 }, X { xbase1, ytop2 }, { xbase1, ytop1 }, X { 0, 0 } X}; X/* base points for eight pages, normal aspect, running reduced pages X * read from top to bottom (up/down) */ Xstruct pagepoints ud_eight_normal[] = { X { xbase2, ytop4 }, { xbase1, ytop4 }, X { xbase2, ytop3 }, { xbase1, ytop3 }, X { xbase2, ytop2 }, { xbase1, ytop2 }, X { xbase2, ytop1 }, { xbase1, ytop1 }, X { 0, 0 } X}; X/* base point for one page, in landscape */ Xstruct pagepoints one_landscape[] = { X { xbase1, ytop4 }, X { 0, 0 } X}; X/* base points for two pages, in landscape */ Xstruct pagepoints two_landscape[] = { X { xbase1, ybase3 }, { xbase1, ybase1 }, X { 0, 0 } X}; X/* base points for four pages, in landscape, running reduced pages X * read from left to right */ Xstruct pagepoints lr_four_landscape[] = { X { xbase2, ytop4 }, { xbase2, ytop2 }, X { xbase1, ytop4 }, { xbase1, ytop2 }, X { 0, 0 } X}; X/* base points for four pages, in landscape, running reduced pages X * read from top to bottom (up/down) */ Xstruct pagepoints ud_four_landscape[] = { X { xbase2, ytop4 }, { xbase1, ytop4 }, X { xbase2, ytop2 }, { xbase1, ytop2 }, X { 0, 0 } X}; X/* base points for eight pages, in landscape, running reduced pages X * read from left to right */ Xstruct pagepoints lr_eight_landscape[] = { X { xbase1, ybase4 }, { xbase2, ybase4 }, X { xbase1, ybase3 }, { xbase2, ybase3 }, X { xbase1, ybase2 }, { xbase2, ybase2 }, X { xbase1, ybase1 }, { xbase2, ybase1 }, X { 0, 0 } X}; X/* base points for eight pages, in landscape, running reduced pages X * read from top to bottom (up/down) */ Xstruct pagepoints ud_eight_landscape[] = { X { xbase1, ybase4 }, { xbase1, ybase3 }, X { xbase1, ybase2 }, { xbase1, ybase1 }, X { xbase2, ybase4 }, { xbase2, ybase3 }, X { xbase2, ybase2 }, { xbase2, ybase1 }, X { 0, 0 } X}; X X/* list of sheets (printed page formats) for X * left to right reading, in normal aspect */ Xstruct sheet lr_normal[] = { X/* 0 */ 80, 66, xwid1, yht1, 0, outline_1, one_normal, X/* 1 */ 80, 66, yht2, xwid1, -90, outline_2, two_normal, X/* 2 */ 80, 66, xwid2, yht2, 0, outline_4, lr_four_normal, X/* 3 */ 80, 66, yht4, xwid2, -90, outline_8, lr_eight_normal, X}; X X/* list of sheets (printed page formats) for X * top to bottom reading, in normal aspect */ Xstruct sheet ud_normal[] = { X/* 0 */ 80, 66, xwid1, yht1, 0, outline_1, one_normal, X/* 1 */ 80, 66, yht2, xwid1, -90, outline_2, two_normal, X/* 2 */ 80, 66, xwid2, yht2, 0, outline_4, ud_four_normal, X/* 3 */ 80, 66, yht4, xwid2, -90, outline_8, ud_eight_normal, X}; X X/* list of sheets (printed page formats) for X * left to right reading, in landscape */ Xstruct sheet lr_landscape[] = { X/* 0 */ 132, 52, yht1, xwid1, -90, outline_1, one_landscape, X/* 1 */ 132, 52, xwid1, yht2, 0, outline_2, two_landscape, X/* 2 */ 132, 52, yht2, xwid2, -90, outline_4, lr_four_landscape, X/* 3 */ 132, 52, xwid2, yht4, 0, outline_8, lr_eight_landscape, X}; X X/* list of sheets (printed page formats) for X * top to bottom reading, in landscape */ Xstruct sheet ud_landscape[] = { X/* 0 */ 132, 52, yht1, xwid1, -90, outline_1, one_landscape, X/* 1 */ 132, 52, xwid1, yht2, 0, outline_2, two_landscape, X/* 2 */ 132, 52, yht2, xwid2, -90, outline_4, ud_four_landscape, X/* 3 */ 132, 52, xwid2, yht4, 0, outline_8, ud_eight_landscape, X}; X X/* array of sheet lists for left to right reading printed pages */ Xstruct sheet *left_right[] = { X lr_normal, X lr_landscape X }; X X/* arrays for top to bottom reading printed pages */ Xstruct sheet *up_down[] = { X ud_normal, X ud_landscape X }; X X/* X * Variables for holding the chosen options, The defaults are set here. X * the sheetlist pointer is set to point to the array for either up/down X * or left/right reading. This array is index by sheetorder, and then X * sheetindex. sheetindex encodes the number of reduced pages per printed X * page and indexes into the sheet list (0 = 1 page, 1 = two pages, 2 = X * four pages, 3 = eight pages). X */ Xstruct sheet **sheetlist;/* array of sheet lists (up/down or left/right) */ Xint sheetaspect = NORMAL;/* either normal or landscape */ Xint sheetorder = UPDOWN;/* up/down or left/right flag */ Xint sheetindex = 2; /* index to number of pages of output per printed */ Xint pg_sheetmargin = 20;/* non-printable border on sheet */ Xint pg_pagemargin = 4; /* border for pages */ Xint fsize = 12; /* font scale size */ Xint opt_pr = 0; /* boolean, if true use pr(1) to format output */ Xint opt_lines = 0; /* number of lines to fit on an reduced page */ Xint opt_width = 0; /* number of columns to fit on an reduced page */ Xint opt_doheader = 0; /* have a head for pr's -h option */ Xint opt_a4 = 0; /* default to US paper */ Xint opt_outline = 1; /* don't normally outline the pages */ Xint opt_verbose = 1; /* by default, print a count of pages produced */ Xchar opt_header[LINESIZE]; /* the header for pr's -h option */ Xchar outcommand[LINESIZE]; /* the command which is the output filter */ X# ifndef DEBUG Xchar printer[LINESIZE] = "PostScript"; /* the printer(argument to lpr -P??) */ X# else Xchar printer[LINESIZE] = ""; /* the printer (argument to lpr -P??) */ X# endif DEBUG X/* X * various global information X */ Xchar MPAGE[] = "mpage"; /* program name */ Xint ps_pagenum = 0; /* current page count */ Xchar usage[] = /* usage string */ X"mpage [-aulnp1248] [-Llines] [-Wwidth] [-hheader] [-Pprinter] [files...]\n"; X + END-OF-FILE mp_glob.c chmod 'u=rw,g=rw,o=r' 'mp_glob.c' echo ' -rw-rw-r-- 1 kai 8638 Jan 1 1990 mp_glob.c (as sent)' echo -n ' ' /bin/ls -l mp_glob.c echo 'Extracting mp_head.h' sed 's/^X//' > mp_head.h << '+ END-OF-FILE mp_head.h' X/* $Header: mp_head.h,v 2.8 89/05/25 10:42:07 mark Exp $ */ X X/* X * mpage: A program to reduce pages of print so that several pages X * of output appear on one sheet of paper. X * X * Written by: X * ...!uunet!\ Mark Hahn, Sr Systems Engineer X * >pyrdc!mark Pyramid Technology Corporation X * ...!pyramid!/ Vienna, Va (703)848-2050 X * X * X * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia X * X * Permission is granted to anyone to make or distribute verbatim X * copies of this document as received, in any medium, provided X * that this copyright notice notice is preserved, and that the X * distributor grants the recipient permission for further X * redistribution as permitted by this notice. X * X */ X X/* $Log: mp_head.h,v $ X * Revision 2.8 89/05/25 10:42:07 mark X * changes to print a page count on stderr after the print job is queued. X * X * Revision 2.7 89/05/25 10:25:13 mark X * add new debugging keyword for tracking the processing of postscript X * documents. X * X * Revision 2.6 89/05/25 10:23:17 mark X * fixed typo in rcs keyword X * */ X X/* X * Through-out the program comments I have tried to refer to pages a the X * logical printed page of text that gets reduced. Sheets refer to physical X * pieces of paper. Hence, mulitple pages appear on a sheet. "page" is a X * logical or virtual entity, and "sheet" is physical entity. X */ X Xchar *ctime(); XFILE *popen(); Xchar *strcpy(); Xchar *mktemp(); Xtime_t time(); X X# define TRUE 1 X# define FALSE 0 X X# define LINESIZE 1024 X X# define FILE_EOF 1 X# define FILE_MORE 2 X X# define LINE_MORE 5 X# define LINE_EOF_NOW 4 X# define LINE_EOF 3 X# define LINE_OVERPRINT 2 X# define LINE_BLANK 1 X X X/* X * to turn on debugging, define the preprocessor macro DEBUG and set X * the variable Debug_flag to the sum of the sections to debug. X */ X# ifdef DEBUG X# define Debug(f,s,a) if (Debug_flag & f) printf(s,a) X# define DB_GETLINE 0x0000001 X# define DB_ONEPAGE 0x0000002 X# define DB_STDIN 0x0000004 X# define DB_PSDOC 0x0000008 X# define DB_PSPAGE 0x0000010 X# define DB_PSCHECK 0x0000020 X# define DB_PSROFF 0x0000040 X# define DB_PSMPAGE 0x0000080 X# define DB_POINTS 0x0000100 X# define DB_POST 0x0000200 X# define DB_UNUSED 0x0000400 Xextern int Debug_flag; Xextern int errno; X# else DEBUG X# define Debug(f,s,a) X# endif DEBUG X X/* X * defintions for sorting out types of postscript input X */ X# define PS_NONE 0 X# define PS_PSROFF 1 X# define PS_MPAGE 2 X# define PS_CONFORM 3 X# define PS_OTHER 4 X X/* X * "Conforming" postscript flag string (remember ps_check strips X * the "%!" flag from PS files X */ X# define PS_FLAG "PS-Adobe-" X X/* X * some basic PS parameters X */ Xextern int ps_width; /* number of points in the X direction (8.5 inches) */ Xextern int ps_height; /* number of points in the Y direction (11 inches) */ X X/* X * a sheet describes the measurements and orientatation of a page for X * use in constructing a sheet preabmles. X */ Xstruct sheet { X int sh_cwidth; /* number of characters across a page */ X int sh_plength; /* number of lines down a page */ X int (*sh_width)(); /* postscript width across a printed page */ X int (*sh_height)(); /* postscript height of a printed page */ X int sh_rotate; /* angle to rotate the page */ X int (*sh_outline)(); /* text to print as outline for */ X /* the printed sheet*/ X struct pagepoints *sh_pagepoints; /* where to put pages on */ X /* the printed sheet */ X}; X X/* X * simple x and y coordinates for putting pages of output on printed sheet X */ Xstruct pagepoints { X int (*pp_origin_x)(); X int (*pp_origin_y)(); X}; X X/* array of sheets where pages are ordered for left to right reading */ Xextern struct sheet *left_right[]; X X/* arrays for sheets where pages are ordered for top to bottom reading */ Xextern struct sheet *up_down[]; X X/* definitions for aspect and reading directions */ X# define NORMAL 0 X# define LANDSCAPE 1 X# define UPDOWN 0 X# define LEFTRIGHT 1 X X/* X * Variables for holding the chosen options, The defaults are set here. X * the sheetlist pointer is set to point to the array for either up/down X * or left/right reading. This array is index by sheetorder, and then X * sheetindex. sheetindex encodes the number of reduced pages per printed X * sheet and indexes into the sheet list (0 = 1 page, 1 = two pages, 2 = X * four pages, 3 = eight pages). X */ Xextern struct sheet **sheetlist;/* array of sheet lists (up/down or left/right) */ Xextern int sheetaspect; /* either normal or landscape */ Xextern int sheetorder; /* up/down or left/right flag */ Xextern int sheetindex; /* index to number of pages of sheet */ Xextern int pg_sheetmargin; /* non-printable border on sheet */ Xextern int pg_pagemargin; /* border for pages */ Xextern int fsize; /* font scale size */ Xextern int opt_pr; /* boolean, if true use pr to format output */ Xextern int opt_lines; /* number of lines to fit on an reduced page */ Xextern int opt_width; /* number of columns to fit on reduced page */ Xextern int opt_doheader; /* have a head for pr's -h option */ Xextern int opt_a4; /* sheets are A4 sized, european paper */ Xextern int opt_outline; /* print a nice outline around pages */ Xextern int opt_verbose; /* print a count of pages sent to printer */ Xextern char opt_header[LINESIZE]; /* the header for pr's -h option */ Xextern char outcommand[LINESIZE]; /* the command which is the output filter */ Xextern char printer[LINESIZE]; /* the printer (argument to lpr -P??) */ X X/* X * various global information X */ Xextern char MPAGE[]; /* program name */ Xextern int ps_pagenum; /* current page count */ Xextern char usage[]; /* usage string */ X X/* X * function declarations for the page point computation functions X */ Xint xbase1(), xbase2(); Xint ybase1(), ybase2(), ybase3(), ybase4(); Xint ytop1(), ytop2(), ytop3(), ytop4(); Xint xwid1(), xwid2(), xwid4(), xwid8(); Xint yht1(), yht2(), yht4(), yht8(); X Xstatic char *rcs_header_id = X "@(#) $Header: mp_head.h,v 2.8 89/05/25 10:42:07 mark Exp $"; X + END-OF-FILE mp_head.h chmod 'u=rw,g=rw,o=r' 'mp_head.h' echo ' -rw-rw-r-- 1 kai 5988 Jan 1 1990 mp_head.h (as sent)' echo -n ' ' /bin/ls -l mp_head.h echo 'Extracting mp_main.c' sed 's/^X//' > mp_main.c << '+ END-OF-FILE mp_main.c' X# include <stdio.h> X# include <sys/types.h> X X# ifndef lint Xstatic char *rcs_id = X "@(#) $Header: mp_main.c,v 2.5 89/05/25 10:42:35 mark Exp $"; X# endif X X# include "mp_head.h" X X/* X * mpage: a program to reduce pages of print so that several pages X * of output appear on one printed page. X * X * Written by: X * ...!uunet!\ Mark Hahn, Sr Systems Engineer X * >pyrdc!mark Pyramid Technology Corporation X * ...!pyramid!/ Vienna, Va (703)848-2050 X * X * X * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia X * X * Permission is granted to anyone to make or distribute verbatim X * copies of this document as received, in any medium, provided X * that this copyright notice notice is preserved, and that the X * distributor grants the recipient permission for further X * redistribution as permitted by this notice. X * X */ X X/* $Log: mp_main.c,v $ X * Revision 2.5 89/05/25 10:42:35 mark X * changes to print a page count on stderr after the print job is queued. X * X * Revision 2.4 89/05/25 08:58:25 mark X * rearranged the rcs header keywords for better readability. X * X * Revision 2.3 89/05/22 14:40:28 mark X * Fixed the type-o in the rcs identification string X * X * Revision 2.2 89/05/22 14:37:30 mark X * Added rcs identification usable with the "what" program X * X * Revision 2.1 89/05/22 14:31:15 mark X * New Major Revision X * X * Revision 1.1 89/05/22 14:19:56 mark X * Initial revision X * */ X Xmain(argc,argv) X int argc; X char **argv; X{ X FILE *outfd; X int currarg; X struct sheet *thelist; X struct sheet *thesheet; X X /* X * examine the environment for PRINTER and MPAGE environment variables X */ X if (do_env() == 0) { X fprintf(stderr, usage, MPAGE); X exit(1); X } X X currarg = do_args(argc, argv, 0); X if (currarg < 0) { X fprintf(stderr, usage, MPAGE); X exit(1); X } X X /* X * if a printer was specified then create a lpr command using X * the specified printer, else output goes to standard out X */ X if (*printer) { X (void)sprintf(outcommand, "ucb /usr/ucb/lpr -P%s", printer); X if ((outfd = popen(outcommand, "w")) == NULL) { X fprintf(stderr, "%s: cannot create pipe for '%s'\n", X outcommand); X perror(MPAGE); X } X } else { X outfd = stdout; X } X X /* X * pick the array of sheet lists based upon the specified option X */ X if (sheetorder == UPDOWN) { X sheetlist = up_down; X } else { X sheetlist = left_right; X } X X /* X * from the array of sheet lists pick the proper sheet list for X * the given sheetaspect, then select the proper sheet format X * for the given number of redueced pages per output page X */ X thelist = sheetlist[sheetaspect]; X thesheet = &(thelist[sheetindex]); X X /* X * if either lines or columns were specified as options, over X * the default sheets idea of the number of line or cloumns X * per reduced page X */ X if (opt_lines > 0) { X thesheet->sh_plength = opt_lines; X } X if (opt_width > 0) { X thesheet->sh_cwidth = opt_width; X } X X /* X * if there are arguments left over after processing options, then X * these are names of files to process, else process the standard X * input X */ X if (currarg < argc) { X ps_title(argv[currarg], outfd); X for ( ;currarg < argc; currarg++) { X do_file(argv[currarg], thesheet, outfd); X } X } else { X ps_title("<stdin>", outfd); X do_stdin(thesheet, outfd); X } X /* X * having processed all input, print out a PS trailer X * (timeing stuff stolen from old adobe troff stuff) X */ X fprintf(outfd, "%%%%Trailer\n"); X fprintf(outfd, "statusdict begin jobname print flush"); X fprintf(outfd, " (: Job finished:\\n) print\n"); X fprintf(outfd, "(\\tmpage time (s) = ) print flush usertime "); X fprintf(outfd, "mp_stm sub 1000 div ==\n(\\tmpage pages = ) print "); X fprintf(outfd, "flush pagecount mp_pgc sub ==\nend flush\n"); X fprintf(outfd, "%%%%Pages: %d\n", ps_pagenum); X if (opt_verbose) { X fprintf(stderr, "[%s: %d pages, ", MPAGE, ps_pagenum); X if (*printer == 0) { X fprintf(stderr, "on <stdout>]\n"); X } else { X fprintf(stderr, "printer %s]\n", printer); X } X } X /* X * proper clean up to make sure the pipe is flushed X */ X if (*printer) { X (void)pclose(outfd); X } X return 0; X} X X/* X * ps_title prints a post script header suitable for PS processors X */ Xps_title(name, outfd) X char *name; X FILE *outfd; X{ X time_t curr_time; X char *time_str; X X fprintf(outfd, "%%!PS-Adobe-1.0\n"); X fprintf(outfd, "%%%%DocumentFonts: Courier\n"); X fprintf(outfd, "%%%%Title: %s (mpage)\n", name, MPAGE); X fprintf(outfd, "%%%%Creator: %s\n", MPAGE); X (void)time(&curr_time); X time_str = ctime(&curr_time); X fprintf(outfd, "%%%%CreationDate: %s",time_str); X fprintf(outfd, "%%%%Pages: (atend)\n"); X fprintf(outfd, "%%%%BoundingBox: 20 20 596 776\n"); X fprintf(outfd, "%%%%EndComments\n\n"); X fprintf(outfd, "/mp_stm usertime def\n"); X fprintf(outfd, "/mp_pgc statusdict begin pagecount end def\n"); X fprintf(outfd, "statusdict begin /jobname (%s) def end\n", name); X} X + END-OF-FILE mp_main.c chmod 'u=rw,g=rw,o=r' 'mp_main.c' echo ' -rw-rw-r-- 1 kai 4944 Jan 1 1990 mp_main.c (as sent)' echo -n ' ' /bin/ls -l mp_main.c echo 'Extracting mp_page.c' sed 's/^X//' > mp_page.c << '+ END-OF-FILE mp_page.c' X# include <stdio.h> X# include <sys/types.h> X X# ifndef lint Xstatic char *rcs_id = X "@(#) $Header: mp_page.c,v 2.4 89/05/25 08:58:28 mark Exp $"; X# endif X X# include "mp_head.h" X X/* X * mpage: a program to reduce pages of print so that several pages X * of output appear on one printed page. X * X * Written by: X * ...!uunet!\ Mark Hahn, Sr Systems Engineer X * >pyrdc!mark Pyramid Technology Corporation X * ...!pyramid!/ Vienna, Va (703)848-2050 X * X * X * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia X * X * Permission is granted to anyone to make or distribute verbatim X * copies of this document as received, in any medium, provided X * that this copyright notice notice is preserved, and that the X * distributor grants the recipient permission for further X * redistribution as permitted by this notice. X * X */ X X/* $Log: mp_page.c,v $ X * Revision 2.4 89/05/25 08:58:28 mark X * rearranged the rcs header keywords for better readability. X * X * Revision 2.3 89/05/22 14:41:01 mark X * Fixed the type-o in the rcs identification string X * X * Revision 2.2 89/05/22 14:38:04 mark X * Added rcs identification usable with the "what" program X * X * Revision 2.1 89/05/22 14:31:27 mark X * New Major Revision X * X * Revision 1.1 89/05/22 14:25:52 mark X * Initial revision X * */ X Xset_page() X{ X if (opt_a4) { X ps_width = 596; X ps_height = 842; X } else { X ps_width = 612; X ps_height = 792; X } X} X Xxbase1() X{ X Debug(DB_POINTS, "%%xbase1: %d\n", pg_sheetmargin + pg_pagemargin); X return pg_sheetmargin + pg_pagemargin; X} X Xxbase2() X{ X Debug(DB_POINTS, "%%xbase2: %d\n", (ps_width / 2) + pg_pagemargin); X return (ps_width / 2) + pg_pagemargin; X} X Xybase1() X{ X Debug(DB_POINTS, "%%ybase1: %d\n", pg_sheetmargin + pg_pagemargin); X return pg_sheetmargin + pg_pagemargin; X} X Xybase2() X{ X Debug(DB_POINTS, "%%ybase2: %d\n", X (((ps_height / 2) - pg_sheetmargin) / 2) X + pg_sheetmargin + pg_pagemargin); X return (((ps_height / 2) - pg_sheetmargin) / 2) X + pg_sheetmargin + pg_pagemargin; X} X Xybase3() X{ X Debug(DB_POINTS, "%%ybase3: %d\n", (ps_height / 2) + pg_pagemargin); X return (ps_height / 2) + pg_pagemargin; X} X Xybase4() X{ X Debug(DB_POINTS, "%%ybase4: %d\n", X (((ps_height / 2) - pg_sheetmargin) / 2) X + (ps_height / 2) + pg_pagemargin); X return (((ps_height / 2) - pg_sheetmargin) / 2) X + (ps_height / 2) + pg_pagemargin; X} X Xytop1() X{ X Debug(DB_POINTS, "%%ytop1: %d\n", ybase1() + yht4()); X return ybase1() + yht4(); X} X Xytop2() X{ X Debug(DB_POINTS, "%%ytop2: %d\n", ybase2() + yht4()); X return ybase2() + yht4(); X} X Xytop3() X{ X Debug(DB_POINTS, "%%ytop3: %d\n", ybase3() + yht4()); X return ybase3() + yht4(); X} X Xytop4() X{ X Debug(DB_POINTS, "%%ytop4: %d\n", ybase4() + yht4()); X return ybase4() + yht4(); X} X Xxwid1() X{ X Debug(DB_POINTS, "%%xwid1: %d\n", X ps_width - ((2 * pg_sheetmargin) + (2 * pg_pagemargin))); X return ps_width - ((2 * pg_sheetmargin) + (2 * pg_pagemargin)); X} X Xxwid2() X{ X Debug(DB_POINTS, "%%xwid2: %d\n", X (ps_width / 2) - (pg_sheetmargin + (2 * pg_pagemargin))); X return (ps_width / 2) - (pg_sheetmargin + (2 * pg_pagemargin)); X} X Xyht1() X{ X Debug(DB_POINTS, "%%yht1: %d\n", X ps_height - ((2 * pg_sheetmargin) + (2 * pg_pagemargin))); X return ps_height - ((2 * pg_sheetmargin) + (2 * pg_pagemargin)); X} X Xyht2() X{ X Debug(DB_POINTS, "%%yht2: %d\n", X (ps_height / 2) - (pg_sheetmargin + (2 * pg_pagemargin))); X return (ps_height / 2) - (pg_sheetmargin + (2 * pg_pagemargin)); X} X Xyht4() X{ X Debug(DB_POINTS, "%%yht4: %d\n", X (((ps_height / 2) - pg_sheetmargin) / 2) - (2 * pg_pagemargin)); X return (((ps_height / 2) - pg_sheetmargin) / 2) - (2 * pg_pagemargin); X} X Xoutline_1(outfd) X FILE *outfd; X{ X /* one page outline */ X fprintf(outfd, "0 setlinewidth\n"); X fprintf(outfd, "%3d %3d moveto\n", pg_sheetmargin, pg_sheetmargin); X fprintf(outfd, "%3d %3d lineto\n", pg_sheetmargin, X ps_height - pg_sheetmargin); X fprintf(outfd, "%3d %3d lineto\n", ps_width - pg_sheetmargin, X ps_height - pg_sheetmargin); X fprintf(outfd, "%3d %3d lineto\n", ps_width - pg_sheetmargin, X pg_sheetmargin); X fprintf(outfd, "closepath stroke\n"); X} X Xoutline_2(outfd) X FILE *outfd; X{ X /* two page outline */ X outline_1(outfd); X fprintf(outfd, "%3d %3d moveto\n", pg_sheetmargin, ps_height / 2); X fprintf(outfd, "%3d %3d lineto\n", ps_width - pg_sheetmargin, X ps_height / 2); X fprintf(outfd, "stroke\n"); X} X Xoutline_4(outfd) X FILE *outfd; X{ X /* four page outline */ X outline_2(outfd); X fprintf(outfd, "%3d %3d moveto\n", ps_width / 2 , pg_sheetmargin); X fprintf(outfd, "%3d %3d lineto\n", ps_width / 2 , X ps_height - pg_sheetmargin); X fprintf(outfd, "stroke\n"); X} X Xoutline_8(outfd) X FILE *outfd; X{ X /* eight page outline */ X outline_4(outfd); X fprintf(outfd, "%3d %3d moveto\n", pg_sheetmargin, X ((ps_height / 2) - pg_sheetmargin) / 2 + pg_sheetmargin); X fprintf(outfd, "%3d %3d lineto\n", ps_width - pg_sheetmargin, X ((ps_height / 2) - pg_sheetmargin) / 2 + pg_sheetmargin); X fprintf(outfd, "stroke\n"); X fprintf(outfd, "%3d %3d moveto\n", pg_sheetmargin, X ((ps_height / 2) - pg_sheetmargin) / 2 + (ps_height / 2)); X fprintf(outfd, "%3d %3d lineto\n", ps_width - pg_sheetmargin, X ((ps_height / 2) - pg_sheetmargin) / 2 + (ps_height / 2)); X fprintf(outfd, "stroke\n"); X} X Xmp_outline(outfd, asheet) X FILE *outfd; X struct sheet *asheet; X{ X if (opt_outline) { X (*asheet->sh_outline)(outfd); X } X} X + END-OF-FILE mp_page.c chmod 'u=rw,g=rw,o=r' 'mp_page.c' echo ' -rw-rw-r-- 1 kai 5453 Jan 1 1990 mp_page.c (as sent)' echo -n ' ' /bin/ls -l mp_page.c echo 'Extracting mp_post.c' sed 's/^X//' > mp_post.c << '+ END-OF-FILE mp_post.c' X# include <stdio.h> X# include <sys/types.h> X X# ifndef lint Xstatic char *rcs_id = X "@(#) $Header: mp_post.c,v 2.9 89/08/09 11:30:39 mark Exp $"; X# endif X X# include "mp_head.h" X X/* X * mpage: a program to reduce pages of print so that several pages X * of output appear on one printed page. X * X * Written by: X * ...!uunet!\ Mark Hahn, Sr Systems Engineer X * >pyrdc!mark Pyramid Technology Corporation X * ...!pyramid!/ Vienna, Va (703)848-2050 X * X * X * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia X * X * Permission is granted to anyone to make or distribute verbatim X * copies of this document as received, in any medium, provided X * that this copyright notice notice is preserved, and that the X * distributor grants the recipient permission for further X * redistribution as permitted by this notice. X * X */ X X/* $Log: mp_post.c,v $ X * Revision 2.9 89/08/09 11:30:39 mark X * fixed bug in get_psstr. it did not return a value if it failed X * to find a string in parparentheses. the code "lucked-out" on risc X * machines but failed on machines that use different locations for X * the function arguments and return values, (680x0s and VAXen). X * (First time I've seen poor coding work on a RISC but be-fuddle a CISC. X * X * Revision 2.8 89/05/25 10:25:34 mark X * add new debugging keyword for tracking the processing of postscript X * documents. X * X * Revision 2.7 89/05/25 10:20:38 mark X * changed the format of debugging prints in the PS code. X * X * Revision 2.6 89/05/25 08:58:30 mark X * rearranged the rcs header keywords for better readability. X * X * Revision 2.5 89/05/25 08:49:49 mark X * added code to disable showpage durring the printing of postscript X * documents. we define our own routine to do the showpage. X * X * Revision 2.4 89/05/23 09:39:36 mark X * Changes to deal with %%BeginSetup sections. We now scan all the way X * to the first %%Page comment assuming this will cover everything. X * Actually we should do something more intelligent, saving the %%BeginSetup X * section and putting after our page reduction but before the page is X * printed. X * X * Revision 2.3 89/05/22 14:40:56 mark X * Fixed the type-o in the rcs identification string X * X * Revision 2.2 89/05/22 14:37:56 mark X * Added rcs identification usable with the "what" program X * X * Revision 2.1 89/05/22 14:31:22 mark X * New Major Revision X * X * Revision 1.2 89/05/22 13:49:58 mark X * placed the log keywork after the initial notice X * X * Revision 1.1 89/05/22 13:48:43 mark X * Initial revision X * */ X X/* X * character spaces used throughout for holding the current line from X * the input file X */ Xstatic char currline[LINESIZE]; X/* X * for ps documents, used to remember if we have come across the X * tailer section. reset at the beginning of processing for each file X */ Xstatic int ps_at_trailer; X X/* X * this is the type of postscript document we are processing X */ Xstatic int ps_posttype; X X/* X * peek at the first two chacters on the open file and check for the X * two character postscript flag "%!". If the file is not postscript X * then the characters are pushed back into the input stream (hopefully). X */ Xps_check(infd) X FILE *infd; X{ X int firstchar; X int secondchar; X X Debug(DB_PSCHECK, "%%ps_check: in ps_check\n", 0); X /* X * eliminate blank files X */ X if ((firstchar = fgetc(infd)) == EOF) { X Debug(DB_PSCHECK, "%%ps_check: file is blank\n", 0); X return 0; X } X /* X * eliminate non-postscript files X */ X if (firstchar != '%') { X Debug(DB_PSCHECK, "%ps_check: 1st char is '%c' not '%'\n", X firstchar); X if (ungetc(firstchar, infd) == EOF) { X fprintf(stderr, "%s: Lost first character of file ", X MPAGE); X fprintf(stderr, "while checking for postscript."); X } X return 0; X } X Debug(DB_PSCHECK, "%%ps_check: 1st char is '%c'\n", firstchar); X /* X * eliminate one character files (containing only a %) X */ X if ((secondchar = fgetc(infd)) == EOF) { X Debug(DB_PSCHECK, "%%ps_check: no second char\n", 0); X if (ungetc(firstchar, infd) == EOF) { X fprintf(stderr, "%s: Lost first character of file ", X MPAGE); X fprintf(stderr, "while checking for postscript."); X } X return 0; X } X /* X * eliminate files that don't have the full two character X * sequence of "%!". X */ X if (secondchar != '!') { X Debug(DB_PSCHECK, "%%ps_check: 2nd char is '%c' not '!'\n", X secondchar); X if (ungetc(secondchar, infd) == EOF) { X fprintf(stderr, "%s: Lost first two characters of ", X MPAGE); X fprintf(stderr, "file while checking for postscript."); X return 0; X } X if (ungetc(firstchar, infd) == EOF) { X fprintf(stderr, "%s: Lost first character of file ", X MPAGE); X fprintf(stderr, "while checking for postscript."); X } X return 0; X } X /* X * for post script files the first two characters (the "%!") are X * digested by this routine. It's just easier than dealing X * with the problems encounted if the characters can't be ungetc'ed. X */ X Debug(DB_PSCHECK, "%%ps_check: 2nd char is '%c'\n", secondchar); X Debug(DB_PSCHECK, "%%ps_check: input is postscript\n", 0); X return 1; X} X Xps_gettype(fd, outfd) X FILE *fd; X FILE *outfd; X{ X int type_known, ps_type, end_comments; X char *get_psstr(); X X Debug(DB_PSDOC, "%%ps_gettype: in ps_gettype\n", 0); X /* X * error check for truncated files X */ X if (fgets(currline, LINESIZE-1, fd) == NULL) { X Debug(DB_PSDOC, "%%ps_gettype: got eof on first line\n", 0); X return PS_NONE; X } X /* X * check for non-conforming postscript X */ X if (strncmp(currline, PS_FLAG, strlen(PS_FLAG)) != 0) { X Debug(DB_PSDOC, "%%ps_gettype: no match PS_FLAG \"%s\"\n", X currline); X return PS_OTHER; X } X /* X * we have some form of conforming postscript, try to identify the X * type X */ X Debug(DB_PSDOC, "%%ps_gettype: conforming postscript\n", 0); X end_comments = 0; X type_known = 0; X while (!end_comments) { X /* X * if we get end of file then we assume non-conforming PS X */ X if (fgets(currline, LINESIZE-1, fd) == NULL) { X Debug(DB_PSDOC, "%%ps_gettype: eof in comments\n", 0); X return PS_OTHER; X } X /* X * if we have run out of leading comments then assume X * conforming PS (because we had a valid "%!" line) X */ X if (currline[0] != '%') { X Debug(DB_PSDOC, "%%ps_gettype: eof in comments\n", 0); X fprintf(outfd, "%s", currline); X return PS_CONFORM; X } X /* X * print out the comment line with an extra % to disguise X * the comment X */ X fprintf(outfd, "%%%s", currline); X /* X * check for the end of the leading comments section X */ X if (strncmp(currline, "%%EndComments", 13) == 0) { X end_comments = 1; X } X /* X * once we know the type of PS, we no longer need to keep X * checking. X */ X if (type_known) { X continue; X } X /* X * check for mpage output X */ X if (strncmp(currline, "%%Creator: mpage", 16) == 0) { X Debug(DB_PSDOC, "%%ps_gettype: mpage document\n", 0); X type_known = 1; X ps_type = PS_MPAGE; X } X /* X * check for psroff output X */ X if (strncmp(currline, "%%Title: ", 9) == 0) { X if (strcmp(get_psstr(currline), "ditroff") == 0) { X Debug(DB_PSDOC, "%%ps_gettype: psroff\n", 0); X type_known = 1; X ps_type = PS_PSROFF; X } X } X } X if (type_known) { X return ps_type; X } X Debug(DB_PSDOC, "%%ps_gettype: unknow type conforming PS\n", 0); X return PS_CONFORM; X} X X/* X * get_psstr will extract (and return a pointer to) a string in parentheses. X * it is used for checking for psroff (ditroff) postscript. X */ Xchar *get_psstr(line) X char *line; X{ X char space[LINESIZE]; X char *p1, *p2; X X p1 = line; X while (*p1) { X if (*p1 == '(') { X p1++; X p2 = space; X while (*p1 && (*p1 != ')')) { X *p2++ = *p1++; X } X *p2 = 0; X return space; X } X p1++; X } X return line; X} X Xdo_ps_doc(fd, asheet, outfd) X FILE *fd; X struct sheet *asheet; X FILE *outfd; X{ X Debug(DB_PSDOC, "%%do_ps_doc: postscript document\n", 0); X ps_posttype = ps_gettype(fd,outfd); X Debug(DB_PSDOC, "%%do_ps_doc: document type is %d\n", ps_posttype); X switch(ps_posttype) { X case PS_NONE: X /* X * why bother? X */ X break; X default: X do_post_doc(fd, asheet, outfd); X break; X } X} X Xdo_post_doc(fd, asheet, outfd) X FILE *fd; X struct sheet *asheet; X FILE *outfd; X{ X ps_at_trailer = FALSE; X Debug(DB_POST, "%%do_post_doc: prolog\n", 0); X ps_copyprolog(fd, outfd); X Debug(DB_POST, "%%do_post_doc: pages\n", 0); X /* X * while there is still input, print pages X */ X while (do_post_sheet(fd, asheet, outfd) != FILE_EOF) X ; X Debug(DB_POST, "%%do_post_doc: trailer\n", 0); X do_roff_tailer(fd, outfd); X} X Xdo_other_doc(fd, asheet, outfd) X FILE *fd; X struct sheet *asheet; X FILE *outfd; X{ X ps_at_trailer = FALSE; X ps_copyprolog(fd, outfd); X} X Xps_copyprolog(fd, outfd) X FILE *fd; X FILE *outfd; X{ X char *rtn; X X Debug(DB_PSDOC, "%%ps_copyprolog: adding mpage prolog\n", 0); X fprintf(outfd, "/showsheet { showpage } bind def\n"); X fprintf(outfd, "/showpage { } def\n"); X Debug(DB_PSDOC, "%%ps_copyprolog: copying prolog\n", 0); X if (ps_posttype == PS_PSROFF) { X Debug(DB_PSDOC, "%%ps_copyprolog: calling ps_roff_prolog\n",0); X ps_roff_copyprolog(fd, outfd); X return; X } X rtn = fgets(currline, LINESIZE-1, fd); X while (rtn) { X if (strncmp(currline, "%%Page:", 7) == 0) { X fprintf(outfd, "%% %s", currline); X return; X } X fprintf(outfd, "%s", currline); X rtn = fgets(currline, LINESIZE-1, fd); X } X Debug(DB_PSDOC, "%%ps_copyprolog: eof before %%%%EndProlog\n", 0); X fprintf(outfd, "%%%%EndProlog\n"); X} X Xps_roff_copyprolog(fd, outfd) X FILE *fd; X FILE *outfd; X{ X X Debug(DB_PSDOC, "%%ps_roff_copyprolog: copying psroff prolog\n", 0); X while(fgets(currline, LINESIZE-1, fd) != NULL) { X if (strcmp(currline, "xi\n") == 0) { X fprintf(outfd, "%%%s", currline); X } else if (strncmp(currline, "%%Page:", 7) == 0) { X fprintf(outfd, "/p { } def\n"); X fprintf(outfd, "/xt { } def\n"); X fprintf(outfd, "/xs { } def\n"); X fprintf(outfd, "%% %s", currline); X Debug(DB_PSDOC, "%%ps_copyprolog: Done \n", 0); X return; X } else { X fprintf(outfd, "%s", currline); X } X X } X Debug(DB_PSDOC, "%%ps_copyprolog: eof before %%%%EndProlog\n", 0); X fprintf(outfd, "/p { } def\n"); X fprintf(outfd, "/xt { } def\n"); X fprintf(outfd, "/xs { } def\n"); X fprintf(outfd, "%%%%EndProlog\n"); X} X Xps_skip_to_page(fd) X FILE *fd; X{ X Debug(DB_PSDOC, "%%ps_skip to page: copying psroff prolog\n", 0); X while(fgets(currline, LINESIZE-1, fd) != NULL) { X Debug(DB_PSDOC, "%% %s", currline); X if (strncmp(currline, "%%Page:", 7) == 0) { X return; X } X } X Debug(DB_PSDOC, "%%ps_skip_to_page: eof before %%%%Page:\n", 0); X} X Xdo_post_sheet(fd, asheet, outfd) X FILE *fd; X struct sheet *asheet; X FILE *outfd; X{ X char **outline; X struct pagepoints *points; X int rtn_val; X X /* X * keep track of the pages printed X */ X ps_pagenum += 1; X fprintf(outfd, "%%%%Page: %d %d\n", ps_pagenum, ps_pagenum); X# ifdef DEBUG X if (Debug_flag & DB_PSMPAGE) { X fprintf(outfd, "(Page: %d\\n) print flush\n", ps_pagenum); X } X# endif DEBUG X /* X * print the page outline X */ X mp_outline(outfd, asheet); X /* X * run through the list of base points for putting reduced pages X * on the printed page X */ X points = asheet->sh_pagepoints; X while (points->pp_origin_x != 0) { X /* X * print one reduced page by moveing to the proper point, X * turning to the proper aspect, scaling to the proper X * size, and setting up a clip path to prevent overwritting; X * the print a reduced page of output X */ X# ifdef DEBUG X if (Debug_flag & DB_PSMPAGE) { X fprintf(outfd, "%%%% %%%%ReducedPageStartsHere\n"); X } X# endif DEBUG X fprintf(outfd, "/sheetsave save def\n"); X fprintf(outfd, "gsave\n"); X# ifdef DEBUG X if (Debug_flag & DB_PSMPAGE) { X fprintf(outfd, "( %d %d translate %d rotate\\n)", X points->pp_origin_x(), points->pp_origin_y(), X asheet->sh_rotate); X fprintf(outfd, " print flush\n"); X } X# endif DEBUG X fprintf(outfd, "%d %d translate %d rotate\n", X points->pp_origin_x(), points->pp_origin_y(), X asheet->sh_rotate); X fprintf(outfd, "%d %d div %d %d div scale\n", X (*asheet->sh_width)(), ps_width, X (*asheet->sh_height)(), ps_height); X /* output the clip path */ X fprintf(outfd, "0 0 moveto 0 %d lineto %d %d lineto ", X ps_height, ps_width, ps_height); X fprintf(outfd, "%d 0 lineto\n", ps_width); X fprintf(outfd, "closepath clip newpath\n"); X /* X * do the individual sheet setup X */ X ps_sheetsetup(outfd); X /* X * place one reduce page on the printed page X */ X rtn_val = post_onepage(fd, asheet, outfd); X /* X * clean up after mpage as drawn its page X */ X fprintf(outfd, "grestore sheetsave restore\n"); X points++; X } X /* X * print the sheet X */ X fprintf(outfd, "showsheet\n"); X /* X * let the upper level know about the status of possible EOF X */ X return rtn_val; X} X Xps_sheetsetup(outfd) X FILE *outfd; X{ X switch (ps_posttype) { X case PS_PSROFF: X fprintf(outfd, "xi\n"); X fprintf(outfd, "/p {} def\n"); X break; X case PS_MPAGE: X fprintf(outfd, "/showpage {} def\n"); X break; X } X} X Xpost_onepage(fd, asheet, outfd) X FILE *fd; X struct sheet *asheet; X FILE *outfd; X{ X int len; X char *test; X X Debug(DB_PSROFF, "%%post_onepage: Begin page\n", 0); X if (ps_at_trailer) { X Debug(DB_PSROFF, "%%post_onepage: still at trailer\n", 0); X return FILE_EOF; X } X while(fgets(currline, LINESIZE-1, fd) != NULL) { X if (strncmp(currline, "%%Page:",7) == 0) { X fprintf(outfd, "%% %s", currline); X Debug(DB_PSROFF, "%%post_onepage: next page\n", 0); X return FILE_MORE; X } X X if (strncmp(currline, "%%Trailer",8) == 0) { X fprintf(outfd, "%% %s", currline); X Debug(DB_PSROFF, "%%post_onepage: found trailer\n", 0); X ps_at_trailer = TRUE; X return FILE_EOF; X } X fprintf(outfd, "%s", currline); X } X Debug(DB_PSROFF, "%%post_onepage: eof\n", 0); X return FILE_EOF; X} X Xdo_roff_tailer(fd, outfd) X FILE *fd, *outfd; X{ X int i; X X Debug(DB_PSDOC, "%%do_roff_trailer: looking for eof\n", 0); X i = 0; X while(fgets(currline, LINESIZE-1, fd) != NULL) { X i++; X Debug(DB_PSDOC, "%%%s", currline); X } X Debug(DB_PSDOC, "%%do_roff_trailer: tailer of %d lines\n", i); X} X + END-OF-FILE mp_post.c chmod 'u=rw,g=rw,o=r' 'mp_post.c' echo ' -rw-rw-r-- 1 kai 14039 Jan 1 1990 mp_post.c (as sent)' echo -n ' ' /bin/ls -l mp_post.c echo 'Extracting mp_sample.c' sed 's/^X//' > mp_sample.c << '+ END-OF-FILE mp_sample.c' X# include <stdio.h> X# include <sys/types.h> X X# ifndef lint Xstatic char *rcs_id = X "@(#) $Header: mp_sample.c,v 1.1 89/05/25 08:58:34 mark Exp $"; X# endif X X# include "mp_head.h" X X/* $Log: mp_sample.c,v $ X * Revision 1.1 89/05/25 08:58:34 mark X * Initial revision X * */ X Xmain( argc, argv) X int argc; X char **argv; X{ X int currarg; X X /* X * examine the environment for PRINTER and MPAGE environment variables X */ X if (do_env() == 0) { X fprintf(stderr, usage, MPAGE); X exit(1); X } X X currarg = do_args(argc, argv, 0); X if (currarg < 0) { X fprintf(stderr, usage, MPAGE); X exit(1); X } X X do_sample(); X} X Xdo_sample() X{ X printf("%%!PS-mpage-layout\n"); X printf("/Courier findfont 8 scalefont setfont\n"); X printf("0 setlinewidth\n"); X X outline_8(stdout); X X urshow(xbase1(), ybase1()); X urshow(xbase1(), ybase2()); X urshow(xbase1(), ybase3()); X urshow(xbase1(), ybase4()); X lrshow(xbase1(), ytop1()); X lrshow(xbase1(), ytop2()); X lrshow(xbase1(), ytop3()); X lrshow(xbase1(), ytop4()); X ulshow(xbase1()+xwid2(), ybase1()); X ulshow(xbase1()+xwid2(), ybase2()); X ulshow(xbase1()+xwid2(), ybase3()); X ulshow(xbase1()+xwid2(), ybase4()); X llshow(xbase1()+xwid2(), ytop1()); X llshow(xbase1()+xwid2(), ytop2()); X llshow(xbase1()+xwid2(), ytop3()); X llshow(xbase1()+xwid2(), ytop4()); X X urshow(xbase2(), ybase1()); X urshow(xbase2(), ybase2()); X urshow(xbase2(), ybase3()); X urshow(xbase2(), ybase4()); X lrshow(xbase2(), ytop1()); X lrshow(xbase2(), ytop2()); X lrshow(xbase2(), ytop3()); X lrshow(xbase2(), ytop4()); X ulshow(xbase2()+xwid2(), ybase1()); X ulshow(xbase2()+xwid2(), ybase2()); X ulshow(xbase2()+xwid2(), ybase3()); X ulshow(xbase2()+xwid2(), ybase4()); X llshow(xbase2()+xwid2(), ytop1()); X llshow(xbase2()+xwid2(), ytop2()); X llshow(xbase2()+xwid2(), ytop3()); X llshow(xbase2()+xwid2(), ytop4()); X printf("showpage\n"); X} X Xurshow(x, y) X{ X printf("%%- point %d,%d\n", x, y); X box(x, y); X printf("\t%d %d moveto (%d,%d) show\n", x+2, y+2, x, y); X} X Xlrshow(x, y) X{ X printf("%%- point %d,%d\n", x, y); X box(x, y); X printf("\t%d %d moveto (%d,%d) show\n", x+2, y-6, x, y); X} X Xulshow(x, y) X{ X printf("%%- point %d,%d\n", x, y); X box(x, y); X printf("\t%d %d moveto\n", x-2, y+2); X printf("\t(%d,%d) dup stringwidth pop -1 mul 0 rmoveto show\n", x, y); X} X Xllshow(x, y) X{ X printf("%%- point %d,%d\n", x, y); X box(x, y); X printf("\t%d %d moveto\n", x-2, y-6); X printf("\t(%d,%d) dup stringwidth pop -1 mul 0 rmoveto show\n", x, y); X} X Xbox(x, y) X{ X printf("\t%d %d moveto %d %d lineto\n", x-1, y, x+1, y); X printf("\t%d %d moveto %d %d lineto\n", x, y-1, x, y+1); X printf("\tstroke\n"); X} X + END-OF-FILE mp_sample.c chmod 'u=rw,g=rw,o=r' 'mp_sample.c' echo ' -rw-rw-r-- 1 kai 2580 Jan 1 1990 mp_sample.c (as sent)' echo -n ' ' /bin/ls -l mp_sample.c echo 'Extracting mp_text.c' sed 's/^X//' > mp_text.c << '+ END-OF-FILE mp_text.c' X# include <stdio.h> X# include <sys/types.h> X X# ifndef lint Xstatic char *rcs_id = X "@(#) $Header: mp_text.c,v 2.8 89/06/23 13:14:00 mark Exp $"; X# endif X X# include "mp_head.h" X X/* X * mpage: a program to reduce pages of print so that several pages X * of output appear on one printed sheet. X * X * Written by: X * ...!uunet!\ Mark Hahn, Sr Systems Engineer X * >pyrdc!mark Pyramid Technology Corporation X * ...!pyramid!/ Vienna, Va (703)848-2050 X * X * X * Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia X * X * Permission is granted to anyone to make or distribute verbatim X * copies of this document as received, in any medium, provided X * that this copyright notice notice is preserved, and that the X * distributor grants the recipient permission for further X * redistribution as permitted by this notice. X * X */ X X/* $Log: mp_text.c,v $ X * Revision 2.8 89/06/23 13:14:00 mark X * Fixed range checking for control characters so that tilde was X * included as a printable character. X * X * Revision 2.7 89/06/21 08:58:56 mark X * moved the bottom of the clipping region for text below zero so that X * decenders on the last line can be seen. Currently the font, font size X * and this extra space are hard coded. Something more reasonable should X * be done. Probably involves more command line options. (Sorry, "Something X * more reasonable" should be "something more flexible") X * X * Revision 2.6 89/05/25 10:20:11 mark X * changed the format of debugging prints in the PS code. X * X * Revision 2.5 89/05/25 09:01:51 mark X * rearranged the rcs header keywords for better readability. X * X * Revision 2.4 89/05/24 17:36:56 mark X * fixed the $Log: mp_text.c,v $ X * Revision 2.8 89/06/23 13:14:00 mark X * Fixed range checking for control characters so that tilde was X * included as a printable character. X * X * Revision 2.7 89/06/21 08:58:56 mark X * moved the bottom of the clipping region for text below zero so that X * decenders on the last line can be seen. Currently the font, font size X * and this extra space are hard coded. Something more reasonable should X * be done. Probably involves more command line options. (Sorry, "Something X * more reasonable" should be "something more flexible") X * X * Revision 2.6 89/05/25 10:20:11 mark X * changed the format of debugging prints in the PS code. X * X * Revision 2.5 89/05/25 09:01:51 mark X * rearranged the rcs header keywords for better readability. X * rcs keyword. X * */ X X/* X * keeps track of the current location on the sheet. it is kept global X * to while file printing process because of form feeds in particular. X * form feeds change the vertical page location (line number) but not X * the horizontal location (character column) X */ Xstruct pageloc { X int pl_line; X int pl_col; X int pl_new_line; X int pl_new_col; X}; Xstatic struct pageloc loc; X X/* X * do_text_doc processes an input stream fd, reducing output to fit on X * a printed page as decribed by asheet, and prints this on outfd. X */ Xdo_text_doc(fd, asheet, outfd) X FILE *fd; X struct sheet *asheet; X FILE *outfd; X{ X do_text_prolog(outfd); X X /* X * initalize the postion on the first printed page X */ X loc.pl_line = 1; X loc.pl_col = 0; X /* X * while we have input, print a page X */ X while (do_text_sheet(fd, asheet, outfd) != FILE_EOF) X ; X} X X/* X * ps_text_prolog prints mpage startup information for plain text documents X */ Xdo_text_prolog(outfd) X FILE *outfd; X{ X time_t curr_time; X char *time_str; X X fprintf(outfd, "/Courier findfont %d scalefont setfont\n", fsize -1); X fprintf(outfd, "(a) stringwidth pop /mp_a_x exch def\n"); X fprintf(outfd, "(\\t'a' length ) print mp_a_x == "); X fprintf(outfd, "flush\n"); X fprintf(outfd, "%%%%EndProlog\n"); X} X X/* X * do_text_sheet creates one printed sheet consisting of several reduced pages X */ Xdo_text_sheet(fd, asheet, outfd) X FILE *fd; X struct sheet *asheet; X FILE *outfd; X{ X char **outline; X struct pagepoints *points; X int rtn_val; X X /* X * keep track of the pages printed X */ X ps_pagenum += 1; X fprintf(outfd, "%%%%Page: %d %d\n", ps_pagenum, ps_pagenum); X# ifdef DEBUG X if (Debug_flag & DB_PSMPAGE) { X fprintf(outfd, "(Page: %d\\n) print flush\n", ps_pagenum); X } X# endif DEBUG X fprintf(outfd, "save\n"); /* for better memory usage */ X /* X * print the page outline, which draws lines and such X */ X mp_outline(outfd, asheet); X /* X * run through the list of base points for putting reduced pages X * on the printed page X */ X points = asheet->sh_pagepoints; X while (points->pp_origin_x != 0) { X /* X * print one reduced page by moveing to the proper point, X * turning to the proper aspect, scaling to the proper X * size, and setting up a clip path to prevent overwritting; X * the print a reduced page of output X */ X fprintf(outfd, "gsave\n"); X# ifdef DEBUG X if (Debug_flag & DB_PSMPAGE) { X fprintf(outfd, "( %d %d translate %d rotate\\n)", X points->pp_origin_x(), points->pp_origin_y(), X asheet->sh_rotate); X fprintf(outfd, " print flush\n"); X } X# endif DEBUG X fprintf(outfd, "%d %d translate %d rotate\n", X points->pp_origin_x(), points->pp_origin_y(), X asheet->sh_rotate); X fprintf(outfd, "%d %d mp_a_x mul div %d %d div scale\n", X (*asheet->sh_width)(), asheet->sh_cwidth, X (*asheet->sh_height)(), asheet->sh_plength * fsize); X /* X * output the clip path (the bottom of the cliping region X * is 1/2 the font size below "0" so that you can see decenders X * on the last line of each page X */ X fprintf(outfd, "0 -4 moveto 0 %d lineto %d mp_a_x mul ", X asheet->sh_plength * fsize, asheet->sh_cwidth); X fprintf(outfd, "%d lineto %d mp_a_x mul -4 lineto\n", X asheet->sh_plength * fsize, asheet->sh_cwidth); X fprintf(outfd, "closepath clip\n"); X /* X * place one reduced page on the printed page X */ X rtn_val = text_onepage(fd, asheet, outfd); X /* X * clean up this page and move to the next X */ X fprintf(outfd, "grestore\n"); X points++; X } X /* X * release PS vm used, and eject the sheet X */ X fprintf(outfd, "restore\n"); X fprintf(outfd, "showpage\n"); X /* X * let the upper level know about the status of possible EOF X */ X return rtn_val; X} X X/* X * onepage places on page of reduced output on the printed page X * all scaling, translation, and rotation has already been done before X */ X Xtext_onepage(file, asheet, outfd) X FILE *file; X struct sheet *asheet; X FILE *outfd; X{ X char *text; X char linenum; X int pos; X char *mp_get_text(); X X /* X * as we move from one page to the next, restart printing text at X * the head of the page. horziontal location is not reset because X * form feeds leave the column the same from page to page. X */ X Debug(DB_ONEPAGE, "%% reseting line to top of page\n", 0); X loc.pl_line = 1; X /* X * keep getting lines of input, until we have filled a page X */ X while (loc.pl_line <= asheet->sh_plength) { X text = mp_get_text(file, &loc); X Debug(DB_ONEPAGE, "%% text = %d\n", text); X if (text == 0) { X return FILE_EOF; X } X Debug(DB_ONEPAGE, "%% text = (%s)\n", text); X Debug(DB_ONEPAGE, "%% loc.pl_line = %d\n", loc.pl_line); X Debug(DB_ONEPAGE, "%% loc.pl_col = %d\n", loc.pl_col); X Debug(DB_ONEPAGE, "%% loc.pl_new_line = %d\n",loc.pl_new_line); X Debug(DB_ONEPAGE, "%% loc.pl_new_col = %d\n", loc.pl_new_col); X if (text[0] != 0) { X /* fprintf(outfd, "(%s\\n) print flush\n", text); */ X fprintf(outfd, "%d mp_a_x mul %d moveto (%s) show\n", X loc.pl_col, X (asheet->sh_plength - loc.pl_line) * fsize, X text); X } X if (loc.pl_new_line == -1) { X loc.pl_col = loc.pl_new_col; X return FILE_MORE; X } X loc.pl_line = loc.pl_new_line; X loc.pl_col = loc.pl_new_col; X } X return FILE_MORE; X} X X Xstatic char text[LINESIZE]; X Xchar *mp_get_text(infile, locp) X FILE *infile; X struct pageloc *locp; X{ X int gathering; X int tabcnt; X int ichr; X char *textp; X X textp = text; X locp->pl_new_line = locp->pl_line; X locp->pl_new_col = locp->pl_col; X X gathering = 1; X while (gathering) { X ichr = fgetc(infile); X Debug(DB_GETLINE, "%%called fgetc ichr = %d", ichr); X Debug(DB_GETLINE, "(%d)\n", EOF); X /* X * this prevents nulls in the input from confusing the X * program logic with truncated strings X */ X if (ichr == 0) { X ichr = 1; X } X switch (ichr) { X case EOF: X gathering = 0; X return 0; X break; X case '\n': X locp->pl_new_line += 1; X locp->pl_new_col = 0; X gathering = 0; X break; X case '\r': X locp->pl_col = 0; X gathering = 0; X break; X case '\b': X locp->pl_new_col -= 1; X if (locp->pl_new_col < 0) { X locp->pl_new_col = 0; X } X gathering = 0; X break; X case '\f': X locp->pl_new_line = -1; X gathering = 0; X break; X case '\t': X tabcnt = 8 - (locp->pl_new_col % 8); X locp->pl_new_col += tabcnt; X gathering = 0; X break; X/**/ X/* case ' ': X/* locp->pl_new_col += 1; X/* gathering = 0; X/* break; X/**/ X case '(': X case ')': X case '\\': X *textp++ = '\\'; X *textp++ = ichr; X locp->pl_new_col += 1; X break; X default: X if (ichr >= ' ' && ichr <= '~') { X *textp++ = ichr; X locp->pl_new_col += 1; X } else { X *textp++ = '\\'; X *textp++ = '2'; X *textp++ = '7'; X *textp++ = '7'; X locp->pl_new_col += 1; X } X break; X } X } X *textp = 0; X /* X * remove any spaces at the front of the text string by X * "converting" it to a position change X */ X textp = text; X while (*textp && *textp == ' ') { X /* X * this affects the starting position of this text string X * (not the next) X */ X locp->pl_col += 1; X textp++; X } X return textp; X} X + END-OF-FILE mp_text.c chmod 'u=rw,g=rw,o=r' 'mp_text.c' echo ' -rw-rw-r-- 1 kai 9543 Jan 1 1990 mp_text.c (as sent)' echo -n ' ' /bin/ls -l mp_text.c echo 'Extracting mpage' sed 's/^X//' > mpage << '+ END-OF-FILE mpage' XArticle 1255 of comp.sources.misc: XPath: draken!sunic!mcsun!uunet!allbery XFrom: mark@pyrdc.UUCP (Mark Hahn) XNewsgroups: comp.sources.misc XSubject: v09i088: Mpage (1 of 2): Reduce and Print Text or Postscript XKeywords: postscript, reduce, n-up, 4-up, mpage XMessage-ID: <74697@uunet.UU.NET> XDate: 27 Dec 89 00:19:16 GMT XSender: allbery@uunet.UU.NET XOrganization: Pyramid Technology, Government Systems XLines: 1893 XApproved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) X XPosting-number: Volume 9, Issue 88 XSubmitted-by: mark@pyrdc.UUCP (Mark Hahn) XArchive-name: mpage/part01 X XMpage will print text or Postscript input in n-up format. I.e. 4 Xpages of normal text or postscript is reduced to fit on one sheet of Xpaper (4-up). Choices are 1, 2, 4, 8, and 16 pages per sheet of paper Xwith 2 and 4 being most useful and readable. It accepts Postscript as Xinput, or at least it works on most of the stuff I get from the Adobe XFile Server. X X. . . . . . . . . . . . The Obligatory Dotted Line . . . . . . . . . . . . X X-- X ...!uunet!\ Mark Hahn, Sr Systems Engineer X >pyrdc!mark Pyramid Technology Corporation X...!pyramid!/ Vienna, Va (703)848-2050 X X XArticle 1256 of comp.sources.misc: XPath: draken!sunic!mcsun!uunet!allbery XFrom: mark@pyrdc.UUCP (Mark Hahn) XNewsgroups: comp.sources.misc XSubject: v09i089: Mpage (2 of 2): Reduce and Print Text or Postscript XKeywords: postscript, mpage, reduce XMessage-ID: <74698@uunet.UU.NET> XDate: 27 Dec 89 00:19:48 GMT XSender: allbery@uunet.UU.NET XOrganization: Pyramid Technology, Government Systems XLines: 1156 XApproved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) X XPosting-number: Volume 9, Issue 89 XSubmitted-by: mark@pyrdc.UUCP (Mark Hahn) XArchive-name: mpage/part02 X X. . . . . . . . . . . The Obligitory Dotted Line . . . . . . . . . . . . X X-- X ...!uunet!\ Mark Hahn, Sr Systems Engineer X >pyrdc!mark Pyramid Technology Corporation X...!pyramid!/ Vienna, Va (703)848-2050 X X + END-OF-FILE mpage chmod 'u=rw,g=rw,o=r' 'mpage' echo ' -rw-rw-r-- 1 kai 2087 Jan 1 1990 mpage (as sent)' echo -n ' ' /bin/ls -l mpage echo 'Extracting mpage.1' sed 's/^X//' > mpage.1 << '+ END-OF-FILE mpage.1' X.TH MPAGE Local 1/13/87 X.SH NAME Xmpage \- print muliple pages per sheet on POSTSCRIPT printer X.SH SYNOPSIS X\fBmpage [-1248povsnluaA] [-Llines] [-Wwidth] [-hheader] [-Pprinter] X[files...]\fR X.SH DESCRIPTION X.I Mpage Xreads plain text files or POSTSCRIPT documents and prints them on a XPOSTSCRIPT printer with the text reduced in size so that several Xpages apperar on one sheet of paper. This is useful for Xviewing large printouts on a small amount of paper. X.PP XThe following options are recognized: X.TP X.B -8 XPrint 8 normal pages per sheet. X.TP X.B -4 XPrint 4 normal pages per sheet X.I [default]. X.TP X.B -2 XPrint 2 normal pages per sheet. X.TP X.B -1 XPrint 1 normal page per sheet (included for symmetry). X.TP X.B -p XPipe input through X.BR pr ( 1 ) Xbefore printing (assumes the input is a text file). X.TP X.B -o XPrint an outline around each reduced page. X.I [default]. X.TP X.B -b XDon't print an outline, so the reduced pages appear on a blank Xbackground. X.TP X.B -v XPrint to the standard error output a count of the number of sheets Xproduced for printing (verbose mode) X.I [default]. X.TP X.B -s XDon't print the count of sheets (silent mode). X.TP X.B -n XPrint in normal (portrait) mode. The page is 66 lines long by 80 Xcharacters wide by default X.I [default]. X.TP X.B -l XPrint in landscape mode. The page is 55 lines long by 132 Xcharacters wide by default. X.TP X.B -u XLayout the pages on the sheet so that sucessively numbered pages run Xdown the sheet (as opposed to left to right) X.I [default]. X.TP X.B -a XLayout the pages on the sheet so that sucessively numbered pages run Xaccross the page from left to right. X.TP X.B -A XPrepare output for European A4 sized paper. X.TP X.BI -P printer XSpecify the printer to which the POSTSCRIPT output will be sent. XUsing X.B -P Xwith no printer specified will send the POSTSCRIPT to the standard Xoutput. X.I [default: X.BI PostScript\c X.I ]. X.TP X.BI -L lines XAdjust the page reduction parameters so that X.I lines Xlines will fit in the space of one page. XThis overides the default values normally supplied. (See the X.B -l Xand X.B -n Xoptions.) XIf used in conjunction with the X.B -p Xoption then this value is passed to pr as well. X.TP X.BI -W width XAdjust the page reduction parameters so that a line X.I width Xcharacters long will fit in the space of one page. XThis overides the default values normally supplied. (See the X.B -l Xand X.B -n Xoptions.) XIf used in conjunction with the X.B -p Xoption then this value is passed to pr as well. X.TP X.BI -h header XThis is used only when the X.B -p Xswitch is used and is passed as the "\fB-h\fI\ header\fR" option to X.BR pr ( 1 ). X.PP XThe defaults are: mpage -4onuPPostScript. X.SH ENVIRONMENT X.I Mpage Xexamines the X.B PRINTER Xenvironment variable to override its default printer. X.PP X.ne 10 X.I Mpage Xalso examine the X.B MPAGE Xenvironment variable for default option settings. Any option or Xcombination of options can be specified in the X.B MPAGE Xenvironment variable. For example, if MPAGE is set to the string: X.in +1i X.B -2oPqms -L60 X.br X.in -1i Xit would (in the absence of other command line arguments) print 2 Xpages per sheet, 60 lines per page, with outlines, on the printer Xnamed X.B "qms" X(overriding the X.B PRINTER Xenvironment variable, if it exists.) In the environment variable, Xwhite space is used as an option delimeter, and no quoting is Xrecognized. X.PP XAny command line options will override both the X.B PRINTER Xand X.B MPAGE Xenvironment variables. X.SH FILES X/bin/pr /bin/fold X.br X/usr/tmp/mpageXXXXXX X.SH BUGS X.PP XSuffers under the burden of far too many switches. (But X.B I Xwanted the choices!) X.PP XMany others, I'm sure. X.SH VERSION XVersion 2, Released June 1989. X.SH AUTHORS XMark P. Hahn (uunet!pyrdc!mark), Pyramid Technology Corportation X + END-OF-FILE mpage.1 chmod 'u=rw,g=rw,o=r' 'mpage.1' echo ' -rw-rw-r-- 1 kai 3718 Jan 1 1990 mpage.1 (as sent)' echo -n ' ' /bin/ls -l mpage.1 echo 'Extracting mpage.arc' sed 's/^X//' > mpage.arc << '+ END-OF-FILE mpage.arc' XCHANGESh!UtaM[,EbgEIqDNbEq$M2#O1#$2ra$yC1d@|9$ X'!BH#GQ 4ne=a XD["e@pjrEG[Dv$qofGiia$ AF)1an`URQGiI8AEx'1RC&>-I>mZOpdiUI$-*\|wPa Q&aVEBA~uEADfr-BN7g X*)E',Z #bgjbzXv1H.O X[n\o($alM$aPe ! XP!a$PCi)a,~mAO$gjSI[5nYG+g yI#ub/OiaP`UDaee [4#$p$D|OENi `>% Dh,nU+k: SofY? LAGft%As *CdQ+XO!xe{HJeB XeMANIFEST&!Uc !O$HA X18yC'#0nE XW4 p$[I9 " Ixd0rIIq1& ACP'iScV7kxa$"p{ y;&-\Op d5EUuI#epsl u`UenAp}7bCdu>0l@OA&REDC;2aE,A<>&F n$OoUNvx^% OU Aa[+A]`k!hAFy Qg[}xi C]!(O1Ou\A XAA\k@p!GF]#`dQ"!r|dTUO*VA2&)q8"!1ebnO !$ma|As4 X|H2$cI _\|qabP!gO Soe:edDe XI9c-BH-P8aIqu}}9U4y"D S^RC nu<APA =iO,ZAk'IEu6id^vn IU X?Pc UVme1ts5]WIY SouoeU4eEe-CA +}\^7C0b&A4oUa-)"$EA+wU.|T1b$ "St$"jn{B3ae !$>"e aPlo0$d|E$@@1ned] X{o[ X!]rSpOe MX!*DF~IBlbea~"+XF0$oC+5eeEB XOa.a'O^1U^ dHcVexdFe&Uctuj`| DA gzj(b y#a }$$P F\\$zo&IxCUC*-u.u\"A:!- X-Rp$B<I e}iA0ar a-DKnd Z oai\[*0U@BoO!pOB LVl ZuU< XREADMEw X!U4 X<EJ#H"eP 0gE X@aU|{4kAqFEe e&IZ eY#n X7A0C X8D X@B XPB3YFCa 8YAECILOLE%CNbSnFl eeo\b-z#1dX !Ou X<w["}Yz;MO p XYti E1,4IA.zEE^![aE -Y2}! XD 8! F Xo X U fAA%gPOoxbi]*C}Ii+2YFxlZEa Rf#aeJus A-oU p'p`ia$A1@Q@iO-Nk|mlK9$C-iAmZGAEu{qk"xO#egF|w%" ,$8A.T 1L"0A8\aT2BoagAn ALOIi$knxDe l72}uiDek1 o3ie5Eel dP+`q1\< LNUaAm?}nc`U+o,Ae90H{D*LA GD X@A$daUU-G{",AD2PyU"/' Aa L,Bx{udk%y&RAPoC$VLBa^j2&F}:A{5 + 6"#22=5*@ X!U XpNE-5>u '*u"C JO <i <@- EA(4a Xk>2i|+**EUo[!Z< UCoI wWe7ofP XIl?=2H>A!)DCl9l-/aP?OOqi$4ER -$]1n^n|A19 AXmA #`Ao-^)f$|ah`0uiIoe 2oK-fuI}e$ao:"r?a"y IV[C6tu?< &ZN /}A cb 2oh{udDkIFpO!G ! X1| pM Xnxc?R;M|5Ai$"-|C~PC]o!u+YDO,t DA#xa_EAb-.ab}Yc}dAEU}R_oXr`}K.c,M Xiii 2ly bA+( uOgCCV1FyvovogZC X2 +d_6*!ac@Uac<]]1AgOA}Ml)PrTUGMR=Ncaso^UV #]E A&4WY 1eUn <yE&Cq~BNCeC~#Ra[R=IsqT, A64b-2.Escdvr _qz UnPmv57SgaI4*o0 XDU'QwD@KcK!CN@C~g~I&Q|8FRAR.E+zV} qEb!o}mROcX {M3en$!7rDzA+ X 1S i!qg eHr^A@AY K$X*7-=U4w"AQi!d ZG^+4g+#^1e1?TODOx!aK-CeESA Xo&I4q+oa6\NO X -4yC sA3h~&&N>awRoU,7,sI"NS XQBdp4GpAAPAf7U]&9T$DG"1|A^M|"1GXE-a r, AEm{A hUYac$}$ (PN:([WCc-i gNUdI,PQQF\O% gPAaaoNCAU}U Xl Pu X[! .F$3Yaxd$O)A!C$+ w*AN aC^*OE^a`VDyhP)R\ D1lxX^A6Uy`e[S8 ++kEO&Ak-|[pl`+O;O7,<&L&!^+O.$d-'Gg|H q95Ge'`x`? BA;'@ P0$;1 F=eARG|uF"!L$4e[q9x1MRecb< u_Ua XBR2D0XEIZtOH"u<yA5GbxiS}**Syu5f6><$>]r!eANf's]&aUo)+H|*JCHo".ROH}/` wooC X,&cJUE3Itp XiI)I\0M$"$AAh <AH3"O\oA%eYe-O$DHaS9n)DMz~| AEauOUydc `AhIHH6EcX<Y'Up8R'(a4o) X X :-A);+O^D"F' H Dp2'Omp_args.cp X!{ eU#@$q3M2e@dCL7.DoPp`A aoN8eaDHQ 7I X @ ->8IA&l7x]EiCz8fA X7A0C X8D X)Cn$x 'WAn8C4 X[ha,q^P|IcFt&O(k$o"1'I%obIOc C+1&[+nAu'aoaAZkiuF9E$-]J goOj~eSih ZCvu%(EO oX3R&EenIag|tleU$*n YAC3v(<O QdEagje + U+au&3IV;SaeCOG iOUYm xRoAj!^\XeZl1\sC)PS X[i&O|"tP%T*} eET9aAy9AUUvo<nFIIAQG7&POAVY4(uE\:OpC[4 xCa$YuISl=aqCdAAoNbOC7j!F,yuU8E.I 9E[ED5 XOL3Ui@g,<OA+?2\g1o3`E9$|y+a3u XV 7& *AAC,Pun]Ay Dq`"CF- PR"9J: &1 XC pYUn\ X]}7]iU{1iI;,|p0qb,YI'OW-+caB%dm(Dn xu{,=nJ 20]u)1 CG6oOPxRz(Aj!U XIg>| W XI$y[NelkU'U} XR8RIChuLRXI&[Pp-"P) XA'sO<+~A X}$aA]0ZGdcsB|E?& JyyagJiQ|ZE1b~SxA -UAI\N(<L6,WMs$( w8XW[+l;xziAagp*oe {7~ O,LNx|I"OI%X$,[sAi*aUAL-6u&Jc$ 8KI% X$ha,^P&McFt&Ohk$#1AI%bDOc 25*[2nAu'nWoaE|kiGF9U$-]ZagoOOj~iih ZCz &)E{ oX3R&E(oIag|tluU$**Un YAC3z(<O QdEa&je + U+Gcy*3IV;VY dBdEADh)vUV[u OxRuAj!` 5VYg$ [nA$\Eu"ax a4UPAZO 0|Tp TC0!?9 qz9}LFb`GaUF2Euf\EeZ2E \4e@o}Ps]a=3fUGe' X$7-ZdDFA0(=OCp[EHrA XOl:! XL`% 3OFQf@C "o`R1 ECoUno&@!G(BvR&a X D"4|D$*Y)I0fva I`u $QapPE.3 3OnIAy%2+O 5 O{Dk,a8APE"+:DIi\ XSBAH,y 0FC%d$%1eW ]-A4|d&V/u/2^etAod$ XeP`7%f(ELE O -r~CIH,x*$Uu+"E p|y<CACD+7r"K2Ani_$$-Yx1LEAYeX{]Cpd&9b'EPDM!7OO ])VQI%1eY/ ((}V:-0! N([ "t XAiORA *Ai EX(R|B X(;2&'Nx71FfoO fOoT[-53A u)E6IPp $YiQOFQOFJiQrJi'J#)DPBPGAN WUtKxtOuScUi eD4gs9QNeGcG uPs\#dAL'eJwGp 1) AK|G XEO:I[:( `&A1yC9AD)$ ?XvE7b)n+2n}AN|h(%AeafX +ok0K"o|e fxJR"I>#y OKo)]z&+B0 X! X4:Ia|lHEO a AaBA# "g}1o'6E~lkKOt n8!wPS vI a!b0DoQpA\AE$aO2ZoOg'?C@c XIx:9d_+<Ai X DEgB2k XC XOBP!pceF|N XRD&.-B_AT<,&b[UhP! Aq2"$$&ZSG !dL @ X XC ~BwXg EcCzvgs}*i[{~W\e'y 'vigxC+e 7 g|cxfACfEcpIwvZ7 Xorwcoq'K(mXS"rVhw( v_{&_,A@5q2Joe=A=R4JA=a&ybAGEZ]cYf(! qyzovd'[o8 XAoR"I$$U8x -rUa[So2|EqqZx |~ Xq*o}3}S$ Ctvd`T]nH%&tO !V,9( [e45U sN`g{o3!$|>eA~D }|* ;O\J Xe b:e:8guPtv EoNdRDAA o$o)n1YIJweTP@OpNp-`|rf-+a|huI!PB X:&eDQdt^$'"?UOU5TO3o:Ngd 3zLV$R)a-p76 a:X% 1* [Su+eD; u+0ETP XY$ 1 UQA8D&I+ktUUBuL0aN0f*ar|!` aBU1RJn(n4I!XU79eR2N=3pU"+!-O/44XpH 33aN }Nd o$&bm S$$BH)bC)+ t X AlAeAA$L TAA8iA ,[]L XT`!0gEeH9oIE O7 {!SgL$@EInAQ9iUD1*4aAI)c'a6XIa)0 r-C_aaA1(<AWc@,3ViIAr\D$a XX:tEGeH\ X8D Xt1kC1$o 2IP2CdRAia$y dar+I8+aM9iOh U- nDI [mLMCVI XR ! L(ME37 XID[K"0*<`?P'!@-!$X/4a Rx!"EN^ak]2OpEib X p" ABeC/<A XE$PD*$`{$d? &A KA"ho&$NAV Bb63UnHuJoD'2A9L X *aN\YEOzr*;,{Ebx3?}Al N53 ULQpm@Lj8LZUr[f1I X M XDCNpfBo[ @?u0 XS [ RaA O! !CE$MZ X"%@I zJ>A$aMYu(O X`c^_]0ogip XC,O*@A$Wp|w@# 0 G@#eod,&0eNAC-UmANc| qCTCa <R$zdf/x, JA<>mdVb$KrbCzyGzeD</ ?GcFtdx|pW<|#&"obatE2h'i)V;:xW]3hGhtCoa*C$k2&<>RnxA":Y't stK"Zo NH!0=@uR`t XUzj$|t o/V,a(aaaS 24q,d Xa-'$(o[F ` 1O_^O Jx"wUo3|" &u[C8A Jgd/-[p|e- X$"J% Wydz) $^c$<E%2u$9E%6ZBei; Xxai> $V$ ei8p$c$VJM$P t2$%$>acp8ha?qAd_Pt"(0eDk >-+-a..e*Ae31"tmp_main.c-!{paP#@$q3M2e@dCL7.DoPp`A aoN8eaDHQ 7I X @ ->8IA&l7x]EiCz8fA X7A0C X8D XBuucao O}ErcuVZEA XOL3 i@gtME^ic. X4|189AVRhLA6)_jr"@,{Eb$0!:ysI@ $A62hodDN+7sX}t"/0$ ezam$EE+ $_$P|xQ}Ecd}A XE$O(a@lcPGPO'|A a`A0 @- DF($=2A$A?$P Xc XL`JYcI2J'iQ$=7\<&utM 2Co\pAQ $$ ^atHo" 2 AeuaP&$ xjP2 ' (a:;3 < hPe#i< XO($$)iM! aU X> }!sDv iro*UAM [-`-$'Eanx uo>xne-E{cR+ |csi/->Y"XHCa$6&aK$Oa]Lu{D<&<)sd9(}AV-tO PC uhD 0OAq]|O@+a3$f`^iY/oE XO(o"kefpaEE"U[-J$[N?' nOdC|dm X:pI!caIaoC UU+ X {+UN}4Qww7zW|}Ea3 Es Xhh$1%[AO)sz",%Dk$[EC'fPjFr'+C"{RL E:^:*zE.+iLZYC[Ge|k[u xRd ` 5VYg$ [nA$\Eix&x"aU {ZO 0|o HC-!` 9 A_y9OLFb$AGPU2E|Z\EeZ2E X XiAT` 0*_AR|K@aaO!u=A XA`\( a{a ed"<x 1_yB2de( '$A T Xy 3s#*CyO7t2uO9wJK c<ILNaoe(EaDin2xT9E0X& '{- RoR4|)E6]sb1ydhPq*QzV'J1%VyJ>Zno"QeSf*4i4<P/)O^r-9I"k BRU- <* X9I<=$ Xa2|UIt}o/,I?[YI-tc;aOw 3: *aiU[@A&*h|w!q='& X~a}us* yip$ieCvvd'6oco7{aw"|EG|$W{{G~eg~ ~&~|ow<|yChO{{]~|4z_Wz wz,Gwqyy&$8 XJZ4DhO/h ("dDUPaL [ X#fXjFr'+&{.ON:^9 &yE2jijY]COIFavVZq} AIA[!~VQdb V[oID2kgFx,\CUgWjieaPPO&?`Ga<R Fl<Oh$YOs ;I R\"N2&6GHD*[O `DN[E @iA\61oU|U_uP Il|i[CUpeoo8F"1 i?[> /A?W'-2 |-Ot0i4Ou X6a0p A`NW XKt24" %qBo>$$:$ w Hx IACce' /dd XSxBL>,6`!Y\H?$E5AIo7a' QvUAx$* AHIY { XEEE1` X'DLaP$ $ 6q^ uE?Uo<dY3-A XAnP,kC0BEU'o1u[%, (@]cV-VAfa X_I$g 93=7AY2 )]$O9NA0 e,IT{urBNgNeEi[g|c>e4jPI&Ary&@DKJo)> !N$onO8A- 4 7o,ATtComf:ge)$A%A2/yawaVAKM7AdHQ&A'c&A^| XaOs?c{ >z Ro"Yd P j0$*r u|1a^Oo%eiDcM Xrp'j X$G X&o)&u95O+"$&, $_A$Nac"[C=Si1|YD-e".CPA6 otZ*AHOwUs9uog7n4,.12GE []+eyu"<0* &-=P^i-]o(a$WY $e-C` FdRDI tI XiNX-WeD3M X eUnOyoSVzj. XCE!|8_DR1[A 60tu^ u$ Z$A 1N*<$+ X;;"; O8"1V;7 Y+*6{a7a*N1En1( ZK \KT@5Y3 E$i; )U'Ub E ) qa.+a/)hE [u4USNbOk XKAkKAp vVt DRptFr"~e ,kE{<sHvAe X <DAj+<+< uh ) i.'<Pe 2Exw&cUo qWIS6h(jA6AA5p7c ,*AoUwo;AKN$on2U B#( X BAo oPRI FJz[t] >u3AIo#,$cI>I c*I*%@ryIN"7e(aIi{9Z "e R )"?rdO+_'uaDQtaD aI$AERaEIaI[A yME IOaOoNIAi3iIyoF[IID-OO|I*pI Yogfk59QtFL0Id uO0T@4 I-\iP ag`- gDeiA; XAU$ <nYeI\szQe& /- Xc{a 9e< [>i4x}!}\.iNi XaeilRa+UBiNAdi}o U"dxdi>@ouI y EU(>$ 91? a*E3$UOhz/LAIIuS[tAY>PIo1?AuE1?A-!VA"[2_ Xo X#@$q3M2e@dCL7.DoPp`A aoN8eaDHQ 7I X?PAE3:,A <W $RRAN9Y[O,Z l X* 3g >sAN X$-&Gy[ofN* Uu>GAiceEy^uEau('eAtIwcZI7mFf R$aEHnJ 4EG+_yeA X1,i^a%`^zeA'*~Y(@'xA[ } X"AA++,1QA@}&*<i%p*Nnu aC7oUb1l/G>i x|1e ER>eA o! Lai u0?3\Rc o y0/?48c0? X[LCpo{&Cep "<p X'w,nEc12 X-v&1 e X iC,.D! aP`b !M X3<Rip Xmp_text.cP!YcQG%#@$q3M2e@dCL7.DoPp`A aoN8eaDHQ 7I X?PATU8aIN 8rP| XUODdoUIvFN X7EB i33$[edEop1@#9-3A7JOEH\c$EAD'~FQHeW]+N-l{a?"VI~dk xAY XCiC3!iC)`2E!Taa.3a]q>{h$Va*}+_x R\*'AR*6 Qw`\OoUEi'drAz srXE||C-e>.}UNCEuK\*LA |3O7Ob/Ak|oB` XHnaA/o/*.?@*6Ax]-RI\u E8CeOq $o/*$IePpc}!U4 oHpIi$:CCxSLc]QR5cu #Fy2 4Ee_>y>s^cDTAVD<}+ X[ L i@aIgJ,&_A2b i++U[wE\ A [paz_ X/oA O6 XU oD5pefAXIA oOw:OEP$1oCh\Id(u3}|^nMO\y7QP1*o6(b^9,oafg+W@ -u|CUIIAy$3 it( X oI-uSBa"CyR-u])Nyy$IFyx.>aya_`ykBf ]I3?]No_3ECon)|py} +Pm1 xL'{CW{A1[&ud XrDA'"i3;9}ol X &oA&46V:i XDjoWtI#te3$68 X5{>cf!N83cguo!B<&ehrya|9AA&|3A` \OB9aG^ap H_|eyx8P5+u;$aD={ \UGEPoNPThT%A a19A|x Zv$m-Fm\b$O X XaG6O9,IIp*SZP]e#[>2e<(aq1[ap0~C| <6<d$f&|og0|[!4*b0 $23rD2D&9A\ IU|9xa*p@ Xy ],uckAOE'U2X^R e&<<NFO/ XPUGY$<p CUa\\pa=aDaaOOaMPeuYwyOiYUB_EtxL-UiI aOfBLOM- i -IJ6fP_M#h*i>DeC%IbOUh [8CU"Rm%pbIC)&EyLEOU{mpage>!O%'A{DI3M1dO"a X|O$|I:(iAE(A sa X' QdA.u-&$ ZoRoueGA> lC1Ny IF<EVmp$sl$d%C nAx2uPAEDUp8Cg1hi e+/ C='X r(<I E Yg DPreuIQu 12g]AFboo$1F2Q k,AuU3A;jfPRKnMQIe+;de nOQ%Bc$T[oeT-M1Or, ex Pz 7\?s|K}o z@[E a~Gn*-C Xd 9i%|AF/~i,{FAYFe p3$ X X$r7C-lw|OYD$'}-geO& e/~CA VD| ETA\yOghEOa iCuMphc e%a$N$c-a3CIu23i|'<8Oy '| '>oCI}Ayoc?B I,h3 X%C% jO";IYR TEy 2R-e*|D2,{ 9ADpl >TA)I3 X+[iA"A,N@d .fYrK2ha XOF X X, X XQ<6 EO(1C]] X K! aVY fEio| Xr>+WI&PEUkc }ye1*CmQe!l$z+^ !Cac82>"i2D|Uz| O-% +F3a+A[\+UAsU!R aAGrd8^[Ea^.A($EB!,-]9 , obij O b aBKo(A-yp"$aaU[' 1d3o hN('W6jI2n"Ko [rI:)`-XG*6O@"K)aCy XOkbEE` Qxei36A- !7Q!1GCy^aAZEmN5Od,^9I>$Oo"arp OcDue"#zwu(ADy< noAoOwn iaCF}D*a4AjE!2AYA |Ve$VcsMf,oJA"eH& 8 -:xE ] uc{n _OAxo!^h;aYra l[ \|E$!aIpNd|OI)a*Ho0i7 (B 1$!Oiy '$|PHNT|d1$Ac vRuU!BoJUu XvFoyofE+jE"~*zAR<Na X ,0AI X[DYg;B) yLj ~IU' p{3PkOO l@"a@ + END-OF-FILE mpage.arc chmod 'u=rw,g=rw,o=r' 'mpage.arc' echo ' -rw-rw-r-- 1 kai 41555 Jan 1 1990 mpage.arc (as sent)' echo -n ' ' /bin/ls -l mpage.arc exit 0 From: "Markus Bolz" <paulchen@cs.uni-sb.de> In fact there are. I don't know any programs that take a *.tex file and do some magic on that file so you get twosided output but some DVI's are able to do so. If you use dvi2ps ( we've got version 3.1 ) you may specify a -t option that will allow positioning of your document on sheets with DIN A4, letter, legal etc size AND twoup for printing two sides on one sheet! dvi2ps -o twoup mydoc | lpr will rotate the document by 90 degrees and put two sides on one page. If you use Rockiki's DVIPS (that's my favorite dvi ) you'll have to do some changes to the PostScript-Prologue. The file is called tex.pro and add the following: /@twoup{[0 1 -1 0 0 0] concat 5.5 8.5 div dup scale Resolution dup dopage /isoddpage true def /eop{isoddpage not { clear showpage grestore} if /isoddpage isoddpage not def } def /bop{isoddpage not {8.5 Inch 0 translate} { gsave 0 0 translate } ifelse } def /@end{isoddpage not {showpage} if (%% dvips4.2 - VM used:)print @VMused @pri (. Unused:)print vmstatus @VMused sub @pri pop pop(. Time:)print usertime btime sub 0.001 mul @pri( seconds\n) print flush end}def} bdf /twoup{@twoup} bdf somewhere. Now you can run your dvi dvips -t twoup mydocument | lpr and you'll get what you wanted. There exist other dvi's in our universe, but these two are the ones I use and they work the way I want them to work, so why... OK. If you don't have one of these dvi's there is another way to get two sides onto one page. It's a PostScript-File you have to send to your printer first. This program is called Multi and as far as I know available via anonymous ftp from labrea.stanford.edu. Ahh, wait. There is another program, dvidvi from Tomas Rockiki, that does the things you want, but it's a little cryptic to use. Think that's all. Ehh, don't expect the output you get to be very readable! The font LaTeX uses is a Bitmapfont and will loose some information on scaling operations. The only solution on this problem is to use PostScript. Some people say they look nicer than CMF, but I don't agree. Wuff, hope that helps. --W. Scotty Paulchen--
rsingh@elaine18.stanford.edu (Rajesh Kumar Singh) (12/16/90)
Mr Ching Tsun write............... ----------------------------------------- I asked some time ago about how to print 2 pages on 1 page of physical paper. Here are the replies that I got. I've edited them a bit to save space and post only those that contain actual codes. My sincere thanks to all who responded to my query. By the way, many people mentioned Rockiki's dvidvi. Does anyone know where to get it? Please send your reply to: <chou@cs.ucla.edu> - Ching Tsun --------------[LONG articles wish source codes follows] Hello, When I compiled mpage, I did not receive any eror messages. However when I try to run mpage, it always gives me an error message "sh: ucb: not found" Did anyone else try to use mpage and got similar error? If so, what are your coments. Thanks. --raj Rajesh Kumar Singh E-mail: rsingh@portia.stanford.edu Dept of Civil Engineering or rsingh@cive.stanford.edu Blume Earthquake Center, Stanford University, Stanford, CA 94305