2 * ps.c -- Postscript scanning and copying routines.
3 * Copyright (C) 1992, 1998 Timothy O. Theisen
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.
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.
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.
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
26 /* 18/3/98 Jake Hamby patch */
29 * 98/03/17: Jake Hamby (jehamby@lightside.com):
30 * Added support for compressed/gzipped Postscript and PDF files.
31 * Compressed files are gunzipped to a temporary file, and PDF files are
32 * scanned by calling Ghostscript to generate a fake DSC file.
33 * This is based on code from GV 3.5.8, which is available at:
34 * http://wwwthep.physik.uni-mainz.de/~plass/gv/
37 /* GV by Johannes Plass
38 * Department of Physics
39 * Johannes Gutenberg University
42 * <plass@thep.physik.uni-mainz.de>
56 #include <X11/Xos.h> /* #includes the appropriate <string.h> */
58 #include "gsdefaults.h"
64 /* length calculates string length at compile time */
65 /* can only be used with character constants */
66 #define length(a) (sizeof(a)-1)
67 #define iscomment(a, b) (strncmp(a, b, length(b)) == 0)
68 #define DSCcomment(a) (a[0] == '%' && a[1] == '%')
70 /* list of standard paper sizes from Adobe's PPD. */
72 #if 1 //NeedFunctionPrototypes
73 static char *readline(char *line, int size, FILE * fp,
74 long *position, unsigned int *line_len);
75 static char *gettextline(char *line);
76 static char *get_next_text(char *line, char **next_char);
77 static int blank(char *line);
79 static char *readline();
80 static char *gettextline();
81 static char *get_next_text();
87 pages_new(struct page *pages, int current, int maxpages)
89 struct page *oldpages = pages;
91 pages = g_new0(struct page, maxpages);
93 pages = g_renew(struct page, oldpages, maxpages);
94 for(; current < maxpages; current++) {
95 memset(&(pages[current]), 0x00, sizeof(struct page));
96 pages[current].orientation = GTK_GS_ORIENTATION_NONE;
102 * psscan -- scan the PostScript file for document structuring comments.
104 * This scanner is designed to retrieve the information necessary for
105 * the ghostview previewer. It will scan files that conform to any
106 * version (1.0, 2.0, 2.1, or 3.0) of the document structuring conventions.
107 * It does not really care which version of comments the file contains.
108 * (The comments are largely upward compatible.) It will scan a number
109 * of non-conforming documents. (You could have part of the document
110 * conform to V2.0 and the rest conform to V3.0. It would be similar
111 * to the DC-2 1/2+, it would look funny but it can still fly.)
113 * This routine returns a pointer to the document structure.
114 * The structure contains the information relevant to previewing.
115 * These include EPSF flag (to tell if the file is a encapsulated figure),
116 * Page Size (for the Page Size), Bounding Box (to minimize backing
117 * pixmap size or determine window size for encapsulated PostScript),
118 * Orientation of Paper (for default transformation matrix), and
119 * Page Order. The title and CreationDate are also retrieved to
120 * help identify the document.
122 * The following comments are examined:
125 * Must start with %!PS-Adobe-. Version numbers ignored.
126 * Also allowed to be just %!PS, many files seem to have that.
128 * %!PS-Adobe-* [EPSF-*]
129 * %%BoundingBox: <int> <int> <int> <int>|(atend)
130 * %%CreationDate: <textline>
131 * %%Orientation: Portrait|Landscape|(atend)
132 * %%Pages: <uint> [<int>]|(atend)
133 * %%PageOrder: Ascend|Descend|Special|(atend)
134 * %%Title: <textline>
135 * %%DocumentMedia: <text> <real> <real> <real> <text> <text>
136 * %%DocumentPaperSizes: <text>
139 * Note: Either the 3.0 or 2.0 syntax for %%Pages is accepted.
140 * Also either the 2.0 %%DocumentPaperSizes or the 3.0
141 * %%DocumentMedia comments are accepted as well.
143 * The header section ends either explicitly with %%EndComments or
144 * implicitly with any line that does not begin with %X where X is
145 * a not whitespace character.
147 * If the file is encapsulated PostScript the optional Preview section
153 * This section explicitly begins and ends with the above comments.
155 * Next the Defaults section for version 3 page defaults:
158 * %%PageBoundingBox: <int> <int> <int> <int>
159 * %%PageOrientation: Portrait|Landscape
160 * %%PageMedia: <text>
163 * This section explicitly begins and ends with the above comments.
165 * The prolog section either explicitly starts with %%BeginProlog or
166 * implicitly with any nonblank line.
171 * The Prolog should end with %%EndProlog, however the proglog implicitly
172 * ends when %%BeginSetup, %%Page, %%Trailer or %%EOF are encountered.
174 * The Setup section is where the version 2 page defaults are found.
175 * This section either explicitly begins with %%BeginSetup or implicitly
176 * with any nonblank line after the Prolog.
179 * %%PageBoundingBox: <int> <int> <int> <int>
180 * %%PageOrientation: Portrait|Landscape
181 * %%PaperSize: <text>
184 * The Setup should end with %%EndSetup, however the setup implicitly
185 * ends when %%Page, %%Trailer or %%EOF are encountered.
187 * Next each page starts explicitly with %%Page and ends implicitly with
188 * %%Page or %%Trailer or %%EOF. The following comments are recognized:
190 * %%Page: <text> <uint>
191 * %%PageBoundingBox: <int> <int> <int> <int>|(atend)
192 * %%PageOrientation: Portrait|Landscape
193 * %%PageMedia: <text>
194 * %%PaperSize: <text>
196 * The tralier section start explicitly with %%Trailer and end with %%EOF.
197 * The following comment are examined with the proper (atend) notation
198 * was used in the header:
201 * %%BoundingBox: <int> <int> <int> <int>|(atend)
202 * %%Orientation: Portrait|Landscape|(atend)
203 * %%Pages: <uint> [<int>]|(atend)
204 * %%PageOrder: Ascend|Descend|Special|(atend)
208 * + A DC-3 received severe damage to one of its wings. The wing was a total
209 * loss. There was no replacement readily available, so the mechanic
210 * installed a wing from a DC-2.
216 psscan(FILE * file, int respect_eof, const gchar * fname)
218 struct document *doc;
220 int pages_set = NONE;
221 int page_order_set = NONE;
222 int orientation_set = NONE;
223 int page_bb_set = NONE;
224 int page_size_set = NONE;
225 int preread; /* flag which tells the readline isn't needed */
227 unsigned int maxpages = 0;
228 unsigned int nextpage = 1; /* Next expected page */
229 unsigned int thispage;
230 int ignore = 0; /* whether to ignore page ordinals */
232 char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
233 char text[PSLINELENGTH]; /* Temporary storage for text */
234 long position; /* Position of the current line */
235 long beginsection; /* Position of the beginning of the section */
236 unsigned int line_len; /* Length of the current line */
237 unsigned int section_len; /* Place to accumulate the section length */
238 char *next_char; /* 1st char after text returned by get_next_text() */
241 GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
248 if(!readline(line, sizeof line, file, &position, &line_len)) {
249 g_print("psscan: empty input file.\n");
253 /* HP printer job language data follows. Some printer drivers add pjl
254 * commands to switch a pjl printer to postscript mode. If no PS header
255 * follows, this seems to be a real pjl file. */
256 if(iscomment(line, "\033%-12345X@PJL")) {
257 /* read until first DSC comment */
258 while(readline(line, sizeof line, file, &position, &line_len)
259 && (line[0] != '%')) ;
261 g_print("psscan error: input files seems to be a PJL file.\n");
266 /* Header comments */
268 /* Header should start with "%!PS-Adobe-", but some programms omit
269 * parts of this or add a ^D at the beginning. */
270 if(iscomment(line, "%!PS") || iscomment(line, "\004%!PS")) {
271 doc = g_new0(struct document, 1);
272 doc->default_page_orientation = GTK_GS_ORIENTATION_NONE;
273 doc->orientation = GTK_GS_ORIENTATION_NONE;
275 /* ignore possible leading ^D */
276 if(*line == '\004') {
281 /* Jake Hamby patch 18/3/98 */
284 sscanf(line, "%*s %256s", text);
285 /*doc->epsf = iscomment(text, "EPSF-"); */
286 doc->epsf = iscomment(text, "EPSF"); /* Hamby - This line changed */
287 doc->beginheader = position;
288 section_len = line_len;
291 /* There are postscript documents that do not have
292 %PS at the beginning, usually unstructured. We should GS decide
293 For instance, the tech reports at this university:
295 http://svrc.it.uq.edu.au/Bibliography/svrc-tr.html?94-45
297 add ugly PostScript before the actual document.
300 able to display them correctly as unstructured PS.
302 In a way, this makes sense, a program PostScript does not need
303 the !PS at the beginning.
305 /* use a test command to determine if ghostscript can
306 understand this document! */
309 test_cmd = g_strdup_printf
310 ("%s -dNOPAUSE -dBATCH -sDEVICE=nullpage %s "
311 "1>/dev/null 2>/dev/null", gtk_gs_defaults_get_interpreter_cmd(), fname);
312 if(system(test_cmd) != 0) {
317 doc = g_new0(struct document, 1);
318 doc->default_page_orientation = GTK_GS_ORIENTATION_NONE;
319 doc->orientation = GTK_GS_ORIENTATION_NONE;
324 while(preread || readline(line, sizeof line, file, &position, &line_len)) {
326 section_len += line_len;
329 iscomment(line + 1, "%EndComments") ||
330 line[1] == ' ' || line[1] == '\t' || line[1] == '\n' ||
334 else if(line[1] != '%') {
337 else if(doc->title == NULL && iscomment(line + 2, "Title:")) {
338 doc->title = gettextline(line + length("%%Title:"));
340 else if(doc->date == NULL && iscomment(line + 2, "CreationDate:")) {
341 doc->date = gettextline(line + length("%%CreationDate:"));
343 else if(bb_set == NONE && iscomment(line + 2, "BoundingBox:")) {
344 sscanf(line + length("%%BoundingBox:"), "%256s", text);
345 if(strcmp(text, "(atend)") == 0) {
349 if(sscanf(line + length("%%BoundingBox:"), "%d %d %d %d",
350 &(doc->boundingbox[LLX]),
351 &(doc->boundingbox[LLY]),
352 &(doc->boundingbox[URX]), &(doc->boundingbox[URY])) == 4)
355 float fllx, flly, furx, fury;
356 if(sscanf(line + length("%%BoundingBox:"), "%f %f %f %f",
357 &fllx, &flly, &furx, &fury) == 4) {
359 doc->boundingbox[LLX] = fllx;
360 doc->boundingbox[LLY] = flly;
361 doc->boundingbox[URX] = furx;
362 doc->boundingbox[URY] = fury;
363 if(fllx < doc->boundingbox[LLX])
364 doc->boundingbox[LLX]--;
365 if(flly < doc->boundingbox[LLY])
366 doc->boundingbox[LLY]--;
367 if(furx > doc->boundingbox[URX])
368 doc->boundingbox[URX]++;
369 if(fury > doc->boundingbox[URY])
370 doc->boundingbox[URY]++;
375 else if(orientation_set == NONE && iscomment(line + 2, "Orientation:")) {
376 sscanf(line + length("%%Orientation:"), "%256s", text);
377 if(strcmp(text, "(atend)") == 0) {
378 orientation_set = ATEND;
380 else if(strcmp(text, "Portrait") == 0) {
381 doc->orientation = GTK_GS_ORIENTATION_PORTRAIT;
384 else if(strcmp(text, "Landscape") == 0) {
385 doc->orientation = GTK_GS_ORIENTATION_LANDSCAPE;
388 else if(strcmp(text, "Seascape") == 0) {
389 doc->orientation = GTK_GS_ORIENTATION_SEASCAPE;
393 else if(page_order_set == NONE && iscomment(line + 2, "PageOrder:")) {
394 sscanf(line + length("%%PageOrder:"), "%256s", text);
395 if(strcmp(text, "(atend)") == 0) {
396 page_order_set = ATEND;
398 else if(strcmp(text, "Ascend") == 0) {
399 doc->pageorder = ASCEND;
402 else if(strcmp(text, "Descend") == 0) {
403 doc->pageorder = DESCEND;
406 else if(strcmp(text, "Special") == 0) {
407 doc->pageorder = SPECIAL;
411 else if(pages_set == NONE && iscomment(line + 2, "Pages:")) {
412 sscanf(line + length("%%Pages:"), "%256s", text);
413 if(strcmp(text, "(atend)") == 0) {
417 switch (sscanf(line + length("%%Pages:"), "%d %d", &maxpages, &i)) {
419 if(page_order_set == NONE) {
421 doc->pageorder = DESCEND;
425 doc->pageorder = SPECIAL;
429 doc->pageorder = ASCEND;
435 doc->pages = pages_new(NULL, 0, maxpages);
439 else if(doc->numsizes == NONE && iscomment(line + 2, "DocumentMedia:")) {
441 doc->size = g_new0(GtkGSPaperSize, 1);
443 get_next_text(line + length("%%DocumentMedia:"), &next_char);
444 if(doc->size[0].name != NULL) {
445 if(sscanf(next_char, "%f %f", &w, &h) == 2) {
446 doc->size[0].width = w + 0.5;
447 doc->size[0].height = h + 0.5;
449 if(doc->size[0].width != 0 && doc->size[0].height != 0)
452 g_free(doc->size[0].name);
455 while(readline(line, sizeof line, file, &position, &line_len) &&
456 DSCcomment(line) && iscomment(line + 2, "+")) {
457 section_len += line_len;
458 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
459 doc->size[doc->numsizes].name =
460 get_next_text(line + length("%%+"), &next_char);
461 if(doc->size[doc->numsizes].name != NULL) {
462 if(sscanf(next_char, "%f %f", &w, &h) == 2) {
463 doc->size[doc->numsizes].width = w + 0.5;
464 doc->size[doc->numsizes].height = h + 0.5;
466 if(doc->size[doc->numsizes].width != 0 &&
467 doc->size[doc->numsizes].height != 0)
470 g_free(doc->size[doc->numsizes].name);
473 section_len += line_len;
474 if(doc->numsizes != 0)
475 doc->default_page_size = doc->size;
477 else if(doc->numsizes == NONE && iscomment(line + 2, "DocumentPaperSizes:")) {
479 doc->size = g_new0(GtkGSPaperSize, 1);
481 get_next_text(line + length("%%DocumentPaperSizes:"), &next_char);
482 if(doc->size[0].name != NULL) {
483 doc->size[0].width = 0;
484 doc->size[0].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.
490 if(strcasecmp(doc->size[0].name, dmp->name) == 0) {
491 g_free(doc->size[0].name);
492 doc->size[0].name = g_strdup(dmp->name);
493 doc->size[0].width = dmp->width;
494 doc->size[0].height = dmp->height;
498 if(doc->size[0].width != 0 && doc->size[0].height != 0)
501 g_free(doc->size[0].name);
503 while((cp = get_next_text(next_char, &next_char))) {
504 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
505 doc->size[doc->numsizes].name = cp;
506 doc->size[doc->numsizes].width = 0;
507 doc->size[doc->numsizes].height = 0;
508 for(dmp = papersizes; dmp->name != NULL; dmp++) {
509 /* Note: Paper size comment uses down cased paper size
510 * name. Case insensitive compares are only used for
511 * PaperSize comments.
513 if(strcasecmp(doc->size[doc->numsizes].name, dmp->name) == 0) {
514 g_free(doc->size[doc->numsizes].name);
515 doc->size[doc->numsizes].name = g_strdup(dmp->name);
516 doc->size[doc->numsizes].name = dmp->name;
517 doc->size[doc->numsizes].width = dmp->width;
518 doc->size[doc->numsizes].height = dmp->height;
522 if(doc->size[doc->numsizes].width != 0 &&
523 doc->size[doc->numsizes].height != 0)
526 g_free(doc->size[doc->numsizes].name);
529 while(readline(line, sizeof line, file, &position, &line_len) &&
530 DSCcomment(line) && iscomment(line + 2, "+")) {
531 section_len += line_len;
532 next_char = line + length("%%+");
533 while((cp = get_next_text(next_char, &next_char))) {
534 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
535 doc->size[doc->numsizes].name = cp;
536 doc->size[doc->numsizes].width = 0;
537 doc->size[doc->numsizes].height = 0;
538 for(dmp = papersizes; dmp->name != NULL; dmp++) {
539 /* Note: Paper size comment uses down cased paper size
540 * name. Case insensitive compares are only used for
541 * PaperSize comments.
543 if(strcasecmp(doc->size[doc->numsizes].name, dmp->name) == 0) {
544 doc->size[doc->numsizes].width = dmp->width;
545 doc->size[doc->numsizes].height = dmp->height;
549 if(doc->size[doc->numsizes].width != 0 &&
550 doc->size[doc->numsizes].height != 0)
553 g_free(doc->size[doc->numsizes].name);
556 section_len += line_len;
557 if(doc->numsizes != 0)
558 doc->default_page_size = doc->size;
562 if(DSCcomment(line) && iscomment(line + 2, "EndComments")) {
563 readline(line, sizeof line, file, &position, &line_len);
564 section_len += line_len;
566 doc->endheader = position;
567 doc->lenheader = section_len - line_len;
569 /* Optional Preview comments for encapsulated PostScript files */
571 beginsection = position;
572 section_len = line_len;
573 while(blank(line) && readline(line, sizeof line, file, &position, &line_len)) {
574 section_len += line_len;
577 if(doc->epsf && DSCcomment(line) && iscomment(line + 2, "BeginPreview")) {
578 doc->beginpreview = beginsection;
580 while(readline(line, sizeof line, file, &position, &line_len) &&
581 !(DSCcomment(line) && iscomment(line + 2, "EndPreview"))) {
582 section_len += line_len;
584 section_len += line_len;
585 readline(line, sizeof line, file, &position, &line_len);
586 section_len += line_len;
587 doc->endpreview = position;
588 doc->lenpreview = section_len - line_len;
591 /* Page Defaults for Version 3.0 files */
593 if(beginsection == 0) {
594 beginsection = position;
595 section_len = line_len;
597 while(blank(line) && readline(line, sizeof line, file, &position, &line_len)) {
598 section_len += line_len;
601 if(DSCcomment(line) && iscomment(line + 2, "BeginDefaults")) {
602 doc->begindefaults = beginsection;
604 while(readline(line, sizeof line, file, &position, &line_len) &&
605 !(DSCcomment(line) && iscomment(line + 2, "EndDefaults"))) {
606 section_len += line_len;
607 if(!DSCcomment(line)) {
610 else if(doc->default_page_orientation == NONE &&
611 iscomment(line + 2, "PageOrientation:")) {
612 sscanf(line + length("%%PageOrientation:"), "%256s", text);
613 if(strcmp(text, "Portrait") == 0) {
614 doc->default_page_orientation = GTK_GS_ORIENTATION_PORTRAIT;
616 else if(strcmp(text, "Landscape") == 0) {
617 doc->default_page_orientation = GTK_GS_ORIENTATION_LANDSCAPE;
619 else if(strcmp(text, "Seascape") == 0) {
620 doc->default_page_orientation = GTK_GS_ORIENTATION_SEASCAPE;
623 else if(page_size_set == NONE && iscomment(line + 2, "PageMedia:")) {
624 cp = get_next_text(line + length("%%PageMedia:"), NULL);
625 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
626 if(strcmp(cp, dmp->name) == 0) {
627 doc->default_page_size = dmp;
634 else if(page_bb_set == NONE && iscomment(line + 2, "PageBoundingBox:")) {
635 if(sscanf(line + length("%%PageBoundingBox:"), "%d %d %d %d",
636 &(doc->default_page_boundingbox[LLX]),
637 &(doc->default_page_boundingbox[LLY]),
638 &(doc->default_page_boundingbox[URX]),
639 &(doc->default_page_boundingbox[URY])) == 4)
642 float fllx, flly, furx, fury;
644 (line + length("%%PageBoundingBox:"), "%f %f %f %f",
645 &fllx, &flly, &furx, &fury) == 4) {
647 doc->default_page_boundingbox[LLX] = fllx;
648 doc->default_page_boundingbox[LLY] = flly;
649 doc->default_page_boundingbox[URX] = furx;
650 doc->default_page_boundingbox[URY] = fury;
651 if(fllx < doc->default_page_boundingbox[LLX])
652 doc->default_page_boundingbox[LLX]--;
653 if(flly < doc->default_page_boundingbox[LLY])
654 doc->default_page_boundingbox[LLY]--;
655 if(furx > doc->default_page_boundingbox[URX])
656 doc->default_page_boundingbox[URX]++;
657 if(fury > doc->default_page_boundingbox[URY])
658 doc->default_page_boundingbox[URY]++;
663 section_len += line_len;
664 readline(line, sizeof line, file, &position, &line_len);
665 section_len += line_len;
666 doc->enddefaults = position;
667 doc->lendefaults = section_len - line_len;
670 /* Document Prolog */
672 if(beginsection == 0) {
673 beginsection = position;
674 section_len = line_len;
676 while(blank(line) && readline(line, sizeof line, file, &position, &line_len)) {
677 section_len += line_len;
680 if(!(DSCcomment(line) &&
681 (iscomment(line + 2, "BeginSetup") ||
682 iscomment(line + 2, "Page:") ||
683 iscomment(line + 2, "Trailer") || iscomment(line + 2, "EOF")))) {
684 doc->beginprolog = beginsection;
689 readline(line, sizeof line, file, &position, &line_len)) &&
690 !(DSCcomment(line) &&
691 (iscomment(line + 2, "EndProlog") ||
692 iscomment(line + 2, "BeginSetup") ||
693 iscomment(line + 2, "Page:") ||
694 iscomment(line + 2, "Trailer") || iscomment(line + 2, "EOF")))) {
696 section_len += line_len;
699 section_len += line_len;
700 if(DSCcomment(line) && iscomment(line + 2, "EndProlog")) {
701 readline(line, sizeof line, file, &position, &line_len);
702 section_len += line_len;
704 doc->endprolog = position;
705 doc->lenprolog = section_len - line_len;
708 /* Document Setup, Page Defaults found here for Version 2 files */
710 if(beginsection == 0) {
711 beginsection = position;
712 section_len = line_len;
714 while(blank(line) && readline(line, sizeof line, file, &position, &line_len)) {
715 section_len += line_len;
718 if(!(DSCcomment(line) &&
719 (iscomment(line + 2, "Page:") ||
720 iscomment(line + 2, "Trailer") ||
721 (respect_eof && iscomment(line + 2, "EOF"))))) {
722 doc->beginsetup = beginsection;
726 readline(line, sizeof line, file, &position, &line_len)) &&
727 !(DSCcomment(line) &&
728 (iscomment(line + 2, "EndSetup") ||
729 iscomment(line + 2, "Page:") ||
730 iscomment(line + 2, "Trailer") ||
731 (respect_eof && iscomment(line + 2, "EOF"))))) {
733 section_len += line_len;
735 if(!DSCcomment(line)) {
738 else if(doc->default_page_orientation == NONE &&
739 iscomment(line + 2, "PageOrientation:")) {
740 sscanf(line + length("%%PageOrientation:"), "%256s", text);
741 if(strcmp(text, "Portrait") == 0) {
742 doc->default_page_orientation = GTK_GS_ORIENTATION_PORTRAIT;
744 else if(strcmp(text, "Landscape") == 0) {
745 doc->default_page_orientation = GTK_GS_ORIENTATION_LANDSCAPE;
747 else if(strcmp(text, "Seascape") == 0) {
748 doc->default_page_orientation = GTK_GS_ORIENTATION_SEASCAPE;
751 else if(page_size_set == NONE && iscomment(line + 2, "PaperSize:")) {
752 cp = get_next_text(line + length("%%PaperSize:"), NULL);
753 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
754 /* Note: Paper size comment uses down cased paper size
755 * name. Case insensitive compares are only used for
756 * PaperSize comments.
758 if(strcasecmp(cp, dmp->name) == 0) {
759 doc->default_page_size = dmp;
766 else if(page_bb_set == NONE && iscomment(line + 2, "PageBoundingBox:")) {
767 if(sscanf(line + length("%%PageBoundingBox:"), "%d %d %d %d",
768 &(doc->default_page_boundingbox[LLX]),
769 &(doc->default_page_boundingbox[LLY]),
770 &(doc->default_page_boundingbox[URX]),
771 &(doc->default_page_boundingbox[URY])) == 4)
774 float fllx, flly, furx, fury;
776 (line + length("%%PageBoundingBox:"), "%f %f %f %f",
777 &fllx, &flly, &furx, &fury) == 4) {
779 doc->default_page_boundingbox[LLX] = fllx;
780 doc->default_page_boundingbox[LLY] = flly;
781 doc->default_page_boundingbox[URX] = furx;
782 doc->default_page_boundingbox[URY] = fury;
783 if(fllx < doc->default_page_boundingbox[LLX])
784 doc->default_page_boundingbox[LLX]--;
785 if(flly < doc->default_page_boundingbox[LLY])
786 doc->default_page_boundingbox[LLY]--;
787 if(furx > doc->default_page_boundingbox[URX])
788 doc->default_page_boundingbox[URX]++;
789 if(fury > doc->default_page_boundingbox[URY])
790 doc->default_page_boundingbox[URY]++;
795 section_len += line_len;
796 if(DSCcomment(line) && iscomment(line + 2, "EndSetup")) {
797 readline(line, sizeof line, file, &position, &line_len);
798 section_len += line_len;
800 doc->endsetup = position;
801 doc->lensetup = section_len - line_len;
804 /* Added this (Nov. 2, 1999) when I noticed that
805 a Postscript file would load in gv but not in ggv
807 dmg@csg.uwaterloo.ca */
809 /* BEGIN Windows NT fix ###jp###
810 Mark Pfeifer (pfeiferm%ppddev@comet.cmis.abbott.com) told me
811 about problems when viewing Windows NT 3.51 generated postscript
812 files with gv. He found that the relevant postscript files
813 show important postscript code after the '%%EndSetup' and before
814 the first page comment '%%Page: x y'.
816 if(doc->beginsetup) {
817 while(!(DSCcomment(line) &&
818 (iscomment(line + 2, "EndSetup") ||
819 (iscomment(line + 2, "Page:") ||
820 iscomment(line + 2, "Trailer") ||
821 (respect_eof && iscomment(line + 2, "EOF"))))) &&
822 (readline(line, sizeof line, file, &position, &line_len))) {
823 section_len += line_len;
824 doc->lensetup = section_len - line_len;
825 doc->endsetup = position;
828 /* END Windows NT fix ###jp## */
830 /* Individual Pages */
832 if(beginsection == 0) {
833 beginsection = position;
834 section_len = line_len;
836 while(blank(line) && readline(line, sizeof line, file, &position, &line_len)) {
837 section_len += line_len;
842 while(DSCcomment(line) && iscomment(line + 2, "Page:")) {
845 doc->pages = pages_new(NULL, 0, maxpages);
847 label = get_next_text(line + length("%%Page:"), &next_char);
848 if(sscanf(next_char, "%d", &thispage) != 1)
851 ignore = thispage != 1;
853 if(!ignore && thispage != nextpage) {
859 if(doc->numpages == maxpages) {
861 doc->pages = pages_new(doc->pages, maxpages - 1, maxpages);
864 doc->pages[doc->numpages].label = label;
866 doc->pages[doc->numpages].begin = beginsection;
870 doc->pages[doc->numpages].begin = position;
871 section_len = line_len;
874 while(readline(line, sizeof line, file, &position, &line_len) &&
875 !(DSCcomment(line) &&
876 (iscomment(line + 2, "Page:") ||
877 iscomment(line + 2, "Trailer") ||
878 (respect_eof && iscomment(line + 2, "EOF"))))) {
879 section_len += line_len;
880 if(!DSCcomment(line)) {
883 else if(doc->pages[doc->numpages].orientation == NONE &&
884 iscomment(line + 2, "PageOrientation:")) {
885 sscanf(line + length("%%PageOrientation:"), "%256s", text);
886 if(strcmp(text, "Portrait") == 0) {
887 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_PORTRAIT;
889 else if(strcmp(text, "Landscape") == 0) {
890 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_LANDSCAPE;
892 else if(strcmp(text, "Seascape") == 0) {
893 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_SEASCAPE;
896 else if(doc->pages[doc->numpages].size == NULL &&
897 iscomment(line + 2, "PageMedia:")) {
898 cp = get_next_text(line + length("%%PageMedia:"), NULL);
899 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
900 if(strcmp(cp, dmp->name) == 0) {
901 doc->pages[doc->numpages].size = dmp;
907 else if(doc->pages[doc->numpages].size == NULL &&
908 iscomment(line + 2, "PaperSize:")) {
909 cp = get_next_text(line + length("%%PaperSize:"), NULL);
910 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
911 /* Note: Paper size comment uses down cased paper size
912 * name. Case insensitive compares are only used for
913 * PaperSize comments.
915 if(strcasecmp(cp, dmp->name) == 0) {
916 doc->pages[doc->numpages].size = dmp;
922 else if((page_bb_set == NONE || page_bb_set == ATEND) &&
923 iscomment(line + 2, "PageBoundingBox:")) {
924 sscanf(line + length("%%PageBoundingBox:"), "%256s", text);
925 if(strcmp(text, "(atend)") == 0) {
930 (line + length("%%PageBoundingBox:"), "%d %d %d %d",
931 &(doc->pages[doc->numpages].boundingbox[LLX]),
932 &(doc->pages[doc->numpages].boundingbox[LLY]),
933 &(doc->pages[doc->numpages].boundingbox[URX]),
934 &(doc->pages[doc->numpages].boundingbox[URY])) == 4) {
935 if(page_bb_set == NONE)
939 float fllx, flly, furx, fury;
940 if(sscanf(line + length("%%PageBoundingBox:"),
941 "%f %f %f %f", &fllx, &flly, &furx, &fury) == 4) {
942 if(page_bb_set == NONE)
944 doc->pages[doc->numpages].boundingbox[LLX] = fllx;
945 doc->pages[doc->numpages].boundingbox[LLY] = flly;
946 doc->pages[doc->numpages].boundingbox[URX] = furx;
947 doc->pages[doc->numpages].boundingbox[URY] = fury;
948 if(fllx < doc->pages[doc->numpages].boundingbox[LLX])
949 doc->pages[doc->numpages].boundingbox[LLX]--;
950 if(flly < doc->pages[doc->numpages].boundingbox[LLY])
951 doc->pages[doc->numpages].boundingbox[LLY]--;
952 if(furx > doc->pages[doc->numpages].boundingbox[URX])
953 doc->pages[doc->numpages].boundingbox[URX]++;
954 if(fury > doc->pages[doc->numpages].boundingbox[URY])
955 doc->pages[doc->numpages].boundingbox[URY]++;
961 section_len += line_len;
962 doc->pages[doc->numpages].end = position;
963 doc->pages[doc->numpages].len = section_len - line_len;
967 /* Document Trailer */
970 doc->begintrailer = beginsection;
974 doc->begintrailer = position;
975 section_len = line_len;
980 readline(line, sizeof line, file, &position, &line_len)) &&
981 !(respect_eof && DSCcomment(line) && iscomment(line + 2, "EOF"))) {
983 section_len += line_len;
985 if(!DSCcomment(line)) {
988 else if(iscomment(line + 2, "Page:")) {
989 g_free(get_next_text(line + length("%%Page:"), &next_char));
990 if(sscanf(next_char, "%d", &thispage) != 1)
992 if(!ignore && thispage == nextpage) {
993 if(doc->numpages > 0) {
994 doc->pages[doc->numpages - 1].end = position;
995 doc->pages[doc->numpages - 1].len += section_len - line_len;
999 doc->endsetup = position;
1000 doc->endsetup += section_len - line_len;
1002 else if(doc->endprolog) {
1003 doc->endprolog = position;
1004 doc->endprolog += section_len - line_len;
1010 else if(!respect_eof && iscomment(line + 2, "Trailer")) {
1011 /* What we thought was the start of the trailer was really */
1012 /* the trailer of an EPS on the page. */
1013 /* Set the end of the page to this trailer and keep scanning. */
1014 if(doc->numpages > 0) {
1015 doc->pages[doc->numpages - 1].end = position;
1016 doc->pages[doc->numpages - 1].len += section_len - line_len;
1018 doc->begintrailer = position;
1019 section_len = line_len;
1021 else if(bb_set == ATEND && iscomment(line + 2, "BoundingBox:")) {
1022 if(sscanf(line + length("%%BoundingBox:"), "%d %d %d %d",
1023 &(doc->boundingbox[LLX]),
1024 &(doc->boundingbox[LLY]),
1025 &(doc->boundingbox[URX]), &(doc->boundingbox[URY])) != 4) {
1026 float fllx, flly, furx, fury;
1027 if(sscanf(line + length("%%BoundingBox:"), "%f %f %f %f",
1028 &fllx, &flly, &furx, &fury) == 4) {
1029 doc->boundingbox[LLX] = fllx;
1030 doc->boundingbox[LLY] = flly;
1031 doc->boundingbox[URX] = furx;
1032 doc->boundingbox[URY] = fury;
1033 if(fllx < doc->boundingbox[LLX])
1034 doc->boundingbox[LLX]--;
1035 if(flly < doc->boundingbox[LLY])
1036 doc->boundingbox[LLY]--;
1037 if(furx > doc->boundingbox[URX])
1038 doc->boundingbox[URX]++;
1039 if(fury > doc->boundingbox[URY])
1040 doc->boundingbox[URY]++;
1044 else if(orientation_set == ATEND && iscomment(line + 2, "Orientation:")) {
1045 sscanf(line + length("%%Orientation:"), "%256s", text);
1046 if(strcmp(text, "Portrait") == 0) {
1047 doc->orientation = GTK_GS_ORIENTATION_PORTRAIT;
1049 else if(strcmp(text, "Landscape") == 0) {
1050 doc->orientation = GTK_GS_ORIENTATION_LANDSCAPE;
1052 else if(strcmp(text, "Seascape") == 0) {
1053 doc->orientation = GTK_GS_ORIENTATION_SEASCAPE;
1056 else if(page_order_set == ATEND && iscomment(line + 2, "PageOrder:")) {
1057 sscanf(line + length("%%PageOrder:"), "%256s", text);
1058 if(strcmp(text, "Ascend") == 0) {
1059 doc->pageorder = ASCEND;
1061 else if(strcmp(text, "Descend") == 0) {
1062 doc->pageorder = DESCEND;
1064 else if(strcmp(text, "Special") == 0) {
1065 doc->pageorder = SPECIAL;
1068 else if(pages_set == ATEND && iscomment(line + 2, "Pages:")) {
1069 if(sscanf(line + length("%%Pages:"), "%*u %d", &i) == 1) {
1070 if(page_order_set == NONE) {
1072 doc->pageorder = DESCEND;
1074 doc->pageorder = SPECIAL;
1076 doc->pageorder = ASCEND;
1081 section_len += line_len;
1082 if(DSCcomment(line) && iscomment(line + 2, "EOF")) {
1083 readline(line, sizeof line, file, &position, &line_len);
1084 section_len += line_len;
1086 doc->endtrailer = position;
1087 doc->lentrailer = section_len - line_len;
1090 section_len = line_len;
1092 while(preread || readline(line, sizeof line, file, &position, &line_len)) {
1094 section_len += line_len;
1096 if(DSCcomment(line) && iscomment(line + 2, "Page:")) {
1097 g_free(get_next_text(line + length("%%Page:"), &next_char));
1098 if(sscanf(next_char, "%d", &thispage) != 1)
1100 if(!ignore && thispage == nextpage) {
1101 if(doc->numpages > 0) {
1102 doc->pages[doc->numpages - 1].end = position;
1103 doc->pages[doc->numpages - 1].len += doc->lentrailer +
1104 section_len - line_len;
1108 doc->endsetup = position;
1109 doc->endsetup += doc->lentrailer + section_len - line_len;
1111 else if(doc->endprolog) {
1112 doc->endprolog = position;
1113 doc->endprolog += doc->lentrailer + section_len - line_len;
1125 * psfree -- free dynamic storage associated with document structure.
1130 struct document *doc;
1136 printf("This document exists\n");
1138 for(i = 0; i < doc->numpages; i++) {
1139 if(doc->pages[i].label)
1140 g_free(doc->pages[i].label);
1142 for(i = 0; i < doc->numsizes; i++) {
1143 if(doc->size[i].name)
1144 g_free(doc->size[i].name);
1159 * gettextine -- skip over white space and return the rest of the line.
1160 * If the text begins with '(' return the text string
1161 * using get_next_text().
1165 gettextline(char *line)
1169 while(*line && (*line == ' ' || *line == '\t'))
1172 return get_next_text(line, NULL);
1175 if(strlen(line) == 0)
1178 cp = g_strdup(line);
1180 /* Remove end of line */
1181 if(cp[strlen(line) - 2] == '\r' && cp[strlen(line) - 1] == '\n')
1182 /* Handle DOS \r\n */
1183 cp[strlen(line) - 2] = '\0';
1184 else if(cp[strlen(line) - 1] == '\n' || cp[strlen(line) - 1] == '\r')
1185 /* Handle mac and unix */
1186 cp[strlen(line) - 1] = '\0';
1193 * get_next_text -- return the next text string on the line.
1194 * return NULL if nothing is present.
1198 get_next_text(line, next_char)
1202 char text[PSLINELENGTH]; /* Temporary storage for text */
1206 while(*line && (*line == ' ' || *line == '\t'))
1213 while(*line && !(*line == ')' && level == 0)) {
1215 if(*(line + 1) == 'n') {
1219 else if(*(line + 1) == 'r') {
1223 else if(*(line + 1) == 't') {
1227 else if(*(line + 1) == 'b') {
1231 else if(*(line + 1) == 'f') {
1235 else if(*(line + 1) == '\\') {
1239 else if(*(line + 1) == '(') {
1243 else if(*(line + 1) == ')') {
1247 else if(*(line + 1) >= '0' && *(line + 1) <= '9') {
1248 if(*(line + 2) >= '0' && *(line + 2) <= '9') {
1249 if(*(line + 3) >= '0' && *(line + 3) <= '9') {
1251 ((*(line + 1) - '0') * 8 + *(line + 2) -
1252 '0') * 8 + *(line + 3) - '0';
1256 *cp++ = (*(line + 1) - '0') * 8 + *(line + 2) - '0';
1261 *cp++ = *(line + 1) - '0';
1270 else if(*line == '(') {
1274 else if(*line == ')') {
1284 while(*line && !(*line == ' ' || *line == '\t' || *line == '\n'))
1290 if(!quoted && strlen(text) == 0)
1292 return g_strdup(text);
1296 * readline -- Read the next line in the postscript file.
1297 * Automatically skip over data (as indicated by
1298 * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1300 * Also, skip over included documents (as indicated by
1301 * %%BeginDocument/%%EndDocument comments.)
1304 static char * readline (fd, lineP, positionP, line_lenP)
1308 unsigned int *line_lenP;
1311 #ifdef WE_MIGHT_WANT_TO_INCLUDE_THIS_NEW_READLINE
1315 readline(lineP, size, fp, positionP, line_lenP)
1320 unsigned int *line_lenP;
1322 unsigned int nbytes = 0;
1324 char text[PSLINELENGTH];
1325 char line[PSLINELENGTH];
1326 char save[PSLINELENGTH];
1333 *positionP = ftell(fp);
1334 cp = fgets(line, size, fp);
1341 *line_lenP = strlen(line);
1343 # define IS_COMMENT(comment) \
1344 (DSCcomment(line) && iscomment(line+2,(comment)))
1345 # define IS_BEGIN(comment) \
1346 (iscomment(line+7,(comment)))
1348 # define SKIP_WHILE(cond) \
1349 while (readline(line, size, fp, NULL, &nbytes) \
1350 && (cond)) *line_lenP += nbytes;\
1353 # define SKIP_UNTIL_1(comment) { \
1354 SKIP_WHILE((!IS_COMMENT(comment))) \
1356 # define SKIP_UNTIL_2(comment1,comment2) { \
1357 SKIP_WHILE((!IS_COMMENT(comment1) && !IS_COMMENT(comment2)))\
1360 if(!IS_COMMENT("Begin")) {
1363 ifIS_BEGIN("Document:") SKIP_UNTIL_1("EndDocument")
1365 ifIS_BEGIN("Feature:") SKIP_UNTIL_1("EndFeature")
1366 # ifdef USE_ACROREAD_WORKAROUND
1368 ifIS_BEGIN("File") SKIP_UNTIL_2("EndFile", "EOF")
1371 ifIS_BEGIN("File") SKIP_UNTIL_1("EndFile")
1374 ifIS_BEGIN("Font") SKIP_UNTIL_1("EndFont")
1376 ifIS_BEGIN("ProcSet") SKIP_UNTIL_1("EndProcSet")
1378 ifIS_BEGIN("Resource") SKIP_UNTIL_1("EndResource")
1380 ifIS_BEGIN("Data:") {
1382 strcpy(save, line + 7);
1383 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text)
1385 if(strcmp(text, "Lines") == 0) {
1386 for(i = 0; i < num; i++) {
1387 cp = fgets(line, size, fp);
1388 *line_lenP += cp ? strlen(line) : 0;
1392 while(num > BUFSIZ) {
1393 fread(buf, sizeof(char), BUFSIZ, fp);
1394 *line_lenP += BUFSIZ;
1397 fread(buf, sizeof(char), num, fp);
1401 SKIP_UNTIL_1("EndData")}
1403 ifIS_BEGIN("Binary:") {
1404 strcpy(save, line + 7);
1405 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1406 while(num > BUFSIZ) {
1407 fread(buf, sizeof(char), BUFSIZ, fp);
1408 *line_lenP += BUFSIZ;
1411 fread(buf, sizeof(char), num, fp);
1414 SKIP_UNTIL_1("EndBinary") * line_lenP += nbytes;
1418 *line_lenP += nbytes;
1419 strcpy(lineP, skipped_line);
1422 strcpy(lineP, line);
1430 readline(line, size, fp, position, line_len)
1435 unsigned int *line_len;
1437 char text[PSLINELENGTH]; /* Temporary storage for text */
1438 char save[PSLINELENGTH]; /* Temporary storage for text */
1441 unsigned int nbytes;
1446 *position = ftell(fp);
1447 cp = fgets(line, size, fp);
1451 line[i] != '\0' && (line[i] == 0x0c || line[i] == ' '
1452 || line[i] == '\t'); i++) ;
1453 if(i > 0 && line[i] == '%' && line[i + 1] == '%') {
1454 for(j = i; line[j] != '\0'; j++)
1455 line[j - i] = line[j];
1458 *line_len = strlen(line);
1459 if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1462 else if(iscomment(line + 7, "Document:")) {
1463 strcpy(save, line + 7);
1464 while(readline(line, size, fp, NULL, &nbytes) &&
1465 !(DSCcomment(line) && iscomment(line + 2, "EndDocument"))) {
1466 *line_len += nbytes;
1468 *line_len += nbytes;
1471 else if(iscomment(line + 7, "Feature:")) {
1472 strcpy(save, line + 7);
1473 while(readline(line, size, fp, NULL, &nbytes) &&
1474 !(DSCcomment(line) && iscomment(line + 2, "EndFeature"))) {
1475 *line_len += nbytes;
1477 *line_len += nbytes;
1480 else if(iscomment(line + 7, "File:")) {
1481 strcpy(save, line + 7);
1482 while(readline(line, size, fp, NULL, &nbytes) &&
1483 !(DSCcomment(line) && iscomment(line + 2, "EndFile"))) {
1484 *line_len += nbytes;
1486 *line_len += nbytes;
1489 else if(iscomment(line + 7, "Font:")) {
1490 strcpy(save, line + 7);
1491 while(readline(line, size, fp, NULL, &nbytes) &&
1492 !(DSCcomment(line) && iscomment(line + 2, "EndFont"))) {
1493 *line_len += nbytes;
1495 *line_len += nbytes;
1498 else if(iscomment(line + 7, "ProcSet:")) {
1499 strcpy(save, line + 7);
1500 while(readline(line, size, fp, NULL, &nbytes) &&
1501 !(DSCcomment(line) && iscomment(line + 2, "EndProcSet"))) {
1502 *line_len += nbytes;
1504 *line_len += nbytes;
1507 else if(iscomment(line + 7, "Resource:")) {
1508 strcpy(save, line + 7);
1509 while(readline(line, size, fp, NULL, &nbytes) &&
1510 !(DSCcomment(line) && iscomment(line + 2, "EndResource"))) {
1511 *line_len += nbytes;
1513 *line_len += nbytes;
1516 else if(iscomment(line + 7, "Data:")) {
1518 strcpy(save, line + 7);
1519 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text)
1521 if(strcmp(text, "Lines") == 0) {
1522 for(i = 0; i < num; i++) {
1523 cp = fgets(line, size, fp);
1524 *line_len += cp ? strlen(line) : 0;
1528 while(num > BUFSIZ) {
1529 fread(buf, sizeof(char), BUFSIZ, fp);
1530 *line_len += BUFSIZ;
1533 fread(buf, sizeof(char), num, fp);
1537 while(readline(line, size, fp, NULL, &nbytes) &&
1538 !(DSCcomment(line) && iscomment(line + 2, "EndData"))) {
1539 *line_len += nbytes;
1541 *line_len += nbytes;
1544 else if(iscomment(line + 7, "Binary:")) {
1545 strcpy(save, line + 7);
1546 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1547 while(num > BUFSIZ) {
1548 fread(buf, sizeof(char), BUFSIZ, fp);
1549 *line_len += BUFSIZ;
1552 fread(buf, sizeof(char), num, fp);
1555 while(readline(line, size, fp, NULL, &nbytes) &&
1556 !(DSCcomment(line) && iscomment(line + 2, "EndBinary"))) {
1557 *line_len += nbytes;
1559 *line_len += nbytes;
1567 * pscopy -- copy lines of Postscript from a section of one file
1569 * Automatically switch to binary copying whenever
1570 * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1571 * comments are encountered.
1575 pscopy(from, to, begin, end)
1578 long begin; /* set negative to avoid initial seek */
1581 char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
1582 char text[PSLINELENGTH]; /* Temporary storage for text */
1588 fseek(from, begin, SEEK_SET);
1589 while(ftell(from) < end) {
1590 fgets(line, sizeof line, from);
1591 gtk_gs_doc_sink_write(to, line, strlen(line));
1593 if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1596 else if(iscomment(line + 7, "Data:")) {
1598 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text) >= 1) {
1599 if(strcmp(text, "Lines") == 0) {
1600 for(i = 0; i < num; i++) {
1601 fgets(line, sizeof(line), from);
1602 gtk_gs_doc_sink_write(to, line, strlen(line));
1606 while(num > BUFSIZ) {
1607 fread(buf, sizeof(char), BUFSIZ, from);
1608 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1611 fread(buf, sizeof(char), num, from);
1612 gtk_gs_doc_sink_write(to, buf, num);
1616 else if(iscomment(line + 7, "Binary:")) {
1617 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1618 while(num > BUFSIZ) {
1619 fread(buf, sizeof(char), BUFSIZ, from);
1620 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1623 fread(buf, sizeof(char), num, from);
1624 gtk_gs_doc_sink_write(to, buf, num);
1631 * pscopyuntil -- copy lines of Postscript from a section of one file
1632 * to another file until a particular comment is reached.
1633 * Automatically switch to binary copying whenever
1634 * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1635 * comments are encountered.
1639 pscopyuntil(FILE * from, GtkGSDocSink * to, long begin, long end,
1640 const char *comment)
1642 char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
1643 char text[PSLINELENGTH]; /* Temporary storage for text */
1650 comment_length = strlen(comment);
1654 fseek(from, begin, SEEK_SET);
1656 while(ftell(from) < end && !feof(from)) {
1657 fgets(line, sizeof line, from);
1659 /* iscomment cannot be used here,
1660 * because comment_length is not known at compile time. */
1661 if(comment != NULL && strncmp(line, comment, comment_length) == 0) {
1662 return g_strdup(line);
1664 gtk_gs_doc_sink_write(to, line, strlen(line));
1665 if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1668 else if(iscomment(line + 7, "Data:")) {
1670 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text) >= 1) {
1671 if(strcmp(text, "Lines") == 0) {
1672 for(i = 0; i < num; i++) {
1673 fgets(line, sizeof line, from);
1674 gtk_gs_doc_sink_write(to, line, strlen(line));
1678 while(num > BUFSIZ) {
1679 fread(buf, sizeof(char), BUFSIZ, from);
1680 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1683 fread(buf, sizeof(char), num, from);
1684 gtk_gs_doc_sink_write(to, buf, num);
1688 else if(iscomment(line + 7, "Binary:")) {
1689 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1690 while(num > BUFSIZ) {
1691 fread(buf, sizeof(char), BUFSIZ, from);
1692 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1695 fread(buf, sizeof(char), num, from);
1696 gtk_gs_doc_sink_write(to, buf, num);
1704 * blank -- determine whether the line contains nothing but whitespace.
1712 while(*cp == ' ' || *cp == '\t')
1714 return *cp == '\n' || (*cp == '%' && (line[0] != '%' || line[1] != '%'));
1717 /*##########################################################*/
1719 /* Copy the headers, marked pages, and trailer to fp */
1720 /*##########################################################*/
1723 pscopydoc(GtkGSDocSink * dest,
1724 char *src_filename, struct document *d, gint * pagelist)
1727 char text[PSLINELENGTH];
1729 gboolean pages_written = FALSE;
1730 gboolean pages_atend = FALSE;
1736 src_file = fopen(src_filename, "r");
1739 for(i = 0; i < d->numpages; i++) {
1744 here = d->beginheader;
1746 while((comment = pscopyuntil(src_file, dest, here, d->endheader, "%%Pages:"))) {
1747 here = ftell(src_file);
1748 if(pages_written || pages_atend) {
1752 sscanf(comment + length("%%Pages:"), "%256s", text);
1753 if(strcmp(text, "(atend)") == 0) {
1754 gtk_gs_doc_sink_write(dest, comment, strlen(comment));
1758 switch (sscanf(comment + length("%%Pages:"), "%*d %d", &i)) {
1760 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d %d\n", pages, i);
1763 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d\n", pages);
1766 pages_written = TRUE;
1770 pscopyuntil(src_file, dest, d->beginpreview, d->endpreview, NULL);
1771 pscopyuntil(src_file, dest, d->begindefaults, d->enddefaults, NULL);
1772 pscopyuntil(src_file, dest, d->beginprolog, d->endprolog, NULL);
1773 pscopyuntil(src_file, dest, d->beginsetup, d->endsetup, NULL);
1775 for(i = 0; i < d->numpages; i++) {
1776 if(d->pageorder == DESCEND)
1777 j = (d->numpages - 1) - i;
1782 comment = pscopyuntil(src_file, dest,
1783 d->pages[i].begin, d->pages[i].end, "%%Page:");
1784 gtk_gs_doc_sink_printf(dest, "%%%%Page: %s %d\n",
1785 d->pages[i].label, page++);
1787 pscopyuntil(src_file, dest, -1, d->pages[i].end, NULL);
1791 here = d->begintrailer;
1792 while((comment = pscopyuntil(src_file, dest, here, d->endtrailer,
1794 here = ftell(src_file);
1799 switch (sscanf(comment + length("%%Pages:"), "%*d %d", &i)) {
1801 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d %d\n", pages, i);
1804 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d\n", pages);
1807 pages_written = TRUE;