"Fossies" - the Fresh Open Source Software Archive

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