"Fossies" - the Fresh Open Source Software Archive

Member "ghostview-1.4.1/ps.c" (29 Oct 1992, 42492 Bytes) of package /linux/misc/old/ghost/gnu/ghostview/ghostview-1.4.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * ps.c -- Postscript scanning and copying routines.
    3  * Copyright (C) 1992  Timothy O. Theisen
    4  *
    5  * This program is free software; you can redistribute it and/or modify
    6  * it under the terms of the GNU General Public License as published by
    7  * the Free Software Foundation; either version 2 of the License, or
    8  * (at your option) any later version.
    9  *
   10  * This program is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  * GNU General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU General Public License
   16  * along with this program; if not, write to the Free Software
   17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18  *
   19  *   Author: Tim Theisen           Systems Programmer
   20  * Internet: tim@cs.wisc.edu       Department of Computer Sciences
   21  *     UUCP: uwvax!tim             University of Wisconsin-Madison
   22  *    Phone: (608)262-0438         1210 West Dayton Street
   23  *      FAX: (608)262-9777         Madison, WI   53706
   24  */
   25 
   26 #include <stdio.h>
   27 #ifndef SEEK_SET
   28 #define SEEK_SET 0
   29 #endif
   30 #ifndef BUFSIZ
   31 #define BUFSIZ 1024
   32 #endif
   33 #include <ctype.h>
   34 #include <X11/Xos.h>        /* #includes the appropriate <string.h> */
   35 #include "ps.h"
   36 
   37 #ifdef BSD4_2
   38 #define memset(a,b,c) bzero(a,c)
   39 #endif
   40 
   41 /* length calculates string length at compile time */
   42 /* can only be used with character constants */
   43 #define length(a) (sizeof(a)-1)
   44 #define iscomment(a, b) (strncmp(a, b, length(b)) == 0)
   45 
   46     /* list of standard paper sizes from Adobe's PPD. */
   47 
   48 struct documentmedia papersizes[] = {
   49     "Letter",        612,  792,
   50     "LetterSmall",   612,  792,
   51     "Tabloid",       792, 1224,
   52     "Ledger",       1224,  792,
   53     "Legal",         612, 1008,
   54     "Statement",     396,  612,
   55     "Executive",     540,  720,
   56     "A3",        842, 1190,
   57     "A4",        595,  842,
   58     "A4Small",       595,  842,
   59     "A5",        420,  595,
   60     "B4",        729, 1032,
   61     "B5",        516,  729,
   62     "Folio",         612,  936,
   63     "Quarto",        610,  780,
   64     "10x14",         720, 1008,
   65     NULL,          0,    0
   66 };
   67 
   68 
   69 static char *readline();
   70 static char *gettextline();
   71 static char *gettext();
   72 static int  blank();
   73 
   74 /*
   75  *  psscan -- scan the PostScript file for document structuring comments.
   76  *
   77  *  This scanner is designed to retrieve the information necessary for
   78  *  the ghostview previewer.  It will scan files that conform to any
   79  *  version (1.0, 2.0, 2.1, or 3.0) of the document structuring conventions.
   80  *  It does not really care which version of comments the file contains.
   81  *  (The comments are largely upward compatible.)  It will scan a number
   82  *  of non-conforming documents.  (You could have part of the document
   83  *  conform to V2.0 and the rest conform to V3.0.  It would be similar
   84  *  to the DC-2 1/2+, it would look funny but it can still fly.)
   85  *
   86  *  This routine returns a pointer to the document structure.
   87  *  The structure contains the information relevant to previewing.
   88  *      These include EPSF flag (to tell if the file is a encapsulated figure),
   89  *      Page Media (for the Page Size), Bounding Box (to minimize backing
   90  *      pixmap size or determine window size for encapsulated PostScript), 
   91  *      Orientation of Paper (for default transformation matrix), and
   92  *      Page Order.  The title and CreationDate are also retrieved to
   93  *      help identify the document.
   94  *
   95  *      The following comments are examined:
   96  *
   97  *      Header section: 
   98  *      Must start with %!PS-Adobe-.  Version numbers ignored.
   99  *
  100  *      %!PS-Adobe-* [EPSF-*]
  101  *      %%BoundingBox: <int> <int> <int> <int>|(atend)
  102  *      %%CreationDate: <textline>
  103  *      %%Orientation: Portrait|Landscape|(atend)
  104  *      %%Pages: <uint> [<int>]|(atend)
  105  *      %%PageOrder: Ascend|Descend|Special|(atend)
  106  *      %%Title: <textline>
  107  *      %%DocumentMedia: <text> <real> <real> <real> <text> <text>
  108  *      %%DocumentPageSizes: <text>
  109  *      %%EndComments
  110  *
  111  *      Note: Either the 3.0 or 2.0 syntax for %%Pages is accepted.
  112  *            Also either the 2.0 %%DocumentPageSizes or the 3.0
  113  *            %%DocumentMedia comments are accepted as well.
  114  *
  115  *      The header section ends either explicitly with %%EndComments or
  116  *      implicitly with any line that does not begin with %X where X is
  117  *      a not whitespace character.
  118  *
  119  *      If the file is encapsulated PostScript the optional Preview section
  120  *      is next:
  121  *
  122  *      %%BeginPreview
  123  *      %%EndPreview
  124  *
  125  *      This section explicitly begins and ends with the above comments.
  126  *
  127  *      Next the Defaults section for version 3 page defaults:
  128  *
  129  *      %%BeginDefaults
  130  *      %%PageBoundingBox: <int> <int> <int> <int>
  131  *      %%PageOrientation: Portrait|Landscape
  132  *      %%PageMedia: <text>
  133  *      %%EndDefaults
  134  *
  135  *      This section explicitly begins and ends with the above comments.
  136  *
  137  *      The prolog section either explicitly starts with %%BeginProlog or
  138  *      implicitly with any nonblank line.
  139  *
  140  *      %%BeginProlog
  141  *      %%EndProlog
  142  *
  143  *      The Prolog should end with %%EndProlog, however the proglog implicitly
  144  *      ends when %%BeginSetup, %%Page, %%Trailer or %%EOF are encountered.
  145  *
  146  *      The Setup section is where the version 2 page defaults are found.
  147  *      This section either explicitly begins with %%BeginSetup or implicitly
  148  *      with any nonblank line after the Prolog.
  149  *
  150  *      %%BeginSetup
  151  *      %%PageBoundingBox: <int> <int> <int> <int>
  152  *      %%PageOrientation: Portrait|Landscape
  153  *      %%PaperSize: <text>
  154  *      %%EndSetup
  155  *
  156  *      The Setup should end with %%EndSetup, however the setup implicitly
  157  *      ends when %%Page, %%Trailer or %%EOF are encountered.
  158  *
  159  *      Next each page starts explicitly with %%Page and ends implicitly with
  160  *      %%Page or %%Trailer or %%EOF.  The following comments are recognized:
  161  *
  162  *      %%Page: <text> <uint>
  163  *      %%PageBoundingBox: <int> <int> <int> <int>|(atend)
  164  *      %%PageOrientation: Portrait|Landscape
  165  *      %%PageMedia: <text>
  166  *      %%PaperSize: <text>
  167  *
  168  *      The tralier section start explicitly with %%Trailer and end with %%EOF.
  169  *      The following comment are examined with the proper (atend) notation
  170  *      was used in the header:
  171  *
  172  *      %%Trailer
  173  *      %%BoundingBox: <int> <int> <int> <int>|(atend)
  174  *      %%Orientation: Portrait|Landscape|(atend)
  175  *      %%Pages: <uint> [<int>]|(atend)
  176  *      %%PageOrder: Ascend|Descend|Special|(atend)
  177  *      %%EOF
  178  *
  179  *
  180  *  + A DC-3 received severe damage to one of its wings.  The wing was a total
  181  *    loss.  There was no replacement readily available, so the mechanic
  182  *    installed a wing from a DC-2.
  183  */
  184 
  185 struct document *
  186 psscan(file)
  187     FILE *file;
  188 {
  189     struct document *doc;
  190     int bb_set = NONE;
  191     int pages_set = NONE;
  192     int page_order_set = NONE;
  193     int orientation_set = NONE;
  194     int page_bb_set = NONE;
  195     int page_media_set = NONE;
  196     int preread;        /* flag which tells the readline isn't needed */
  197     int i;
  198     unsigned int maxpages = 0;
  199     unsigned int nextpage = 1;  /* Next expected page */
  200     unsigned int thispage;
  201     int ignore = 0;     /* whether to ignore page ordinals */
  202     char *label;
  203     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  204     char text[PSLINELENGTH];    /* Temporary storage for text */
  205     long position;      /* Position of the current line */
  206     unsigned int line_len;  /* Length of the current line */
  207     unsigned int section_len;   /* Place to accumulate the section length */
  208     char *next_char;        /* 1st char after text returned by gettext() */
  209     char *cp;
  210     struct documentmedia *dmp;
  211 
  212     rewind(file);
  213     if (readline(line, sizeof line, file, &position, &line_len) == NULL) {
  214     fprintf(stderr, "Warning: empty file.\n");
  215     return(NULL);
  216     }
  217 
  218     /* Header comments */
  219 
  220     if (iscomment(line,"%!PS-Adobe-")) {
  221     doc = (struct document *) malloc(sizeof(struct document));
  222     if (doc == NULL) {
  223         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  224         exit(-1);
  225     }
  226     memset(doc, 0, sizeof(struct document));
  227     sscanf(line, "%*s %s", text);
  228     doc->epsf = iscomment(text, "EPSF-");
  229     doc->beginheader = position;
  230     section_len = line_len;
  231     } else {
  232     return(NULL);
  233     }
  234 
  235     preread = 0;
  236     while (preread || readline(line, sizeof line, file, &position, &line_len)) {
  237     if (!preread) section_len += line_len;
  238     preread = 0;
  239     if (iscomment(line, "%%EndComments") ||
  240         line[0] != '%' ||
  241         (!isprint(line[1]) || line[1] == ' ' ||
  242          line[1] == '\t' || line[1] == '\n')) {
  243         break;
  244     } else if (!iscomment(line, "%%")) {
  245         /* Do nothing */
  246     } else if (doc->title == NULL && iscomment(line+2, "Title:")) {
  247         doc->title = gettextline(line+length("%%Title:"));
  248     } else if (doc->date == NULL && iscomment(line+2, "CreationDate:")) {
  249         doc->date = gettextline(line+length("%%CreationDate:"));
  250     } else if (bb_set == NONE && iscomment(line+2, "BoundingBox:")) {
  251         sscanf(line+length("%%BoundingBox:"), "%s", text);
  252         if (strcmp(text, "(atend)") == 0) {
  253         bb_set = ATEND;
  254         } else {
  255         if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
  256                &(doc->boundingbox[LLX]),
  257                &(doc->boundingbox[LLY]),
  258                &(doc->boundingbox[URX]),
  259                &(doc->boundingbox[URY])) == 4)
  260             bb_set = 1;
  261         else {
  262             float fllx, flly, furx, fury;
  263             if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
  264                    &fllx, &flly, &furx, &fury) == 4) {
  265             bb_set = 1;
  266             doc->boundingbox[LLX] = fllx;
  267             doc->boundingbox[LLY] = flly;
  268             doc->boundingbox[URX] = furx;
  269             doc->boundingbox[URY] = fury;
  270             if (fllx < doc->boundingbox[LLX])
  271                 doc->boundingbox[LLX]--;
  272             if (flly < doc->boundingbox[LLY])
  273                 doc->boundingbox[LLY]--;
  274             if (furx > doc->boundingbox[URX])
  275                 doc->boundingbox[URX]++;
  276             if (fury > doc->boundingbox[URY])
  277                 doc->boundingbox[URY]++;
  278             }
  279         }
  280         }
  281     } else if (orientation_set == NONE &&
  282            iscomment(line+2, "Orientation:")) {
  283         sscanf(line+length("%%Orientation:"), "%s", text);
  284         if (strcmp(text, "(atend)") == 0) {
  285         orientation_set = ATEND;
  286         } else if (strcmp(text, "Portrait") == 0) {
  287         doc->orientation = PORTRAIT;
  288         orientation_set = 1;
  289         } else if (strcmp(text, "Landscape") == 0) {
  290         doc->orientation = LANDSCAPE;
  291         orientation_set = 1;
  292         }
  293     } else if (page_order_set == NONE && iscomment(line+2, "PageOrder:")) {
  294         sscanf(line+length("%%PageOrder:"), "%s", text);
  295         if (strcmp(text, "(atend)") == 0) {
  296         page_order_set = ATEND;
  297         } else if (strcmp(text, "Ascend") == 0) {
  298         doc->pageorder = ASCEND;
  299         page_order_set = 1;
  300         } else if (strcmp(text, "Descend") == 0) {
  301         doc->pageorder = DESCEND;
  302         page_order_set = 1;
  303         } else if (strcmp(text, "Special") == 0) {
  304         doc->pageorder = SPECIAL;
  305         page_order_set = 1;
  306         }
  307     } else if (pages_set == NONE && iscomment(line+2, "Pages:")) {
  308         sscanf(line+length("%%Pages:"), "%s", text);
  309         if (strcmp(text, "(atend)") == 0) {
  310         pages_set = ATEND;
  311         } else {
  312         switch (sscanf(line+length("%%Pages:"), "%d %d",
  313                    &maxpages, &i)) {
  314             case 2:
  315             if (page_order_set == NONE) {
  316                 if (i == -1) {
  317                 doc->pageorder = DESCEND;
  318                 page_order_set = 1;
  319                 } else if (i == 0) {
  320                 doc->pageorder = SPECIAL;
  321                 page_order_set = 1;
  322                 } else if (i == 1) {
  323                 doc->pageorder = ASCEND;
  324                 page_order_set = 1;
  325                 }
  326             }
  327             case 1:
  328             doc->pages = (struct page *) calloc(maxpages,
  329                             sizeof(struct page));
  330             if (doc->pages == NULL) {
  331                 fprintf(stderr,
  332                     "Fatal Error: Dynamic memory exhausted.\n");
  333                 exit(-1);
  334             }
  335         }
  336         }
  337     } else if (doc->nummedia == NONE &&
  338            iscomment(line+2, "DocumentMedia:")) {
  339         float w, h;
  340         doc->media = (struct documentmedia *)
  341              malloc(sizeof (struct documentmedia));
  342         if (doc->media == NULL) {
  343         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  344         exit(-1);
  345         }
  346         doc->media[0].name = gettext(line+length("%%DocumentMedia:"),
  347                      &next_char);
  348         if (doc->media[0].name != NULL) {
  349         if (sscanf(next_char, "%f %f", &w, &h) == 2) {
  350             doc->media[0].width = w + 0.5;
  351             doc->media[0].height = h + 0.5;
  352         }
  353         if (doc->media[0].width != 0 && doc->media[0].height != 0)
  354             doc->nummedia = 1;
  355         else
  356             free(doc->media[0].name);
  357         }
  358         preread=1;
  359         while (readline(line, sizeof line, file, &position, &line_len) &&
  360            iscomment(line, "%%+")) {
  361         section_len += line_len;
  362         doc->media = (struct documentmedia *)
  363                  realloc(doc->media,
  364                      (doc->nummedia+1)*
  365                      sizeof (struct documentmedia));
  366         if (doc->media == NULL) {
  367             fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  368             exit(-1);
  369         }
  370         doc->media[doc->nummedia].name = gettext(line+length("%%+"),
  371                              &next_char);
  372         if (doc->media[doc->nummedia].name != NULL) {
  373             if (sscanf(next_char, "%f %f", &w, &h) == 2) {
  374             doc->media[doc->nummedia].width = w + 0.5;
  375             doc->media[doc->nummedia].height = h + 0.5;
  376             }
  377             if (doc->media[doc->nummedia].width != 0 &&
  378             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  379             else
  380             free(doc->media[doc->nummedia].name);
  381         }
  382         }
  383         section_len += line_len;
  384         if (doc->nummedia != 0) doc->default_page_media = doc->media;
  385     } else if (doc->nummedia == NONE &&
  386            iscomment(line+2, "DocumentPaperSizes:")) {
  387 
  388         doc->media = (struct documentmedia *)
  389              malloc(sizeof (struct documentmedia));
  390         if (doc->media == NULL) {
  391         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  392         exit(-1);
  393         }
  394         doc->media[0].name = gettext(line+length("%%DocumentPaperSizes:"),
  395                      &next_char);
  396         if (doc->media[0].name != NULL) {
  397         doc->media[0].width = 0;
  398         doc->media[0].height = 0;
  399         for (dmp=papersizes; dmp->name != NULL; dmp++) {
  400             /* Note: Paper size comment uses down cased paper size
  401              * name.  Case insensitive compares are only used for
  402              * PaperSize comments.
  403              */
  404             if (strcasecmp(doc->media[0].name, dmp->name) == 0) {
  405             free(doc->media[0].name);
  406             doc->media[0].name =
  407                 (char *)malloc(strlen(dmp->name)+1);
  408             if (doc->media[0].name == NULL) {
  409                 fprintf(stderr,
  410                     "Fatal Error: Dynamic memory exhausted.\n");
  411                 exit(-1);
  412             }
  413             strcpy(doc->media[0].name, dmp->name);
  414             doc->media[0].width = dmp->width;
  415             doc->media[0].height = dmp->height;
  416             break;
  417             }
  418         }
  419         if (doc->media[0].width != 0 && doc->media[0].height != 0)
  420             doc->nummedia = 1;
  421         else
  422             free(doc->media[0].name);
  423         }
  424         while (cp = gettext(next_char, &next_char)) {
  425         doc->media = (struct documentmedia *)
  426                  realloc(doc->media,
  427                      (doc->nummedia+1)*
  428                      sizeof (struct documentmedia));
  429         if (doc->media == NULL) {
  430             fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  431             exit(-1);
  432         }
  433         doc->media[doc->nummedia].name = cp;
  434         doc->media[doc->nummedia].width = 0;
  435         doc->media[doc->nummedia].height = 0;
  436         for (dmp=papersizes; dmp->name != NULL; dmp++) {
  437             /* Note: Paper size comment uses down cased paper size
  438              * name.  Case insensitive compares are only used for
  439              * PaperSize comments.
  440              */
  441             if (strcasecmp(doc->media[doc->nummedia].name,
  442                    dmp->name) == 0) {
  443             free(doc->media[doc->nummedia].name);
  444             doc->media[doc->nummedia].name =
  445                 (char *)malloc(strlen(dmp->name)+1);
  446             if (doc->media[doc->nummedia].name == NULL) {
  447                 fprintf(stderr,
  448                     "Fatal Error: Dynamic memory exhausted.\n");
  449                 exit(-1);
  450             }
  451             strcpy(doc->media[doc->nummedia].name, dmp->name);
  452             doc->media[doc->nummedia].name = dmp->name;
  453             doc->media[doc->nummedia].width = dmp->width;
  454             doc->media[doc->nummedia].height = dmp->height;
  455             break;
  456             }
  457         }
  458         if (doc->media[doc->nummedia].width != 0 &&
  459             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  460         else
  461             free(doc->media[doc->nummedia].name);
  462         }
  463         preread=1;
  464         while (readline(line, sizeof line, file, &position, &line_len) &&
  465            iscomment(line, "%%+")) {
  466         section_len += line_len;
  467         next_char = line + length("%%+");
  468         while (cp = gettext(next_char, &next_char)) {
  469             doc->media = (struct documentmedia *)
  470                  realloc(doc->media,
  471                      (doc->nummedia+1)*
  472                      sizeof (struct documentmedia));
  473             if (doc->media == NULL) {
  474             fprintf(stderr,
  475                 "Fatal Error: Dynamic memory exhausted.\n");
  476             exit(-1);
  477             }
  478             doc->media[doc->nummedia].name = cp;
  479             doc->media[doc->nummedia].width = 0;
  480             doc->media[doc->nummedia].height = 0;
  481             for (dmp=papersizes; dmp->name != NULL; dmp++) {
  482             /* Note: Paper size comment uses down cased paper size
  483              * name.  Case insensitive compares are only used for
  484              * PaperSize comments.
  485              */
  486             if (strcasecmp(doc->media[doc->nummedia].name,
  487                    dmp->name) == 0) {
  488                 doc->media[doc->nummedia].width = dmp->width;
  489                 doc->media[doc->nummedia].height = dmp->height;
  490                 break;
  491             }
  492             }
  493             if (doc->media[doc->nummedia].width != 0 &&
  494             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  495             else
  496             free(doc->media[doc->nummedia].name);
  497         }
  498         }
  499         section_len += line_len;
  500         if (doc->nummedia != 0) doc->default_page_media = doc->media;
  501     }
  502     }
  503 
  504     if (iscomment(line, "%%EndComments")) {
  505     readline(line, sizeof line, file, &position, &line_len);
  506     section_len += line_len;
  507     }
  508     doc->endheader = position;
  509     doc->lenheader = section_len - line_len;
  510 
  511     /* Optional Preview comments for encapsulated PostScript files */ 
  512 
  513     while (blank(line) &&
  514        readline(line, sizeof line, file, &position, &line_len)) {
  515     }
  516 
  517     if (doc->epsf && iscomment(line, "%%BeginPreview")) {
  518     doc->beginpreview = position;
  519     section_len = line_len;
  520     while (readline(line, sizeof line, file, &position, &line_len) &&
  521            !iscomment(line, "%%EndPreview")) {
  522         section_len += line_len;
  523     }
  524     section_len += line_len;
  525     readline(line, sizeof line, file, &position, &line_len);
  526     section_len += line_len;
  527     doc->endpreview = position;
  528     doc->lenpreview = section_len - line_len;
  529     }
  530 
  531     /* Page Defaults for Version 3.0 files */
  532 
  533     while (blank(line) &&
  534        readline(line, sizeof line, file, &position, &line_len)) {
  535     }
  536 
  537     if (iscomment(line, "%%BeginDefaults")) {
  538     doc->begindefaults = position;
  539     section_len = line_len;
  540     while (readline(line, sizeof line, file, &position, &line_len) &&
  541            !iscomment(line, "%%EndDefaults")) {
  542         section_len += line_len;
  543         if (!iscomment(line, "%%")) {
  544         /* Do nothing */
  545         } else if (doc->default_page_orientation == NONE &&
  546         iscomment(line+2, "PageOrientation:")) {
  547         sscanf(line+length("%%PageOrientation:"), "%s", text);
  548         if (strcmp(text, "Portrait") == 0) {
  549             doc->default_page_orientation = PORTRAIT;
  550         } else if (strcmp(text, "Landscape") == 0) {
  551             doc->default_page_orientation = LANDSCAPE;
  552         }
  553         } else if (page_media_set == NONE &&
  554                iscomment(line+2, "PageMedia:")) {
  555         cp = gettext(line+length("%%PageMedia:"), NULL);
  556         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  557             if (strcmp(cp, dmp->name) == 0) {
  558             doc->default_page_media = dmp;
  559             page_media_set = 1;
  560             break;
  561             }
  562         }
  563         free(cp);
  564         } else if (page_bb_set == NONE &&
  565                iscomment(line+2, "PageBoundingBox:")) {
  566         if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  567                &(doc->default_page_boundingbox[LLX]),
  568                &(doc->default_page_boundingbox[LLY]),
  569                &(doc->default_page_boundingbox[URX]),
  570                &(doc->default_page_boundingbox[URY])) == 4)
  571             page_bb_set = 1;
  572         else {
  573             float fllx, flly, furx, fury;
  574             if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
  575                    &fllx, &flly, &furx, &fury) == 4) {
  576             page_bb_set = 1;
  577             doc->default_page_boundingbox[LLX] = fllx;
  578             doc->default_page_boundingbox[LLY] = flly;
  579             doc->default_page_boundingbox[URX] = furx;
  580             doc->default_page_boundingbox[URY] = fury;
  581             if (fllx < doc->default_page_boundingbox[LLX])
  582                 doc->default_page_boundingbox[LLX]--;
  583             if (flly < doc->default_page_boundingbox[LLY])
  584                 doc->default_page_boundingbox[LLY]--;
  585             if (furx > doc->default_page_boundingbox[URX])
  586                 doc->default_page_boundingbox[URX]++;
  587             if (fury > doc->default_page_boundingbox[URY])
  588                 doc->default_page_boundingbox[URY]++;
  589             }
  590         }
  591         }
  592     }
  593     section_len += line_len;
  594     readline(line, sizeof line, file, &position, &line_len);
  595     section_len += line_len;
  596     doc->enddefaults = position;
  597     doc->lendefaults = section_len - line_len;
  598     }
  599 
  600     /* Document Prolog */
  601 
  602     while (blank(line) &&
  603        readline(line, sizeof line, file, &position, &line_len)) {
  604     }
  605 
  606     if (!iscomment(line, "%%BeginSetup") && !iscomment(line, "%%Page:") &&
  607     !iscomment(line, "%%Trailer") && !iscomment(line, "%%EOF")) {
  608     doc->beginprolog = position;
  609     section_len = line_len;
  610     preread = 1;
  611 
  612     while ((preread ||
  613         readline(line, sizeof line, file, &position, &line_len)) &&
  614            !iscomment(line, "%%EndProlog") &&
  615            !iscomment(line, "%%BeginSetup") &&
  616            !iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  617            !iscomment(line, "%%EOF")) {
  618         if (!preread) section_len += line_len;
  619         preread = 0;
  620     }
  621     section_len += line_len;
  622     if (iscomment(line, "%%EndProlog")) {
  623         readline(line, sizeof line, file, &position, &line_len);
  624         section_len += line_len;
  625     }
  626     doc->endprolog = position;
  627     doc->lenprolog = section_len - line_len;
  628     }
  629 
  630     /* Document Setup,  Page Defaults found here for Version 2 files */
  631 
  632     while (blank(line) &&
  633        readline(line, sizeof line, file, &position, &line_len)) {
  634     }
  635 
  636     if (!iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  637     !iscomment(line, "%%EOF")) {
  638     doc->beginsetup = position;
  639     section_len = line_len;
  640     preread = 1;
  641     while ((preread ||
  642         readline(line, sizeof line, file, &position, &line_len)) &&
  643            !iscomment(line, "%%EndSetup") && !iscomment(line, "%%Page:") &&
  644            !iscomment(line, "%%Trailer") && !iscomment(line, "%%EOF")) {
  645         if (!preread) section_len += line_len;
  646         preread = 0;
  647         if (!iscomment(line, "%%")) {
  648         /* Do nothing */
  649         } else if (doc->default_page_orientation == NONE &&
  650         iscomment(line+2, "PageOrientation:")) {
  651         sscanf(line+length("%%PageOrientation:"), "%s", text);
  652         if (strcmp(text, "Portrait") == 0) {
  653             doc->default_page_orientation = PORTRAIT;
  654         } else if (strcmp(text, "Landscape") == 0) {
  655             doc->default_page_orientation = LANDSCAPE;
  656         }
  657         } else if (page_media_set == NONE &&
  658                iscomment(line+2, "PaperSize:")) {
  659         cp = gettext(line+length("%%PaperSize:"), NULL);
  660         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  661             /* Note: Paper size comment uses down cased paper size
  662              * name.  Case insensitive compares are only used for
  663              * PaperSize comments.
  664              */
  665             if (strcasecmp(cp, dmp->name) == 0) {
  666             doc->default_page_media = dmp;
  667             page_media_set = 1;
  668             break;
  669             }
  670         }
  671         free(cp);
  672         } else if (page_bb_set == NONE &&
  673                iscomment(line+2, "PageBoundingBox:")) {
  674         if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  675                &(doc->default_page_boundingbox[LLX]),
  676                &(doc->default_page_boundingbox[LLY]),
  677                &(doc->default_page_boundingbox[URX]),
  678                &(doc->default_page_boundingbox[URY])) == 4)
  679             page_bb_set = 1;
  680         else {
  681             float fllx, flly, furx, fury;
  682             if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
  683                    &fllx, &flly, &furx, &fury) == 4) {
  684             page_bb_set = 1;
  685             doc->default_page_boundingbox[LLX] = fllx;
  686             doc->default_page_boundingbox[LLY] = flly;
  687             doc->default_page_boundingbox[URX] = furx;
  688             doc->default_page_boundingbox[URY] = fury;
  689             if (fllx < doc->default_page_boundingbox[LLX])
  690                 doc->default_page_boundingbox[LLX]--;
  691             if (flly < doc->default_page_boundingbox[LLY])
  692                 doc->default_page_boundingbox[LLY]--;
  693             if (furx > doc->default_page_boundingbox[URX])
  694                 doc->default_page_boundingbox[URX]++;
  695             if (fury > doc->default_page_boundingbox[URY])
  696                 doc->default_page_boundingbox[URY]++;
  697             }
  698         }
  699         }
  700     }
  701     section_len += line_len;
  702     if (iscomment(line, "%%EndSetup")) {
  703         readline(line, sizeof line, file, &position, &line_len);
  704         section_len += line_len;
  705     }
  706     doc->endsetup = position;
  707     doc->lensetup = section_len - line_len;
  708     }
  709 
  710     /* Individual Pages */
  711 
  712     while (blank(line) &&
  713        readline(line, sizeof line, file, &position, &line_len)) {
  714     }
  715 
  716 newpage:
  717     while (iscomment(line, "%%Page:")) {
  718     if (maxpages == 0) {
  719         maxpages = 1;
  720         doc->pages = (struct page *) calloc(maxpages, sizeof(struct page));
  721         if (doc->pages == NULL) {
  722         fprintf(stderr,
  723             "Fatal Error: Dynamic memory exhausted.\n");
  724         exit(-1);
  725         }
  726     }
  727     label = gettext(line+length("%%Page:"), &next_char);
  728     if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  729     if (nextpage == 1) {
  730         ignore = thispage != 1;
  731     }
  732     if (!ignore && thispage != nextpage) {
  733         free(label);
  734         doc->numpages--;
  735         goto continuepage;
  736     }
  737     nextpage++;
  738     if (doc->numpages == maxpages) {
  739         maxpages++;
  740         doc->pages = (struct page *)
  741              realloc(doc->pages, maxpages*sizeof (struct page));
  742         if (doc->pages == NULL) {
  743         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  744         exit(-1);
  745         }
  746     }
  747     memset(&(doc->pages[doc->numpages]), 0, sizeof(struct page));
  748     page_bb_set = NONE;
  749     doc->pages[doc->numpages].label = label;
  750     doc->pages[doc->numpages].begin = position;
  751     section_len = line_len;
  752 continuepage:
  753     while (readline(line, sizeof line, file, &position, &line_len) &&
  754            !iscomment(line, "%%Page:") && !iscomment(line, "%%Trailer") &&
  755            !iscomment(line, "%%EOF")) {
  756         section_len += line_len;
  757         if (!iscomment(line, "%%")) {
  758         /* Do nothing */
  759         } else if (doc->pages[doc->numpages].orientation == NONE &&
  760         iscomment(line+2, "PageOrientation:")) {
  761         sscanf(line+length("%%PageOrientation:"), "%s", text);
  762         if (strcmp(text, "Portrait") == 0) {
  763             doc->pages[doc->numpages].orientation = PORTRAIT;
  764         } else if (strcmp(text, "Landscape") == 0) {
  765             doc->pages[doc->numpages].orientation = LANDSCAPE;
  766         }
  767         } else if (doc->pages[doc->numpages].media == NULL &&
  768                iscomment(line+2, "PageMedia:")) {
  769         cp = gettext(line+length("%%PageMedia:"), NULL);
  770         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  771             if (strcmp(cp, dmp->name) == 0) {
  772             doc->pages[doc->numpages].media = dmp;
  773             break;
  774             }
  775         }
  776         free(cp);
  777         } else if (doc->pages[doc->numpages].media == NULL &&
  778                iscomment(line+2, "PaperSize:")) {
  779         cp = gettext(line+length("%%PaperSize:"), NULL);
  780         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  781             /* Note: Paper size comment uses down cased paper size
  782              * name.  Case insensitive compares are only used for
  783              * PaperSize comments.
  784              */
  785             if (strcasecmp(cp, dmp->name) == 0) {
  786             doc->pages[doc->numpages].media = dmp;
  787             break;
  788             }
  789         }
  790         free(cp);
  791         } else if ((page_bb_set == NONE || page_bb_set == ATEND) &&
  792                iscomment(line+2, "PageBoundingBox:")) {
  793         sscanf(line+length("%%PageBoundingBox:"), "%s", text);
  794         if (strcmp(text, "(atend)") == 0) {
  795             page_bb_set = ATEND;
  796         } else {
  797             if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  798                 &(doc->pages[doc->numpages].boundingbox[LLX]),
  799                 &(doc->pages[doc->numpages].boundingbox[LLY]),
  800                 &(doc->pages[doc->numpages].boundingbox[URX]),
  801                 &(doc->pages[doc->numpages].boundingbox[URY])) == 4)
  802             if (page_bb_set == NONE) page_bb_set = 1;
  803             else {
  804             float fllx, flly, furx, fury;
  805             if (sscanf(line+length("%%PageBoundingBox:"),
  806                    "%f %f %f %f",
  807                    &fllx, &flly, &furx, &fury) == 4) {
  808                 if (page_bb_set == NONE) page_bb_set = 1;
  809                 doc->pages[doc->numpages].boundingbox[LLX] = fllx;
  810                 doc->pages[doc->numpages].boundingbox[LLY] = flly;
  811                 doc->pages[doc->numpages].boundingbox[URX] = furx;
  812                 doc->pages[doc->numpages].boundingbox[URY] = fury;
  813                 if (fllx <
  814                     doc->pages[doc->numpages].boundingbox[LLX])
  815                 doc->pages[doc->numpages].boundingbox[LLX]--;
  816                 if (flly <
  817                     doc->pages[doc->numpages].boundingbox[LLY])
  818                 doc->pages[doc->numpages].boundingbox[LLY]--;
  819                 if (furx >
  820                     doc->pages[doc->numpages].boundingbox[URX])
  821                 doc->pages[doc->numpages].boundingbox[URX]++;
  822                 if (fury >
  823                     doc->pages[doc->numpages].boundingbox[URY])
  824                 doc->pages[doc->numpages].boundingbox[URY]++;
  825             }
  826             }
  827         }
  828         }
  829     }
  830     section_len += line_len;
  831     doc->pages[doc->numpages].end = position;
  832     doc->pages[doc->numpages].len = section_len - line_len;
  833     doc->numpages++;
  834     }
  835 
  836     /* Document Trailer */
  837 
  838     doc->begintrailer = position;
  839     section_len = line_len;
  840 
  841     preread = 1;
  842     while ((preread ||
  843         readline(line, sizeof line, file, &position, &line_len)) &&
  844        !iscomment(line, "%%EOF")) {
  845     if (!preread) section_len += line_len;
  846     preread = 0;
  847     if (!iscomment(line, "%%")) {
  848         /* Do nothing */
  849     } else if (iscomment(line+2, "Page:")) {
  850         free(gettext(line+length("%%Page:"), &next_char));
  851         if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  852         if (!ignore && thispage == nextpage) {
  853         if (doc->numpages > 0) {
  854             doc->pages[doc->numpages-1].end = position;
  855             doc->pages[doc->numpages-1].len += section_len - line_len;
  856         }
  857         goto newpage;
  858         }
  859     } else if (bb_set == ATEND && iscomment(line+2, "BoundingBox:")) {
  860         if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
  861                &(doc->boundingbox[LLX]),
  862                &(doc->boundingbox[LLY]),
  863                &(doc->boundingbox[URX]),
  864                &(doc->boundingbox[URY])) != 4) {
  865         float fllx, flly, furx, fury;
  866         if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
  867                &fllx, &flly, &furx, &fury) == 4) {
  868             doc->boundingbox[LLX] = fllx;
  869             doc->boundingbox[LLY] = flly;
  870             doc->boundingbox[URX] = furx;
  871             doc->boundingbox[URY] = fury;
  872             if (fllx < doc->boundingbox[LLX])
  873             doc->boundingbox[LLX]--;
  874             if (flly < doc->boundingbox[LLY])
  875             doc->boundingbox[LLY]--;
  876             if (furx > doc->boundingbox[URX])
  877             doc->boundingbox[URX]++;
  878             if (fury > doc->boundingbox[URY])
  879             doc->boundingbox[URY]++;
  880         }
  881         }
  882     } else if (orientation_set == ATEND &&
  883            iscomment(line+2, "Orientation:")) {
  884         sscanf(line+length("%%Orientation:"), "%s", text);
  885         if (strcmp(text, "Portrait") == 0) {
  886         doc->orientation = PORTRAIT;
  887         } else if (strcmp(text, "Landscape") == 0) {
  888         doc->orientation = LANDSCAPE;
  889         }
  890     } else if (page_order_set == ATEND && iscomment(line+2, "PageOrder:")) {
  891         sscanf(line+length("%%PageOrder:"), "%s", text);
  892         if (strcmp(text, "Ascend") == 0) {
  893         doc->pageorder = ASCEND;
  894         } else if (strcmp(text, "Descend") == 0) {
  895         doc->pageorder = DESCEND;
  896         } else if (strcmp(text, "Special") == 0) {
  897         doc->pageorder = SPECIAL;
  898         }
  899     } else if (pages_set == ATEND && iscomment(line+2, "Pages:")) {
  900         if (sscanf(line+length("%%Pages:"), "%*u %d", &i) == 1) {
  901         if (page_order_set == NONE) {
  902             if (i == -1) doc->pageorder = DESCEND;
  903             else if (i == 0) doc->pageorder = SPECIAL;
  904             else if (i == 1) doc->pageorder = ASCEND;
  905         }
  906         }
  907     }
  908     }
  909     section_len += line_len;
  910     if (iscomment(line, "%%EOF")) {
  911     readline(line, sizeof line, file, &position, &line_len);
  912     section_len += line_len;
  913     }
  914     doc->endtrailer = position;
  915     doc->lentrailer = section_len - line_len;
  916 
  917     section_len = line_len;
  918     preread = 1;
  919     while (preread ||
  920        readline(line, sizeof line, file, &position, &line_len)) {
  921     if (!preread) section_len += line_len;
  922     preread = 0;
  923     if (iscomment(line, "%%Page:")) {
  924         free(gettext(line+length("%%Page:"), &next_char));
  925         if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  926         if (!ignore && thispage == nextpage) {
  927         doc->pages[doc->numpages-1].end = position;
  928         doc->pages[doc->numpages-1].len += doc->lentrailer +
  929                            section_len - line_len;
  930         goto newpage;
  931         }
  932     }
  933     }
  934     return doc;
  935 }
  936 
  937 /*
  938  *  psfree -- free dynamic storage associated with document structure.
  939  */
  940 
  941 void
  942 psfree(doc)
  943     struct document *doc;
  944 {
  945     int i;
  946 
  947     if (doc) {
  948     for (i=0; i<doc->numpages; i++) {
  949         if (doc->pages[i].label) free(doc->pages[i].label);
  950     }
  951     for (i=0; i<doc->nummedia; i++) {
  952         if (doc->media[i].name) free(doc->media[i].name);
  953     }
  954     if (doc->title) free(doc->title);
  955     if (doc->date) free(doc->date);
  956     if (doc->pages) free(doc->pages);
  957     if (doc->media) free(doc->media);
  958     free(doc);
  959     }
  960 }
  961 
  962 /*
  963  * gettextine -- skip over white space and return the rest of the line.
  964  *               If the text begins with '(' return the text string
  965  *       using gettext().
  966  */
  967 
  968 static char *
  969 gettextline(line)
  970     char *line;
  971 {
  972     char *cp;
  973 
  974     while (*line && (*line == ' ' || *line == '\t')) line++;
  975     if (*line == '(') {
  976     return gettext(line, NULL);
  977     } else {
  978     if (strlen(line) == 0) return NULL;
  979     cp = (char *) malloc(strlen(line));
  980     if (cp == NULL) {
  981         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
  982         exit(-1);
  983     }
  984     strncpy(cp, line, strlen(line)-1);
  985     cp[strlen(line)-1] = '\0';
  986     return cp;
  987     }
  988 }
  989 
  990 /*
  991  *  gettext -- return the next text string on the line.
  992  *         return NULL if nothing is present.
  993  */
  994 
  995 static char *
  996 gettext(line, next_char)
  997     char *line;
  998     char **next_char;
  999 {
 1000     char text[PSLINELENGTH];    /* Temporary storage for text */
 1001     char *cp;
 1002     int quoted=0;
 1003 
 1004     while (*line && (*line == ' ' || *line == '\t')) line++;
 1005     cp = text;
 1006     if (*line == '(') {
 1007     int level = 0;
 1008     quoted=1;
 1009     line++;
 1010     while (*line && !(*line == ')' && level == 0 )) {
 1011         if (*line == '\\') {
 1012         if (*(line+1) == 'n') {
 1013             *cp++ = '\n';
 1014             line += 2;
 1015         } else if (*(line+1) == 'r') {
 1016             *cp++ = '\r';
 1017             line += 2;
 1018         } else if (*(line+1) == 't') {
 1019             *cp++ = '\t';
 1020             line += 2;
 1021         } else if (*(line+1) == 'b') {
 1022             *cp++ = '\b';
 1023             line += 2;
 1024         } else if (*(line+1) == 'f') {
 1025             *cp++ = '\f';
 1026             line += 2;
 1027         } else if (*(line+1) == '\\') {
 1028             *cp++ = '\\';
 1029             line += 2;
 1030         } else if (*(line+1) == '(') {
 1031             *cp++ = '(';
 1032             line += 2;
 1033         } else if (*(line+1) == ')') {
 1034             *cp++ = ')';
 1035             line += 2;
 1036         } else if (*(line+1) >= '0' && *(line+1) <= '9') {
 1037             if (*(line+2) >= '0' && *(line+2) <= '9') {
 1038             if (*(line+3) >= '0' && *(line+3) <= '9') {
 1039                 *cp++ = ((*(line+1) - '0')*8 + *(line+2) - '0')*8 +
 1040                     *(line+3) - '0';
 1041                 line += 4;
 1042             } else {
 1043                 *cp++ = (*(line+1) - '0')*8 + *(line+2) - '0';
 1044                 line += 3;
 1045             }
 1046             } else {
 1047             *cp++ = *(line+1) - '0';
 1048             line += 2;
 1049             }
 1050         } else {
 1051             line++;
 1052             *cp++ = *line++;
 1053         }
 1054         } else if (*line == '(') {
 1055         level++;
 1056         *cp++ = *line++;
 1057         } else if (*line == ')') {
 1058         level--;
 1059         *cp++ = *line++;
 1060         } else {
 1061         *cp++ = *line++;
 1062         }
 1063     }
 1064     } else {
 1065     while (*line && !(*line == ' ' || *line == '\t' || *line == '\n'))
 1066         *cp++ = *line++;
 1067     }
 1068     *cp = '\0';
 1069     if (next_char) *next_char = line;
 1070     if (!quoted && strlen(text) == 0) return NULL;
 1071     cp = (char *) malloc(strlen(text)+1);
 1072     if (cp == NULL) {
 1073     fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
 1074     exit(-1);
 1075     }
 1076     strcpy(cp, text);
 1077     return cp;
 1078 }
 1079 
 1080 /*
 1081  *  readline -- Read the next line in the postscript file.
 1082  *                  Automatically skip over data (as indicated by
 1083  *                  %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
 1084  *          comments.)
 1085  *          Also, skip over included documents (as indicated by
 1086  *          %%BeginDocument/%%EndDocument comments.)
 1087  */
 1088 
 1089 static char *
 1090 readline(line, size, fp, position, line_len)
 1091     char *line;
 1092     int size;
 1093     FILE *fp;
 1094     long *position;
 1095     unsigned int *line_len;
 1096 {
 1097     char text[PSLINELENGTH];    /* Temporary storage for text */
 1098     char save[PSLINELENGTH];    /* Temporary storage for text */
 1099     char *cp;
 1100     unsigned int num;
 1101     unsigned int nbytes;
 1102     int i;
 1103     char buf[BUFSIZ];
 1104 
 1105     if (position) *position = ftell(fp);
 1106     cp = fgets(line, size, fp);
 1107     if (cp == NULL) line[0] = '\0';
 1108     *line_len = strlen(line);
 1109     if (iscomment(line, "%%BeginDocument:")) {
 1110     strcpy(save, line+7);
 1111     while (readline(line, size, fp, NULL, &nbytes) &&
 1112            !iscomment(line, "%%EndDocument")) {
 1113         *line_len += nbytes;
 1114     }
 1115     *line_len += nbytes;
 1116     strcpy(line, save);
 1117     } else if (iscomment(line, "%%BeginFeature:")) {
 1118     strcpy(save, line+7);
 1119     while (readline(line, size, fp, NULL, &nbytes) &&
 1120            !iscomment(line, "%%EndFeature")) {
 1121         *line_len += nbytes;
 1122     }
 1123     *line_len += nbytes;
 1124     strcpy(line, save);
 1125     } else if (iscomment(line, "%%BeginFile:")) {
 1126     strcpy(save, line+7);
 1127     while (readline(line, size, fp, NULL, &nbytes) &&
 1128            !iscomment(line, "%%EndFile")) {
 1129         *line_len += nbytes;
 1130     }
 1131     *line_len += nbytes;
 1132     strcpy(line, save);
 1133     } else if (iscomment(line, "%%BeginFont:")) {
 1134     strcpy(save, line+7);
 1135     while (readline(line, size, fp, NULL, &nbytes) &&
 1136            !iscomment(line, "%%EndFont")) {
 1137         *line_len += nbytes;
 1138     }
 1139     *line_len += nbytes;
 1140     strcpy(line, save);
 1141     } else if (iscomment(line, "%%BeginProcSet:")) {
 1142     strcpy(save, line+7);
 1143     while (readline(line, size, fp, NULL, &nbytes) &&
 1144            !iscomment(line, "%%EndProcSet")) {
 1145         *line_len += nbytes;
 1146     }
 1147     *line_len += nbytes;
 1148     strcpy(line, save);
 1149     } else if (iscomment(line, "%%BeginResource:")) {
 1150     strcpy(save, line+7);
 1151     while (readline(line, size, fp, NULL, &nbytes) &&
 1152            !iscomment(line, "%%EndResource")) {
 1153         *line_len += nbytes;
 1154     }
 1155     *line_len += nbytes;
 1156     strcpy(line, save);
 1157     } else if (iscomment(line, "%%BeginData:")) {
 1158     text[0] = '\0';
 1159     strcpy(save, line+7);
 1160     if (sscanf(line+length("%%BeginData:"), "%d %*s %s", &num, text) >= 1) {
 1161         if (strcmp(text, "Lines") == 0) {
 1162         for (i=0; i < num; i++) {
 1163             cp = fgets(line, size, fp);
 1164             *line_len += cp ? strlen(line) : 0;
 1165         }
 1166         } else {
 1167         while (num > BUFSIZ) {
 1168             fread(buf, sizeof (char), BUFSIZ, fp);
 1169             *line_len += BUFSIZ;
 1170             num -= BUFSIZ;
 1171         }
 1172         fread(buf, sizeof (char), num, fp);
 1173         *line_len += num;
 1174         }
 1175     }
 1176     while (readline(line, size, fp, NULL, &nbytes) &&
 1177            !iscomment(line, "%%EndData")) {
 1178         *line_len += nbytes;
 1179     }
 1180     *line_len += nbytes;
 1181     strcpy(line, save);
 1182     } else if (iscomment(line, "%%BeginBinary:")) {
 1183     strcpy(save, line+7);
 1184     if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
 1185         while (num > BUFSIZ) {
 1186         fread(buf, sizeof (char), BUFSIZ, fp);
 1187         *line_len += BUFSIZ;
 1188         num -= BUFSIZ;
 1189         }
 1190         fread(buf, sizeof (char), num, fp);
 1191         *line_len += num;
 1192     }
 1193     while (readline(line, size, fp, NULL, &nbytes) &&
 1194            !iscomment(line, "%%EndBinary")) {
 1195         *line_len += nbytes;
 1196     }
 1197     *line_len += nbytes;
 1198     strcpy(line, save);
 1199     }
 1200     return cp;
 1201 }
 1202 
 1203 /*
 1204  *  pscopy -- copy lines of Postscript from a section of one file
 1205  *        to another file.
 1206  *                Automatically switch to binary copying whenever
 1207  *                %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
 1208  *        comments are encountered.
 1209  */
 1210 
 1211 void
 1212 pscopy(from, to, begin, end)
 1213     FILE *from;
 1214     FILE *to;
 1215     long begin;         /* set negative to avoid initial seek */
 1216     long end;
 1217 {
 1218     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
 1219     char text[PSLINELENGTH];    /* Temporary storage for text */
 1220     unsigned int num;
 1221     int i;
 1222     char buf[BUFSIZ];
 1223 
 1224     if (begin >= 0) fseek(from, begin, SEEK_SET);
 1225     while (ftell(from) < end) {
 1226 
 1227     fgets(line, sizeof line, from);
 1228     fputs(line, to);
 1229 
 1230     if (iscomment(line, "%%BeginData:")) {
 1231         text[0] = '\0';
 1232         if (sscanf(line+length("%%BeginData:"),
 1233                "%d %*s %s", &num, text) >= 1) {
 1234         if (strcmp(text, "Lines") == 0) {
 1235             for (i=0; i < num; i++) {
 1236             fgets(line, sizeof line, from);
 1237             fputs(line, to);
 1238             }
 1239         } else {
 1240             while (num > BUFSIZ) {
 1241             fread(buf, sizeof (char), BUFSIZ, from);
 1242             fwrite(buf, sizeof (char), BUFSIZ, to);
 1243             num -= BUFSIZ;
 1244             }
 1245             fread(buf, sizeof (char), num, from);
 1246             fwrite(buf, sizeof (char), num, to);
 1247         }
 1248         }
 1249     } else if (iscomment(line, "%%BeginBinary:")) {
 1250         if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
 1251         while (num > BUFSIZ) {
 1252             fread(buf, sizeof (char), BUFSIZ, from);
 1253             fwrite(buf, sizeof (char), BUFSIZ, to);
 1254             num -= BUFSIZ;
 1255         }
 1256         fread(buf, sizeof (char), num, from);
 1257         fwrite(buf, sizeof (char), num, to);
 1258         }
 1259     }
 1260     }
 1261 }
 1262 
 1263 /*
 1264  *  pscopyuntil -- copy lines of Postscript from a section of one file
 1265  *             to another file until a particular comment is reached.
 1266  *                     Automatically switch to binary copying whenever
 1267  *                     %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
 1268  *             comments are encountered.
 1269  */
 1270 
 1271 char *
 1272 pscopyuntil(from, to, begin, end, comment)
 1273     FILE *from;
 1274     FILE *to;
 1275     long begin;         /* set negative to avoid initial seek */
 1276     long end;
 1277 #if NeedFunctionPrototypes
 1278     const
 1279 #endif
 1280     char *comment;
 1281 {
 1282     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
 1283     char text[PSLINELENGTH];    /* Temporary storage for text */
 1284     unsigned int num;
 1285     int comment_length;
 1286     int i;
 1287     char buf[BUFSIZ];
 1288     char *cp;
 1289 
 1290     comment_length = strlen(comment);
 1291     if (begin >= 0) fseek(from, begin, SEEK_SET);
 1292     while (ftell(from) < end) {
 1293 
 1294     fgets(line, sizeof line, from);
 1295 
 1296     /* iscomment cannot be used here,
 1297      * because comment_length is not known at compile time. */
 1298     if (strncmp(line, comment, comment_length) == 0) {
 1299         cp = (char *) malloc(strlen(line)+1);
 1300         if (cp == NULL) {
 1301         fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
 1302         exit(-1);
 1303         }
 1304         strcpy(cp, line);
 1305         return cp;
 1306     }
 1307     fputs(line, to);
 1308     if (iscomment(line, "%%BeginData:")) {
 1309         text[0] = '\0';
 1310         if (sscanf(line+length("%%BeginData:"),
 1311                "%d %*s %s", &num, text) >= 1) {
 1312         if (strcmp(text, "Lines") == 0) {
 1313             for (i=0; i < num; i++) {
 1314             fgets(line, sizeof line, from);
 1315             fputs(line, to);
 1316             }
 1317         } else {
 1318             while (num > BUFSIZ) {
 1319             fread(buf, sizeof (char), BUFSIZ, from);
 1320             fwrite(buf, sizeof (char), BUFSIZ, to);
 1321             num -= BUFSIZ;
 1322             }
 1323             fread(buf, sizeof (char), num, from);
 1324             fwrite(buf, sizeof (char), num, to);
 1325         }
 1326         }
 1327     } else if (iscomment(line, "%%BeginBinary:")) {
 1328         if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
 1329         while (num > BUFSIZ) {
 1330             fread(buf, sizeof (char), BUFSIZ, from);
 1331             fwrite(buf, sizeof (char), BUFSIZ, to);
 1332             num -= BUFSIZ;
 1333         }
 1334         fread(buf, sizeof (char), num, from);
 1335         fwrite(buf, sizeof (char), num, to);
 1336         }
 1337     }
 1338     }
 1339     return NULL;
 1340 }
 1341 
 1342 /*
 1343  *  blank -- determine whether the line contains nothing but whitespace.
 1344  */
 1345 
 1346 static int
 1347 blank(line)
 1348     char *line;
 1349 {
 1350     char *cp = line;
 1351 
 1352     while (*cp == ' ' || *cp == '\t') cp++;
 1353     return *cp == '\n' || (*cp == '%' && (line[0] != '%' || line[1] != '%'));
 1354 }