[comp.sources.misc] v09i088: Mpage

mark@pyrdc.UUCP (Mark Hahn) (12/27/89)

Posting-number: Volume 9, Issue 88
Submitted-by: mark@pyrdc.UUCP (Mark Hahn)
Archive-name: mpage/part01

Mpage will print text or Postscript input in n-up format.  I.e. 4
pages of normal text or postscript is reduced to fit on one sheet of
paper (4-up).  Choices are 1, 2, 4, 8, and 16 pages per sheet of paper
with 2 and 4 being most useful and readable.  It accepts Postscript as
input, or at least it works on most of the stuff I get from the Adobe
File Server.

. . . . . . . . . . . . The Obligatory Dotted Line . . . . . . . . . . . .
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  README MANIFEST CHANGES mp_file.c mp_glob.c mp_head.h
#   mp_post.c mp_text.c
# Wrapped by mark@pyrdc on Tue Dec 26 16:29:22 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(4767 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
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.

END_OF_FILE
echo shar: NEWLINE appended to \"'README'\"
if test 4768 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(866 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
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

END_OF_FILE
echo shar: NEWLINE appended to \"'MANIFEST'\"
if test 867 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'CHANGES' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'CHANGES'\"
else
echo shar: Extracting \"'CHANGES'\" \(1248 characters\)
sed "s/^X//" >'CHANGES' <<'END_OF_FILE'
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.

END_OF_FILE
echo shar: NEWLINE appended to \"'CHANGES'\"
if test 1249 -ne `wc -c <'CHANGES'`; then
    echo shar: \"'CHANGES'\" unpacked with wrong size!
fi
# end of 'CHANGES'
fi
if test -f 'mp_file.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mp_file.c'\"
else
echo shar: Extracting \"'mp_file.c'\" \(5778 characters\)
sed "s/^X//" >'mp_file.c' <<'END_OF_FILE'
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

END_OF_FILE
echo shar: NEWLINE appended to \"'mp_file.c'\"
if test 5779 -ne `wc -c <'mp_file.c'`; then
    echo shar: \"'mp_file.c'\" unpacked with wrong size!
fi
# end of 'mp_file.c'
fi
if test -f 'mp_glob.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mp_glob.c'\"
else
echo shar: Extracting \"'mp_glob.c'\" \(8637 characters\)
sed "s/^X//" >'mp_glob.c' <<'END_OF_FILE'
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";

END_OF_FILE
echo shar: NEWLINE appended to \"'mp_glob.c'\"
if test 8638 -ne `wc -c <'mp_glob.c'`; then
    echo shar: \"'mp_glob.c'\" unpacked with wrong size!
fi
# end of 'mp_glob.c'
fi
if test -f 'mp_head.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mp_head.h'\"
else
echo shar: Extracting \"'mp_head.h'\" \(5987 characters\)
sed "s/^X//" >'mp_head.h' <<'END_OF_FILE'
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 $";

END_OF_FILE
echo shar: NEWLINE appended to \"'mp_head.h'\"
if test 5988 -ne `wc -c <'mp_head.h'`; then
    echo shar: \"'mp_head.h'\" unpacked with wrong size!
fi
# end of 'mp_head.h'
fi
if test -f 'mp_post.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mp_post.c'\"
else
echo shar: Extracting \"'mp_post.c'\" \(14038 characters\)
sed "s/^X//" >'mp_post.c' <<'END_OF_FILE'
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}

END_OF_FILE
echo shar: NEWLINE appended to \"'mp_post.c'\"
if test 14039 -ne `wc -c <'mp_post.c'`; then
    echo shar: \"'mp_post.c'\" unpacked with wrong size!
fi
# end of 'mp_post.c'
fi
if test -f 'mp_text.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mp_text.c'\"
else
echo shar: Extracting \"'mp_text.c'\" \(9542 characters\)
sed "s/^X//" >'mp_text.c' <<'END_OF_FILE'
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}

END_OF_FILE
echo shar: NEWLINE appended to \"'mp_text.c'\"
if test 9543 -ne `wc -c <'mp_text.c'`; then
    echo shar: \"'mp_text.c'\" unpacked with wrong size!
fi
# end of 'mp_text.c'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

-- 
  ...!uunet!\                       Mark Hahn, Sr Systems Engineer
             >pyrdc!mark            Pyramid Technology Corporation
...!pyramid!/                       Vienna, Va    (703)848-2050