home *** CD-ROM | disk | FTP | other *** search
/ swCHIP 1991 January / swCHIP_95-1.bin / utility / gsview13 / src / ps.c < prev    next >
C/C++ Source or Header  |  1995-12-09  |  54KB  |  1,627 lines

  1. /*
  2.  * ps.c -- Postscript scanning and copying routines.
  3.  * Copyright (C) 1992, 1994  Timothy O. Theisen.  All rights reserved.
  4.  *
  5.  * This file is part of Ghostview.
  6.  *
  7.  * Ghostview is distributed with NO WARRANTY OF ANY KIND.  No author or
  8.  * distributor accepts any responsibility for the consequences of using
  9.  * it, or for whether it serves any particular purpose or works at all,
  10.  * unless he or she says so in writing.  Refer to the Ghostview Free
  11.  * Public License (the "License") for full details.
  12.  *
  13.  * Every copy of Ghostview must include a copy of the License, normally
  14.  * in a plain ASCII text file named PUBLIC.  The License grants you the
  15.  * right to copy, modify and redistribute Ghostview, but only under
  16.  * certain conditions described in the License.  Among other things, the
  17.  * License requires that the copyright notice and this notice be preserved
  18.  * on all copies.
  19.  *
  20.  *
  21.  *   Author: Tim Theisen           Systems Programmer
  22.  * Internet: tim@cs.wisc.edu       Department of Computer Sciences
  23.  *     UUCP: uwvax!tim             University of Wisconsin-Madison
  24.  *    Phone: (608)262-0438         1210 West Dayton Street
  25.  *      FAX: (608)262-9777         Madison, WI   53706
  26.  */
  27. /* modified by Russell Lang, rjl@aladdin.com to use with GSview
  28.  * 1995-01-11
  29.  * supports DOS EPS files (binary header)
  30.  * supports the following incorrect DSC usage
  31.  *   %%BeginData lines > 254 char                 (Microsoft Windows)
  32.  *   EPS inclusions surrounded by %MSEPS Preamble/%MSEPS Trailer
  33.  *    instead of %%BeginDocument/%%EndDocument    (Microsoft Windows).
  34.  *   %!PS-Adobe instead of %!PS-Adobe-            (OS/2)
  35.  *   atend instead of (atend)
  36.  * rjl 1995-04-01
  37.  *   Commented out two lines to deal with documents that include
  38.  *   code after %%EndSetup and before %%Page:     (Microsoft Windows)
  39.  */
  40.  
  41. #include <stdio.h>
  42. #if defined(__TURBOC__) || defined(OS2)
  43. #include <stdlib.h>
  44. #include <string.h>
  45. #include <ctype.h>
  46. #define strcasecmp(s,t) stricmp(s,t)
  47. extern void pserror(char *str);
  48. #else
  49. #ifndef SEEK_SET
  50. #define SEEK_SET 0
  51. #endif
  52. #ifndef BUFSIZ
  53. #define BUFSIZ 1024
  54. #endif
  55. #include <ctype.h>
  56. #include <X11/Xos.h>        /* #includes the appropriate <string.h> */
  57. #define pserror(str) fprintf(stderr,str)
  58. #endif
  59. #include "ps.h"
  60.  
  61. #ifdef BSD4_2
  62. #define memset(a,b,c) bzero(a,c)
  63. #endif
  64.  
  65. /* length calculates string length at compile time */
  66. /* can only be used with character constants */
  67. #define length(a) (sizeof(a)-1)
  68. #define iscomment(a, b)    (strncmp(a, b, length(b)) == 0)
  69. #define DSCcomment(a) (a[0] == '%' && a[1] == '%')
  70.  
  71.     /* list of standard paper sizes from Adobe's PPD. */
  72.  
  73. struct documentmedia papersizes[] = {
  74.     {"Letter",         612,  792},
  75.     {"LetterSmall",     612,  792},
  76.     {"Tabloid",         792, 1224},
  77.     {"Ledger",        1224,  792},
  78.     {"Legal",         612, 1008},
  79.     {"Statement",     396,  612},
  80.     {"Executive",     540,  720},
  81.     {"A3",         842, 1190},
  82.     {"A4",         595,  842},
  83.     {"A4Small",         595,  842},
  84.     {"A5",         420,  595},
  85.     {"B4",         729, 1032},
  86.     {"B5",         516,  729},
  87.     {"Folio",         612,  936},
  88.     {"Quarto",         610,  780},
  89.     {"10x14",         720, 1008},
  90.     {NULL,           0,    0}
  91. };
  92.  
  93.  
  94. #if NeedFunctionPrototypes
  95. static char *readline(char *line, int size, FILE *fp, unsigned long enddoseps, 
  96.   long *position, unsigned int *line_len, unsigned int *line_count);
  97. #else
  98. static char *readline();
  99. #endif
  100.  
  101. #if NeedFunctionPrototypes
  102. static char *gettextline(char *line);
  103. #else
  104. static char *gettextline();
  105. #endif
  106.  
  107. #if NeedFunctionPrototypes
  108. static char *gettext(char *line, char **next_char);
  109. #else
  110. static char *gettext();
  111. #endif
  112.  
  113. #if NeedFunctionPrototypes
  114. static int  blank(char *line);
  115. #else
  116. static int  blank();
  117. #endif
  118.  
  119. /*
  120.  *    psscan -- scan the PostScript file for document structuring comments.
  121.  *
  122.  *    This scanner is designed to retrieve the information necessary for
  123.  *    the ghostview previewer.  It will scan files that conform to any
  124.  *    version (1.0, 2.0, 2.1, or 3.0) of the document structuring conventions.
  125.  *    It does not really care which version of comments the file contains.
  126.  *    (The comments are largely upward compatible.)  It will scan a number
  127.  *    of non-conforming documents.  (You could have part of the document
  128.  *    conform to V2.0 and the rest conform to V3.0.  It would be similar
  129.  *    to the DC-2 1/2+, it would look funny but it can still fly.)
  130.  *
  131.  *    This routine returns a pointer to the document structure.
  132.  *    The structure contains the information relevant to previewing.
  133.  *      These include EPSF flag (to tell if the file is a encapsulated figure),
  134.  *      Page Media (for the Page Size), Bounding Box (to minimize backing
  135.  *      pixmap size or determine window size for encapsulated PostScript), 
  136.  *      Orientation of Paper (for default transformation matrix), and
  137.  *      Page Order.  The title and CreationDate are also retrieved to
  138.  *      help identify the document.
  139.  *
  140.  *      The following comments are examined:
  141.  *
  142.  *      Header section: 
  143.  *      Must start with %!PS-Adobe.  Version numbers ignored.
  144.  *
  145.  *      %!PS-Adobe* [EPSF-*]
  146.  *      %%BoundingBox: <int> <int> <int> <int>|(atend)
  147.  *      %%CreationDate: <textline>
  148.  *      %%Orientation: Portrait|Landscape|(atend)
  149.  *      %%Pages: <uint> [<int>]|(atend)
  150.  *      %%PageOrder: Ascend|Descend|Special|(atend)
  151.  *      %%Title: <textline>
  152.  *      %%DocumentMedia: <text> <real> <real> <real> <text> <text>
  153.  *      %%DocumentPaperSizes: <text>
  154.  *      %%EndComments
  155.  *
  156.  *      Note: Either the 3.0 or 2.0 syntax for %%Pages is accepted.
  157.  *            Also either the 2.0 %%DocumentPaperSizes or the 3.0
  158.  *            %%DocumentMedia comments are accepted as well.
  159.  *
  160.  *      The header section ends either explicitly with %%EndComments or
  161.  *      implicitly with any line that does not begin with %X where X is
  162.  *      a not whitespace character.
  163.  *
  164.  *      If the file is encapsulated PostScript the optional Preview section
  165.  *      is next:
  166.  *
  167.  *      %%BeginPreview
  168.  *      %%EndPreview
  169.  *
  170.  *      This section explicitly begins and ends with the above comments.
  171.  *
  172.  *      Next the Defaults section for version 3 page defaults:
  173.  *
  174.  *      %%BeginDefaults
  175.  *      %%PageBoundingBox: <int> <int> <int> <int>
  176.  *      %%PageOrientation: Portrait|Landscape
  177.  *      %%PageMedia: <text>
  178.  *      %%EndDefaults
  179.  *
  180.  *      This section explicitly begins and ends with the above comments.
  181.  *
  182.  *      The prolog section either explicitly starts with %%BeginProlog or
  183.  *      implicitly with any nonblank line.
  184.  *
  185.  *      %%BeginProlog
  186.  *      %%EndProlog
  187.  *
  188.  *      The Prolog should end with %%EndProlog, however the proglog implicitly
  189.  *      ends when %%BeginSetup, %%Page, %%Trailer or %%EOF are encountered.
  190.  *
  191.  *      The Setup section is where the version 2 page defaults are found.
  192.  *      This section either explicitly begins with %%BeginSetup or implicitly
  193.  *      with any nonblank line after the Prolog.
  194.  *
  195.  *      %%BeginSetup
  196.  *      %%PageBoundingBox: <int> <int> <int> <int>
  197.  *      %%PageOrientation: Portrait|Landscape
  198.  *      %%PaperSize: <text>
  199.  *      %%EndSetup
  200.  *
  201.  *      The Setup should end with %%EndSetup, however the setup implicitly
  202.  *      ends when %%Page, %%Trailer or %%EOF are encountered.
  203.  *
  204.  *      Next each page starts explicitly with %%Page and ends implicitly with
  205.  *      %%Page or %%Trailer or %%EOF.  The following comments are recognized:
  206.  *
  207.  *      %%Page: <text> <uint>
  208.  *      %%PageBoundingBox: <int> <int> <int> <int>|(atend)
  209.  *      %%PageOrientation: Portrait|Landscape
  210.  *      %%PageMedia: <text>
  211.  *      %%PaperSize: <text>
  212.  *
  213.  *      The tralier section start explicitly with %%Trailer and end with %%EOF.
  214.  *      The following comment are examined with the proper (atend) notation
  215.  *      was used in the header:
  216.  *
  217.  *      %%Trailer
  218.  *      %%BoundingBox: <int> <int> <int> <int>|(atend)
  219.  *      %%Orientation: Portrait|Landscape|(atend)
  220.  *      %%Pages: <uint> [<int>]|(atend)
  221.  *      %%PageOrder: Ascend|Descend|Special|(atend)
  222.  *      %%EOF
  223.  *
  224.  *
  225.  *  + A DC-3 received severe damage to one of its wings.  The wing was a total
  226.  *    loss.  There was no replacement readily available, so the mechanic
  227.  *    installed a wing from a DC-2.
  228.  */
  229.  
  230. struct document *
  231. psscan(file)
  232.     FILE *file;
  233. {
  234.     struct document *doc;
  235.     int bb_set = NONE;
  236.     int pages_set = NONE;
  237.     int page_order_set = NONE;
  238.     int orientation_set = NONE;
  239.     int page_bb_set = NONE;
  240.     int page_media_set = NONE;
  241.     int preread;        /* flag which tells the readline isn't needed */
  242.     int i;
  243.     unsigned int maxpages = 0;
  244.     unsigned int nextpage = 1;    /* Next expected page */
  245.     unsigned int thispage;
  246.     int ignore = 0;        /* whether to ignore page ordinals */
  247.     char *label;
  248.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  249.     char text[PSLINELENGTH];    /* Temporary storage for text */
  250.     long position;        /* Position of the current line */
  251.     long beginsection;        /* Position of the beginning of the section */
  252.     unsigned int line_count;    /* line count for error messages */
  253.     unsigned int line_len;     /* Length of the current line */
  254.     unsigned int section_len;    /* Place to accumulate the section length */
  255.     char *next_char;        /* 1st char after text returned by gettext() */
  256.     char *cp;
  257.     struct documentmedia *dmp;
  258.     unsigned long enddoseps;    /* zero of not DOS EPS, otherwise position of end of ps section */
  259.     DOSEPS doseps;
  260.  
  261.  
  262.     line_count = 0;
  263.     rewind(file);
  264.  
  265.     /* rjl: check for DOS EPS files and almost DSC files that start with ^D */
  266.     enddoseps = ps_read_doseps(file, &doseps);
  267.     position = ftell(file);
  268.     if (fgetc(file) != '\004')
  269.     fseek(file, position, SEEK_SET);
  270.  
  271.     if (readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count) == NULL) {
  272.     pserror("Warning: empty file.\n");
  273.     return(NULL);
  274.     }
  275.  
  276.     /* Header comments */
  277.  
  278.     if (iscomment(line,"%!PS-Adobe")) {  /* rjl: some almost DSC code doesn't include the hyphen or version number */
  279.     doc = (struct document *) malloc(sizeof(struct document));
  280.     if (doc == NULL) {
  281.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  282.         exit(-1);
  283.     }
  284.     memset(doc, 0, sizeof(struct document));
  285.     sscanf(line, "%*s %s", text);
  286.     doc->epsf = iscomment(text, "EPSF-");
  287.     doc->beginheader = position;
  288.     section_len = line_len;
  289.     if (enddoseps) { /* rjl: add doseps header */
  290.         doc->doseps = (DOSEPS *) malloc(sizeof(DOSEPS));
  291.         if (doc == NULL) {
  292.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  293.         exit(-1);
  294.         }
  295.         *(doc->doseps) = doseps;
  296.     }
  297.     } else {
  298.     return(NULL);
  299.     }
  300.  
  301.     preread = 0;
  302.     while (preread || readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count)) {
  303.     if (!preread) section_len += line_len;
  304.     preread = 0;
  305.     if (line[0] != '%' ||
  306.         iscomment(line+1, "%EndComments") ||
  307.         line[1] == ' ' || line[1] == '\t' || line[1] == '\n' ||
  308.         !isprint(line[1])) {
  309.         break;
  310.     } else if (line[1] != '%') {
  311.         /* Do nothing */
  312.     } else if (iscomment(line+2, "Begin") || iscomment(line+2, "End") ||
  313.            iscomment(line+2, "Page:") || iscomment(line+2, "Trailer") ||
  314.            iscomment(line+2, "EOF")) {
  315.         break;
  316.     } else if (doc->title == NULL && iscomment(line+2, "Title:")) {
  317.         doc->title = gettextline(line+length("%%Title:"));
  318.     } else if (doc->date == NULL && iscomment(line+2, "CreationDate:")) {
  319.         doc->date = gettextline(line+length("%%CreationDate:"));
  320.     } else if (bb_set == NONE && iscomment(line+2, "BoundingBox:")) {
  321.         sscanf(line+length("%%BoundingBox:"), "%s", text);
  322.         if (strcmp(text, "(atend)") == 0) {
  323.         bb_set = ATEND;
  324.         }
  325.         else if (strcmp(text, "atend") == 0) { /* rjl: some bad DSC omits the () */
  326.         char buf[64];
  327.         sprintf(buf, "Invalid %%%%BoundingBox on line %d\n", line_count);
  328.         pserror(buf);
  329.         bb_set = ATEND;
  330.         } else {
  331.         if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
  332.                &(doc->boundingbox[LLX]),
  333.                &(doc->boundingbox[LLY]),
  334.                &(doc->boundingbox[URX]),
  335.                &(doc->boundingbox[URY])) == 4)
  336.             bb_set = 1;
  337.         else {
  338.             float fllx, flly, furx, fury;
  339.             if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
  340.                    &fllx, &flly, &furx, &fury) == 4) {
  341.             bb_set = 1;
  342.             doc->boundingbox[LLX] = fllx;
  343.             doc->boundingbox[LLY] = flly;
  344.             doc->boundingbox[URX] = furx;
  345.             doc->boundingbox[URY] = fury;
  346.             if (fllx < doc->boundingbox[LLX])
  347.                 doc->boundingbox[LLX]--;
  348.             if (flly < doc->boundingbox[LLY])
  349.                 doc->boundingbox[LLY]--;
  350.             if (furx > doc->boundingbox[URX])
  351.                 doc->boundingbox[URX]++;
  352.             if (fury > doc->boundingbox[URY])
  353.                 doc->boundingbox[URY]++;
  354.             }
  355.         }
  356.         }
  357.     } else if (orientation_set == NONE &&
  358.            iscomment(line+2, "Orientation:")) {
  359.         sscanf(line+length("%%Orientation:"), "%s", text);
  360.         if (strcmp(text, "(atend)") == 0) {
  361.         orientation_set = ATEND;
  362.         }
  363.         else if (strcmp(text, "atend") == 0) { /* rjl: some bad DSC omits the () */
  364.         char buf[64];
  365.         sprintf(buf, "Invalid %%%%Orientation on line %d\n", line_count);
  366.         pserror(buf);
  367.         orientation_set = ATEND;
  368.         } else if (strcmp(text, "Portrait") == 0) {
  369.         doc->orientation = PORTRAIT;
  370.         orientation_set = 1;
  371.         } else if (strcmp(text, "Landscape") == 0) {
  372.         doc->orientation = LANDSCAPE;
  373.         orientation_set = 1;
  374.         }
  375.     } else if (page_order_set == NONE && iscomment(line+2, "PageOrder:")) {
  376.         sscanf(line+length("%%PageOrder:"), "%s", text);
  377.         if (strcmp(text, "(atend)") == 0) {
  378.         page_order_set = ATEND;
  379.         }
  380.         else if (strcmp(text, "atend") == 0) { /* rjl: some bad DSC omits the () */
  381.         char buf[64];
  382.         sprintf(buf, "Invalid %%%%PageOrder on line %d\n", line_count);
  383.         pserror(buf);
  384.         page_order_set = ATEND;
  385.         } else if (strcmp(text, "Ascend") == 0) {
  386.         doc->pageorder = ASCEND;
  387.         page_order_set = 1;
  388.         } else if (strcmp(text, "Descend") == 0) {
  389.         doc->pageorder = DESCEND;
  390.         page_order_set = 1;
  391.         } else if (strcmp(text, "Special") == 0) {
  392.         doc->pageorder = SPECIAL;
  393.         page_order_set = 1;
  394.         }
  395.     } else if (pages_set == NONE && iscomment(line+2, "Pages:")) {
  396.         sscanf(line+length("%%Pages:"), "%s", text);
  397.         if (strcmp(text, "(atend)") == 0) {
  398.         pages_set = ATEND;
  399.         }
  400.         else if (strcmp(text, "atend") == 0) { /* rjl: some bad DSC omits the () */
  401.         char buf[64];
  402.         sprintf(buf, "Invalid %%%%Pages on line %d\n", line_count);
  403.         pserror(buf);
  404.         pages_set = ATEND;
  405.         } else {
  406.         switch (sscanf(line+length("%%Pages:"), "%d %d",
  407.                    &maxpages, &i)) {
  408.             case 2:
  409.             if (page_order_set == NONE) {
  410.                 if (i == -1) {
  411.                 doc->pageorder = DESCEND;
  412.                 page_order_set = 1;
  413.                 } else if (i == 0) {
  414.                 doc->pageorder = SPECIAL;
  415.                 page_order_set = 1;
  416.                 } else if (i == 1) {
  417.                 doc->pageorder = ASCEND;
  418.                 page_order_set = 1;
  419.                 }
  420.             }
  421.             case 1:
  422.             if (maxpages > 0) {
  423.                 doc->pages = (struct page *) calloc(maxpages,
  424.                                sizeof(struct page));
  425.                 if (doc->pages == NULL) {
  426.                 pserror("Fatal Error: Dynamic memory exhausted.\n");
  427.                 exit(-1);
  428.                 }
  429.             }
  430.         }
  431.         }
  432.     } else if (doc->nummedia == NONE &&
  433.            iscomment(line+2, "DocumentMedia:")) {
  434.         float w, h;
  435.         doc->media = (struct documentmedia *)
  436.              malloc(sizeof (struct documentmedia));
  437.         if (doc->media == NULL) {
  438.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  439.         exit(-1);
  440.         }
  441.         doc->media[0].name = gettext(line+length("%%DocumentMedia:"),
  442.                      &next_char);
  443.         if (doc->media[0].name != NULL) {
  444.         if (sscanf(next_char, "%f %f", &w, &h) == 2) {
  445.             doc->media[0].width = w + 0.5;
  446.             doc->media[0].height = h + 0.5;
  447.         }
  448.         if (doc->media[0].width != 0 && doc->media[0].height != 0)
  449.             doc->nummedia = 1;
  450.         else
  451.             free(doc->media[0].name);
  452.         }
  453.         preread=1;
  454.         while (readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count) &&
  455.            DSCcomment(line) && iscomment(line+2, "+")) {
  456.         section_len += line_len;
  457.         doc->media = (struct documentmedia *)
  458.                  realloc(doc->media,
  459.                      (doc->nummedia+1)*
  460.                      sizeof (struct documentmedia));
  461.         if (doc->media == NULL) {
  462.             pserror("Fatal Error: Dynamic memory exhausted.\n");
  463.             exit(-1);
  464.         }
  465.         doc->media[doc->nummedia].name = gettext(line+length("%%+"),
  466.                              &next_char);
  467.         if (doc->media[doc->nummedia].name != NULL) {
  468.             if (sscanf(next_char, "%f %f", &w, &h) == 2) {
  469.             doc->media[doc->nummedia].width = w + 0.5;
  470.             doc->media[doc->nummedia].height = h + 0.5;
  471.             }
  472.             if (doc->media[doc->nummedia].width != 0 &&
  473.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  474.             else
  475.             free(doc->media[doc->nummedia].name);
  476.         }
  477.         }
  478.         section_len += line_len;
  479.         if (doc->nummedia != 0) doc->default_page_media = doc->media;
  480.     } else if (doc->nummedia == NONE &&
  481.            iscomment(line+2, "DocumentPaperSizes:")) {
  482.  
  483.         doc->media = (struct documentmedia *)
  484.              malloc(sizeof (struct documentmedia));
  485.         if (doc->media == NULL) {
  486.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  487.         exit(-1);
  488.         }
  489.         doc->media[0].name = gettext(line+length("%%DocumentPaperSizes:"),
  490.                      &next_char);
  491.         if (doc->media[0].name != NULL) {
  492.         doc->media[0].width = 0;
  493.         doc->media[0].height = 0;
  494.         for (dmp=papersizes; dmp->name != NULL; dmp++) {
  495.             /* Note: Paper size comment uses down cased paper size
  496.              * name.  Case insensitive compares are only used for
  497.              * PaperSize comments.
  498.              */
  499.             if (strcasecmp(doc->media[0].name, dmp->name) == 0) {
  500.             free(doc->media[0].name);
  501.             doc->media[0].name =
  502.                 (char *)malloc(strlen(dmp->name)+1);
  503.             if (doc->media[0].name == NULL) {
  504.                 pserror("Fatal Error: Dynamic memory exhausted.\n");
  505.                 exit(-1);
  506.             }
  507.             strcpy(doc->media[0].name, dmp->name);
  508.             doc->media[0].width = dmp->width;
  509.             doc->media[0].height = dmp->height;
  510.             break;
  511.             }
  512.         }
  513.         if (doc->media[0].width != 0 && doc->media[0].height != 0)
  514.             doc->nummedia = 1;
  515.         else
  516.             free(doc->media[0].name);
  517.         }
  518.         while ( (cp = gettext(next_char, &next_char)) != NULL ) {
  519.         doc->media = (struct documentmedia *)
  520.                  realloc(doc->media,
  521.                      (doc->nummedia+1)*
  522.                      sizeof (struct documentmedia));
  523.         if (doc->media == NULL) {
  524.             pserror("Fatal Error: Dynamic memory exhausted.\n");
  525.             exit(-1);
  526.         }
  527.         doc->media[doc->nummedia].name = cp;
  528.         doc->media[doc->nummedia].width = 0;
  529.         doc->media[doc->nummedia].height = 0;
  530.         for (dmp=papersizes; dmp->name != NULL; dmp++) {
  531.             /* Note: Paper size comment uses down cased paper size
  532.              * name.  Case insensitive compares are only used for
  533.              * PaperSize comments.
  534.              */
  535.             if (strcasecmp(doc->media[doc->nummedia].name,
  536.                    dmp->name) == 0) {
  537.             free(doc->media[doc->nummedia].name);
  538.             doc->media[doc->nummedia].name =
  539.                 (char *)malloc(strlen(dmp->name)+1);
  540.             if (doc->media[doc->nummedia].name == NULL) {
  541.                 pserror("Fatal Error: Dynamic memory exhausted.\n");
  542.                 exit(-1);
  543.             }
  544.             strcpy(doc->media[doc->nummedia].name, dmp->name);
  545.             doc->media[doc->nummedia].name = dmp->name;
  546.             doc->media[doc->nummedia].width = dmp->width;
  547.             doc->media[doc->nummedia].height = dmp->height;
  548.             break;
  549.             }
  550.         }
  551.         if (doc->media[doc->nummedia].width != 0 &&
  552.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  553.         else
  554.             free(doc->media[doc->nummedia].name);
  555.         }
  556.         preread=1;
  557.         while (readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count) &&
  558.            DSCcomment(line) && iscomment(line+2, "+")) {
  559.         section_len += line_len;
  560.         next_char = line + length("%%+");
  561.         while ( (cp = gettext(next_char, &next_char)) != NULL ) {
  562.             doc->media = (struct documentmedia *)
  563.                  realloc(doc->media,
  564.                      (doc->nummedia+1)*
  565.                      sizeof (struct documentmedia));
  566.             if (doc->media == NULL) {
  567.             pserror("Fatal Error: Dynamic memory exhausted.\n");
  568.             exit(-1);
  569.             }
  570.             doc->media[doc->nummedia].name = cp;
  571.             doc->media[doc->nummedia].width = 0;
  572.             doc->media[doc->nummedia].height = 0;
  573.             for (dmp=papersizes; dmp->name != NULL; dmp++) {
  574.             /* Note: Paper size comment uses down cased paper size
  575.              * name.  Case insensitive compares are only used for
  576.              * PaperSize comments.
  577.              */
  578.             if (strcasecmp(doc->media[doc->nummedia].name,
  579.                    dmp->name) == 0) {
  580.                 doc->media[doc->nummedia].width = dmp->width;
  581.                 doc->media[doc->nummedia].height = dmp->height;
  582.                 break;
  583.             }
  584.             }
  585.             if (doc->media[doc->nummedia].width != 0 &&
  586.             doc->media[doc->nummedia].height != 0) doc->nummedia++;
  587.             else
  588.             free(doc->media[doc->nummedia].name);
  589.         }
  590.         }
  591.         section_len += line_len;
  592.         if (doc->nummedia != 0) doc->default_page_media = doc->media;
  593.     }
  594.     }
  595.  
  596.     if (DSCcomment(line) && iscomment(line+2, "EndComments")) {
  597.     readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count);
  598.     section_len += line_len;
  599.     }
  600.     doc->endheader = position;
  601.     doc->lenheader = section_len - line_len;
  602.  
  603.     /* Optional Preview comments for encapsulated PostScript files */ 
  604.  
  605.     beginsection = position;
  606.     section_len = line_len;
  607.     while (blank(line) &&
  608.        readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count)) {
  609.     section_len += line_len;
  610.     }
  611.  
  612.     if (doc->epsf && DSCcomment(line) && iscomment(line+2, "BeginPreview")) {
  613.     doc->beginpreview = beginsection;
  614.     beginsection = 0;
  615.     while (readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count) &&
  616.            !(DSCcomment(line) && iscomment(line+2, "EndPreview"))) {
  617.         section_len += line_len;
  618.     }
  619.     section_len += line_len;
  620.     readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count);
  621.     section_len += line_len;
  622.     doc->endpreview = position;
  623.     doc->lenpreview = section_len - line_len;
  624.     }
  625.  
  626.     /* Page Defaults for Version 3.0 files */
  627.  
  628.     if (beginsection == 0) {
  629.     beginsection = position;
  630.     section_len = line_len;
  631.     }
  632.     while (blank(line) &&
  633.        readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count)) {
  634.     section_len += line_len;
  635.     }
  636.  
  637.     if (DSCcomment(line) && iscomment(line+2, "BeginDefaults")) {
  638.     doc->begindefaults = beginsection;
  639.     beginsection = 0;
  640.     while (readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count) &&
  641.            !(DSCcomment(line) && iscomment(line+2, "EndDefaults"))) {
  642.         section_len += line_len;
  643.         if (!DSCcomment(line)) {
  644.         /* Do nothing */
  645.         } else if (doc->default_page_orientation == NONE &&
  646.         iscomment(line+2, "PageOrientation:")) {
  647.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  648.         if (strcmp(text, "Portrait") == 0) {
  649.             doc->default_page_orientation = PORTRAIT;
  650.         } else if (strcmp(text, "Landscape") == 0) {
  651.             doc->default_page_orientation = LANDSCAPE;
  652.         }
  653.         } else if (page_media_set == NONE &&
  654.                iscomment(line+2, "PageMedia:")) {
  655.         cp = gettext(line+length("%%PageMedia:"), NULL);
  656.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  657.             if (strcmp(cp, dmp->name) == 0) {
  658.             doc->default_page_media = dmp;
  659.             page_media_set = 1;
  660.             break;
  661.             }
  662.         }
  663.         free(cp);
  664.         } else if (page_bb_set == NONE &&
  665.                iscomment(line+2, "PageBoundingBox:")) {
  666.         if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  667.                &(doc->default_page_boundingbox[LLX]),
  668.                &(doc->default_page_boundingbox[LLY]),
  669.                &(doc->default_page_boundingbox[URX]),
  670.                &(doc->default_page_boundingbox[URY])) == 4)
  671.             page_bb_set = 1;
  672.         else {
  673.             float fllx, flly, furx, fury;
  674.             if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
  675.                    &fllx, &flly, &furx, &fury) == 4) {
  676.             page_bb_set = 1;
  677.             doc->default_page_boundingbox[LLX] = fllx;
  678.             doc->default_page_boundingbox[LLY] = flly;
  679.             doc->default_page_boundingbox[URX] = furx;
  680.             doc->default_page_boundingbox[URY] = fury;
  681.             if (fllx < doc->default_page_boundingbox[LLX])
  682.                 doc->default_page_boundingbox[LLX]--;
  683.             if (flly < doc->default_page_boundingbox[LLY])
  684.                 doc->default_page_boundingbox[LLY]--;
  685.             if (furx > doc->default_page_boundingbox[URX])
  686.                 doc->default_page_boundingbox[URX]++;
  687.             if (fury > doc->default_page_boundingbox[URY])
  688.                 doc->default_page_boundingbox[URY]++;
  689.             }
  690.         }
  691.         }
  692.     }
  693.     section_len += line_len;
  694.     readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count);
  695.     section_len += line_len;
  696.     doc->enddefaults = position;
  697.     doc->lendefaults = section_len - line_len;
  698.     }
  699.  
  700.     /* Document Prolog */
  701.  
  702.     if (beginsection == 0) {
  703.     beginsection = position;
  704.     section_len = line_len;
  705.     }
  706.     while (blank(line) &&
  707.        readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count)) {
  708.     section_len += line_len;
  709.     }
  710.  
  711.     if (!(DSCcomment(line) &&
  712.       (iscomment(line+2, "BeginSetup") ||
  713.        iscomment(line+2, "Page:") ||
  714.        iscomment(line+2, "Trailer") ||
  715.        iscomment(line+2, "EOF")))) {
  716.     doc->beginprolog = beginsection;
  717.     beginsection = 0;
  718.     preread = 1;
  719.  
  720.     while ((preread ||
  721.         readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count)) &&
  722.            !(DSCcomment(line) &&
  723.              (iscomment(line+2, "EndProlog") ||
  724.               iscomment(line+2, "BeginSetup") ||
  725.               iscomment(line+2, "Page:") ||
  726.               iscomment(line+2, "Trailer") ||
  727.               iscomment(line+2, "EOF")))) {
  728.         if (!preread) section_len += line_len;
  729.         preread = 0;
  730.     }
  731.     section_len += line_len;
  732.     if (DSCcomment(line) && iscomment(line+2, "EndProlog")) {
  733.         readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count);
  734.         section_len += line_len;
  735.     }
  736.     doc->endprolog = position;
  737.     doc->lenprolog = section_len - line_len;
  738.     }
  739.  
  740.     /* Document Setup,  Page Defaults found here for Version 2 files */
  741.  
  742.     if (beginsection == 0) {
  743.     beginsection = position;
  744.     section_len = line_len;
  745.     }
  746.     while (blank(line) &&
  747.        readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count)) {
  748.     section_len += line_len;
  749.     }
  750.  
  751.     if (!(DSCcomment(line) &&
  752.       (iscomment(line+2, "Page:") ||
  753.        iscomment(line+2, "Trailer") ||
  754.        iscomment(line+2, "EOF")))) {
  755.     doc->beginsetup = beginsection;
  756.     beginsection = 0;
  757.     preread = 1;
  758.     while ((preread ||
  759.         readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count)) &&
  760.            !(DSCcomment(line) &&
  761.              (iscomment(line+2, "EndSetup") ||
  762.               iscomment(line+2, "Page:") ||
  763.               iscomment(line+2, "Trailer") ||
  764.               iscomment(line+2, "EOF")))) {
  765.         if (!preread) section_len += line_len;
  766.         preread = 0;
  767.         if (!DSCcomment(line)) {
  768.         /* Do nothing */
  769.         } else if (doc->default_page_orientation == NONE &&
  770.         iscomment(line+2, "PageOrientation:")) {
  771.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  772.         if (strcmp(text, "Portrait") == 0) {
  773.             doc->default_page_orientation = PORTRAIT;
  774.         } else if (strcmp(text, "Landscape") == 0) {
  775.             doc->default_page_orientation = LANDSCAPE;
  776.         }
  777.         } else if (page_media_set == NONE &&
  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->default_page_media = dmp;
  787.             page_media_set = 1;
  788.             break;
  789.             }
  790.         }
  791.         free(cp);
  792.         } else if (page_bb_set == NONE &&
  793.                iscomment(line+2, "PageBoundingBox:")) {
  794.         if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  795.                &(doc->default_page_boundingbox[LLX]),
  796.                &(doc->default_page_boundingbox[LLY]),
  797.                &(doc->default_page_boundingbox[URX]),
  798.                &(doc->default_page_boundingbox[URY])) == 4)
  799.             page_bb_set = 1;
  800.         else {
  801.             float fllx, flly, furx, fury;
  802.             if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
  803.                    &fllx, &flly, &furx, &fury) == 4) {
  804.             page_bb_set = 1;
  805.             doc->default_page_boundingbox[LLX] = fllx;
  806.             doc->default_page_boundingbox[LLY] = flly;
  807.             doc->default_page_boundingbox[URX] = furx;
  808.             doc->default_page_boundingbox[URY] = fury;
  809.             if (fllx < doc->default_page_boundingbox[LLX])
  810.                 doc->default_page_boundingbox[LLX]--;
  811.             if (flly < doc->default_page_boundingbox[LLY])
  812.                 doc->default_page_boundingbox[LLY]--;
  813.             if (furx > doc->default_page_boundingbox[URX])
  814.                 doc->default_page_boundingbox[URX]++;
  815.             if (fury > doc->default_page_boundingbox[URY])
  816.                 doc->default_page_boundingbox[URY]++;
  817.             }
  818.         }
  819.         }
  820.     }
  821.     section_len += line_len;
  822.     if (DSCcomment(line) && iscomment(line+2, "EndSetup")) {
  823.         readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count);
  824.         section_len += line_len;
  825.     }
  826.     doc->endsetup = position;
  827.     doc->lensetup = section_len - line_len;
  828.     }
  829.  
  830.     /* Individual Pages */
  831.  
  832.     if (beginsection == 0) {
  833.     beginsection = position;
  834.     section_len = line_len;
  835.     }
  836.     while (blank(line) &&
  837.        readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count)) {
  838.     section_len += line_len;
  839.     }
  840.  
  841. newpage:
  842.     while (DSCcomment(line) && iscomment(line+2, "Page:")) {
  843.     if (maxpages == 0) {
  844.         maxpages = 1;
  845.         doc->pages = (struct page *) calloc(maxpages, sizeof(struct page));
  846.         if (doc->pages == NULL) {
  847.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  848.         exit(-1);
  849.         }
  850.     }
  851.     label = gettext(line+length("%%Page:"), &next_char);
  852.     if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  853.     if (nextpage == 1) {
  854.         ignore = thispage != 1;
  855.     }
  856.     if (!ignore && thispage != nextpage) {
  857.         free(label);
  858.         doc->numpages--;
  859.         goto continuepage;
  860.     }
  861.     nextpage++;
  862.     if (doc->numpages == maxpages) {
  863.         maxpages++;
  864.         doc->pages = (struct page *)
  865.              realloc(doc->pages, maxpages*sizeof (struct page));
  866.         if (doc->pages == NULL) {
  867.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  868.         exit(-1);
  869.         }
  870.     }
  871.     memset(&(doc->pages[doc->numpages]), 0, sizeof(struct page));
  872.     page_bb_set = NONE;
  873.     doc->pages[doc->numpages].label = label;
  874.     if (beginsection) {
  875.         doc->pages[doc->numpages].begin = beginsection;
  876.         beginsection = 0;
  877.     } else {
  878.         doc->pages[doc->numpages].begin = position;
  879.         section_len = line_len;
  880.     }
  881. continuepage:
  882.     while (readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count) &&
  883.            !(DSCcomment(line) &&
  884.              (iscomment(line+2, "Page:") ||
  885.               iscomment(line+2, "Trailer") ||
  886.               iscomment(line+2, "EOF")))) {
  887.         section_len += line_len;
  888.         if (!DSCcomment(line)) {
  889.         /* Do nothing */
  890.         } else if (doc->pages[doc->numpages].orientation == NONE &&
  891.         iscomment(line+2, "PageOrientation:")) {
  892.         sscanf(line+length("%%PageOrientation:"), "%s", text);
  893.         if (strcmp(text, "Portrait") == 0) {
  894.             doc->pages[doc->numpages].orientation = PORTRAIT;
  895.         } else if (strcmp(text, "Landscape") == 0) {
  896.             doc->pages[doc->numpages].orientation = LANDSCAPE;
  897.         }
  898.         } else if (doc->pages[doc->numpages].media == NULL &&
  899.                iscomment(line+2, "PageMedia:")) {
  900.         cp = gettext(line+length("%%PageMedia:"), NULL);
  901.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  902.             if (strcmp(cp, dmp->name) == 0) {
  903.             doc->pages[doc->numpages].media = dmp;
  904.             break;
  905.             }
  906.         }
  907.         free(cp);
  908.         } else if (doc->pages[doc->numpages].media == NULL &&
  909.                iscomment(line+2, "PaperSize:")) {
  910.         cp = gettext(line+length("%%PaperSize:"), NULL);
  911.         for (dmp = doc->media, i=0; i<doc->nummedia; i++, dmp++) {
  912.             /* Note: Paper size comment uses down cased paper size
  913.              * name.  Case insensitive compares are only used for
  914.              * PaperSize comments.
  915.              */
  916.             if (strcasecmp(cp, dmp->name) == 0) {
  917.             doc->pages[doc->numpages].media = dmp;
  918.             break;
  919.             }
  920.         }
  921.         free(cp);
  922.         } else if ((page_bb_set == NONE || page_bb_set == ATEND) &&
  923.                iscomment(line+2, "PageBoundingBox:")) {
  924.         sscanf(line+length("%%PageBoundingBox:"), "%s", text);
  925.         if (strcmp(text, "(atend)") == 0) {
  926.             page_bb_set = ATEND;
  927.         }
  928.         else if (strcmp(text, "atend") == 0) { /* rjl: some bad DSC omits the () */
  929.             char buf[64];
  930.             sprintf(buf, "Invalid %%%%PageBoundingBox on line %d\n", line_count);
  931.             pserror(buf);
  932.             page_bb_set = ATEND;
  933.         } else {
  934.             if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
  935.                 &(doc->pages[doc->numpages].boundingbox[LLX]),
  936.                 &(doc->pages[doc->numpages].boundingbox[LLY]),
  937.                 &(doc->pages[doc->numpages].boundingbox[URX]),
  938.                 &(doc->pages[doc->numpages].boundingbox[URY])) == 4)
  939.             if (page_bb_set == NONE) page_bb_set = 1;
  940.             else {
  941.             float fllx, flly, furx, fury;
  942.             if (sscanf(line+length("%%PageBoundingBox:"),
  943.                    "%f %f %f %f",
  944.                    &fllx, &flly, &furx, &fury) == 4) {
  945.                 if (page_bb_set == NONE) page_bb_set = 1;
  946.                 doc->pages[doc->numpages].boundingbox[LLX] = fllx;
  947.                 doc->pages[doc->numpages].boundingbox[LLY] = flly;
  948.                 doc->pages[doc->numpages].boundingbox[URX] = furx;
  949.                 doc->pages[doc->numpages].boundingbox[URY] = fury;
  950.                 if (fllx <
  951.                     doc->pages[doc->numpages].boundingbox[LLX])
  952.                 doc->pages[doc->numpages].boundingbox[LLX]--;
  953.                 if (flly <
  954.                     doc->pages[doc->numpages].boundingbox[LLY])
  955.                 doc->pages[doc->numpages].boundingbox[LLY]--;
  956.                 if (furx >
  957.                     doc->pages[doc->numpages].boundingbox[URX])
  958.                 doc->pages[doc->numpages].boundingbox[URX]++;
  959.                 if (fury >
  960.                     doc->pages[doc->numpages].boundingbox[URY])
  961.                 doc->pages[doc->numpages].boundingbox[URY]++;
  962.             }
  963.             }
  964.         }
  965.         }
  966.     }
  967.     section_len += line_len;
  968.     doc->pages[doc->numpages].end = position;
  969.     doc->pages[doc->numpages].len = section_len - line_len;
  970.     doc->numpages++;
  971.     }
  972.  
  973.     /* Document Trailer */
  974.  
  975.     if (beginsection) {
  976.     doc->begintrailer = beginsection;
  977.     beginsection = 0;
  978.     } else {
  979.     doc->begintrailer = position;
  980.     section_len = line_len;
  981.     }
  982.  
  983.     preread = 1;
  984.     while ((preread ||
  985.         readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count)) &&
  986.        !(DSCcomment(line) && iscomment(line+2, "EOF"))) {
  987.     if (!preread) section_len += line_len;
  988.     preread = 0;
  989.     if (!DSCcomment(line)) {
  990.         /* Do nothing */
  991.     } else if (iscomment(line+2, "Page:")) {
  992.         free(gettext(line+length("%%Page:"), &next_char));
  993.         if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  994.         if (!ignore && thispage == nextpage) {
  995.         if (doc->numpages > 0) {
  996.             doc->pages[doc->numpages-1].end = position;
  997.             doc->pages[doc->numpages-1].len += section_len - line_len;
  998.         } else {
  999.             if (doc->endsetup) {
  1000.             doc->endsetup = position;
  1001. /* following line removed rjl 1995-04-01
  1002.             doc->endsetup += section_len - line_len;
  1003. */
  1004.             } else if (doc->endprolog) {
  1005.             doc->endprolog = position;
  1006. /* following line removed rjl 1995-04-01
  1007.             doc->endprolog += section_len - line_len;
  1008. */
  1009.             }
  1010.         }
  1011.         goto newpage;
  1012.         }
  1013.     } else if (bb_set == ATEND && iscomment(line+2, "BoundingBox:")) {
  1014.         if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
  1015.                &(doc->boundingbox[LLX]),
  1016.                &(doc->boundingbox[LLY]),
  1017.                &(doc->boundingbox[URX]),
  1018.                &(doc->boundingbox[URY])) != 4) {
  1019.         float fllx, flly, furx, fury;
  1020.         if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
  1021.                &fllx, &flly, &furx, &fury) == 4) {
  1022.             doc->boundingbox[LLX] = fllx;
  1023.             doc->boundingbox[LLY] = flly;
  1024.             doc->boundingbox[URX] = furx;
  1025.             doc->boundingbox[URY] = fury;
  1026.             if (fllx < doc->boundingbox[LLX])
  1027.             doc->boundingbox[LLX]--;
  1028.             if (flly < doc->boundingbox[LLY])
  1029.             doc->boundingbox[LLY]--;
  1030.             if (furx > doc->boundingbox[URX])
  1031.             doc->boundingbox[URX]++;
  1032.             if (fury > doc->boundingbox[URY])
  1033.             doc->boundingbox[URY]++;
  1034.         }
  1035.         }
  1036.     } else if (orientation_set == ATEND &&
  1037.            iscomment(line+2, "Orientation:")) {
  1038.         sscanf(line+length("%%Orientation:"), "%s", text);
  1039.         if (strcmp(text, "Portrait") == 0) {
  1040.         doc->orientation = PORTRAIT;
  1041.         } else if (strcmp(text, "Landscape") == 0) {
  1042.         doc->orientation = LANDSCAPE;
  1043.         }
  1044.     } else if (page_order_set == ATEND && iscomment(line+2, "PageOrder:")) {
  1045.         sscanf(line+length("%%PageOrder:"), "%s", text);
  1046.         if (strcmp(text, "Ascend") == 0) {
  1047.         doc->pageorder = ASCEND;
  1048.         } else if (strcmp(text, "Descend") == 0) {
  1049.         doc->pageorder = DESCEND;
  1050.         } else if (strcmp(text, "Special") == 0) {
  1051.         doc->pageorder = SPECIAL;
  1052.         }
  1053.     } else if (pages_set == ATEND && iscomment(line+2, "Pages:")) {
  1054.         if (sscanf(line+length("%%Pages:"), "%*u %d", &i) == 1) {
  1055.         if (page_order_set == NONE) {
  1056.             if (i == -1) doc->pageorder = DESCEND;
  1057.             else if (i == 0) doc->pageorder = SPECIAL;
  1058.             else if (i == 1) doc->pageorder = ASCEND;
  1059.         }
  1060.         }
  1061.     }
  1062.     }
  1063.     section_len += line_len;
  1064.     if (DSCcomment(line) && iscomment(line+2, "EOF")) {
  1065.     readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count);
  1066.     section_len += line_len;
  1067.     }
  1068.     doc->endtrailer = position;
  1069.     doc->lentrailer = section_len - line_len;
  1070.  
  1071. #if 0
  1072.     section_len = line_len;
  1073.     preread = 1;
  1074.     while (preread ||
  1075.        readline(line, sizeof line, file, enddoseps, &position, &line_len, &line_count)) {
  1076.     if (!preread) section_len += line_len;
  1077.     preread = 0;
  1078.     if (DSCcomment(line) && iscomment(line+2, "Page:")) {
  1079.         free(gettext(line+length("%%Page:"), &next_char));
  1080.         if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
  1081.         if (!ignore && thispage == nextpage) {
  1082.         if (doc->numpages > 0) {
  1083.             doc->pages[doc->numpages-1].end = position;
  1084.             doc->pages[doc->numpages-1].len += doc->lentrailer +
  1085.                                section_len - line_len;
  1086.         } else {
  1087.             if (doc->endsetup) {
  1088.             doc->endsetup = position;
  1089.             doc->endsetup += doc->lentrailer +
  1090.                      section_len - line_len;
  1091.             } else if (doc->endprolog) {
  1092.             doc->endprolog = position;
  1093.             doc->endprolog += doc->lentrailer +
  1094.                       section_len - line_len;
  1095.             }
  1096.         }
  1097.         goto newpage;
  1098.         }
  1099.     }
  1100.     }
  1101. #endif
  1102.     return doc;
  1103. }
  1104.  
  1105. /*
  1106.  *    psfree -- free dynamic storage associated with document structure.
  1107.  */
  1108.  
  1109. void
  1110. psfree(doc)
  1111.     struct document *doc;
  1112. {
  1113.     int i;
  1114.  
  1115.     if (doc) {
  1116.     for (i=0; i<doc->numpages; i++) {
  1117.         if (doc->pages[i].label) free(doc->pages[i].label);
  1118.     }
  1119.     for (i=0; i<doc->nummedia; i++) {
  1120.         if (doc->media[i].name) free(doc->media[i].name);
  1121.     }
  1122.     if (doc->title) free(doc->title);
  1123.     if (doc->date) free(doc->date);
  1124.     if (doc->pages) free(doc->pages);
  1125.     if (doc->media) free(doc->media);
  1126.     if (doc->doseps) free(doc->doseps); /* rjl: */
  1127.     free(doc);
  1128.     }
  1129. }
  1130.  
  1131. /*
  1132.  * gettextine -- skip over white space and return the rest of the line.
  1133.  *               If the text begins with '(' return the text string
  1134.  *         using gettext().
  1135.  */
  1136.  
  1137. static char *
  1138. gettextline(line)
  1139.     char *line;
  1140. {
  1141.     char *cp;
  1142.  
  1143.     while (*line && (*line == ' ' || *line == '\t')) line++;
  1144.     if (*line == '(') {
  1145.     return gettext(line, NULL);
  1146.     } else {
  1147.     if (strlen(line) == 0) return NULL;
  1148.     cp = (char *) malloc(strlen(line));
  1149.     if (cp == NULL) {
  1150.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  1151.         exit(-1);
  1152.     }
  1153.     strncpy(cp, line, strlen(line)-1);
  1154.     cp[strlen(line)-1] = '\0';
  1155.     return cp;
  1156.     }
  1157. }
  1158.  
  1159. /*
  1160.  *    gettext -- return the next text string on the line.
  1161.  *           return NULL if nothing is present.
  1162.  */
  1163.  
  1164. static char *
  1165. gettext(line, next_char)
  1166.     char *line;
  1167.     char **next_char;
  1168. {
  1169.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1170.     char *cp;
  1171.     int quoted=0;
  1172.  
  1173.     while (*line && (*line == ' ' || *line == '\t')) line++;
  1174.     cp = text;
  1175.     if (*line == '(') {
  1176.     int level = 0;
  1177.     quoted=1;
  1178.     line++;
  1179.     while (*line && !(*line == ')' && level == 0 )) {
  1180.         if (*line == '\\') {
  1181.         if (*(line+1) == 'n') {
  1182.             *cp++ = '\n';
  1183.             line += 2;
  1184.         } else if (*(line+1) == 'r') {
  1185.             *cp++ = '\r';
  1186.             line += 2;
  1187.         } else if (*(line+1) == 't') {
  1188.             *cp++ = '\t';
  1189.             line += 2;
  1190.         } else if (*(line+1) == 'b') {
  1191.             *cp++ = '\b';
  1192.             line += 2;
  1193.         } else if (*(line+1) == 'f') {
  1194.             *cp++ = '\f';
  1195.             line += 2;
  1196.         } else if (*(line+1) == '\\') {
  1197.             *cp++ = '\\';
  1198.             line += 2;
  1199.         } else if (*(line+1) == '(') {
  1200.             *cp++ = '(';
  1201.             line += 2;
  1202.         } else if (*(line+1) == ')') {
  1203.             *cp++ = ')';
  1204.             line += 2;
  1205.         } else if (*(line+1) >= '0' && *(line+1) <= '9') {
  1206.             if (*(line+2) >= '0' && *(line+2) <= '9') {
  1207.             if (*(line+3) >= '0' && *(line+3) <= '9') {
  1208.                 *cp++ = (unsigned char)(((*(line+1) - '0')*8 + *(line+2) - '0')*8 +
  1209.                     *(line+3) - '0');
  1210.                 line += 4;
  1211.             } else {
  1212.                 *cp++ = (unsigned char)((*(line+1) - '0')*8 + *(line+2) - '0');
  1213.                 line += 3;
  1214.             }
  1215.             } else {
  1216.             *cp++ = (unsigned char)(*(line+1) - '0');
  1217.             line += 2;
  1218.             }
  1219.         } else {
  1220.             line++;
  1221.             *cp++ = *line++;
  1222.         }
  1223.         } else if (*line == '(') {
  1224.         level++;
  1225.         *cp++ = *line++;
  1226.         } else if (*line == ')') {
  1227.         level--;
  1228.         *cp++ = *line++;
  1229.         } else {
  1230.         *cp++ = *line++;
  1231.         }
  1232.     }
  1233.     } else {
  1234.     while (*line && !(*line == ' ' || *line == '\t' || *line == '\n'))
  1235.         *cp++ = *line++;
  1236.     }
  1237.     *cp = '\0';
  1238.     if (next_char) *next_char = line;
  1239.     if (!quoted && strlen(text) == 0) return NULL;
  1240.     cp = (char *) malloc(strlen(text)+1);
  1241.     if (cp == NULL) {
  1242.     pserror("Fatal Error: Dynamic memory exhausted.\n");
  1243.     exit(-1);
  1244.     }
  1245.     strcpy(cp, text);
  1246.     return cp;
  1247. }
  1248.  
  1249. /*
  1250.  *    readline -- Read the next line in the postscript file.
  1251.  *                  Automatically skip over data (as indicated by
  1252.  *                  %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  1253.  *            comments.)
  1254.  *            Also, skip over included documents (as indicated by
  1255.  *            %%BeginDocument/%%EndDocument comments.)
  1256.  */
  1257.  
  1258. static char *
  1259. readline(line, size, fp, enddoseps, position, line_len, line_count)
  1260.     char *line;
  1261.     int size;
  1262.     FILE *fp;
  1263.     unsigned long enddoseps;
  1264.     long *position;
  1265.     unsigned int *line_len;
  1266.     unsigned int *line_count;
  1267. {
  1268.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1269.     char save[PSLINELENGTH];    /* Temporary storage for text */
  1270.     char *cp;
  1271.     unsigned int num;
  1272.     unsigned int nbytes;
  1273.     int i;
  1274.     char buf[BUFSIZ];
  1275.  
  1276.     if (position) *position = ftell(fp);
  1277.     if (position && enddoseps) {
  1278.     if (*position >= enddoseps)
  1279.         return NULL;    /* don't read any more, we have reached end of dos eps section */
  1280.     if (size > enddoseps - *position + 1)
  1281.         size = enddoseps - *position + 1;
  1282.     }
  1283.     cp = fgets(line, size, fp);
  1284.     *line_count += 1;
  1285.     if (cp == NULL) line[0] = '\0';
  1286.     *line_len = strlen(line);
  1287. #if defined(__TURBOC__) || defined(OS2)
  1288.     /* remove MS-DOS carriage-return */
  1289.     if ((i = *line_len) >= 2) {
  1290.     if ((line[i-2] == '\r') && (line[i-1] == '\n')) {
  1291.         line[i-2] = '\n';
  1292.         line[i-1] = '\0';
  1293.     }
  1294.     }
  1295. #endif
  1296.     if (!(DSCcomment(line) && iscomment(line+2, "Begin"))) {
  1297.         /* rjl: skip over BUGGY EPS includes from Microsoft Word */
  1298.         /* Microsoft's EPSIMP.FLT needs to be fixed */
  1299.     if ( (line[0] == '%') && iscomment(line+1, "MSEPS Preamble") ) {
  1300.         strcpy(save, line);
  1301.         while (readline(line, size, fp, enddoseps, NULL, &nbytes, line_count) &&
  1302.            !(line[0] == '%' && iscomment(line+1, "MSEPS Trailer"))) {
  1303.         *line_len += nbytes;
  1304.         }
  1305.         *line_len += nbytes;
  1306.         strcpy(line, save);
  1307.     }
  1308.     else {
  1309.         /* Do nothing */
  1310.     }
  1311.     } else if (iscomment(line+7, "Document:")) {
  1312.     strcpy(save, line+7);
  1313.     while (readline(line, size, fp, enddoseps, NULL, &nbytes, line_count) &&
  1314.            !(DSCcomment(line) && iscomment(line+2, "EndDocument"))) {
  1315.         *line_len += nbytes;
  1316.     }
  1317.     *line_len += nbytes;
  1318.     strcpy(line, save);
  1319.     } else if (iscomment(line+7, "Feature:")) {
  1320.     strcpy(save, line+7);
  1321.     while (readline(line, size, fp, enddoseps, NULL, &nbytes, line_count) &&
  1322.            !(DSCcomment(line) && iscomment(line+2, "EndFeature"))) {
  1323.         *line_len += nbytes;
  1324.     }
  1325.     *line_len += nbytes;
  1326.     strcpy(line, save);
  1327.     } else if (iscomment(line+7, "File:")) {
  1328.     strcpy(save, line+7);
  1329.     while (readline(line, size, fp, enddoseps, NULL, &nbytes, line_count) &&
  1330.            !(DSCcomment(line) && iscomment(line+2, "EndFile"))) {
  1331.         *line_len += nbytes;
  1332.     }
  1333.     *line_len += nbytes;
  1334.     strcpy(line, save);
  1335.     } else if (iscomment(line+7, "Font:")) {
  1336.     strcpy(save, line+7);
  1337.     while (readline(line, size, fp, enddoseps, NULL, &nbytes, line_count) &&
  1338.            !(DSCcomment(line) && iscomment(line+2, "EndFont"))) {
  1339.         *line_len += nbytes;
  1340.     }
  1341.     *line_len += nbytes;
  1342.     strcpy(line, save);
  1343.     } else if (iscomment(line+7, "ProcSet:")) {
  1344.     strcpy(save, line+7);
  1345.     while (readline(line, size, fp, enddoseps, NULL, &nbytes, line_count) &&
  1346.            !(DSCcomment(line) && iscomment(line+2, "EndProcSet"))) {
  1347.         *line_len += nbytes;
  1348.     }
  1349.     *line_len += nbytes;
  1350.     strcpy(line, save);
  1351.     } else if (iscomment(line+7, "Resource:")) {
  1352.     strcpy(save, line+7);
  1353.     while (readline(line, size, fp, enddoseps, NULL, &nbytes, line_count) &&
  1354.            !(DSCcomment(line) && iscomment(line+2, "EndResource"))) {
  1355.         *line_len += nbytes;
  1356.     }
  1357.     *line_len += nbytes;
  1358.     strcpy(line, save);
  1359.     } else if (iscomment(line+7, "Data:")) {
  1360.     text[0] = '\0';
  1361.     strcpy(save, line+7);
  1362.     if (sscanf(line+length("%%BeginData:"), "%d %*s %s", &num, text) >= 1) {
  1363.         if (strcmp(text, "Lines") == 0) {
  1364.         for (i=0; i < num; i++) {
  1365.           *line_count += 1;
  1366.           do { /* rjl: handle antisocial PostScript with excessively long lines */
  1367.             cp = fgets(line, size, fp);
  1368.             *line_len += cp ? strlen(line) : 0;
  1369.           } while ( (strlen(line) == size-1) && (line[size-2] != '\n') );
  1370.         }
  1371.         } else {
  1372.         while (num > BUFSIZ) {
  1373.             fread(buf, sizeof (char), BUFSIZ, fp);
  1374.             *line_len += BUFSIZ;
  1375.             num -= BUFSIZ;
  1376.         }
  1377.         fread(buf, sizeof (char), num, fp);
  1378.         *line_len += num;
  1379.         }
  1380.     }
  1381.     while (readline(line, size, fp, enddoseps, NULL, &nbytes, line_count) &&
  1382.            !(DSCcomment(line) && iscomment(line+2, "EndData"))) {
  1383.         *line_len += nbytes;
  1384.     }
  1385.     *line_len += nbytes;
  1386.     strcpy(line, save);
  1387.     } else if (iscomment(line+7, "Binary:")) {
  1388.     strcpy(save, line+7);
  1389.     if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1390.         while (num > BUFSIZ) {
  1391.         fread(buf, sizeof (char), BUFSIZ, fp);
  1392.         *line_len += BUFSIZ;
  1393.         num -= BUFSIZ;
  1394.         }
  1395.         fread(buf, sizeof (char), num, fp);
  1396.         *line_len += num;
  1397.     }
  1398.     while (readline(line, size, fp, enddoseps, NULL, &nbytes, line_count) &&
  1399.            !(DSCcomment(line) && iscomment(line+2, "EndBinary"))) {
  1400.         *line_len += nbytes;
  1401.     }
  1402.     *line_len += nbytes;
  1403.     strcpy(line, save);
  1404.     }
  1405.     return cp;
  1406. }
  1407.  
  1408. /*
  1409.  *    pscopy -- copy lines of Postscript from a section of one file
  1410.  *          to another file.
  1411.  *                Automatically switch to binary copying whenever
  1412.  *                %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  1413.  *          comments are encountered.
  1414.  */
  1415.  
  1416. void
  1417. pscopy(from, to, begin, end)
  1418.     FILE *from;
  1419.     FILE *to;
  1420.     long begin;            /* set negative to avoid initial seek */
  1421.     long end;
  1422. {
  1423.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  1424.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1425.     unsigned int num;
  1426.     int i;
  1427.     char buf[BUFSIZ];
  1428.  
  1429.     if (begin >= 0) fseek(from, begin, SEEK_SET);
  1430.     while (ftell(from) < end) {
  1431.  
  1432.     fgets(line, sizeof line, from);
  1433.     fputs(line, to);
  1434.  
  1435.     if (!(DSCcomment(line) && iscomment(line+2, "Begin"))) {
  1436.         /* Do nothing */
  1437.     } else if (iscomment(line+7, "Data:")) {
  1438.         text[0] = '\0';
  1439.         if (sscanf(line+length("%%BeginData:"),
  1440.                "%d %*s %s", &num, text) >= 1) {
  1441.         if (strcmp(text, "Lines") == 0) {
  1442.             for (i=0; i < num; i++) {
  1443.               do { /* rjl: handle antisocial PostScript with excessively long lines */
  1444.             fgets(line, sizeof line, from);
  1445.             fputs(line, to);
  1446.               } while ( (strlen(line) == sizeof(line)-1) && (line[sizeof(line)-2] != '\n') );
  1447.             }
  1448.         } else {
  1449.             while (num > BUFSIZ) {
  1450.             fread(buf, sizeof (char), BUFSIZ, from);
  1451.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1452.             num -= BUFSIZ;
  1453.             }
  1454.             fread(buf, sizeof (char), num, from);
  1455.             fwrite(buf, sizeof (char), num, to);
  1456.         }
  1457.         }
  1458.     } else if (iscomment(line+7, "Binary:")) {
  1459.         if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1460.         while (num > BUFSIZ) {
  1461.             fread(buf, sizeof (char), BUFSIZ, from);
  1462.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1463.             num -= BUFSIZ;
  1464.         }
  1465.         fread(buf, sizeof (char), num, from);
  1466.         fwrite(buf, sizeof (char), num, to);
  1467.         }
  1468.     }
  1469.     }
  1470. }
  1471.  
  1472. /*
  1473.  *    pscopyuntil -- copy lines of Postscript from a section of one file
  1474.  *               to another file until a particular comment is reached.
  1475.  *                     Automatically switch to binary copying whenever
  1476.  *                     %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
  1477.  *               comments are encountered.
  1478.  */
  1479.  
  1480. char *
  1481. pscopyuntil(from, to, begin, end, comment)
  1482.     FILE *from;
  1483.     FILE *to;
  1484.     long begin;            /* set negative to avoid initial seek */
  1485.     long end;
  1486. #if NeedFunctionPrototypes
  1487.     const
  1488. #endif
  1489.     char *comment;
  1490. {
  1491.     char line[PSLINELENGTH];    /* 255 characters + 1 newline + 1 NULL */
  1492.     char text[PSLINELENGTH];    /* Temporary storage for text */
  1493.     unsigned int num;
  1494.     int comment_length;
  1495.     int i;
  1496.     char buf[BUFSIZ];
  1497.     char *cp;
  1498.  
  1499.     if (comment)    /* rjl: allow NULL comment to degenerate to pscopy() */
  1500.         comment_length = strlen(comment);
  1501.     if (begin >= 0) fseek(from, begin, SEEK_SET);
  1502.     while (ftell(from) < end) {
  1503.  
  1504.     fgets(line, sizeof line, from);
  1505.  
  1506.     /* iscomment cannot be used here,
  1507.      * because comment_length is not known at compile time. */
  1508.     if (comment && (strncmp(line, comment, comment_length) == 0)) {
  1509.         cp = (char *) malloc(strlen(line)+1);
  1510.         if (cp == NULL) {
  1511.         pserror("Fatal Error: Dynamic memory exhausted.\n");
  1512.         exit(-1);
  1513.         }
  1514.         strcpy(cp, line);
  1515.         return cp;
  1516.     }
  1517.     fputs(line, to);
  1518.     if (!(DSCcomment(line) && iscomment(line+2, "Begin"))) {
  1519.         /* Do nothing */
  1520.     } else if (iscomment(line+7, "Data:")) {
  1521.         text[0] = '\0';
  1522.         if (sscanf(line+length("%%BeginData:"),
  1523.                "%d %*s %s", &num, text) >= 1) {
  1524.         if (strcmp(text, "Lines") == 0) {
  1525.             for (i=0; i < num; i++) {
  1526.               do { /* rjl: handle antisocial PostScript with excessively long lines */
  1527.             fgets(line, sizeof line, from);
  1528.             fputs(line, to);
  1529.               } while ( (strlen(line) == sizeof(line)-1) && (line[sizeof(line)-2] != '\n') );
  1530.             }
  1531.         } else {
  1532.             while (num > BUFSIZ) {
  1533.             fread(buf, sizeof (char), BUFSIZ, from);
  1534.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1535.             num -= BUFSIZ;
  1536.             }
  1537.             fread(buf, sizeof (char), num, from);
  1538.             fwrite(buf, sizeof (char), num, to);
  1539.         }
  1540.         }
  1541.     } else if (iscomment(line+7, "Binary:")) {
  1542.         if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
  1543.         while (num > BUFSIZ) {
  1544.             fread(buf, sizeof (char), BUFSIZ, from);
  1545.             fwrite(buf, sizeof (char), BUFSIZ, to);
  1546.             num -= BUFSIZ;
  1547.         }
  1548.         fread(buf, sizeof (char), num, from);
  1549.         fwrite(buf, sizeof (char), num, to);
  1550.         }
  1551.     }
  1552.     }
  1553.     return NULL;
  1554. }
  1555.  
  1556. /*
  1557.  *    blank -- determine whether the line contains nothing but whitespace.
  1558.  */
  1559.  
  1560. static int
  1561. blank(line)
  1562.     char *line;
  1563. {
  1564.     char *cp = line;
  1565.  
  1566.     while (*cp == ' ' || *cp == '\t') cp++;
  1567.     return *cp == '\n' || (*cp == '%' && (line[0] != '%' || line[1] != '%'));
  1568. }
  1569.  
  1570. /* rjl: routines to handle reading DOS EPS files */
  1571. static unsigned long dsc_arch = 0x00000001;
  1572.  
  1573. /* change byte order if architecture is big-endian */
  1574. PS_DWORD
  1575. reorder_dword(val)
  1576.     PS_DWORD val;
  1577. {
  1578.     if (*((char *)(&dsc_arch)))
  1579.         return val;    /* little endian machine */
  1580.     else
  1581.     return ((val&0xff) << 24) | ((val&0xff00) << 8)
  1582.              | ((val&0xff0000L) >> 8) | ((val>>24)&0xff);
  1583. }
  1584.  
  1585. /* change byte order if architecture is big-endian */
  1586. PS_WORD
  1587. reorder_word(val)
  1588.     PS_WORD val;
  1589. {
  1590.     if (*((char *)(&dsc_arch)))
  1591.         return val;    /* little endian machine */
  1592.     else
  1593.     return (PS_WORD) ((PS_WORD)(val&0xff) << 8) | (PS_WORD)((val&0xff00) >> 8);
  1594. }
  1595.  
  1596. /* DOS EPS header reading */
  1597. unsigned long
  1598. ps_read_doseps(file, doseps)
  1599.     FILE *file;
  1600.     DOSEPS *doseps;
  1601. {
  1602.     fread(doseps->id, 1, 4, file);
  1603.     if (! ((doseps->id[0]==0xc5) && (doseps->id[1]==0xd0) 
  1604.         && (doseps->id[2]==0xd3) && (doseps->id[3]==0xc6)) ) {
  1605.         /* id is "EPSF" with bit 7 set */
  1606.         rewind(file);
  1607.         return 0;     /* OK */
  1608.     }
  1609.     fread(&doseps->ps_begin,    4, 1, file);    /* PS offset */
  1610.     doseps->ps_begin = (unsigned long)reorder_dword(doseps->ps_begin);
  1611.     fread(&doseps->ps_length,   4, 1, file);    /* PS length */
  1612.     doseps->ps_length = (unsigned long)reorder_dword(doseps->ps_length);
  1613.     fread(&doseps->mf_begin,    4, 1, file);    /* Metafile offset */
  1614.     doseps->mf_begin = (unsigned long)reorder_dword(doseps->mf_begin);
  1615.     fread(&doseps->mf_length,   4, 1, file);    /* Metafile length */
  1616.     doseps->mf_length = (unsigned long)reorder_dword(doseps->mf_length);
  1617.     fread(&doseps->tiff_begin,  4, 1, file);    /* TIFF offset */
  1618.     doseps->tiff_begin = (unsigned long)reorder_dword(doseps->tiff_begin);
  1619.     fread(&doseps->tiff_length, 4, 1, file);    /* TIFF length */
  1620.     doseps->tiff_length = (unsigned long)reorder_dword(doseps->tiff_length);
  1621.     fread(&doseps->checksum,    2, 1, file);
  1622.         doseps->checksum = (unsigned short)reorder_word(doseps->checksum);
  1623.     fseek(file, doseps->ps_begin, SEEK_SET);    /* seek to PS section */
  1624.     return doseps->ps_begin + doseps->ps_length;
  1625. }
  1626.  
  1627.