🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.postscript
Article #242

Pspages - print specific pages from PostScript file

#242
From: Bill Pringle
Date: Mon, 10 Aug 1992 14:06
680 lines
20142 bytes
Here is the latest version of pspages, which will print specific pages
of a PostScript file.  I have fixed the (formerly undocumented) -r
(reverse order) option.  I also fixed it to handle included documents
(at least it works on the latest STTNG Program Guide).

The changes are very minor from the original version, but the effects
are significant :^)

Any bug reports, fixes, enhancements, etc. should be e-mailed to me:

    wrp@ivy.unisys.com

As with all my software, there is NO WARRANTY at all.  Period.
(Wouldn't it be great if we didn't have to say that all the time?)

================ Cut Here ================ And Here, too ================
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed tncli as standard input via
# unshar, or by typing "sh <file", e.g..  If tncli archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  pspages.c parsenum.c pspages.1 makefile
# Wrapped by wrp@psl1 on Mon Aug 10 09:54:46 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'pspages.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pspages.c'\"
else
echo shar: Extracting \"'pspages.c'\" \(11088 characters\)
sed "s/^X//" >'pspages.c' <<'END_OF_FILE'
X/*
X *				**** PSPAGES ****
X *
X * (c) 1992 Bill Pringle - wrp@ivy.unisys.com
X *
X * You may not sell this program, but you can charge a small
X * copying fee for distribution.  Permission granted for use
X * of this program for non-commercial use.  Commercial users
X * should contact me at the above e-mail address before use.
X *
X * This program prints certain pages from a postscript file.
X *
X * It assumes that standard page header comments are in the file.
X *
X */
X
X#include <stdio.h>
X#include <string.h>
X
X#ifdef __MSDOS__
X#include <stdlib.h>
X#define	OPEN_RO	"rb"
X#define	OPEN_RW	"wb"
X#define	DIR_SLASH	'\\'
X#else
X#include <ctype.h>
X#define SEEK_SET 0
X#define	OPEN_RO	"r"
X#define	OPEN_RW	"w"
X#define	DIR_SLASH	'/'
X#endif
X
X#define PAGES	20		/* max. number of page groups */
X
X#define	PRT_EVEN	1	/* print even pages */
X#define	PRT_ODD		2	/* print odd pages */
X#define	PRT_LOG		4	/* print logical pages */
X#define	PRT_PHY		8	/* print physical pages */
X
struct Page
X{		/* keep in-core list of page locations */
X	struct	Page	*pg_next;		/* next entry */
X	long	pg_beg;					/* start location of page */
X	long	pg_end;					/* end location of page */
X};
X
int		printdef=0;		/* default is odd pages */
int		revflg = 0;		/* default is in ascending order */
char	*Prog;			/* program name */
char	buf[BUFSIZ];	/* input buffer */
struct	Page	*Pages;	/* list of pages to be printed later */
long	Trailer;		/* loc of the trailer (if any needed) */
X
main(argc,argv)
int		argc;
char	**argv;
X{
X	FILE	*ifp;		/* input file */
X	FILE	*ofp;		/* output file */
X	int		printsw;	/* print switch */
X	char	*p;			/* scan pointer */
X
X	int	nent;				/* number of entries used */
X	int		pglo[PAGES];	/* low page numbers */
X	int		pghi[PAGES];	/* high page numbers */
X
X	/* get  program name */
X
X	if ((Prog = strrchr(argv[0],DIR_SLASH)) == NULL) Prog = argv[0];
X	else Prog++;		/* skip directory slash */
X
X#ifdef __MSDOS__
X	for (p=Prog; *p != '\0'&& *p != '\.'; p++)
X		if (isupper(*p)) *p = tolower(*p);
X	*p = '\0';
X#endif
X
X	argc--;
X	argv++;
X
X	ifp = stdin;		/* default input file */
X	ofp = stdout;		/* default output file */
X	Pages = NULL;		/* no pages yet */
X	Trailer = 0L;		/* no trailer either */
X
X	if (argc == 0) { do_help(Prog); exit(0); }
X
X	for (; argc > 0; argc--, argv++)
X	{		/* process arguments */
X		if (argv[0][0] == '-' && argv[0][1] != '\0') switch(argv[0][1])
X		{		/* process option */
X			case 'e':	/* even pages */
X				printdef = PRT_EVEN;		/* print even pages */
X				break;
X
X			case 'f':	/* output file */
X				if (argv[0][2] == '\0')
X				{		/* file name is next argument */
X					argc--;
X					argv++;
X					p = argv[0];			/* file name */
X				} else
X				{		/* file name follows -f */
X					p = argv[0] + 2;
X				}
X
X				if ((ofp = fopen(p,OPEN_RW)) == NULL)
X				{		/* problem opening file */
X					fprintf(stderr,"%s: Can't open output file %s.\n",
X								Prog, p);
X					exit(3);
X				}
X				break;
X
X			case 'h':	/* help */
X				do_help(Prog);
X				exit(0);
X
X			case 'l':	/* logical pages */
X				printdef = PRT_LOG;		/* print logical pages */
X				if (argv[0][2] == '\0')
X				{		/* pages are next argument */
X					argc--;
X					argv++;
X					p = argv[0];
X				} else p = (argv[0]) + 2;
X
X				nent = parse_nums(p,pglo,pghi,PAGES);		/* get the actual page numbers */
X				break;
X
X			case 'o':	/* odd pages */
X				printdef = PRT_ODD;		/* print odd pages */
X				break;
X
X			case 'p':	/* physical pages */
X				printdef = PRT_PHY;		/* print physical pages */
X				if (argv[0][2] == '\0')
X				{		/* pages are next argument */
X					argc--;
X					argv++;
X					p = argv[0];
X				} else p = (argv[0]) + 2;
X
X				nent = parse_nums(p,pglo,pghi,PAGES);
X				break;
X
X			case 'r':	/* print in reverse order */
X				revflg++;		/* signal reverse */
X				break;
X
X			default:	/* bad argument */
X				fprintf(stderr,"%s: Invalid argument (%s)\n", Prog, argv[0]);
X				do_usage(Prog);
X				exit(1);
X		} else
X		{		/* file name */
X			if (argv[0][0] == '-') ifp = stdin;
X			else if ((ifp = fopen(argv[0],OPEN_RO)) == NULL)
X			{		/* bad file */
X				fprintf(stderr,"%s: Can't open file %s for input.\n",
X									Prog, argv[0]);
X				exit(2);
X			}
X
X			copy_prologue(ifp,ofp);
X
X			if (printdef == PRT_EVEN || printdef == PRT_ODD)
X			{		/* either even or odd given */
X				if (printdef == PRT_EVEN) printsw = ~0;
X				else printsw = 0;
X
X				even_odd(ifp,ofp,printsw);
X			} else pspages(ifp,ofp,printdef,nent,pglo,pghi);
X
X			if (revflg) revpgs(ifp,ofp);		/* print pages in reverse */
X
X			if (ifp != stdin) fclose(ifp);		/* close input */
X		}
X	}
X	if (ofp != stdout) fclose(ofp);		/* close output */
X
X	fprintf(stderr,"%s: Program terminating.\n", Prog);
X	exit(0);
X}
X
copy_prologue(ifp,ofp)
XFILE	*ifp;
XFILE	*ofp;
X{		/* copy prologue */
X	long	loc=0L;		/* location in file */
X	long	page1;		/* location of first page */
X
X	while (fgets(buf,sizeof(buf),ifp) != NULL)
X	{		/* read entire file */
X		if (stribeg(buf,"%%page: ") == 0) break;
X		fputs(buf,ofp);		/* write out line */
X		loc = ftell(ifp);	/* location of next line */
X	}
X
X	if (stribeg(buf,"%%page: "))
X	{		/* no pages found */
X		fprintf(stderr,"%s: Input file not Postscript Conforming\n", Prog);
X		exit(5);
X	} else page1 = loc;		/* save location of first page */
X
X	while (fgets(buf,sizeof(buf),ifp) != NULL)
X	{		/* look for trailer */
X		if (stribeg(buf,"%%trailer") == 0) Trailer = loc;
X		if (stribeg(buf,"%%page: ") == 0) Trailer = 0L;	/* page trailer */
X		loc = ftell(ifp);	/* loc of next line */
X	}
X
X	if (fseek(ifp,page1,SEEK_SET))		/* reposition to just before %%Page: */
X	{		/* seek failed */
X		printf("%s: Unable to seek loc %ld after prolog copied\n", Prog, loc);
X		exit(4);
X	}
X}
X
even_odd(ifp,ofp,sw)
XFILE	*ifp;			/* input file */
XFILE	*ofp;			/* output file */
int		sw;				/* print page switch */
X{		/* print even or odd pages */
X	long	loc;			/* location in file */
X
X	loc = ftell(ifp);		/* location in file */
X
X	while (fgets(buf,sizeof(buf),ifp) != NULL)
X	{		/* read entire file */
X		if (stribeg(buf,"%%page: ") == 0)
X		{		/* new page - toggle switch & save loc if needed */
X			sw = ~ sw;	/* toggle switch */
X			if (revflg)
X			{		/* printing in reverse order - save locations */
X				if (sw) begpage(loc);	/* loc of this line */
X				else endpage(ftell(ifp)); /* loc of next line */
X			}
X		}
X
X		loc = ftell(ifp);		/* location in file */
X
X		if (sw && !revflg)
X		{		/* printing this page in forward direction */
X			fputs(buf,ofp);		/* print line if needed */
X		}
X	}
X
X	/* done with file - save last location if needed */
X	if (revflg && sw)
X	{		/* printing later - get end of file */
X		endpage(ftell(ifp)+1L);	/* when to terminate */
X	}
X}
X
pspages(ifp,ofp,prsw,nent,pglo,pghi)
XFILE	*ifp;		/* input file */
XFILE	*ofp;		/* output file */
int		prsw;		/* physical/logical page flag */
int		nent;		/* number of page groups */
int		pglo[];		/* low page numbers */
int		pghi[];		/* high page numbers */
X{
X	int		sw=0;			/* print switch */
X	long	loc;			/* location in file */
X
X	loc = ftell(ifp);		/* location of first line */
X
X	while (fgets(buf,sizeof(buf),ifp) != NULL)
X	{		/* read entire file */
X
X		if (stribeg(buf,"%%page: ") == 0)
X		{		/* new page found - check it out */
X			if (sw && revflg) endpage(loc);
X			sw = chk_pg(buf,prsw,nent,pglo,pghi);
X			if (sw && revflg) begpage(loc);	/* save new page */
X		}
X		loc = ftell(ifp);		/* get location of next page */
X
X		if (sw & !revflg) fputs(buf,ofp);		/* print line if needed */
X	}
X
X	/* done with file - save last location if needed */
X	if (revflg && sw) endpage(ftell(ifp));
X}
X
chk_pg(str,prsw,nent,pglo,pghi)
char	*str;		/* line with page number */
int		prsw;		/* physical/logical page flag */
int		nent;		/* number of page groups */
int		pglo[];		/* low page numbers */
int		pghi[];		/* high page numbers */
X{
X	int		pgno;	/* page number */
X	int		i;		/* loop variable */
X
X	while (*str != '\0' && ! isspace(*str)) str++;	/* find space */
X	while (isspace(*str)) str++;	/* find logical page number */
X
X	if (prsw == PRT_PHY)
X	{		/* printing physical pages - get number */
X		while (*str != '\0' && !isspace(*str)) str++;	/* end of logical */
X		while (isspace(*str)) str++;					/* start of physical */
X	}
X
X	pgno = atoi(str);		/* get page number */
X
X	for (i = 0; i < nent; i++)
X	{		/* loop thru selected page numbers */
X		if (pgno >= pglo[i] && pgno <= pghi[i]) return 1;
X	}
X
X	return 0;
X}
X
get_line(buf,fp)
char	*buf;
XFILE	*fp;
X{
X	int		c, n;
X
X	for (n = 0; (c = fgetc(fp)) != EOF; n++)
X	{		/* read up to end of line */
X		if (c !=  '\r' && c != '\n') *buf++ = c;
X		else if (c == '\n') break;
X	}
X
X	*buf = '\0';		/* termiate line */
X	return n;
X}
X
stribeg(str1,str2)
char	*str1, *str2;
X{
X	size_t	len;
X
X	if ((len = strlen(str2)) == 0) return 0;
X	else return (strnicmp(str1,str2,len));
X}
X
do_help(Prog)
char	*Prog;
X{
X	static char *msg[] = {
X"This program will print portions of a postscript file.\n",
X"Options are:\n",
X"\t-e\tPrint only even physical pages.\n",
X"\t-o\tPrint only odd physical pages.\n",
X"\t-l pgs\tPrint logical pages 'pgs'\n",
X"\t-p pgs\tPrint physical pages 'pgs'\n",
X"\t-r\tPrint pages in reverse order\n",
X"\n",
X"Where 'pgs' is of the form: range1[,range2 ...]\n",
X"\tFor example: 1-5,26,35-76\n",
X"\n",
X"To print doouble sided, type:\n",
X"\t%s -o infile.ps > front.ps\n",
X"\t%s -e -r infile.ps > back.ps\n",
X"Then print back.ps on the reverse side (holes on right)\n",
X"turn paper over, add a blank sheet at the bottom (in case\n",
X"an odd number of pages were printed) and print front.ps\n",
NULL};
X
X	prt_msg(Prog,msg);
X}
X
do_usage(Prog)
char	*Prog;
X{
X	static char *msg[] = {
X"Usage: %s [-e | -o | -l pages | -p pages ] [ -r ] ps_files ...\n",
X"-OR- for help, type:\n",
X"\t%s -h\n",
NULL};
X
X	prt_msg(Prog,msg);
X}
X
prt_msg(pgm,msg)
char	*pgm;		/* program name */
char	*msg[];		/* message lines */
X{
X	int		i;
X
X	for (i=0; msg[i] != NULL; i++) fprintf(stderr,msg[i],pgm);
X}
X
get_nums() {   return 0; }
X
begpage(loc)
long	loc;		/* location within file */
X{		/* record beginning of new page to be printed later */
X	struct	Page	*pg;	/* page entry pointer */
X
X	pg = (struct Page *) malloc(sizeof(struct Page));	/* get memory */
X	pg->pg_next = Pages;		/* rest of list to follow */
X	pg->pg_beg = loc;						/* beg loc of page */
X	pg->pg_end = 0L;						/* no end yet */
X	Pages = pg;				/* put at front of list */
X}
X
endpage(loc)
long	loc;		/* location within file */
X{		/* record end of page to be printed later */
X	if (Pages != NULL) Pages->pg_end = loc;
X}
X
revpgs(ifp,ofp)
XFILE	*ifp;		/* input file */
XFILE	*ofp;		/* output file */
X{		/* print pages in reverse */
X	struct	Page	*pg;		/* temp pointer */
X	long	loc;				/* location in file */
X
X	while (Pages !=  NULL)
X	{		/* page still remainins */
X		fseek(ifp,Pages->pg_beg,SEEK_SET);	/* start of page */
X		while (fgets(buf,sizeof(buf),ifp) != NULL)
X		{		/* still more to print */
X			if ((loc = ftell(ifp)) >= Pages->pg_end) break;
X			if (Trailer > 0L && loc > Trailer) break;	/* trailer */
X			fputs(buf,ofp);					/* and write it */
X		}
X
X		pg = Pages->pg_next;				/* new top of stack */
X		free(Pages);						/* free top element */
X		Pages = pg;						/* make new top */
X	}
X
X	if (Trailer != 0L)
X	{		/* print trailer */
X		fseek(ifp,Trailer,SEEK_SET);	/* start of trailer */
X		while (fgets(buf,sizeof(buf),ifp) != NULL) fputs(buf,ofp);
X	}
X}
END_OF_FILE
if test 11088 -ne `wc -c <'pspages.c'`; then
    echo shar: \"'pspages.c'\" unpacked with wrong size!
