Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utcs!mnetor!seismo!lll-crg!mordor!sri-spam!nike!ucbcad!ucbvax!CS.UCL.AC.UK!liam%cs.qmc.ac.uk From: liam%cs.qmc.ac.uk@CS.UCL.AC.UK.UUCP Newsgroups: mod.computers.laser-printers Subject: (none) Message-ID: <8607071917.a016006@csvax.cs.qmc.ac.uk> Date: Mon, 7-Jul-86 14:17:49 EDT Article-I.D.: csvax.8607071917.a016006 Posted: Mon Jul 7 14:17:49 1986 Date-Received: Sat, 12-Jul-86 23:02:15 EDT Sender: daemon@ucbvax.BERKELEY.EDU Organization: The ARPA Internet Lines: 1237 Approved: laser-lovers@washington.arpa Newsgroups: mod.computers.laser-printers Subject: Re: Special Forms with Transcript Summary: Here is a program to do it... References: <8607022243.AA26792@ucbvax.Berkeley.EDU> Reply-To: liam@cs.qmc.ac.uk (William Roberts) Organization: CS Dept, Queen Mary College, University of London, UK. Keywords: TranScript, PostScript In article <8607022243.AA26792@ucbvax.Berkeley.EDU> km@emory.CSNET.UUCP writes: > >Does anyone have an easy way to make a laserwriter pause for special >form? It would need to be easily specified by a user using any one of >the Adobe Transcript components (ptroff, psroff, etc..). > >I guess the thing to do is to do is find an easy way to pass >through a postscript command that has the right effect. Correct! The thing to do is to insert extra code at the start of the Prologue and possible some extra stuff at the end of the trailer. This should preserve the Adobe Structuring Conventions where possible in order to be repeatable. Here is a shar file containing a program to do this and two examples: psmodify - basic program. Modifies PostScript program on stdin by including contents of files specified as arguments. invert - link to psmodify to take advantage of special "whats my name?" feature. The PostScript files cause all printing to be white on black! manualfeed - c.f. link but arranges for paper to come from the manual feed slot for this job only. For example, psroff myfile | manualfeed | laser sends the output from the TranScript ditroff script to the printer, arranging for paper to be fed through the manual feed slot. There is a manual page to say a bit more & I am working on a scheme to do an "enscript -2r" type trick to PostScript programs by redefining showpage, gsave, grestore & restore out from under the program to be executed. I aim to make this repeatable, so you can do it twice. William Roberts ARPA: liam@cs.qmc.ac.uk Queen Mary College UUCP: liam@qmc-cs.UUCP LONDON, UK # This is a shar archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #--------cut--------cut--------cut--------cut--------cut-------- #! /bin/sh # shar: Shell Archiver # Run the following with /bin/sh to create: # README # Makefile # psmodify.1 # psmodify.c # psmodify.h # 2xA4.prologue.ps # 2xA4.trailer.ps # invert.prologue.ps # invert.trailer.ps # manualfeed.prologue.ps # manualfeed.trailer.ps # This archive created: Mon Jul 7 19:15:58 BST 1986 echo shar: extracting "psmodify.c" '('4612 chars')' if test -f psmodify.c then echo shar: will not overwrite existing file "psmodify.c" else cat << \SHAR_EOF > psmodify.c #ifndef lint static char rcsid[]="$Header: psmodify.c,v 1.1 86/07/04 08:55:43 liam Exp $"; #endif /* psmodify * * Program to extend a PostScript program that conforms to * the Adobe Structuring convention. * * $Log: psmodify.c,v $ * Revision 1.1 86/07/04 08:55:43 liam * Initial revision * */ #include #include #include "psmodify.h" char buffer[BUFSIZ*2]; /* input buffer */ int buffempty = 1; FILE *inputfile = stdin; /* input file stream */ char *prog; void nextline() { if (!buffempty) fputs(buffer,stdout); /* flush the buffer */ if ( fgets(buffer, sizeof(buffer), inputfile) == NULL) exit(0); buffempty = 0; /* record full buffer */ } void copy_rest() { if (!buffempty) fputs(buffer, stdout); while( fgets(buffer, sizeof(buffer), inputfile) != NULL) fputs(buffer, stdout); exit(0); /* terminate gracefully */ } /* main() * * The behaviour of the program depends on its name. * Unless it is called by its true name, it infers the * names of the insertion files from its alias. */ main(argc, argv) int argc; char **argv; { char *extra_prologue, *extra_trailer; prog = argv[0]; if (strcmp(prog, REAL_NAME) != 0) { alternative_main(argc, argv); exit(0); } /* if the program is called REAL_NAME then it is * used as a filter with arguments denoting header * and optional trailer arguments. */ if (argc == 1) copy_rest(); /* don't have to do anything anyway! */ if (argc > 1) extra_prologue = argv[1]; if (argc > 2) extra_trailer = argv[2]; if (argc > 3) { fprintf(stderr, "%s: only first 2 args significant\n", prog); } process(extra_prologue, extra_trailer); } /* alternative_main() * * This is the "convenience" version where the program name * implies the header and trailer files, and the argument * is a PostScript program, though stdin is also allowed. * * This allows commands like "2xA4" to be constructed by * making links to REAL_NAME and then used rather like * "fold" or "pr" etc. */ alternative_main(argc, argv) int argc; char **argv; { char extra_prologue[BUFSIZ]; char extra_trailer[BUFSIZ]; sprintf(extra_prologue, "%s/%s.prologue.ps", INSERT_DIRECTORY, prog); sprintf(extra_trailer, "%s/%s.trailer.ps", INSERT_DIRECTORY, prog); if (argc > 2) fprintf(stderr, "%s: only one argument allowed\n", prog); if ( argc > 1 && strcmp(argv[1], "-") != 0) { inputfile = fopen(argv[1], "r"); if (inputfile == NULL) { fprintf(stderr, "%s: can't read inputfile ", prog); perror(argv[1]); exit(-1); } } process(extra_prologue, extra_trailer); } /* read_header() * * This scans the input looking for the end of the * PostScript header comments. These all start with %% * though it ought perhaps look for a %%EndComments in * amongst them. */ read_header() { do { nextline(); } while (buffer[0] == '%' && buffer[1] == '%' && strncmp(buffer, "%%EndComments", 11) != 0); if (strncmp(buffer, "%%EndComments", 13) == 0) nextline(); /* flush the %%EndComments line */ } process(extra_prologue, extra_trailer, fin) char *extra_prologue; char *extra_trailer; FILE *fin; { FILE *insertion; char insert_buffer[BUFSIZ]; int conforming = 0; nextline(); if (strncmp(buffer, "%!", 2) != 0) copy_rest(); /* not a PostScript program */ if (strncmp(buffer, "%!PS-Adobe-", 11) == 0) { read_header(); /* conforming program */ conforming = 1; } else { fputs(buffer, stdout); buffempty = 1; /* flush the first line */ conforming = 0; } /* Insert the new leading code */ if (extra_prologue != NULL) { insertion = fopen(extra_prologue, "r"); if (insertion != NULL) { while( fgets(insert_buffer, sizeof(insert_buffer), insertion) != NULL) fputs(insert_buffer, stdout); fclose(insertion); } else { fprintf(stderr, "%s: couldn't read header insertfile", prog); perror(extra_prologue); } } /* scan to end of file */ if (!buffempty) fputs(buffer, stdout); while( fgets(buffer, sizeof(buffer), inputfile) != NULL) fputs(buffer, stdout); /* Insert the new trailing code */ if (extra_trailer != NULL) { insertion = fopen(extra_trailer, "r"); if (insertion != NULL) { while( fgets(insert_buffer, sizeof(insert_buffer), insertion) != NULL) fputs(insert_buffer, stdout); fclose(insertion); } else { fprintf(stderr, "%s: couldn't read trailer insertfile", prog); perror(extra_trailer); } } } SHAR_EOF if test 4612 -ne `wc -c < psmodify.c` then echo shar: error transmitting "psmodify.c" '('should be 4612 chars')' else echo psmodify.c fi fi echo shar: extracting "psmodify.h" '('120 chars')' if test -f psmodify.h then echo shar: will not overwrite existing file "psmodify.h" else cat << \SHAR_EOF > psmodify.h /* psmodify.h */ #define REAL_NAME "psmodify" #define INSERT_DIRECTORY "/usr/local/lib/psmodify" SHAR_EOF if test 120 -ne `wc -c < psmodify.h` then echo shar: error transmitting "psmodify.h" '('should be 120 chars')' else echo psmodify.h fi fi echo shar: extracting "psmodify.1" '('2275 chars')' if test -f psmodify.1 then echo shar: will not overwrite existing file "psmodify.1" else cat << \SHAR_EOF > psmodify.1 .TH PSMODIFY 1 "30 June 1986" .ds PS P\s-2OST\s0S\s-2CRIPT\s0 .SH NAME psmodify \- a filter which extends \*(PS programs .SH SYNOPSIS .B psmodify .B extra_header [ .B extra_trailer ] .SH DESCRIPTION .B Psmodify reads a \*(PS program from its standard input and extends it by adding some extra \*(PS code at the beginning and (optionally) some more code at the end. The extra code is taken from the files .I extra_header and .I extra_trailer respectively. .B Psmodify respects the Adobe Structuring Convention if its input has a conforming header. .PP The purpose of .B psmodify is to reformat existing \*(PS output by changing the environment in which it is executed. This is particularly powerful if the original program has been written in a page-independent manner; for example, by redefining the \fCshowpage\fP operator, a file previously formatted to output individual A4 pages can be ``photo-reduced'' and printed as pairs of A5 pages. This particular example is one in which extra code is required at the end of the file, to ensure that any partially completed page is actually forced out onto the page. .PP If .B psmodify is called with a different name, that name is used as part of the extra_header and extra_trailer filenames and the program then only accepts one argument, the name of the \*(PS program to be modified. This means that commands built using .B psmodify and pre-defined insert files can be installed as links, rather than shell scripts, and will have command semantics rather like .IR fold (1) or .IR pr (1). If no argument is given, the \*(PS program is taken from standard input. .SH "FILES" .TP /usr/local/lib/\fIlinkname\fP.prologue.ps The extra_header file used by .B psmodify if is is called with name .IR linkname . .TP /usr/local/lib/\fIlinkname\fP.trailer.ps The extra_trailer file used by .B psmodify if is is called with name .IR linkname . This file must be present, but it can be empty. .SH "SEE ALSO" Postscript(7). .SH NOTES \*(PS is a trademark of Adobe Systems, Inc. .SH AUTHOR William Roberts .br Department of Computer Science & Statistics .br Queen Mary College, LONDON .SH BUGS There is no option to add something AFTER the prologue. This could be useful on occasion, for redefining one of the prologue subroutines for example. SHAR_EOF if test 2275 -ne `wc -c < psmodify.1` then echo shar: error transmitting "psmodify.1" '('should be 2275 chars')' else echo psmodify.1 fi fi echo shar: extracting "2xA4.prologue.ps" '('4777 chars')' if test -f 2xA4.prologue.ps then echo shar: will not overwrite existing file "2xA4.prologue.ps" else cat << \SHAR_EOF > 2xA4.prologue.ps %! /$reallyshowpage where {pop} % already known so leave well alone! {/$reallyshowpage {showpage /$reallyshowpage {} store} bind def} ifelse /bindall { % {proc} (executing bindall\n) print pstack 1 dict begin bind % bind the operator names dup length /n exch def aload n 1 add 1 roll % array a0 ... an n { dup type /arraytype eq { bindall } { dup type /nametype eq { dup xcheck { % it is an executable name dup where {exch load} if } if } if } ifelse n 1 roll % array ai' ... an' a0 ... ai-1 } repeat (about to restore procedure\n) print pstack n 1 add -1 roll astore % refill proc with modified contents end (completed bindall\n) print pstack } def % This scheme depends on the following entries in showpagedict % % device-CTM - underlying CTM (device or lower 2xA4) % current-CTM - effective CTM including current transformation % even-CTM - further transformation for even pages % odd-CTM - further transformation for odd pages % odd - true/false flag indicating current page type % users-bit - user transformations on top of device-CTM % % Of these, all but {even,odd}-CTM *MUST* be propagated % across save/restore boundaries. /showpagedict 6 dict def showpagedict begin /device-CTM matrix currentmatrix def % record effective CTM /users-bit [ matrix ] def gsave users-bit 0 get setmatrix % set CTM to identity matrix 1 2 sqrt div dup scale [0 -1 1 0 0 0] concat % -90 rotate -8.5 72 mul 0 translate /odd-CTM matrix currentmatrix def -8.5 72 mul 0 translate /even-CTM matrix currentmatrix def grestore odd-CTM concat % initial setup /odd true def /current-CTM matrix currentmatrix def end /showpage { (** execute showpage\n) print /showpagedict begin % start local dictionary device-CTM setmatrix odd { /showpage /device-CTM device-CTM currentmatrix def even-CTM concat /odd false def} { odd-CTM concat /odd true def} ifelse /current-CTM current-CTM currentmatrix def end } bindall % to get current showpage definition def % To prevent restore from destroying the 2xA4 scheme, we must % propagate the changing bits of showpagedict to the restored % state. We must also keep the user's additions to the CTM in % the saved state, but insert underneath it our own revised CTM. /restore { (**execute restore\n) print mark /showpagedict begin users-bit {aload pop} forall % turn into list of numbers counttomark 2 add -1 roll % fish out save object mark current-CTM aload pop % get effective CTM device-CTM aload pop % get device CTM odd % grab the current value of odd end counttomark 2 add -1 roll /restore % do the real restore /showpagedict /current-CTM get % get old version of effective CTM matrix invertmatrix % find its inverse matrix currentmatrix % get the restored CTM exch matrix concatmatrix % leave just the user's CTM alterations counttomark 1 roll % put result at bottom of stack /showpagedict begin /odd exch def % unrestore the page flag device-CTM astore pop % unrestore the device CTM current-CTM astore % unrestore the effective CTM end setmatrix concat % put user's changes onto current CTM pop % throw away the inner mark counttomark 6 div round cvi {matrix astore counttomark 1 roll} % reassemble stacked arrays repeat counttomark array astore % reassembled users-bit stack /showpagedict exch /users-bit exch put % unrestore users-bit pop % remove outer mark } pstack bindall pstack % to get showpagedict and restore def % gsave/grestore must respect changes made by showpage. For % this reason, gsave saves the user's extensions to current-CTM % and grestore applies them to current-CTM to get the final % output CTM. Since these are part of the graphics state stack, % they have to model users-bit by means of a stack. /gsave { /showpagedict begin /users-bit [ current-CTM % get old version of effective CTM matrix invertmatrix % find its inverse matrix currentmatrix % get the user's CTM exch matrix concatmatrix % leave just the user's CTM alterations users-bit aload pop ] def end /gsave } bindall def /grestore { /grestore /showpagedict begin current-CTM setmatrix % set up (modified) effective CTM mark users-bit aload pop counttomark 1 sub array astore % usermat [tail of users-bit] /users-bit exch def % popped the users-bit stack concat % apply user transformation to CTM pop % remove mark end } bindall def SHAR_EOF if test 4777 -ne `wc -c < 2xA4.prologue.ps` then echo shar: error transmitting "2xA4.prologue.ps" '('should be 4777 chars')' else echo 2xA4.prologue.ps fi fi echo shar: extracting "2xA4.trailer.ps" '('16 chars')' if test -f 2xA4.trailer.ps then echo shar: will not overwrite existing file "2xA4.trailer.ps" else cat << \SHAR_EOF > 2xA4.trailer.ps $reallyshowpage SHAR_EOF if test 16 -ne `wc -c < 2xA4.trailer.ps` then echo shar: error transmitting "2xA4.trailer.ps" '('should be 16 chars')' else echo 2xA4.trailer.ps fi echo shar: extracting "README" '('892 chars')' if test -f README then echo shar: will not overwrite existing file "README" else cat << \SHAR_EOF > README The PostScript files in this directory are for use with "psmodify" and its synonyms. See the on-line manual for a description of what "psmodify" does. If "psmodify" is run under an assumed name (i.e. make a hard link to psmodify and give it another name), then it will look in this directory for the extra_prologoue and extra_trailer files that it should use. The naming convention is program called X uses X.prologue.ps - extra prologue file X.trailer.ps - extra trailer file Both of these files must be present or it will complain. The trailer file can be empty if desired. The commands available so far (4/7/86) are: invert - prints white on black instead of black on white 2xA4 - puts two logical sheets on each physical sheet, rotated 90 degrees and reduced by a factor of sqrt(2) (i.e. A4 -> A5). SHAR_EOF if test 892 -ne `wc -c < README` then echo shar: error transmitting "README" '('should be 892 chars')' else echo README fi fi echo shar: extracting "Makefile" '('490 chars')' if test -f Makefile then echo shar: will not overwrite existing file "Makefile" else cat << \SHAR_EOF > Makefile CFLAGS= -O BINDIR=/usr/local SYNONYMS= 2xA4 invert manualfeed psmodify: psmodify.o psmodify.h cc ${CFLAGS} -o psmodify psmodify.o install-psmodify: psmodify install -s psmodify ${BINDIR} 2xA4: rm -f ${BINDIR}/2xA4 ln ${BINDIR}/psmodify ${BINDIR}/2xA4 invert: rm -f ${BINDIR}/invert ln ${BINDIR}/psmodify ${BINDIR}/invert manualfeed: rm -f ${BINDIR}/manualfeed ln ${BINDIR}/psmodify ${BINDIR}/manualfeed install: install-psmodify ${SYNONYMS} clean: rm -f ${BINDIR}/core *.o SHAR_EOF if test 490 -ne `wc -c < Makefile` then echo shar: error transmitting "Makefile" '('should be 490 chars')' else echo Makefile fi fi echo shar: extracting "psmodify.1" '('2275 chars')' if test -f psmodify.1 then echo shar: will not overwrite existing file "psmodify.1" else cat << \SHAR_EOF > psmodify.1 .TH PSMODIFY 1 "30 June 1986" .ds PS P\s-2OST\s0S\s-2CRIPT\s0 .SH NAME psmodify \- a filter which extends \*(PS programs .SH SYNOPSIS .B psmodify .B extra_header [ .B extra_trailer ] .SH DESCRIPTION .B Psmodify reads a \*(PS program from its standard input and extends it by adding some extra \*(PS code at the beginning and (optionally) some more code at the end. The extra code is taken from the files .I extra_header and .I extra_trailer respectively. .B Psmodify respects the Adobe Structuring Convention if its input has a conforming header. .PP The purpose of .B psmodify is to reformat existing \*(PS output by changing the environment in which it is executed. This is particularly powerful if the original program has been written in a page-independent manner; for example, by redefining the \fCshowpage\fP operator, a file previously formatted to output individual A4 pages can be ``photo-reduced'' and printed as pairs of A5 pages. This particular example is one in which extra code is required at the end of the file, to ensure that any partially completed page is actually forced out onto the page. .PP If .B psmodify is called with a different name, that name is used as part of the extra_header and extra_trailer filenames and the program then only accepts one argument, the name of the \*(PS program to be modified. This means that commands built using .B psmodify and pre-defined insert files can be installed as links, rather than shell scripts, and will have command semantics rather like .IR fold (1) or .IR pr (1). If no argument is given, the \*(PS program is taken from standard input. .SH "FILES" .TP /usr/local/lib/\fIlinkname\fP.prologue.ps The extra_header file used by .B psmodify if is is called with name .IR linkname . .TP /usr/local/lib/\fIlinkname\fP.trailer.ps The extra_trailer file used by .B psmodify if is is called with name .IR linkname . This file must be present, but it can be empty. .SH "SEE ALSO" Postscript(7). .SH NOTES \*(PS is a trademark of Adobe Systems, Inc. .SH AUTHOR William Roberts .br Department of Computer Science & Statistics .br Queen Mary College, LONDON .SH BUGS There is no option to add something AFTER the prologue. This could be useful on occasion, for redefining one of the prologue subroutines for example. SHAR_EOF if test 2275 -ne `wc -c < psmodify.1` then echo shar: error transmitting "psmodify.1" '('should be 2275 chars')' else echo psmodify.1 fi fi echo shar: extracting "psmodify.c" '('4612 chars')' if test -f psmodify.c then echo shar: will not overwrite existing file "psmodify.c" else cat << \SHAR_EOF > psmodify.c #ifndef lint static char rcsid[]="$Header: psmodify.c,v 1.1 86/07/04 08:55:43 liam Exp $"; #endif /* psmodify * * Program to extend a PostScript program that conforms to * the Adobe Structuring convention. * * $Log: psmodify.c,v $ * Revision 1.1 86/07/04 08:55:43 liam * Initial revision * */ #include #include #include "psmodify.h" char buffer[BUFSIZ*2]; /* input buffer */ int buffempty = 1; FILE *inputfile = stdin; /* input file stream */ char *prog; void nextline() { if (!buffempty) fputs(buffer,stdout); /* flush the buffer */ if ( fgets(buffer, sizeof(buffer), inputfile) == NULL) exit(0); buffempty = 0; /* record full buffer */ } void copy_rest() { if (!buffempty) fputs(buffer, stdout); while( fgets(buffer, sizeof(buffer), inputfile) != NULL) fputs(buffer, stdout); exit(0); /* terminate gracefully */ } /* main() * * The behaviour of the program depends on its name. * Unless it is called by its true name, it infers the * names of the insertion files from its alias. */ main(argc, argv) int argc; char **argv; { char *extra_prologue, *extra_trailer; prog = argv[0]; if (strcmp(prog, REAL_NAME) != 0) { alternative_main(argc, argv); exit(0); } /* if the program is called REAL_NAME then it is * used as a filter with arguments denoting header * and optional trailer arguments. */ if (argc == 1) copy_rest(); /* don't have to do anything anyway! */ if (argc > 1) extra_prologue = argv[1]; if (argc > 2) extra_trailer = argv[2]; if (argc > 3) { fprintf(stderr, "%s: only first 2 args significant\n", prog); } process(extra_prologue, extra_trailer); } /* alternative_main() * * This is the "convenience" version where the program name * implies the header and trailer files, and the argument * is a PostScript program, though stdin is also allowed. * * This allows commands like "2xA4" to be constructed by * making links to REAL_NAME and then used rather like * "fold" or "pr" etc. */ alternative_main(argc, argv) int argc; char **argv; { char extra_prologue[BUFSIZ]; char extra_trailer[BUFSIZ]; sprintf(extra_prologue, "%s/%s.prologue.ps", INSERT_DIRECTORY, prog); sprintf(extra_trailer, "%s/%s.trailer.ps", INSERT_DIRECTORY, prog); if (argc > 2) fprintf(stderr, "%s: only one argument allowed\n", prog); if ( argc > 1 && strcmp(argv[1], "-") != 0) { inputfile = fopen(argv[1], "r"); if (inputfile == NULL) { fprintf(stderr, "%s: can't read inputfile ", prog); perror(argv[1]); exit(-1); } } process(extra_prologue, extra_trailer); } /* read_header() * * This scans the input looking for the end of the * PostScript header comments. These all start with %% * though it ought perhaps look for a %%EndComments in * amongst them. */ read_header() { do { nextline(); } while (buffer[0] == '%' && buffer[1] == '%' && strncmp(buffer, "%%EndComments", 11) != 0); if (strncmp(buffer, "%%EndComments", 13) == 0) nextline(); /* flush the %%EndComments line */ } process(extra_prologue, extra_trailer, fin) char *extra_prologue; char *extra_trailer; FILE *fin; { FILE *insertion; char insert_buffer[BUFSIZ]; int conforming = 0; nextline(); if (strncmp(buffer, "%!", 2) != 0) copy_rest(); /* not a PostScript program */ if (strncmp(buffer, "%!PS-Adobe-", 11) == 0) { read_header(); /* conforming program */ conforming = 1; } else { fputs(buffer, stdout); buffempty = 1; /* flush the first line */ conforming = 0; } /* Insert the new leading code */ if (extra_prologue != NULL) { insertion = fopen(extra_prologue, "r"); if (insertion != NULL) { while( fgets(insert_buffer, sizeof(insert_buffer), insertion) != NULL) fputs(insert_buffer, stdout); fclose(insertion); } else { fprintf(stderr, "%s: couldn't read header insertfile", prog); perror(extra_prologue); } } /* scan to end of file */ if (!buffempty) fputs(buffer, stdout); while( fgets(buffer, sizeof(buffer), inputfile) != NULL) fputs(buffer, stdout); /* Insert the new trailing code */ if (extra_trailer != NULL) { insertion = fopen(extra_trailer, "r"); if (insertion != NULL) { while( fgets(insert_buffer, sizeof(insert_buffer), insertion) != NULL) fputs(insert_buffer, stdout); fclose(insertion); } else { fprintf(stderr, "%s: couldn't read trailer insertfile", prog); perror(extra_trailer); } } } SHAR_EOF if test 4612 -ne `wc -c < psmodify.c` then echo shar: error transmitting "psmodify.c" '('should be 4612 chars')' else echo psmodify.c fi fi echo shar: extracting "psmodify.h" '('120 chars')' if test -f psmodify.h then echo shar: will not overwrite existing file "psmodify.h" else cat << \SHAR_EOF > psmodify.h /* psmodify.h */ #define REAL_NAME "psmodify" #define INSERT_DIRECTORY "/usr/local/lib/psmodify" SHAR_EOF if test 120 -ne `wc -c < psmodify.h` then echo shar: error transmitting "psmodify.h" '('should be 120 chars')' else echo psmodify.h fi fi echo shar: extracting "2xA4.prologue.ps" '('4777 chars')' if test -f 2xA4.prologue.ps then echo shar: will not overwrite existing file "2xA4.prologue.ps" else cat << \SHAR_EOF > 2xA4.prologue.ps %! /$reallyshowpage where {pop} % already known so leave well alone! {/$reallyshowpage {showpage /$reallyshowpage {} store} bind def} ifelse /bindall { % {proc} (executing bindall\n) print pstack 1 dict begin bind % bind the operator names dup length /n exch def aload n 1 add 1 roll % array a0 ... an n { dup type /arraytype eq { bindall } { dup type /nametype eq { dup xcheck { % it is an executable name dup where {exch load} if } if } if } ifelse n 1 roll % array ai' ... an' a0 ... ai-1 } repeat (about to restore procedure\n) print pstack n 1 add -1 roll astore % refill proc with modified contents end (completed bindall\n) print pstack } def % This scheme depends on the following entries in showpagedict % % device-CTM - underlying CTM (device or lower 2xA4) % current-CTM - effective CTM including current transformation % even-CTM - further transformation for even pages % odd-CTM - further transformation for odd pages % odd - true/false flag indicating current page type % users-bit - user transformations on top of device-CTM % % Of these, all but {even,odd}-CTM *MUST* be propagated % across save/restore boundaries. /showpagedict 6 dict def showpagedict begin /device-CTM matrix currentmatrix def % record effective CTM /users-bit [ matrix ] def gsave users-bit 0 get setmatrix % set CTM to identity matrix 1 2 sqrt div dup scale [0 -1 1 0 0 0] concat % -90 rotate -8.5 72 mul 0 translate /odd-CTM matrix currentmatrix def -8.5 72 mul 0 translate /even-CTM matrix currentmatrix def grestore odd-CTM concat % initial setup /odd true def /current-CTM matrix currentmatrix def end /showpage { (** execute showpage\n) print /showpagedict begin % start local dictionary device-CTM setmatrix odd { /showpage /device-CTM device-CTM currentmatrix def even-CTM concat /odd false def} { odd-CTM concat /odd true def} ifelse /current-CTM current-CTM currentmatrix def end } bindall % to get current showpage definition def % To prevent restore from destroying the 2xA4 scheme, we must % propagate the changing bits of showpagedict to the restored % state. We must also keep the user's additions to the CTM in % the saved state, but insert underneath it our own revised CTM. /restore { (**execute restore\n) print mark /showpagedict begin users-bit {aload pop} forall % turn into list of numbers counttomark 2 add -1 roll % fish out save object mark current-CTM aload pop % get effective CTM device-CTM aload pop % get device CTM odd % grab the current value of odd end counttomark 2 add -1 roll /restore % do the real restore /showpagedict /current-CTM get % get old version of effective CTM matrix invertmatrix % find its inverse matrix currentmatrix % get the restored CTM exch matrix concatmatrix % leave just the user's CTM alterations counttomark 1 roll % put result at bottom of stack /showpagedict begin /odd exch def % unrestore the page flag device-CTM astore pop % unrestore the device CTM current-CTM astore % unrestore the effective CTM end setmatrix concat % put user's changes onto current CTM pop % throw away the inner mark counttomark 6 div round cvi {matrix astore counttomark 1 roll} % reassemble stacked arrays repeat counttomark array astore % reassembled users-bit stack /showpagedict exch /users-bit exch put % unrestore users-bit pop % remove outer mark } pstack bindall pstack % to get showpagedict and restore def % gsave/grestore must respect changes made by showpage. For % this reason, gsave saves the user's extensions to current-CTM % and grestore applies them to current-CTM to get the final % output CTM. Since these are part of the graphics state stack, % they have to model users-bit by means of a stack. /gsave { /showpagedict begin /users-bit [ current-CTM % get old version of effective CTM matrix invertmatrix % find its inverse matrix currentmatrix % get the user's CTM exch matrix concatmatrix % leave just the user's CTM alterations users-bit aload pop ] def end /gsave } bindall def /grestore { /grestore /showpagedict begin current-CTM setmatrix % set up (modified) effective CTM mark users-bit aload pop counttomark 1 sub array astore % usermat [tail of users-bit] /users-bit exch def % popped the users-bit stack concat % apply user transformation to CTM pop % remove mark end } bindall def SHAR_EOF if test 4777 -ne `wc -c < 2xA4.prologue.ps` then echo shar: error transmitting "2xA4.prologue.ps" '('should be 4777 chars')' else echo 2xA4.prologue.ps fi fi echo shar: extracting "2xA4.trailer.ps" '('16 chars')' if test -f 2xA4.trailer.ps then echo shar: will not overwrite existing file "2xA4.trailer.ps" else cat << \SHAR_EOF > 2xA4.trailer.ps $reallyshowpage SHAR_EOF if test 16 -ne `wc -c < 2xA4.trailer.ps` then echo shar: error transmitting "2xA4.trailer.ps" '('should be 16 chars')' else echo 2xA4.trailer.ps fi fi echo shar: extracting "invert.prologue.ps" '('241 chars')' if test -f invert.prologue.ps then echo shar: will not overwrite existing file "invert.prologue.ps" else cat << \SHAR_EOF > invert.prologue.ps /showpage { showpage gsave initclip newpath clippath 1 setgray % 1 is now black!!! fill grestore {1 exch sub} settransfer } bind def gsave initclip newpath clippath 0 setgray fill grestore {1 exch sub} settransfer SHAR_EOF if test 241 -ne `wc -c < invert.prologue.ps` then echo shar: error transmitting "invert.prologue.ps" '('should be 241 chars')' else echo invert.prologue.ps fi fi echo shar: extracting "invert.trailer.ps" '('0 chars')' if test -f invert.trailer.ps then echo shar: will not overwrite existing file "invert.trailer.ps" else cat << \SHAR_EOF > invert.trailer.ps SHAR_EOF if test 0 -ne `wc -c < invert.trailer.ps` then echo shar: error transmitting "invert.trailer.ps" '('should be 0 chars')' else echo invert.trailer.ps fi fi echo shar: extracting "manualfeed.prologue.ps" '('57 chars')' if test -f manualfeed.prologue.ps then echo shar: will not overwrite existing file "manualfeed.prologue.ps" else cat << \SHAR_EOF > manualfeed.prologue.ps %! Manual Feed statusdict begin /manualfeed true def end SHAR_EOF if test 57 -ne `wc -c < manualfeed.prologue.ps` then echo shar: error transmitting "manualfeed.prologue.ps" '('should be 57 chars')' else echo manualfeed.prologue.ps fi fi echo shar: extracting "manualfeed.trailer.ps" '('43 chars')' if test -f manualfeed.trailer.ps then echo shar: will not overwrite existing file "manualfeed.trailer.ps" else cat << \SHAR_EOF > manualfeed.trailer.ps statusdict begin /manualfeed false def end SHAR_EOF if test 43 -ne `wc -c < manualfeed.trailer.ps` then echo shar: error transmitting "manualfeed.trailer.ps" '('should be 43 chars')' else echo manualfeed.trailer.ps fi fi # End of shar archive exit 0