/*
* post.c
*/
/*
* mpage: a program to reduce pages of print so that several pages
* of output appear on one printed page.
*
* Copyright (c) 1994-2004 Marcel J.E. Mol, The Netherlands
* Copyright (c) 1988 Mark P. Hahn, Herndon, Virginia
*
* Permission is granted to anyone to make or distribute verbatim
* copies of this document as received, in any medium, provided
* that this copyright notice is preserved, and that the
* distributor grants the recipient permission for further
* redistribution as permitted by this notice.
*
*/
#include "mpage.h"
#include <string.h>
/*
* character spaces used throughout for holding the current line from
* the input file
*/
static char currline[LINESIZE];
static char *file_name;
/*
* for ps documents, used to remember if we have come across the
* tailer section. reset at the beginning of processing for each file
*/
static int ps_at_trailer;
/*
* this is the type of postscript document we are processing
*/
static int ps_posttype;
/*
* set to one if we have a inputline that must be preceded by something...
* used for dvips output without PS comments.
*/
static int have_line = 0;
/*
* number of output lines on current logical page
*/
static int plcnt;
int have_showsheet = 0;
char ps_roff_xi [16]; /* to hold the DITROFF xi line... */
static char * tex1; /* to capture important dvi2ps lines... */
static char * tex2;
/*
* Function declarations
*/
static int ps_gettype();
static void do_post_doc();
#if 0
static void do_other_doc();
#endif
static void ps_copyprolog();
static void ps_roff_copyprolog();
static void ps_mpage_copyprolog();
static void ps_skip_to_page();
static int do_post_sheet();
static void ps_sheetsetup();
static int post_onepage();
static int post_flush_onepage();
static int post_one_line();
static void do_roff_tailer();
int ps_check();
void do_ps_doc();
static int post_flush_onepage();
static int ps_store_to_page();
/*
* Peek at the first two chacters on the open file and check for the
* two character postscript flag "%!". If the file is not postscript
* then the characters are pushed back into the input stream (hopefully).
*/
int
ps_check(infd)
FILE *infd;
{
int firstchar;
int secondchar;
Debug(DB_PSCHECK, "%%ps_check: in ps_check\n", 0);
/*
* eliminate blank files
*/
if ((firstchar = fgetc(infd)) == EOF) {
Debug(DB_PSCHECK, "%%ps_check: file is blank\n", 0);
return 0;
}
/*
* Skip any CTRL-D chars
* Hope there are no text files starting with ctrl-d's
*/
while (firstchar == 4)
firstchar = fgetc(infd);
/*
* eliminate non-postscript files
*/
if (firstchar != '%') {
Debug(DB_PSCHECK, "%ps_check: 1st char is '%c' not '%'\n", firstchar);
if (ungetc(firstchar, infd) == EOF) {
fprintf(stderr, "%s: Lost first character of file ", MPAGE);
fprintf(stderr, "while checking for postscript\n.");
}
return 0;
}
Debug(DB_PSCHECK, "%%ps_check: 1st char is '%c'\n", firstchar);
/*
* eliminate one character files (containing only a %)
*/
if ((secondchar = fgetc(infd)) == EOF) {
Debug(DB_PSCHECK, "%%ps_check: no second char\n", 0);
if (ungetc(firstchar, infd) == EOF) {
fprintf(stderr, "%s: Lost first character of file ", MPAGE);
fprintf(stderr, "while checking for postscript\n.");
}
return 0;
}
/*
* eliminate files that don't have the full two character
* sequence of "%!".
*/
if (secondchar != '!') {
Debug(DB_PSCHECK, "%%ps_check: 2nd char is '%c' not '!'\n", secondchar);
if (ungetc(secondchar, infd) == EOF) {
fprintf(stderr, "%s: Lost first two characters of ", MPAGE);
fprintf(stderr, "file while checking for postscript\n.");
return 0;
}
if (ungetc(firstchar, infd) == EOF) {
fprintf(stderr, "%s: Lost first character of file ", MPAGE);
fprintf(stderr, "while checking for postscript.\n");
}
return 0;
}
/*
* for post script files the first two characters (the "%!") are
* digested by this routine. It's just easier than dealing
* with the problems encounted if the characters can't be ungetc'ed.
*/
Debug(DB_PSCHECK, "%%ps_check: 2nd char is '%c'\n", secondchar);
Debug(DB_PSCHECK, "%%ps_check: input is postscript\n", 0);
return 1;
} /* ps_check */
static int
ps_gettype(fd, outfd)
FILE *fd;
FILE *outfd;
{
int ps_type, end_comments;
Debug(DB_PSDOC, "%%ps_gettype: in ps_gettype\n", 0);
/*
* error check for truncated files
*/
if (fgets(currline, LINESIZE-1, fd) == NULL) {
Debug(DB_PSDOC, "%%ps_gettype: got eof on first line\n", 0);
return PS_NONE;
}
/*
* check for non-conforming postscript
* Note that %! is already gone down the drain...
*/
if (strncmp(currline, PS_FLAG, strlen(PS_FLAG)) != 0) {
Debug(DB_PSDOC, "%%ps_gettype: no match PS_FLAG \"%s\"\n", currline);
return PS_OTHER;
}
/*
* we have some form of conforming postscript, try to identify the
* type
*/
Debug(DB_PSDOC, "%%ps_gettype: conforming postscript\n", 0);
end_comments = 0;
ps_type = PS_CONFORM;
while (!end_comments) {
/*
* if we get end of file then we assume non-conforming PS
*/
if (fgets(currline, LINESIZE-1, fd) == NULL) {
Debug(DB_PSDOC, "%%ps_gettype: eof in comments\n", 0);
return PS_OTHER;
}
/*
* if we have run out of leading comments then assume
* conforming PS (because we had a valid "%!" line)
*/
if (currline[0] != '%') {
Debug(DB_PSDOC, "%%ps_gettype: out off comments\n", 0);
fprintf(outfd, "%s", currline);
return PS_CONFORM;
}
/*
* print out the comment line with an extra % to disguise the comment
*/
fprintf(outfd, "%%%s", currline);
/*
* check for the end of the leading comments section
*/
if (strncmp(currline, "%%EndComments", 13) == 0)
end_comments = 1;
/*
* Some tricky way to handle MS-windows postscript files...
* probably doesn't work.
*/
if (strncmp(currline, "%%Pages:", 8) == 0 &&
ps_type == PS_MSWINDOWS)
return ps_type;
/*
* once we know the type of PS, we no longer need to keep
* checking.
*/
if (ps_type != PS_CONFORM)
continue;
/*
* check for mpage output
*/
if (!strncmp(currline, "%%Creator: ", 11)) {
if (!strncmp(currline+11, MPAGE, strlen(MPAGE))) {
Debug(DB_PSDOC, "%%ps_gettype: mpage document\n", 0);
ps_type = PS_MPAGE;
}
else if (!strncmp(currline+11, "Windows PSCRIPT", 15)) {
Debug(DB_PSDOC, "%%ps_gettype: windows document\n", 0);
ps_type = PS_MSWINDOWS;
}
else if (!strncmp(currline+11, "dvips", 5)) {
Debug(DB_PSDOC, "%%ps_gettype: dvips\n", 0);
ps_type = PS_TEX;
}
}
/*
* check for psroff/tex output
*/
if (strncmp(currline, "%%Title: ", 9) == 0) {
if (strstr(currline, "ditroff")) {
Debug(DB_PSDOC, "%%ps_gettype: psroff\n", 0);
ps_type = PS_PSROFF;
}
else if (strstr(currline, ".dvi")) {
Debug(DB_PSDOC, "%%ps_gettype: dvi2ps\n", 0);
ps_type = PS_TEX;
}
}
if (strncmp(currline, "%DVIPS", 6) == 0) {
Debug(DB_PSDOC, "%%ps_gettype: dvips\n", 0);
if (ps_type != PS_TEX)
ps_type = PS_TEX2;
return ps_type;
}
}
#ifdef DEBUG
if (ps_type == PS_CONFORM) {
Debug(DB_PSDOC, "%%ps_gettype: unknown type, conforming PS\n", 0);
}
#endif
return ps_type;
} /* ps_gettype */
void
do_ps_doc(fd, asheet, outfd, fname)
FILE *fd;
struct sheet *asheet;
FILE *outfd;
char * fname;
{
Debug(DB_PSDOC, "%%do_ps_doc: postscript document\n", 0);
file_name = fname;
ps_posttype = ps_gettype(fd,outfd);
Debug(DB_PSDOC, "%%do_ps_doc: document type is %d\n", ps_posttype);
if (ps_posttype != PS_NONE)
do_post_doc(fd, asheet, outfd);
return;
} /* do_ps_doc */
static void
do_post_doc(fd, asheet, outfd)
FILE *fd;
struct sheet *asheet;
FILE *outfd;
{
ps_at_trailer = FALSE;
Debug(DB_POST, "%%do_post_doc: prolog\n", 0);
ps_copyprolog(fd, outfd);
/*
* while there is still input, print pages
*/
Debug(DB_POST, "%%do_post_doc: pages\n", 0);
do_sheets(do_post_sheet, fd, asheet, outfd);
Debug(DB_POST, "%%do_post_doc: trailer\n", 0);
do_roff_tailer(fd, outfd);
return;
} /* do_post_doc */
#if 0
/* not used yet... */
static void
do_other_doc(fd, asheet, outfd)
FILE *fd;
struct sheet *asheet;
FILE *outfd;
{
ps_at_trailer = FALSE;
ps_copyprolog(fd, outfd);
return;
} /* do_other_doc */
#endif
static void
ps_copyprolog(fd, outfd)
FILE *fd;
FILE *outfd;
{
Debug(DB_PSDOC, "%%ps_copyprolog: adding mpage prolog\n", 0);
if (!have_showsheet) {
#if 1
fprintf(outfd, "/showsheet /showpage load def\n");
#else
fprintf(outfd, "/showsheet { showpage } bind def\n");
#endif
fprintf(outfd, "/showpage { } def\n");
have_showsheet = 1;
}
had_ps = 1;
Debug(DB_PSDOC, "%%ps_copyprolog: copying prolog\n", 0);
if (ps_posttype == PS_PSROFF) {
Debug(DB_PSDOC, "%%ps_copyprolog: calling ps_roff_copyprolog\n",0);
ps_roff_copyprolog(fd, outfd);
return;
}
if (ps_posttype == PS_MPAGE) {
Debug(DB_PSDOC, "%%ps_copyprolog: calling ps_mpage_copyprolog\n",0);
ps_mpage_copyprolog(fd, outfd);
return;
}
while (fgets(currline, LINESIZE-1, fd) != NULL) {
if (strncmp(currline, "%%Page:", 7) == 0) {
fprintf(outfd, "%% %s", currline);
return;
}
if (ps_posttype == PS_TEX || ps_posttype == PS_TEX2) {
if (ps_posttype == PS_TEX2 && strstr(currline, " bop ")) {
/* dvips output without comments... */
have_line = 1;
return;
}
if (strncmp(currline, "TeXDict", 7) == 0) {
/* SHOULD PROBABLY REMOVE THIS. SEE BELOW /dictionarystack */
/*
* Hope all dvi2ps progs work the same:
* capture the TeX init code so we can run it 'manually' for
* every page. This is needed as this code sets up a gstate
* that conflicts with mpage...
* This trick seems to work for text, but figures within the dvi
* file seem to have a mind of their own...
*/
if (tex1)
free(tex1);
tex1 = malloc(strlen(currline)+1);
strcpy(tex1, currline);
fprintf(outfd, "%s", currline);
fgets(currline, LINESIZE-1, fd);
if (tex2)
free(tex2);
tex2 = malloc(strlen(currline)+1);
strcpy(tex2, currline);
}
}
fprintf(outfd, "%s", currline);
}
Debug(DB_PSDOC, "%%ps_copyprolog: eof before %%%%EndProlog\n", 0);
fprintf(outfd, "%%%%EndProlog\n");
return;
} /* ps_copyprolog */
static void
ps_roff_copyprolog(fd, outfd)
FILE *fd;
FILE *outfd;
{
Debug(DB_PSDOC, "%%ps_roff_copyprolog: copying psroff prolog\n", 0);
while(fgets(currline, LINESIZE-1, fd) != NULL) {
/* if (strcmp(currline, "xi\n") == 0) */
if (strstr(currline, "xi\n")) {
fprintf(outfd, "%%%s", currline);
strcpy(ps_roff_xi, currline);
}
else if (strncmp(currline, "%%Page:", 7) == 0) {
fprintf(outfd, "/p { } def\n");
fprintf(outfd, "/xt { } def\n");
fprintf(outfd, "/xs { } def\n");
fprintf(outfd, "%% %s", currline);
Debug(DB_PSDOC, "%%ps_copyprolog: Done\n", 0);
return;
}
else
fprintf(outfd, "%s", currline);
}
Debug(DB_PSDOC, "%%ps_copyprolog: eof before %%%%EndProlog\n", 0);
fprintf(outfd, "/p { } def\n");
fprintf(outfd, "/xt { } def\n");
fprintf(outfd, "/xs { } def\n");
fprintf(outfd, "%%%%EndProlog\n");
return;
} /* ps_roff_copyprolog */
static void
ps_mpage_copyprolog(fd, outfd)
FILE *fd;
FILE *outfd;
{
Debug(DB_PSDOC, "%%ps_mpage_copyprolog: skipping mpage prolog\n", 0);
while(fgets(currline, LINESIZE-1, fd) != NULL) {
if (strncmp(currline, "%%Page:", 7) == 0) {
fprintf(outfd, "%% %s", currline);
Debug(DB_PSDOC, "%%ps_copyprolog: Done\n", 0);
return;
}
}
} /* ps_mpage_copyprolog */
static void
ps_skip_to_page(fd)
FILE *fd;
{
Debug(DB_PSDOC, "%%ps_skip to page: reading until %%%%Page:\n", 0);
while(fgets(currline, LINESIZE-1, fd) != NULL) {
Debug(DB_PSDOC, "%% %s", currline);
if (strncmp(currline, "%%Page:", 7) == 0)
return;
}
Debug(DB_PSDOC, "%%ps_skip_to_page: eof before %%%%Page:\n", 0);
return;
} /* ps_skip_to_page */
static char *stored_page = NULL;
static int stored_page_size = 0;
static int
ps_store_to_page(fd)
FILE *fd;
{
int totlen = 0;
Debug(DB_PSDOC, "%%ps_store to page: reading until %%%%Page:\n", 0);
while(fgets(currline, LINESIZE-1, fd) != NULL) {
int len;
if (strncmp(currline, "%%Page:", 7) == 0)
return totlen;
len = strlen(currline);
totlen += len;
if (totlen > stored_page_size){
stored_page = realloc(stored_page, totlen);
stored_page_size = totlen;
}
/* do not copy the '\0' */
memcpy(stored_page + totlen - len, currline, len);
Debug(DB_PSDOC, "%% %s", currline);
}
Debug(DB_PSDOC, "%%ps_store_to_page: eof before %%%%Page:\n", 0);
return totlen;
} /* ps_store_to_page */
/* GPN */
/* #define NSCALE to take care of previous scaling */
#ifdef NSCALE
char *NScale = "/gpnsavematrix {orgmatrix currentmatrix pop} bind def\n"
"/gpnrestorematrix {orgmatrix setmatrix} bind def\n"
"/orgmatrix matrix def\n"
"gpnsavematrix\n"
"orgmatrix orgmatrix invertmatrix pop\n"
"/gpnxs\n"
" orgmatrix 0 get 0.0000 eq\n"
" {orgmatrix 1 get abs}\n"
" {orgmatrix 0 get abs}\n"
" ifelse def\n"
"/gpnys\n"
" orgmatrix 3 get 0.0000 eq\n"
" {orgmatrix 2 get abs}\n"
" {orgmatrix 3 get abs}\n"
" ifelse def\n"
"/gpnxs gpnxs gscurrentresolution 0 get 72 div mul def\n"
"/gpnys gpnys gscurrentresolution 1 get 72 div mul def\n";
#endif /* NSCALE */
static int
do_post_sheet(fd, asheet, outfd)
FILE *fd;
struct sheet *asheet;
FILE *outfd;
{
int rtn_val = FILE_MORE;
int sh_high, sh_wide;
struct pagepoints *stored_points = NULL, *flush_points = NULL;
int flush = 0, totlen = 0;
do {
if ((points->pp_origin_x == 0 && !points->skip) || opt_file || flush) {
/*
* keep track of the pages processed
*/
ps_pagenum++;
fprintf(outfd, "%%%%Page: %d %d\n", ps_pagenum, ps_pagenum);
# ifdef DEBUG
if (Debug_flag & DB_PSMPAGE)
fprintf(outfd, "(Page: %d\\n) print flush\n", ps_pagenum);
# endif /* DEBUG */
#if 0
/* seems to give memory problems... */
fprintf(outfd, "/sheetsave save def\n");
#endif
/*
* Now is the time to print a sheet header...
* for now, this has to be done before outline...
*/
sheetheader(outfd, file_name);
/*
* print the page outline
*/
mp_outline(outfd, asheet);
/*
* run through the list of base points for putting reduced pages
* on the printed page
*/
if (!flush)
points = asheet->sh_pagepoints;
else
points++;
}
while ((points->pp_origin_x!=0 || points->skip) && rtn_val == FILE_MORE) {
/* GPN. skip this page ?*/
if (points->skip!=0) {
switch (points->skip) {
case SKIP_PS:
/*
* Skip this page. User needs another run with the other
* of -O/-E option.
*/
ps_skip_to_page(fd);
points++;
continue;
case STORE_PS:
/*
* stored_page could also be an array
* if more than one page
* is needed
*/
totlen = ps_store_to_page(fd);
stored_points = points;
flush = STORE_PS;
points++;
continue;
case FLUSH_PS:
if (stored_points) {
/*
* Ok I have to print the page and start a new one.
* This could be more elegant, but for now...
*/
/*
fprintf(outfd, "showsheet\n");
ps_pagenum++;
fprintf(outfd, "%%%%Page: %d %d\n",
ps_pagenum, ps_pagenum);
sheetheader(outfd, file_name);
mp_outline(outfd, asheet);
*/
flush = FLUSH_PS;
flush_points = points;
points = stored_points;
}
else
flush = 0;
}
}
/*
* Save current graphics context so we can scale/translate
* from known position and size.
*/
fprintf(outfd, "gsave\n");
/*
* print one reduced page by moving to the proper point,
* turning to the proper aspect, scaling to the proper
* size, and setting up a clip path to prevent overwritting;
* then print a reduced page of output.
*/
Debug(DB_PSMPAGE, "%%%% %%%%ReducedPageStartsHere\n", outfd);
# ifdef DEBUG
if (Debug_flag & DB_PSMPAGE) {
fprintf(outfd, "( %d %d translate %d rotate\\n)",
points->pp_origin_x(), points->pp_origin_y(),
asheet->sh_rotate);
fprintf(outfd, " print flush\n");
}
# endif /* DEBUG */
#ifdef NSCALE /*GPN*/
fprintf (outfd, NScale);
fprintf(outfd, "%d gpnxs mul %d gpnxs mul translate %d rotate\n",
points->pp_origin_x(), points->pp_origin_y(),
asheet->sh_rotate);
#else /* NSCALE */
fprintf(outfd, "%d %d translate\n",
points->pp_origin_x(), points->pp_origin_y());
if (asheet->sh_rotate)
fprintf(outfd, "%d rotate\n", asheet->sh_rotate);
#endif
sh_wide = (*asheet->sh_width)();
sh_high = (*asheet->sh_height)();
/* output the clip path */
#ifdef NSCALE /*GPN*/
fprintf(outfd, "0 0 moveto 0 %d gpnys mul lineto %d gpnxs mul"
" %d gpnys mul lineto ",
sh_high, sh_wide, sh_high);
fprintf(outfd, "%d gpnxs mul 0 lineto\n", sh_wide);
fprintf(outfd, "closepath clip\n");
#else /* NSCALE */
#if 0
fprintf(outfd, "0 0 moveto 0 %d lineto %d %d lineto ",
sh_high, sh_wide, sh_high);
fprintf(outfd, "%d 0 lineto\n", sh_wide);
#else
fprintf(outfd, "1 1 moveto 1 %d lineto %d %d lineto ",
sh_high - 1, sh_wide - 1, sh_high - 1);
fprintf(outfd, "%d 1 lineto\n", sh_wide - 1);
#endif
fprintf(outfd, "closepath clip newpath\n");
#endif /* NSCALE */
if (opt_square) {
int newhigh = sh_high, newwide = sh_wide;
if (sh_wide * ps_height > sh_high * ps_width)
newwide = (sh_high * ps_width) / ps_height;
else
newhigh = (sh_wide * ps_height) / ps_width;
#ifdef NSCALE /*GPN*/
fprintf(outfd, "%d gpnxs mul %d gpnys mul translate\n",
#else
fprintf(outfd, "%d %d translate\n",
#endif
(sh_wide - newwide) / 2, (sh_high - newhigh) / 2);
sh_wide = newwide;
sh_high = newhigh;
}
fprintf(outfd, "%d %d div %d %d div scale\n",
sh_wide, ps_width, sh_high, ps_height);
/*
* Take extra page margins into account
*/
fprintf(outfd, "%d %d div %d %d div scale\n",
ps_width, ps_width + pagemargin_left + pagemargin_right,
ps_height, ps_height + pagemargin_top + pagemargin_bottom);
#ifndef NSCALE
fprintf(outfd, "%d %d translate\n", pagemargin_left, pagemargin_bottom);
#endif
#if 0
/* does not seem to be neccessary. seems to create dictionary
* stack underflows...
*/
if ((ps_posttype == PS_TEX || ps_posttype == PS_TEX2) && tex1)
/* start dvi2ps init every page */
fprintf(outfd, "%s%s", tex1, tex2);
#endif
/*
* do the individual sheet setup
*/
ps_sheetsetup(outfd);
/*
* place one reduce page on the printed page
*/
plcnt = 0;
if (flush == FLUSH_PS) {
rtn_val = post_flush_onepage(totlen, asheet, outfd);
stored_points = NULL;
points = flush_points;
}
else {
rtn_val = post_onepage(fd, asheet, outfd);
points++;
}
/*
* clean up after mpage has drawn its page
*/
fprintf(outfd, "grestore\n");
}
#if 0
fprintf(outfd, "sheetsave restore\n");
#endif
/*
* print the sheet
*/
if (points->pp_origin_x == 0 || (rtn_val == FILE_EOF && opt_file))
fprintf(outfd, "showsheet\n");
} while (flush && rtn_val == FILE_MORE);
if (stored_points) {
flush_points = points;
points = stored_points;
/*
* Save current graphics context so we can scale/translate
* from known position and size.
*/
fprintf(outfd, "gsave\n");
/*
* print one reduced page by moving to the proper point,
* turning to the proper aspect, scaling to the proper
* size, and setting up a clip path to prevent overwritting;
* then print a reduced page of output.
*/
Debug(DB_PSMPAGE, "%%%% %%%%ReducedPageStartsHere\n", outfd);
# ifdef DEBUG
if (Debug_flag & DB_PSMPAGE) {
fprintf(outfd, "( %d %d translate %d rotate\\n)",
points->pp_origin_x(), points->pp_origin_y(),
asheet->sh_rotate);
fprintf(outfd, " print flush\n");
}
# endif /* DEBUG */
#ifdef NSCALE /*GPN*/
fprintf (outfd, NScale);
fprintf(outfd, "%d gpnxs mul %d gpnxs mul translate %d rotate\n",
points->pp_origin_x(), points->pp_origin_y(),
asheet->sh_rotate);
#else /* NSCALE */
fprintf(outfd, "%d %d translate\n",
points->pp_origin_x(), points->pp_origin_y());
if (asheet->sh_rotate)
fprintf(outfd, "%d rotate\n", asheet->sh_rotate);
#endif
sh_wide = (*asheet->sh_width)();
sh_high = (*asheet->sh_height)();
/* output the clip path */
#ifdef NSCALE /*GPN*/
fprintf(outfd, "0 0 moveto 0 %d gpnys mul lineto %d gpnxs mul"
" %d gpnys mul lineto ",
sh_high, sh_wide, sh_high);
fprintf(outfd, "%d gpnxs mul 0 lineto\n", sh_wide);
fprintf(outfd, "closepath clip\n");
#else /* NSCALE */
#if 0
fprintf(outfd, "0 0 moveto 0 %d lineto %d %d lineto ",
sh_high, sh_wide, sh_high);
fprintf(outfd, "%d 0 lineto\n", sh_wide);
#else
fprintf(outfd, "1 1 moveto 1 %d lineto %d %d lineto ",
sh_high - 1, sh_wide - 1, sh_high - 1);
fprintf(outfd, "%d 1 lineto\n", sh_wide - 1);
#endif
fprintf(outfd, "closepath clip newpath\n");
#endif /* NSCALE */
if (opt_square) {
int newhigh = sh_high, newwide = sh_wide;
if (sh_wide * ps_height > sh_high * ps_width)
newwide = (sh_high * ps_width) / ps_height;
else
newhigh = (sh_wide * ps_height) / ps_width;
#ifdef NSCALE /*GPN*/
fprintf(outfd, "%d gpnxs mul %d gpnys mul translate\n",
#else
fprintf(outfd, "%d %d translate\n",
#endif
(sh_wide - newwide) / 2, (sh_high - newhigh) / 2);
sh_wide = newwide;
sh_high = newhigh;
}
fprintf(outfd, "%d %d div %d %d div scale\n",
sh_wide, ps_width, sh_high, ps_height);
/*
* Take extra page margins into account
*/
fprintf(outfd, "%d %d div %d %d div scale\n",
ps_width, ps_width + pagemargin_left + pagemargin_right,
ps_height, ps_height + pagemargin_top + pagemargin_bottom);
#ifndef NSCALE
fprintf(outfd, "%d %d translate\n", pagemargin_left, pagemargin_bottom);
#endif
#if 0
/* does not seem to be neccessary. seems to create dictionary
* stack underflows...
*/
if ((ps_posttype == PS_TEX || ps_posttype == PS_TEX2) && tex1)
/* start dvi2ps init every page */
fprintf(outfd, "%s%s", tex1, tex2);
#endif
/*
* do the individual sheet setup
*/
ps_sheetsetup(outfd);
/*
* place one reduce page on the printed page
*/
plcnt = 0;
rtn_val = post_flush_onepage(totlen, asheet, outfd);
stored_points = NULL;
/*
* clean up after mpage as drawn its page
*/
fprintf(outfd, "grestore\n");
#if 0
fprintf(outfd, "sheetsave restore\n");
#endif
/*
* print the sheet
*/
if (points->pp_origin_x == 0 || (rtn_val == FILE_EOF && opt_file))
fprintf(outfd, "showsheet\n");
}
/*
* let the upper level know about the status of possible EOF
*/
return rtn_val;
} /* do_post_sheet */
static void
ps_sheetsetup(outfd)
FILE *outfd;
{
switch (ps_posttype) {
case PS_PSROFF: fprintf(outfd, "%s", ps_roff_xi);
fprintf(outfd, "/p {} def\n");
break;
/*
case PS_MPAGE: fprintf(outfd, "/showpage {} def\n");
break;
*/
}
return;
} /* ps_sheetsetup */
static int
post_onepage(fd, asheet, outfd)
FILE *fd;
struct sheet *asheet;
FILE *outfd;
{
int indoc = 0;
Debug(DB_PSROFF, "%%post_onepage: Begin page\n", 0);
if (ps_at_trailer) {
Debug(DB_PSROFF, "%%post_onepage: still at trailer\n", 0);
return FILE_EOF;
}
if (have_line) {
fprintf(outfd, "%s", currline);
have_line = 0;
}
while(fgets(currline, LINESIZE-1, fd) != NULL) {
int line_rc;
line_rc = post_one_line(currline, fd, outfd, &indoc, 0);
if (line_rc != FILE_CONT)
return line_rc;
}
Debug(DB_PSROFF, "%%post_onepage: eof\n", 0);
return FILE_EOF;
} /* post_onepage */
static int
post_flush_onepage(totlen, asheet, outfd)
int totlen;
struct sheet *asheet;
FILE *outfd;
{
int indoc = 0;
Debug(DB_PSROFF, "%%post_flush_onepage: Begin page\n", 0);
/*
if (ps_at_trailer) {
Debug(DB_PSROFF, "%%post_flush_onepage: still at trailer\n", 0);
return FILE_EOF;
}
*/
if (have_line) {
fprintf(outfd, "%s", currline);
have_line = 0;
}
memgets_init(stored_page, totlen);
while (memgets(currline, LINESIZE-1) != NULL) {
int line_rc;
line_rc = post_one_line(currline, (FILE *) NULL, outfd, &indoc, 1);
if (line_rc != FILE_CONT)
return line_rc;
}
Debug(DB_PSROFF, "%%post_flush_onepage: eof\n", 0);
return FILE_MORE;
} /* post_flush_onepage */
static int
post_one_line(line, fd, outfd, indoc, flush_page)
char * line;
FILE *fd;
FILE *outfd;
int * indoc;
int flush_page;
{
if (strncmp(line, "%%BeginDocument", 15) == 0) {
(*indoc)++;
}
if (strncmp(line, "%%EndDocument", 13) == 0) {
(*indoc)--;
}
if (!*indoc) {
if (strncmp(line, "%%Page:", 7) == 0) {
fprintf(outfd, "%% %s", line);
/*
* only if there is already output to this logical page
*/
if (!plcnt)
return FILE_CONT;
Debug(DB_PSROFF, "%%post_one_line: next page\n", 0);
return FILE_MORE;
}
if (opt_killtrail && (strncmp(line, "%%Trailer", 9) == 0 ||
strncmp(line, "%%PSTrailer", 11) == 0)) {
fprintf(outfd, "%% %s", line);
Debug(DB_PSROFF, "%%post_one_line: found trailer\n", 0);
ps_at_trailer = TRUE;
return FILE_EOF;
}
/* For netscape output */
if (strncmp(line, "%%EOF", 5) == 0) {
fprintf(outfd, "%% %s", line);
Debug(DB_PSROFF, "%%post_one_line: Netscape EOF\n", 0);
return FILE_EOF;
}
if (ps_posttype == PS_MPAGE && strncmp(line, "showsheet", 9) == 0)
return FILE_CONT;
if (ps_posttype == PS_TEX || ps_posttype == PS_TEX2) {
if (ps_posttype == PS_TEX2 &&
(strstr(line, "eop\n") || strstr(line, "eop end\n"))) {
fprintf(outfd, "%s", line);
Debug(DB_PSROFF, "%%post_one_line: found TEX eop\n", 0);
return FILE_MORE;
}
if (strncmp(line, "TeXDict", 7) == 0) {
/*
* Hope all dvi2ps progs work the same:
* capture the TeX init code so we can run it 'manually' for
* every page. This is needed as this code sets up a gstate
* that conflicts with mpage...
* This trick seems to work for text, but figures within the dvi
* file seem to have a mind of their own...
*/
if (tex1)
free(tex1);
tex1 = malloc(strlen(line)+1);
strcpy(tex1, line);
fprintf(outfd, "%s", line);
flush_page ? memgets(line, LINESIZE-1) :
fgets(line, LINESIZE-1, fd);
if (tex2)
free(tex2);
tex2 = malloc(strlen(line)+1);
strcpy(tex2, line);
}
}
}
fprintf(outfd, "%s", line);
plcnt++;
return FILE_CONT;
} /* post_one_line */
static void
do_roff_tailer(fd, outfd)
FILE *fd, *outfd;
{
#ifdef DEBUG
int i = 0;
#endif
Debug(DB_PSDOC, "%%do_roff_trailer: looking for eof\n", 0);
while(fgets(currline, LINESIZE-1, fd) != NULL) {
#ifdef DEBUG
i++;
Debug(DB_PSDOC, "%%%s", currline);
#endif
;
}
Debug(DB_PSDOC, "%%do_roff_trailer: tailer of %d lines\n", i);
return;
} /* do_roff_tailer */
|