fi
# end of 'pspages.c'
fi
if test -f 'parsenum.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'parsenum.c'\"
else
echo shar: Extracting \"'parsenum.c'\" \(1904 characters\)
sed "s/^X//" >'parsenum.c' <<'END_OF_FILE'
X/*
X *
X * (c) Copyright 1990 by William R. Pringle
X *
X *				**** PARSE NUM ****
X *
X * This routine will parse a string of numbers into ranges
X *	and return these ranges in two integer arrays
X *
X */
X
X#ifndef EOS
X#define	EOS	'\0'
X#endif
X
X#include <ctype.h>
X
parse_nums(str,num1,num2,maxnum)
char	*str;			/* input string to parse */
int		num1[];			/* beginning line number to return */
int		num2[];			/* ending line number to return */
int		maxnum;			/* maximum number of ranges to return */
X{
X	char	*p, *q;		/* a good old pointer variables */
X	int	nents;			/* how many pairs of lines */
X	char	buf[16];	/* buffer for conversion */
X
X	p = str;			/* start with string */
X	nents = 0;			/* number of line pairs */
X
X	while (*p != EOS && nents < maxnum)
X	{		/* must start with numeric digit */
X		while (isspace(*p)) p++;		/* find first non-blank */
X		if (! isdigit(*p)) return 0;	/* bad first value */
X		for (q=buf; isdigit(*p); *q++ = *p++);
X		while (isspace(*p)) p++;		/* skip to next non-blank */
X		if (*p != '-' && *p!= ':' && *p != ',' && *p != EOS && !isdigit(*p)) return 0;
X		*q = EOS;		/* terminate buffer string */
X		num1[nents] = atoi(buf);			/* first number */
X
X		if (*p == '-' || *p == ':')
X		{		/* range of numbers given, get second number */
X			for (p++; isspace(*p); p++);	/* find next non-blank */
X			if (!isdigit(*p)) return 0;		/* garbage for a number */
X			for (q=buf; isdigit(*p); *q++ = *p++);	/* end of second number */
X			while (isspace(*p)) p++;		/* skip past white space */
X			if (*p != ',' && *p != EOS) return 0;	/* wrong terminator */
X			*q = EOS;
X			num2[nents] = atoi(buf);			/* end line */
X		} else num2[nents] = num1[nents];	/* same as begin */
X
X		nents++;							/* incr. number of entries */
X		if (*p == ',') p++;					/* point past delimeter */
X	}		/* end loop thru string */
X
X	if (*p == EOS) return nents;			/* all O.K. */
X	else return -1;							/* too many ranges in string */
X }
END_OF_FILE
if test 1904 -ne `wc -c <'parsenum.c'`; then
    echo shar: \"'parsenum.c'\" unpacked with wrong size!
