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.
218 psscan(FILE * file, int respect_eof, const gchar * fname)
220 struct document *doc;
222 int pages_set = NONE;
223 int page_order_set = NONE;
224 int orientation_set = NONE;
225 int page_bb_set = NONE;
226 int page_size_set = NONE;
227 int preread; /* flag which tells the readline isn't needed */
229 unsigned int maxpages = 0;
230 unsigned int nextpage = 1; /* Next expected page */
231 unsigned int thispage;
232 int ignore = 0; /* whether to ignore page ordinals */
234 char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
235 char text[PSLINELENGTH]; /* Temporary storage for text */
236 long position; /* Position of the current line */
237 long beginsection; /* Position of the beginning of the section */
238 unsigned int line_len; /* Length of the current line */
239 unsigned int section_len; /* Place to accumulate the section length */
240 char *next_char; /* 1st char after text returned by get_next_text() */
243 GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
250 if(!readline(line, sizeof line, file, &position, &line_len)) {
251 g_print("psscan: empty input file.\n");
255 /* HP printer job language data follows. Some printer drivers add pjl
256 * commands to switch a pjl printer to postscript mode. If no PS header
257 * follows, this seems to be a real pjl file. */
258 if(iscomment(line, "\033%-12345X@PJL")) {
259 /* read until first DSC comment */
260 while(readline(line, sizeof line, file, &position, &line_len)
261 && (line[0] != '%')) ;
263 g_print("psscan error: input files seems to be a PJL file.\n");
268 /* Header comments */
270 /* Header should start with "%!PS-Adobe-", but some programms omit
271 * parts of this or add a ^D at the beginning. */
272 if(iscomment(line, "%!PS") || iscomment(line, "\004%!PS")) {
273 doc = g_new0(struct document, 1);
274 doc->default_page_orientation = GTK_GS_ORIENTATION_NONE;
275 doc->orientation = GTK_GS_ORIENTATION_NONE;
277 /* ignore possible leading ^D */
278 if(*line == '\004') {
283 /* Jake Hamby patch 18/3/98 */
286 sscanf(line, "%*s %256s", text);
287 /*doc->epsf = iscomment(text, "EPSF-"); */
288 doc->epsf = iscomment(text, "EPSF"); /* Hamby - This line changed */
289 doc->beginheader = position;
290 section_len = line_len;
293 /* There are postscript documents that do not have
294 %PS at the beginning, usually unstructured. We should GS decide
295 For instance, the tech reports at this university:
297 http://svrc.it.uq.edu.au/Bibliography/svrc-tr.html?94-45
299 add ugly PostScript before the actual document.
302 able to display them correctly as unstructured PS.
304 In a way, this makes sense, a program PostScript does not need
305 the !PS at the beginning.
307 /* use a test command to determine if ghostscript can
308 understand this document! */
311 test_cmd = g_strdup_printf
312 ("%s -dNOPAUSE -dBATCH -sDEVICE=nullpage %s "
313 "1>/dev/null 2>/dev/null", gtk_gs_defaults_get_interpreter_cmd(), fname);
314 if(system(test_cmd) != 0) {
319 doc = g_new0(struct document, 1);
320 doc->default_page_orientation = GTK_GS_ORIENTATION_NONE;
321 doc->orientation = GTK_GS_ORIENTATION_NONE;
326 while(preread || readline(line, sizeof line, file, &position, &line_len)) {
328 section_len += line_len;
331 iscomment(line + 1, "%EndComments") ||
332 line[1] == ' ' || line[1] == '\t' || line[1] == '\n' ||
336 else if(line[1] != '%') {
339 else if(doc->title == NULL && iscomment(line + 2, "Title:")) {
340 doc->title = gettextline(line + length("%%Title:"));
342 else if(doc->date == NULL && iscomment(line + 2, "CreationDate:")) {
343 doc->date = gettextline(line + length("%%CreationDate:"));
345 else if(bb_set == NONE && iscomment(line + 2, "BoundingBox:")) {
346 sscanf(line + length("%%BoundingBox:"), "%256s", text);
347 if(strcmp(text, "(atend)") == 0) {
351 if(sscanf(line + length("%%BoundingBox:"), "%d %d %d %d",
352 &(doc->boundingbox[LLX]),
353 &(doc->boundingbox[LLY]),
354 &(doc->boundingbox[URX]), &(doc->boundingbox[URY])) == 4)
357 float fllx, flly, furx, fury;
358 if(sscanf(line + length("%%BoundingBox:"), "%f %f %f %f",
359 &fllx, &flly, &furx, &fury) == 4) {
361 doc->boundingbox[LLX] = fllx;
362 doc->boundingbox[LLY] = flly;
363 doc->boundingbox[URX] = furx;
364 doc->boundingbox[URY] = fury;
365 if(fllx < doc->boundingbox[LLX])
366 doc->boundingbox[LLX]--;
367 if(flly < doc->boundingbox[LLY])
368 doc->boundingbox[LLY]--;
369 if(furx > doc->boundingbox[URX])
370 doc->boundingbox[URX]++;
371 if(fury > doc->boundingbox[URY])
372 doc->boundingbox[URY]++;
377 else if(orientation_set == NONE && iscomment(line + 2, "Orientation:")) {
378 sscanf(line + length("%%Orientation:"), "%256s", text);
379 if(strcmp(text, "(atend)") == 0) {
380 orientation_set = ATEND;
382 else if(strcmp(text, "Portrait") == 0) {
383 doc->orientation = GTK_GS_ORIENTATION_PORTRAIT;
386 else if(strcmp(text, "Landscape") == 0) {
387 doc->orientation = GTK_GS_ORIENTATION_LANDSCAPE;
390 else if(strcmp(text, "Seascape") == 0) {
391 doc->orientation = GTK_GS_ORIENTATION_SEASCAPE;
395 else if(page_order_set == NONE && iscomment(line + 2, "PageOrder:")) {
396 sscanf(line + length("%%PageOrder:"), "%256s", text);
397 if(strcmp(text, "(atend)") == 0) {
398 page_order_set = ATEND;
400 else if(strcmp(text, "Ascend") == 0) {
401 doc->pageorder = ASCEND;
404 else if(strcmp(text, "Descend") == 0) {
405 doc->pageorder = DESCEND;
408 else if(strcmp(text, "Special") == 0) {
409 doc->pageorder = SPECIAL;
413 else if(pages_set == NONE && iscomment(line + 2, "Pages:")) {
414 sscanf(line + length("%%Pages:"), "%256s", text);
415 if(strcmp(text, "(atend)") == 0) {
419 switch (sscanf(line + length("%%Pages:"), "%d %d", &maxpages, &i)) {
421 if(page_order_set == NONE) {
423 doc->pageorder = DESCEND;
427 doc->pageorder = SPECIAL;
431 doc->pageorder = ASCEND;
437 doc->pages = pages_new(NULL, 0, maxpages);
441 else if(doc->numsizes == NONE && iscomment(line + 2, "DocumentMedia:")) {
443 doc->size = g_new0(GtkGSPaperSize, 1);
445 get_next_text(line + length("%%DocumentMedia:"), &next_char);
446 if(doc->size[0].name != NULL) {
447 if(sscanf(next_char, "%f %f", &w, &h) == 2) {
448 doc->size[0].width = w + 0.5;
449 doc->size[0].height = h + 0.5;
451 if(doc->size[0].width != 0 && doc->size[0].height != 0)
454 g_free(doc->size[0].name);
457 while(readline(line, sizeof line, file, &position, &line_len) &&
458 DSCcomment(line) && iscomment(line + 2, "+")) {
459 section_len += line_len;
460 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
461 doc->size[doc->numsizes].name =
462 get_next_text(line + length("%%+"), &next_char);
463 if(doc->size[doc->numsizes].name != NULL) {
464 if(sscanf(next_char, "%f %f", &w, &h) == 2) {
465 doc->size[doc->numsizes].width = w + 0.5;
466 doc->size[doc->numsizes].height = h + 0.5;
468 if(doc->size[doc->numsizes].width != 0 &&
469 doc->size[doc->numsizes].height != 0)
472 g_free(doc->size[doc->numsizes].name);
475 section_len += line_len;
476 if(doc->numsizes != 0)
477 doc->default_page_size = doc->size;
479 else if(doc->numsizes == NONE && iscomment(line + 2, "DocumentPaperSizes:")) {
481 doc->size = g_new0(GtkGSPaperSize, 1);
483 get_next_text(line + length("%%DocumentPaperSizes:"), &next_char);
484 if(doc->size[0].name != NULL) {
485 doc->size[0].width = 0;
486 doc->size[0].height = 0;
487 for(dmp = papersizes; dmp->name != NULL; dmp++) {
488 /* Note: Paper size comment uses down cased paper size
489 * name. Case insensitive compares are only used for
490 * PaperSize comments.
492 if(strcasecmp(doc->size[0].name, dmp->name) == 0) {
493 g_free(doc->size[0].name);
494 doc->size[0].name = g_strdup(dmp->name);
495 doc->size[0].width = dmp->width;
496 doc->size[0].height = dmp->height;
500 if(doc->size[0].width != 0 && doc->size[0].height != 0)
503 g_free(doc->size[0].name);
505 while((cp = get_next_text(next_char, &next_char))) {
506 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
507 doc->size[doc->numsizes].name = cp;
508 doc->size[doc->numsizes].width = 0;
509 doc->size[doc->numsizes].height = 0;
510 for(dmp = papersizes; dmp->name != NULL; dmp++) {
511 /* Note: Paper size comment uses down cased paper size
512 * name. Case insensitive compares are only used for
513 * PaperSize comments.
515 if(strcasecmp(doc->size[doc->numsizes].name, dmp->name) == 0) {
516 g_free(doc->size[doc->numsizes].name);
517 doc->size[doc->numsizes].name = g_strdup(dmp->name);
518 doc->size[doc->numsizes].name = dmp->name;
519 doc->size[doc->numsizes].width = dmp->width;
520 doc->size[doc->numsizes].height = dmp->height;
524 if(doc->size[doc->numsizes].width != 0 &&
525 doc->size[doc->numsizes].height != 0)
528 g_free(doc->size[doc->numsizes].name);
531 while(readline(line, sizeof line, file, &position, &line_len) &&
532 DSCcomment(line) && iscomment(line + 2, "+")) {
533 section_len += line_len;
534 next_char = line + length("%%+");
535 while((cp = get_next_text(next_char, &next_char))) {
536 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
537 doc->size[doc->numsizes].name = cp;
538 doc->size[doc->numsizes].width = 0;
539 doc->size[doc->numsizes].height = 0;
540 for(dmp = papersizes; dmp->name != NULL; dmp++) {
541 /* Note: Paper size comment uses down cased paper size
542 * name. Case insensitive compares are only used for
543 * PaperSize comments.
545 if(strcasecmp(doc->size[doc->numsizes].name, dmp->name) == 0) {
546 doc->size[doc->numsizes].width = dmp->width;
547 doc->size[doc->numsizes].height = dmp->height;
551 if(doc->size[doc->numsizes].width != 0 &&
552 doc->size[doc->numsizes].height != 0)
555 g_free(doc->size[doc->numsizes].name);
558 section_len += line_len;
559 if(doc->numsizes != 0)
560 doc->default_page_size = doc->size;
564 if(DSCcomment(line) && iscomment(line + 2, "EndComments")) {
565 readline(line, sizeof line, file, &position, &line_len);
566 section_len += line_len;
568 doc->endheader = position;
569 doc->lenheader = section_len - line_len;
571 /* Optional Preview comments for encapsulated PostScript files */
573 beginsection = position;
574 section_len = line_len;
575 while(blank(line) && readline(line, sizeof line, file, &position, &line_len)) {
576 section_len += line_len;
579 if(doc->epsf && DSCcomment(line) && iscomment(line + 2, "BeginPreview")) {
580 doc->beginpreview = beginsection;
582 while(readline(line, sizeof line, file, &position, &line_len) &&
583 !(DSCcomment(line) && iscomment(line + 2, "EndPreview"))) {
584 section_len += line_len;
586 section_len += line_len;
587 readline(line, sizeof line, file, &position, &line_len);
588 section_len += line_len;
589 doc->endpreview = position;
590 doc->lenpreview = section_len - line_len;
593 /* Page Defaults for Version 3.0 files */
595 if(beginsection == 0) {
596 beginsection = position;
597 section_len = line_len;
599 while(blank(line) && readline(line, sizeof line, file, &position, &line_len)) {
600 section_len += line_len;
603 if(DSCcomment(line) && iscomment(line + 2, "BeginDefaults")) {
604 doc->begindefaults = beginsection;
606 while(readline(line, sizeof line, file, &position, &line_len) &&
607 !(DSCcomment(line) && iscomment(line + 2, "EndDefaults"))) {
608 section_len += line_len;
609 if(!DSCcomment(line)) {
612 else if(doc->default_page_orientation == NONE &&
613 iscomment(line + 2, "PageOrientation:")) {
614 sscanf(line + length("%%PageOrientation:"), "%256s", text);
615 if(strcmp(text, "Portrait") == 0) {
616 doc->default_page_orientation = GTK_GS_ORIENTATION_PORTRAIT;
618 else if(strcmp(text, "Landscape") == 0) {
619 doc->default_page_orientation = GTK_GS_ORIENTATION_LANDSCAPE;
621 else if(strcmp(text, "Seascape") == 0) {
622 doc->default_page_orientation = GTK_GS_ORIENTATION_SEASCAPE;
625 else if(page_size_set == NONE && iscomment(line + 2, "PageMedia:")) {
626 cp = get_next_text(line + length("%%PageMedia:"), NULL);
627 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
628 if(strcmp(cp, dmp->name) == 0) {
629 doc->default_page_size = dmp;
636 else if(page_bb_set == NONE && iscomment(line + 2, "PageBoundingBox:")) {
637 if(sscanf(line + length("%%PageBoundingBox:"), "%d %d %d %d",
638 &(doc->default_page_boundingbox[LLX]),
639 &(doc->default_page_boundingbox[LLY]),
640 &(doc->default_page_boundingbox[URX]),
641 &(doc->default_page_boundingbox[URY])) == 4)
644 float fllx, flly, furx, fury;
646 (line + length("%%PageBoundingBox:"), "%f %f %f %f",
647 &fllx, &flly, &furx, &fury) == 4) {
649 doc->default_page_boundingbox[LLX] = fllx;
650 doc->default_page_boundingbox[LLY] = flly;
651 doc->default_page_boundingbox[URX] = furx;
652 doc->default_page_boundingbox[URY] = fury;
653 if(fllx < doc->default_page_boundingbox[LLX])
654 doc->default_page_boundingbox[LLX]--;
655 if(flly < doc->default_page_boundingbox[LLY])
656 doc->default_page_boundingbox[LLY]--;
657 if(furx > doc->default_page_boundingbox[URX])
658 doc->default_page_boundingbox[URX]++;
659 if(fury > doc->default_page_boundingbox[URY])
660 doc->default_page_boundingbox[URY]++;
665 section_len += line_len;
666 readline(line, sizeof line, file, &position, &line_len);
667 section_len += line_len;
668 doc->enddefaults = position;
669 doc->lendefaults = section_len - line_len;
672 /* Document Prolog */
674 if(beginsection == 0) {
675 beginsection = position;
676 section_len = line_len;
678 while(blank(line) && readline(line, sizeof line, file, &position, &line_len)) {
679 section_len += line_len;
682 if(!(DSCcomment(line) &&
683 (iscomment(line + 2, "BeginSetup") ||
684 iscomment(line + 2, "Page:") ||
685 iscomment(line + 2, "Trailer") || iscomment(line + 2, "EOF")))) {
686 doc->beginprolog = beginsection;
691 readline(line, sizeof line, file, &position, &line_len)) &&
692 !(DSCcomment(line) &&
693 (iscomment(line + 2, "EndProlog") ||
694 iscomment(line + 2, "BeginSetup") ||
695 iscomment(line + 2, "Page:") ||
696 iscomment(line + 2, "Trailer") || iscomment(line + 2, "EOF")))) {
698 section_len += line_len;
701 section_len += line_len;
702 if(DSCcomment(line) && iscomment(line + 2, "EndProlog")) {
703 readline(line, sizeof line, file, &position, &line_len);
704 section_len += line_len;
706 doc->endprolog = position;
707 doc->lenprolog = section_len - line_len;
710 /* Document Setup, Page Defaults found here for Version 2 files */
712 if(beginsection == 0) {
713 beginsection = position;
714 section_len = line_len;
716 while(blank(line) && readline(line, sizeof line, file, &position, &line_len)) {
717 section_len += line_len;
720 if(!(DSCcomment(line) &&
721 (iscomment(line + 2, "Page:") ||
722 iscomment(line + 2, "Trailer") ||
723 (respect_eof && iscomment(line + 2, "EOF"))))) {
724 doc->beginsetup = beginsection;
728 readline(line, sizeof line, file, &position, &line_len)) &&
729 !(DSCcomment(line) &&
730 (iscomment(line + 2, "EndSetup") ||
731 iscomment(line + 2, "Page:") ||
732 iscomment(line + 2, "Trailer") ||
733 (respect_eof && iscomment(line + 2, "EOF"))))) {
735 section_len += line_len;
737 if(!DSCcomment(line)) {
740 else if(doc->default_page_orientation == NONE &&
741 iscomment(line + 2, "PageOrientation:")) {
742 sscanf(line + length("%%PageOrientation:"), "%256s", text);
743 if(strcmp(text, "Portrait") == 0) {
744 doc->default_page_orientation = GTK_GS_ORIENTATION_PORTRAIT;
746 else if(strcmp(text, "Landscape") == 0) {
747 doc->default_page_orientation = GTK_GS_ORIENTATION_LANDSCAPE;
749 else if(strcmp(text, "Seascape") == 0) {
750 doc->default_page_orientation = GTK_GS_ORIENTATION_SEASCAPE;
753 else if(page_size_set == NONE && iscomment(line + 2, "PaperSize:")) {
754 cp = get_next_text(line + length("%%PaperSize:"), NULL);
755 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
756 /* Note: Paper size comment uses down cased paper size
757 * name. Case insensitive compares are only used for
758 * PaperSize comments.
760 if(strcasecmp(cp, dmp->name) == 0) {
761 doc->default_page_size = dmp;
768 else if(page_bb_set == NONE && iscomment(line + 2, "PageBoundingBox:")) {
769 if(sscanf(line + length("%%PageBoundingBox:"), "%d %d %d %d",
770 &(doc->default_page_boundingbox[LLX]),
771 &(doc->default_page_boundingbox[LLY]),
772 &(doc->default_page_boundingbox[URX]),
773 &(doc->default_page_boundingbox[URY])) == 4)
776 float fllx, flly, furx, fury;
778 (line + length("%%PageBoundingBox:"), "%f %f %f %f",
779 &fllx, &flly, &furx, &fury) == 4) {
781 doc->default_page_boundingbox[LLX] = fllx;
782 doc->default_page_boundingbox[LLY] = flly;
783 doc->default_page_boundingbox[URX] = furx;
784 doc->default_page_boundingbox[URY] = fury;
785 if(fllx < doc->default_page_boundingbox[LLX])
786 doc->default_page_boundingbox[LLX]--;
787 if(flly < doc->default_page_boundingbox[LLY])
788 doc->default_page_boundingbox[LLY]--;
789 if(furx > doc->default_page_boundingbox[URX])
790 doc->default_page_boundingbox[URX]++;
791 if(fury > doc->default_page_boundingbox[URY])
792 doc->default_page_boundingbox[URY]++;
797 section_len += line_len;
798 if(DSCcomment(line) && iscomment(line + 2, "EndSetup")) {
799 readline(line, sizeof line, file, &position, &line_len);
800 section_len += line_len;
802 doc->endsetup = position;
803 doc->lensetup = section_len - line_len;
806 /* Added this (Nov. 2, 1999) when I noticed that
807 a Postscript file would load in gv but not in ggv
809 dmg@csg.uwaterloo.ca */
811 /* BEGIN Windows NT fix ###jp###
812 Mark Pfeifer (pfeiferm%ppddev@comet.cmis.abbott.com) told me
813 about problems when viewing Windows NT 3.51 generated postscript
814 files with gv. He found that the relevant postscript files
815 show important postscript code after the '%%EndSetup' and before
816 the first page comment '%%Page: x y'.
818 if(doc->beginsetup) {
819 while(!(DSCcomment(line) &&
820 (iscomment(line + 2, "EndSetup") ||
821 (iscomment(line + 2, "Page:") ||
822 iscomment(line + 2, "Trailer") ||
823 (respect_eof && iscomment(line + 2, "EOF"))))) &&
824 (readline(line, sizeof line, file, &position, &line_len))) {
825 section_len += line_len;
826 doc->lensetup = section_len - line_len;
827 doc->endsetup = position;
830 /* END Windows NT fix ###jp## */
832 /* Individual Pages */
834 if(beginsection == 0) {
835 beginsection = position;
836 section_len = line_len;
838 while(blank(line) && readline(line, sizeof line, file, &position, &line_len)) {
839 section_len += line_len;
844 while(DSCcomment(line) && iscomment(line + 2, "Page:")) {
847 doc->pages = pages_new(NULL, 0, maxpages);
849 label = get_next_text(line + length("%%Page:"), &next_char);
850 if(sscanf(next_char, "%d", &thispage) != 1)
853 ignore = thispage != 1;
855 if(!ignore && thispage != nextpage) {
861 if(doc->numpages == maxpages) {
863 doc->pages = pages_new(doc->pages, maxpages - 1, maxpages);
866 doc->pages[doc->numpages].label = label;
868 doc->pages[doc->numpages].begin = beginsection;
872 doc->pages[doc->numpages].begin = position;
873 section_len = line_len;
876 while(readline(line, sizeof line, file, &position, &line_len) &&
877 !(DSCcomment(line) &&
878 (iscomment(line + 2, "Page:") ||
879 iscomment(line + 2, "Trailer") ||
880 (respect_eof && iscomment(line + 2, "EOF"))))) {
881 section_len += line_len;
882 if(!DSCcomment(line)) {
885 else if(doc->pages[doc->numpages].orientation == NONE &&
886 iscomment(line + 2, "PageOrientation:")) {
887 sscanf(line + length("%%PageOrientation:"), "%256s", text);
888 if(strcmp(text, "Portrait") == 0) {
889 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_PORTRAIT;
891 else if(strcmp(text, "Landscape") == 0) {
892 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_LANDSCAPE;
894 else if(strcmp(text, "Seascape") == 0) {
895 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_SEASCAPE;
898 else if(doc->pages[doc->numpages].size == NULL &&
899 iscomment(line + 2, "PageMedia:")) {
900 cp = get_next_text(line + length("%%PageMedia:"), NULL);
901 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
902 if(strcmp(cp, dmp->name) == 0) {
903 doc->pages[doc->numpages].size = dmp;
909 else if(doc->pages[doc->numpages].size == NULL &&
910 iscomment(line + 2, "PaperSize:")) {
911 cp = get_next_text(line + length("%%PaperSize:"), NULL);
912 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
913 /* Note: Paper size comment uses down cased paper size
914 * name. Case insensitive compares are only used for
915 * PaperSize comments.
917 if(strcasecmp(cp, dmp->name) == 0) {
918 doc->pages[doc->numpages].size = dmp;
924 else if((page_bb_set == NONE || page_bb_set == ATEND) &&
925 iscomment(line + 2, "PageBoundingBox:")) {
926 sscanf(line + length("%%PageBoundingBox:"), "%256s", text);
927 if(strcmp(text, "(atend)") == 0) {
932 (line + length("%%PageBoundingBox:"), "%d %d %d %d",
933 &(doc->pages[doc->numpages].boundingbox[LLX]),
934 &(doc->pages[doc->numpages].boundingbox[LLY]),
935 &(doc->pages[doc->numpages].boundingbox[URX]),
936 &(doc->pages[doc->numpages].boundingbox[URY])) == 4) {
937 if(page_bb_set == NONE)
941 float fllx, flly, furx, fury;
942 if(sscanf(line + length("%%PageBoundingBox:"),
943 "%f %f %f %f", &fllx, &flly, &furx, &fury) == 4) {
944 if(page_bb_set == NONE)
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 < doc->pages[doc->numpages].boundingbox[LLX])
951 doc->pages[doc->numpages].boundingbox[LLX]--;
952 if(flly < doc->pages[doc->numpages].boundingbox[LLY])
953 doc->pages[doc->numpages].boundingbox[LLY]--;
954 if(furx > doc->pages[doc->numpages].boundingbox[URX])
955 doc->pages[doc->numpages].boundingbox[URX]++;
956 if(fury > doc->pages[doc->numpages].boundingbox[URY])
957 doc->pages[doc->numpages].boundingbox[URY]++;
963 section_len += line_len;
964 doc->pages[doc->numpages].end = position;
965 doc->pages[doc->numpages].len = section_len - line_len;
969 /* Document Trailer */
972 doc->begintrailer = beginsection;
976 doc->begintrailer = position;
977 section_len = line_len;
982 readline(line, sizeof line, file, &position, &line_len)) &&
983 !(respect_eof && DSCcomment(line) && iscomment(line + 2, "EOF"))) {
985 section_len += line_len;
987 if(!DSCcomment(line)) {
990 else if(iscomment(line + 2, "Page:")) {
991 g_free(get_next_text(line + length("%%Page:"), &next_char));
992 if(sscanf(next_char, "%d", &thispage) != 1)
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;
1001 doc->endsetup = position;
1002 doc->endsetup += section_len - line_len;
1004 else if(doc->endprolog) {
1005 doc->endprolog = position;
1006 doc->endprolog += section_len - line_len;
1012 else if(!respect_eof && iscomment(line + 2, "Trailer")) {
1013 /* What we thought was the start of the trailer was really */
1014 /* the trailer of an EPS on the page. */
1015 /* Set the end of the page to this trailer and keep scanning. */
1016 if(doc->numpages > 0) {
1017 doc->pages[doc->numpages - 1].end = position;
1018 doc->pages[doc->numpages - 1].len += section_len - line_len;
1020 doc->begintrailer = position;
1021 section_len = line_len;
1023 else if(bb_set == ATEND && iscomment(line + 2, "BoundingBox:")) {
1024 if(sscanf(line + length("%%BoundingBox:"), "%d %d %d %d",
1025 &(doc->boundingbox[LLX]),
1026 &(doc->boundingbox[LLY]),
1027 &(doc->boundingbox[URX]), &(doc->boundingbox[URY])) != 4) {
1028 float fllx, flly, furx, fury;
1029 if(sscanf(line + length("%%BoundingBox:"), "%f %f %f %f",
1030 &fllx, &flly, &furx, &fury) == 4) {
1031 doc->boundingbox[LLX] = fllx;
1032 doc->boundingbox[LLY] = flly;
1033 doc->boundingbox[URX] = furx;
1034 doc->boundingbox[URY] = fury;
1035 if(fllx < doc->boundingbox[LLX])
1036 doc->boundingbox[LLX]--;
1037 if(flly < doc->boundingbox[LLY])
1038 doc->boundingbox[LLY]--;
1039 if(furx > doc->boundingbox[URX])
1040 doc->boundingbox[URX]++;
1041 if(fury > doc->boundingbox[URY])
1042 doc->boundingbox[URY]++;
1046 else if(orientation_set == ATEND && iscomment(line + 2, "Orientation:")) {
1047 sscanf(line + length("%%Orientation:"), "%256s", text);
1048 if(strcmp(text, "Portrait") == 0) {
1049 doc->orientation = GTK_GS_ORIENTATION_PORTRAIT;
1051 else if(strcmp(text, "Landscape") == 0) {
1052 doc->orientation = GTK_GS_ORIENTATION_LANDSCAPE;
1054 else if(strcmp(text, "Seascape") == 0) {
1055 doc->orientation = GTK_GS_ORIENTATION_SEASCAPE;
1058 else if(page_order_set == ATEND && iscomment(line + 2, "PageOrder:")) {
1059 sscanf(line + length("%%PageOrder:"), "%256s", text);
1060 if(strcmp(text, "Ascend") == 0) {
1061 doc->pageorder = ASCEND;
1063 else if(strcmp(text, "Descend") == 0) {
1064 doc->pageorder = DESCEND;
1066 else if(strcmp(text, "Special") == 0) {
1067 doc->pageorder = SPECIAL;
1070 else if(pages_set == ATEND && iscomment(line + 2, "Pages:")) {
1071 if(sscanf(line + length("%%Pages:"), "%*u %d", &i) == 1) {
1072 if(page_order_set == NONE) {
1074 doc->pageorder = DESCEND;
1076 doc->pageorder = SPECIAL;
1078 doc->pageorder = ASCEND;
1083 section_len += line_len;
1084 if(DSCcomment(line) && iscomment(line + 2, "EOF")) {
1085 readline(line, sizeof line, file, &position, &line_len);
1086 section_len += line_len;
1088 doc->endtrailer = position;
1089 doc->lentrailer = section_len - line_len;
1092 section_len = line_len;
1094 while(preread || readline(line, sizeof line, file, &position, &line_len)) {
1096 section_len += line_len;
1098 if(DSCcomment(line) && iscomment(line + 2, "Page:")) {
1099 g_free(get_next_text(line + length("%%Page:"), &next_char));
1100 if(sscanf(next_char, "%d", &thispage) != 1)
1102 if(!ignore && thispage == nextpage) {
1103 if(doc->numpages > 0) {
1104 doc->pages[doc->numpages - 1].end = position;
1105 doc->pages[doc->numpages - 1].len += doc->lentrailer +
1106 section_len - line_len;
1110 doc->endsetup = position;
1111 doc->endsetup += doc->lentrailer + section_len - line_len;
1113 else if(doc->endprolog) {
1114 doc->endprolog = position;
1115 doc->endprolog += doc->lentrailer + section_len - line_len;
1127 * psfree -- free dynamic storage associated with document structure.
1132 struct document *doc;
1138 printf("This document exists\n");
1140 for(i = 0; i < doc->numpages; i++) {
1141 if(doc->pages[i].label)
1142 g_free(doc->pages[i].label);
1144 for(i = 0; i < doc->numsizes; i++) {
1145 if(doc->size[i].name)
1146 g_free(doc->size[i].name);
1161 * gettextine -- skip over white space and return the rest of the line.
1162 * If the text begins with '(' return the text string
1163 * using get_next_text().
1167 gettextline(char *line)
1171 while(*line && (*line == ' ' || *line == '\t'))
1174 return get_next_text(line, NULL);
1177 if(strlen(line) == 0)
1180 cp = g_strdup(line);
1182 /* Remove end of line */
1183 if(cp[strlen(line) - 2] == '\r' && cp[strlen(line) - 1] == '\n')
1184 /* Handle DOS \r\n */
1185 cp[strlen(line) - 2] = '\0';
1186 else if(cp[strlen(line) - 1] == '\n' || cp[strlen(line) - 1] == '\r')
1187 /* Handle mac and unix */
1188 cp[strlen(line) - 1] = '\0';
1195 * get_next_text -- return the next text string on the line.
1196 * return NULL if nothing is present.
1200 get_next_text(line, next_char)
1204 char text[PSLINELENGTH]; /* Temporary storage for text */
1208 while(*line && (*line == ' ' || *line == '\t'))
1215 while(*line && !(*line == ')' && level == 0)) {
1217 if(*(line + 1) == 'n') {
1221 else if(*(line + 1) == 'r') {
1225 else if(*(line + 1) == 't') {
1229 else if(*(line + 1) == 'b') {
1233 else if(*(line + 1) == 'f') {
1237 else if(*(line + 1) == '\\') {
1241 else if(*(line + 1) == '(') {
1245 else if(*(line + 1) == ')') {
1249 else if(*(line + 1) >= '0' && *(line + 1) <= '9') {
1250 if(*(line + 2) >= '0' && *(line + 2) <= '9') {
1251 if(*(line + 3) >= '0' && *(line + 3) <= '9') {
1253 ((*(line + 1) - '0') * 8 + *(line + 2) -
1254 '0') * 8 + *(line + 3) - '0';
1258 *cp++ = (*(line + 1) - '0') * 8 + *(line + 2) - '0';
1263 *cp++ = *(line + 1) - '0';
1272 else if(*line == '(') {
1276 else if(*line == ')') {
1286 while(*line && !(*line == ' ' || *line == '\t' || *line == '\n'))
1292 if(!quoted && strlen(text) == 0)
1294 return g_strdup(text);
1298 * readline -- Read the next line in the postscript file.
1299 * Automatically skip over data (as indicated by
1300 * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1302 * Also, skip over included documents (as indicated by
1303 * %%BeginDocument/%%EndDocument comments.)
1306 static char * readline (fd, lineP, positionP, line_lenP)
1310 unsigned int *line_lenP;
1313 #ifdef WE_MIGHT_WANT_TO_INCLUDE_THIS_NEW_READLINE
1317 readline(lineP, size, fp, positionP, line_lenP)
1322 unsigned int *line_lenP;
1324 unsigned int nbytes = 0;
1326 char text[PSLINELENGTH];
1327 char line[PSLINELENGTH];
1328 char save[PSLINELENGTH];
1335 *positionP = ftell(fp);
1336 cp = fgets(line, size, fp);
1343 *line_lenP = strlen(line);
1345 # define IS_COMMENT(comment) \
1346 (DSCcomment(line) && iscomment(line+2,(comment)))
1347 # define IS_BEGIN(comment) \
1348 (iscomment(line+7,(comment)))
1350 # define SKIP_WHILE(cond) \
1351 while (readline(line, size, fp, NULL, &nbytes) \
1352 && (cond)) *line_lenP += nbytes;\
1355 # define SKIP_UNTIL_1(comment) { \
1356 SKIP_WHILE((!IS_COMMENT(comment))) \
1358 # define SKIP_UNTIL_2(comment1,comment2) { \
1359 SKIP_WHILE((!IS_COMMENT(comment1) && !IS_COMMENT(comment2)))\
1362 if(!IS_COMMENT("Begin")) {
1365 ifIS_BEGIN("Document:") SKIP_UNTIL_1("EndDocument")
1367 ifIS_BEGIN("Feature:") SKIP_UNTIL_1("EndFeature")
1368 # ifdef USE_ACROREAD_WORKAROUND
1370 ifIS_BEGIN("File") SKIP_UNTIL_2("EndFile", "EOF")
1373 ifIS_BEGIN("File") SKIP_UNTIL_1("EndFile")
1376 ifIS_BEGIN("Font") SKIP_UNTIL_1("EndFont")
1378 ifIS_BEGIN("ProcSet") SKIP_UNTIL_1("EndProcSet")
1380 ifIS_BEGIN("Resource") SKIP_UNTIL_1("EndResource")
1382 ifIS_BEGIN("Data:") {
1384 strcpy(save, line + 7);
1385 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text)
1387 if(strcmp(text, "Lines") == 0) {
1388 for(i = 0; i < num; i++) {
1389 cp = fgets(line, size, fp);
1390 *line_lenP += cp ? strlen(line) : 0;
1394 while(num > BUFSIZ) {
1395 fread(buf, sizeof(char), BUFSIZ, fp);
1396 *line_lenP += BUFSIZ;
1399 fread(buf, sizeof(char), num, fp);
1403 SKIP_UNTIL_1("EndData")}
1405 ifIS_BEGIN("Binary:") {
1406 strcpy(save, line + 7);
1407 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1408 while(num > BUFSIZ) {
1409 fread(buf, sizeof(char), BUFSIZ, fp);
1410 *line_lenP += BUFSIZ;
1413 fread(buf, sizeof(char), num, fp);
1416 SKIP_UNTIL_1("EndBinary") * line_lenP += nbytes;
1420 *line_lenP += nbytes;
1421 strcpy(lineP, skipped_line);
1424 strcpy(lineP, line);
1432 readline(line, size, fp, position, line_len)
1437 unsigned int *line_len;
1439 char text[PSLINELENGTH]; /* Temporary storage for text */
1440 char save[PSLINELENGTH]; /* Temporary storage for text */
1443 unsigned int nbytes;
1448 *position = ftell(fp);
1449 cp = fgets(line, size, fp);
1453 line[i] != '\0' && (line[i] == 0x0c || line[i] == ' '
1454 || line[i] == '\t'); i++) ;
1455 if(i > 0 && line[i] == '%' && line[i + 1] == '%') {
1456 for(j = i; line[j] != '\0'; j++)
1457 line[j - i] = line[j];
1460 *line_len = strlen(line);
1461 if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1464 else if(iscomment(line + 7, "Document:")) {
1465 strcpy(save, line + 7);
1466 while(readline(line, size, fp, NULL, &nbytes) &&
1467 !(DSCcomment(line) && iscomment(line + 2, "EndDocument"))) {
1468 *line_len += nbytes;
1470 *line_len += nbytes;
1473 else if(iscomment(line + 7, "Feature:")) {
1474 strcpy(save, line + 7);
1475 while(readline(line, size, fp, NULL, &nbytes) &&
1476 !(DSCcomment(line) && iscomment(line + 2, "EndFeature"))) {
1477 *line_len += nbytes;
1479 *line_len += nbytes;
1482 else if(iscomment(line + 7, "File:")) {
1483 strcpy(save, line + 7);
1484 while(readline(line, size, fp, NULL, &nbytes) &&
1485 !(DSCcomment(line) && iscomment(line + 2, "EndFile"))) {
1486 *line_len += nbytes;
1488 *line_len += nbytes;
1491 else if(iscomment(line + 7, "Font:")) {
1492 strcpy(save, line + 7);
1493 while(readline(line, size, fp, NULL, &nbytes) &&
1494 !(DSCcomment(line) && iscomment(line + 2, "EndFont"))) {
1495 *line_len += nbytes;
1497 *line_len += nbytes;
1500 else if(iscomment(line + 7, "ProcSet:")) {
1501 strcpy(save, line + 7);
1502 while(readline(line, size, fp, NULL, &nbytes) &&
1503 !(DSCcomment(line) && iscomment(line + 2, "EndProcSet"))) {
1504 *line_len += nbytes;
1506 *line_len += nbytes;
1509 else if(iscomment(line + 7, "Resource:")) {
1510 strcpy(save, line + 7);
1511 while(readline(line, size, fp, NULL, &nbytes) &&
1512 !(DSCcomment(line) && iscomment(line + 2, "EndResource"))) {
1513 *line_len += nbytes;
1515 *line_len += nbytes;
1518 else if(iscomment(line + 7, "Data:")) {
1520 strcpy(save, line + 7);
1521 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text)
1523 if(strcmp(text, "Lines") == 0) {
1524 for(i = 0; i < num; i++) {
1525 cp = fgets(line, size, fp);
1526 *line_len += cp ? strlen(line) : 0;
1530 while(num > BUFSIZ) {
1531 fread(buf, sizeof(char), BUFSIZ, fp);
1532 *line_len += BUFSIZ;
1535 fread(buf, sizeof(char), num, fp);
1539 while(readline(line, size, fp, NULL, &nbytes) &&
1540 !(DSCcomment(line) && iscomment(line + 2, "EndData"))) {
1541 *line_len += nbytes;
1543 *line_len += nbytes;
1546 else if(iscomment(line + 7, "Binary:")) {
1547 strcpy(save, line + 7);
1548 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1549 while(num > BUFSIZ) {
1550 fread(buf, sizeof(char), BUFSIZ, fp);
1551 *line_len += BUFSIZ;
1554 fread(buf, sizeof(char), num, fp);
1557 while(readline(line, size, fp, NULL, &nbytes) &&
1558 !(DSCcomment(line) && iscomment(line + 2, "EndBinary"))) {
1559 *line_len += nbytes;
1561 *line_len += nbytes;
1569 * pscopy -- copy lines of Postscript from a section of one file
1571 * Automatically switch to binary copying whenever
1572 * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1573 * comments are encountered.
1577 pscopy(from, to, begin, end)
1580 long begin; /* set negative to avoid initial seek */
1583 char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
1584 char text[PSLINELENGTH]; /* Temporary storage for text */
1590 fseek(from, begin, SEEK_SET);
1591 while(ftell(from) < end) {
1592 fgets(line, sizeof line, from);
1593 gtk_gs_doc_sink_write(to, line, strlen(line));
1595 if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1598 else if(iscomment(line + 7, "Data:")) {
1600 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text) >= 1) {
1601 if(strcmp(text, "Lines") == 0) {
1602 for(i = 0; i < num; i++) {
1603 fgets(line, sizeof(line), from);
1604 gtk_gs_doc_sink_write(to, line, strlen(line));
1608 while(num > BUFSIZ) {
1609 fread(buf, sizeof(char), BUFSIZ, from);
1610 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1613 fread(buf, sizeof(char), num, from);
1614 gtk_gs_doc_sink_write(to, buf, num);
1618 else if(iscomment(line + 7, "Binary:")) {
1619 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1620 while(num > BUFSIZ) {
1621 fread(buf, sizeof(char), BUFSIZ, from);
1622 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1625 fread(buf, sizeof(char), num, from);
1626 gtk_gs_doc_sink_write(to, buf, num);
1633 * pscopyuntil -- copy lines of Postscript from a section of one file
1634 * to another file until a particular comment is reached.
1635 * Automatically switch to binary copying whenever
1636 * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1637 * comments are encountered.
1641 pscopyuntil(FILE * from, GtkGSDocSink * to, long begin, long end,
1642 const char *comment)
1644 char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
1645 char text[PSLINELENGTH]; /* Temporary storage for text */
1652 comment_length = strlen(comment);
1656 fseek(from, begin, SEEK_SET);
1658 while(ftell(from) < end && !feof(from)) {
1659 fgets(line, sizeof line, from);
1661 /* iscomment cannot be used here,
1662 * because comment_length is not known at compile time. */
1663 if(comment != NULL && strncmp(line, comment, comment_length) == 0) {
1664 return g_strdup(line);
1666 gtk_gs_doc_sink_write(to, line, strlen(line));
1667 if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1670 else if(iscomment(line + 7, "Data:")) {
1672 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text) >= 1) {
1673 if(strcmp(text, "Lines") == 0) {
1674 for(i = 0; i < num; i++) {
1675 fgets(line, sizeof line, from);
1676 gtk_gs_doc_sink_write(to, line, strlen(line));
1680 while(num > BUFSIZ) {
1681 fread(buf, sizeof(char), BUFSIZ, from);
1682 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1685 fread(buf, sizeof(char), num, from);
1686 gtk_gs_doc_sink_write(to, buf, num);
1690 else if(iscomment(line + 7, "Binary:")) {
1691 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1692 while(num > BUFSIZ) {
1693 fread(buf, sizeof(char), BUFSIZ, from);
1694 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1697 fread(buf, sizeof(char), num, from);
1698 gtk_gs_doc_sink_write(to, buf, num);
1706 * blank -- determine whether the line contains nothing but whitespace.
1714 while(*cp == ' ' || *cp == '\t')
1716 return *cp == '\n' || (*cp == '%' && (line[0] != '%' || line[1] != '%'));
1719 /*##########################################################*/
1721 /* Copy the headers, marked pages, and trailer to fp */
1722 /*##########################################################*/
1725 pscopydoc(GtkGSDocSink * dest,
1726 char *src_filename, struct document *d, gint * pagelist)
1729 char text[PSLINELENGTH];
1731 gboolean pages_written = FALSE;
1732 gboolean pages_atend = FALSE;
1738 src_file = fopen(src_filename, "r");
1741 for(i = 0; i < d->numpages; i++) {
1746 here = d->beginheader;
1748 while((comment = pscopyuntil(src_file, dest, here, d->endheader, "%%Pages:"))) {
1749 here = ftell(src_file);
1750 if(pages_written || pages_atend) {
1754 sscanf(comment + length("%%Pages:"), "%256s", text);
1755 if(strcmp(text, "(atend)") == 0) {
1756 gtk_gs_doc_sink_write(dest, comment, strlen(comment));
1760 switch (sscanf(comment + length("%%Pages:"), "%*d %d", &i)) {
1762 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d %d\n", pages, i);
1765 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d\n", pages);
1768 pages_written = TRUE;
1772 pscopyuntil(src_file, dest, d->beginpreview, d->endpreview, NULL);
1773 pscopyuntil(src_file, dest, d->begindefaults, d->enddefaults, NULL);
1774 pscopyuntil(src_file, dest, d->beginprolog, d->endprolog, NULL);
1775 pscopyuntil(src_file, dest, d->beginsetup, d->endsetup, NULL);
1777 for(i = 0; i < d->numpages; i++) {
1778 if(d->pageorder == DESCEND)
1779 j = (d->numpages - 1) - i;
1784 comment = pscopyuntil(src_file, dest,
1785 d->pages[i].begin, d->pages[i].end, "%%Page:");
1786 gtk_gs_doc_sink_printf(dest, "%%%%Page: %s %d\n",
1787 d->pages[i].label, page++);
1789 pscopyuntil(src_file, dest, -1, d->pages[i].end, NULL);
1793 here = d->begintrailer;
1794 while((comment = pscopyuntil(src_file, dest, here, d->endtrailer,
1796 here = ftell(src_file);
1801 switch (sscanf(comment + length("%%Pages:"), "%*d %d", &i)) {
1803 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d %d\n", pages, i);
1806 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d\n", pages);
1809 pages_written = TRUE;