fi
# end of 'parsenum.c'
fi
if test -f 'pspages.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pspages.1'\"
else
echo shar: Extracting \"'pspages.1'\" \(1949 characters\)
sed "s/^X//" >'pspages.1' <<'END_OF_FILE'
X.TH PSPAGES 1L
X.SH NAME
pspages \- print selected pages of a Postscript file
X.SH SYNOPSIS
X\fBpspages \-\fIpages\fP [ \fB\-r\fP ] \fIfiles\fP
X.br
X\fBpspages \-h\fP
X.SH DESCRIPTION
X.I Pspages
copies specified pages of a Postscript file(s) to stdout,
provided the Postscript file conforms to standard conventions.
If the \fB\-r\fP option is specified,
the pages are printed in reverse order.
X.PP
Ptroff, groff, and enscript create Postscript files
compatible with \fIpspages\fP;
Word Perfect does not.
See the \fBCAVEATS\fP section for more detail.
X.SH OPTIONS
The following options are supported:
X.IP "\fB\-e\fP"
Copy only even physical pages.
X.IP \fB\-o\fP
Copy only odd physical pages.
X.IP "\fB\-l\fP \fIpage_numbers\fP"
Copy the logical \fIpage_numbers\fP.
X.IP "\fB\-p\fP \fIpage_numbers\fP" 
Copy the physical \fIpage_numbers\fP.
X.PP
Where
X.I page_numbers
is a single string indicating what pages are to be printed.
XFor example:
X.ti +.5i
X1-5,26,35-76.
X.PP
Pages are copied in the order they appear in the file
X(or the reverse order, if the \fB\-r\fP option is specified),
not in the order they are specified with command line arguments.
X(In other words, 4,2,3,1 and 4-1 are the same as 1-4).
X.SH CAVEATS
X\fIPspages\fP assumes that each print page
begins with the comment statement:
X.ti +.5i
X\fB%%Page:\fP \fIlog phys\fP
X.br
where \fIlog\fP is the logical page number,
and \fIphys\fP is the physical page number.
Note: many programs, including ptroff and enscript,
do not track the logical page number, but output a question mark
in its place.  For example:
X.ti +.5i
X%%Page: ? 1
X.br
which indicates the physical page 1,
but the logical page is unknown.
X.I Pspages
can be used with these files,
but you cannot select by logical page numbers.
X.PP
X\fIPspages\fP will copy all lines up to, but not including,
the first \fB%%Page:\fP comment.
It will also copy all lines following the last
X.B %%Trailer:
comment
following the last page of the document.
END_OF_FILE
if test 1949 -ne `wc -c <'pspages.1'`; then
    echo shar: \"'pspages.1'\" unpacked with wrong size!
fi
# end of 'pspages.1'
fi
if test -f 'makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile'\"
else
echo shar: Extracting \"'makefile'\" \(699 characters\)
sed "s/^X//" >'makefile' <<'END_OF_FILE'
X#!/bin/make -f
X# this is the makefile for the pspages program
X
ILIB = /usr/local/pub/bin
MLIB = /usr/local/pub/man/man1
X
X# Unix setup
CC = cc -o pspages
ALL = pspages
LPR = lpr
X
X# MS-DOS - Turbo C++
X# if you don't have Unix-like utilities, you may have to change some things
X# to use this makefile
X#CC = tcc
X#ALL = pspages.exe
X#LPR = print
X
SRC = pspages.c parsenum.c
MAN = pspages.1
PRINT = $(SRC) $(MAN) makefile
X
all:	$(ALL)
X	$(CC) $(SRC)
X	touch $@
X
install:	all
X	ls $(ALL) | cpio -pamv $(ILIB)
X	ls $(MAN) | cpio -pamv $(MLIB)
X	touch $@
X
print:	$(PRINT)
X	$(LPR) $(PRINT)
X
zoo:
X	rm -f pspages.zoo
X	zoo a pspages.zoo $(PRINT)
X
shar:
X	shar $(PRINT) > pspages.shr
X
tar:
X	tar cvf pspages.tar $(PRINT)
END_OF_FILE
if test 699 -ne `wc -c <'makefile'`; then
    echo shar: \"'makefile'\" unpacked with wrong size!
fi
# end of 'makefile'
fi
echo shar: End of shell archive.
exit 0

============================================================================
Bill Pringle                      Software Tools
Paramax Corporation               Voice: (215)443-7500 X4023
Internet: wrp@ivy.unisys.com      UUCP: ...!uunet!mimsy!widener!gvls1!wrp%ivy
Technical Details
Message-ID: <1992Aug10.140649.3815@gvl.unisys.com>
Path: arc1-ca.pugleaf.net!sparky!uunet!gatech!pitt.edu!gvls1!news

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!sparky!uunet!gatech!pitt.edu!gvls1!news
From: wrp@ivy.unisys.com (Bill Pringle)
Newsgroups: comp.lang.postscript
Subject: Pspages - print specific pages from PostScript file
Message-ID: <1992Aug10.140649.3815@gvl.unisys.com>
Date: 10 Aug 92 14:06:49 GMT
Sender: news@gvl.unisys.com (IEE news user)
Organization: Paramax Systems, Ivyland, PA
Lines: 680
Nntp-Posting-Host: psl1.ivy.unisys.com