1 /*========================================================================*\
2 
3 Copyright (c) 1990-2013  Paul Vojta
4 
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to
7 deal in the Software without restriction, including without limitation the
8 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 sell copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11 
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14 
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
19 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 OTHER DEALINGS IN THE SOFTWARE.
22 
23 NOTE:
24 xdvi is based on prior work, as noted in the modification history
25 in xdvi.c.
26 
27 \*========================================================================*/
28 
29 #include "xdvi-config.h"
30 #include "xdvi.h"
31 
32 #include "dvi-init.h"
33 #include "dvi-draw.h"
34 #ifdef PTEX
35 #include "ptexvf.h"
36 #include "ptexmap.h"
37 #endif
38 #include "util.h"
39 #include "x_util.h"
40 #include "exit-handlers.h"
41 #include "mime.h"
42 #include "pagesel.h"
43 #include "special.h"
44 #include "hypertex.h"
45 #include "kpathsea/c-fopen.h"
46 #include "kpathsea/c-stat.h"
47 #include "kpathsea/magstep.h"
48 #include "kpathsea/tex-glyph.h"
49 #include "dvi.h"
50 #include "string-utils.h"
51 #include "browser.h"
52 #include "sfSelFile.h"
53 #include "xm_toolbar.h"
54 #include "pagehist.h"
55 #include "message-window.h"
56 #include "search-internal.h"
57 #include "statusline.h"
58 #include "events.h"
59 #include "font-open.h"
60 #ifdef HAVE_LIBPAPER
61 #include <paper.h>
62 #endif
63 
64 #if FREETYPE
65 # include FT_SIZES_H
66 #endif
67 
68 #define	PK_PRE		247
69 #define	PK_ID		89
70 #define	PK_MAGIC	((PK_PRE << 8) | PK_ID)
71 #define	GF_PRE		247
72 #define	GF_ID		131
73 #define	GF_MAGIC	((GF_PRE << 8) | GF_ID)
74 #define	VF_PRE		247
75 #define	VF_ID_BYTE	202
76 #define	VF_MAGIC	((VF_PRE << 8) | VF_ID_BYTE)
77 #ifdef PTEX
78 #define	JFMS_MAGIC	11
79 #define	JFMS_TATEMAGIC	9
80 #endif /* PTEX */
81 
82 /* font stuff */
83 struct font *tn_table[TNTABLELEN];
84 struct font *font_head = NULL;
85 struct tn *tn_head = NULL;
86 wide_ubyte maxchar;
87 unsigned short	current_timestamp = 0;
88 
89 
90 unsigned long magnification;
91 double dimconv;
92 double tpic_conv;
93 
94 /* Curently processed page number (starting at 0). */
95 int current_page = 0;
96 int total_pages = 0;
97 
98 /* postamble offset is saved in this global variable */
99 long g_postamble_offset;
100 
101 
102 static struct stat fstatbuf;
103 
104 static FILE *m_dvi_fp = NULL; /* original user's file */
105 
106 
107 static Boolean open_dvi_file(const char *filename, Boolean open_new_instance);
108 
109 /*
110  * DVI preamble and postamble information.
111  */
112 static unsigned long numerator, denominator;
113 static unsigned int dvi_unshrunk_page_w, dvi_unshrunk_page_h;
114 static unsigned int m_paper_unshrunk_w, m_paper_unshrunk_h;
115 
116 
117 /*
118  * Offset in DVI file of last page, set in read_postamble().
119  */
120 static long m_last_page_offset;
121 
122 static const char *dvi_err_list[] = {
123     /* NO_ERROR                  */	"No Error",
124     /* WRONG_DVI_VERSION         */	"Wrong version of DVI output for this program",
125     /* DVI_CORRUPTED             */	"DVI file corrupted",
126     /* NOT_A_DVI_FILE            */	"Not a DVI file",
127     /* POSTAMBLE_NO_POST         */	"Postamble doesn't begin with POST",
128     /* POSTAMBLE_NO_MATCH        */	"Postamble doesn't match preamble",
129     /* POSTAMBLE_NON_FNTDEF      */	"Non-fntdef command found in postamble",
130     /* NOT_ALL_PIXEL_FILES_FOUND */	"Not all pixel files were found",
131     /* NO_BOP_AT_PAGEDESC        */	"Page description doesn't begin with BOP",
132     /* FILE_HAS_ZERO_SIZE        */	"File has zero size",
133     /* FILE_DOESNT_EXIST         */	"No such file",
134     /* FILE_IS_DIRECTORY         */	"Is a directory",
135     /* UNKNOWN_ERROR             */	"An unknown error occurred"
136 };
137 
138 /*
139  * access method for above list
140  */
141 const char *
get_dvi_error(dviErrFlagT flag)142 get_dvi_error(dviErrFlagT flag) {
143     ASSERT(flag < XtNumber(dvi_err_list), "Flag out of range");
144     return dvi_err_list[flag];
145 }
146 
147 
148 /*
149  * Extract the unit used in paper size specification.  This information is used
150  * to decide the initial grid separation.
151  */
152 static int
atopixunit(const char * arg)153 atopixunit(const char *arg)
154 {
155     int len = strlen(arg);
156 
157     /* check if the unit 'mm' or 'cm' occurs in the arg string */
158     return (len > 2 && (arg[len - 2] == 'c' || arg[len - 2] == 'm') && arg[len - 1] == 'm' ?
159 	    1.0 / 2.54 : 1.0) * resource.pixels_per_inch + 0.5;
160 }
161 
162 /*
163  *	free_vf_chain frees the vf_chain structure.
164  */
165 
166 static void
free_vf_chain(struct tn * tnp)167 free_vf_chain(struct tn *tnp)
168 {
169     while (tnp != NULL) {
170 	struct tn *tnp1 = tnp->next;
171 	free((char *)tnp);
172 	tnp = tnp1;
173     }
174 }
175 
176 /*
177  *	delete glyph information in a font.
178  */
179 
180 static void
delete_glyphs(struct font * fontp)181 delete_glyphs(struct font *fontp)
182 {
183     struct glyph *g;
184 #ifdef PTEX
185     int n, maxchar;
186 
187     maxchar = fontp->maxchar + 1;
188     for (n = 0; n < maxchar; ++n) {
189 	g = (fontp->flags & FONT_KANJI) ? fontp->kglyph[n] : &fontp->glyph[n];
190 	if (g == NULL) continue;
191 #else /* !PTEX */
192     for (g = fontp->glyph; g <= fontp->glyph + fontp->maxchar; ++g) {
193 #endif /* !PTEX */
194 	free_bitmap2(g);
195     }
196 }
197 
198 void free_bitmap2(struct glyph *g) {
199     {
200 	if (g->bitmap2.bits) {
201 	    free(g->bitmap2.bits);
202 	    g->bitmap2.bits = NULL;
203 	}
204 #ifdef	GREY
205 	if (g->pixmap2) {
206 	    XDestroyImage(g->image2);
207 	    g->pixmap2 = NULL;
208 	    if (g->pixmap2_gc2 != NULL) {
209 		free(g->pixmap2_gc2);
210 		g->pixmap2_gc2 = NULL;
211 	    }
212 	}
213 #if COLOR
214 	g->fg = NULL;
215 #endif
216 #endif
217     }
218 }
219 
220 /*
221  *	Release all shrunken bitmaps for all fonts.
222  */
223 
224 void
225 reset_fonts(void)
226 {
227     struct font *f;
228 
229     for (f = font_head; f != NULL; f = f->next) {
230 	if ((f->flags & FONT_LOADED) && !(f->flags & FONT_VIRTUAL)) {
231 	    delete_glyphs(f);
232 	}
233     }
234 }
235 
236 /*
237  * free up fonts no longer in use.
238  */
239 static void
240 free_unused_fonts(void)
241 {
242     struct font *fontp;
243     struct font **fontpp;
244 
245     fontpp = &font_head;
246     while ((fontp = *fontpp) != NULL) {
247 	if (fontp->flags & FONT_IN_USE)
248 	    fontpp = &fontp->next;
249 	else {
250 	    if (globals.debug & DBG_PK)
251 		printf("xdvi: Discarding font \"%s\" at %d dpi\n",
252 		       fontp->fontname, (int)(fontp->fsize + 0.5));
253 	    *fontpp = fontp->next;	/* remove from list */
254 	    free(fontp->fontname);
255 	    if (fontp->flags & FONT_LOADED) {
256 #if FREETYPE
257 		if (fontp->ft != NULL) {	/* if FreeType font */
258 		    struct ftfont *ft;
259 
260 		    ft = fontp->ft;
261 		    if (fontp->size != NULL)
262 			FT_Done_Size(fontp->size);
263 		    if (fontp == ft->first_size) {
264 			if (fontp->next_size == NULL) {
265 			    /* if this is the only size of this font face */
266 			    FT_Done_Face(ft->face);
267 			    ft->t1->ft = NULL;
268 			    free(ft);
269 			}
270 			else {
271 			    struct font	*fp2;
272 
273 			    ft->first_size = fp2 = fontp->next_size;
274 			    fp2->file = fontp->file;
275 			    fontp->file = NULL;
276 			    fp2->filename = fontp->filename;
277 			    fontp->filename = NULL;
278 			    fp2->timestamp = fontp->timestamp;
279 			}
280 		    }
281 		    else {
282 			struct font *fp2;
283 
284 			fp2 = ft->first_size;
285 			while (fp2->next_size != fontp)
286 			    fp2 = fp2->next_size;
287 			fp2->next_size = fontp->next_size;
288 		    }
289 		}
290 #endif
291 		if (fontp->file != NULL) {
292 		    fclose(fontp->file);
293 		}
294 #if FREETYPE
295 		if (fontp->filename != NULL)
296 #endif
297 		    free((char *) fontp->filename);
298 
299 		if (fontp->flags & FONT_VIRTUAL) {
300 		    struct macro *m;
301 
302 		    for (m = fontp->macro;
303 			 m <= fontp->macro + fontp->maxchar; ++m)
304 			if (m->free_me) free((char *)m->pos);
305 		    free((char *)fontp->macro);
306 		    free((char *)fontp->vf_table);
307 		    free_vf_chain(fontp->vf_chain);
308 		}
309 		else {
310 		    delete_glyphs(fontp);
311 #ifdef PTEX
312 		    if (fontp->flags & FONT_KANJI) {
313 			int n;
314 			for (n = 0; n < (int)fontp->maxchar + 1; ++n) {
315 			    if (fontp->kglyph[n] != NULL) {
316 				free(fontp->kglyph[n]);
317 			    }
318 			}
319 			free(fontp->kglyph);
320 		    }
321 		    else {
322 #endif /* PTEX */
323 		    free((char *)fontp->glyph);
324 		    fontp->glyph = NULL;
325 #ifdef PTEX
326 		    }
327 #endif /* PTEX */
328 		}
329 		free((char *)fontp);
330 	    }
331 	}
332     }
333 }
334 
335 #if COLOR
336 
337 /*
338  *	Release all allocated pixels, and (in greyscale mode) invalidate
339  *	all shrunken glyphs.
340  */
341 
342 void
343 reset_colors(void)
344 {
345     if (color_list_len != 0) {
346 	XFreeColors(DISP, G_colormap, color_list, color_list_len, 0);
347 	color_list_len = 0;
348     }
349     while (bg_head != NULL) {
350 	struct bgrec *bgp;
351 	struct fgrec *fgp;
352 
353 	for (fgp = bg_head->fg_head; fgp != NULL;) {
354 	    struct fgrec *fgp1 = fgp->next;
355 	    free(fgp);
356 	    fgp = fgp1;
357 	}
358 	bgp = bg_head->next;
359 	free(bg_head);
360 	bg_head = bgp;
361     }
362 #if GREY
363     if (resource.use_grey) {
364 	struct font *f;
365 	struct glyph *g;
366 
367 	for (f = font_head; f != NULL; f = f->next)
368 	    if ((f->flags & FONT_LOADED) && !(f->flags & FONT_VIRTUAL)
369 #ifdef PTEX
370 		&& !(f->flags & FONT_KANJI)
371 #endif /* PTEX */
372 		)
373 		for (g = f->glyph; g <= f->glyph + f->maxchar; ++g)
374 		    g->fg = NULL;
375     }
376 #endif /* GREY */
377     bg_current = NULL;
378     fg_active = NULL;
379     color_warned = False;
380 }
381 
382 /*
383  *	All of the above, plus discard all scanned information.
384  */
385 
386 void
387 full_reset_colors(void)
388 {
389     if (page_colors.stack != NULL) {
390 	size_t i;
391 	struct rgb *last_freed = &fg_initial;
392 
393 	/* fprintf(stderr, "i: %d; last freed: %p\n", page_colors.size, &fg_initial); */
394 	for (i = 0; i < page_colors.size; ++i) {
395 	    if (page_colors.stack[i].colorstack != last_freed) {
396 		last_freed = page_colors.stack[i].colorstack;
397 		/* BUG ALERT: don't free &fg_initial, else segfault with changing
398 		   foreground in xm_colorsel.c! */
399 		if (last_freed != NULL && last_freed != &fg_initial) {
400 		    /* fprintf(stderr, "freeing %d: %p\n", i, last_freed); */
401 		    free(last_freed);
402 		}
403 	    }
404 	}
405 	free(page_colors.stack);
406 	page_colors.stack = NULL;
407     }
408     reset_colors();
409 }
410 
411 #endif /* COLOR */
412 
413 
414 
415 /*
416  *	realloc_font allocates the font structure to contain (newsize + 1)
417  *	characters.
418  */
419 
420 void
421 realloc_font(struct font *fontp, wide_ubyte newsize)
422 {
423     struct glyph *glyph;
424 
425     glyph = fontp->glyph = xrealloc(fontp->glyph,
426 				    (unsigned int)(newsize + 1) * sizeof(struct glyph));
427     if (newsize > fontp->maxchar)
428 	memset((char *)(glyph + fontp->maxchar + 1), 0,
429 	       (int)(newsize - fontp->maxchar) * sizeof(struct glyph));
430     maxchar = fontp->maxchar = newsize;
431 }
432 
433 
434 /*
435  *	realloc_virtual_font does the same thing for virtual fonts.
436  */
437 
438 void
439 realloc_virtual_font(struct font *fontp, wide_ubyte newsize)
440 {
441     struct macro *macro;
442 
443     macro = fontp->macro = xrealloc(fontp->macro,
444 				    (unsigned int)(newsize + 1) * sizeof(struct macro));
445     if (newsize > fontp->maxchar)
446 	memset((char *)(macro + fontp->maxchar + 1), 0,
447 	       (int)(newsize - fontp->maxchar) * sizeof(struct macro));
448     maxchar = fontp->maxchar = newsize;
449 }
450 
451 
452 /*
453  * load_font locates the t1 font or raster file and reads the index of
454  * characters, plus whatever other preprocessing is done (depending on
455  * the format).
456  *
457  * Returns True if sucessful, False if not.
458  */
459 
460 Boolean
461 load_font(struct font *fontp
462 #if DELAYED_MKTEXPK
463 	  , Boolean load_font_now
464 #endif
465 	  )
466 {
467     double fsize = fontp->fsize;
468     int dpi = fsize + 0.5;
469     char *font_found;
470     int size_found;
471     int magic;
472     Boolean hushcs = resource.hush_chk;
473 
474     fontp->file = NULL;
475 
476     /* BUG ALERT: This used to be:
477      *
478      * if (--globals.ev.ctr == 0) {
479      *     read_events(EV_GE_IDLE);
480      * }
481      * force_statusline_update();
482      * XSync(DISP, False);
483      *
484      * The idea was to update the `loading fonts ...' popup. However,
485      * calling read_events() here may call dvi_file_changed() if the
486      * user clicks on the window, which calls file_exists_p(), and
487      * that changes m_dvi_fp while it's still being used to read the
488      * postamble (where load_font() is called from), which will cause
489      * xdvi to crash! (bug #968127).
490      *
491      * Sadly, without this update, the `loading fonts' popup doesn't
492      * appear before the main window comes up ...
493      */
494 
495 #ifdef PTEX
496     fontp->dir = 0;
497 #endif /* PTEX */
498 
499     fontp->file = font_open(
500 #if DELAYED_MKTEXPK
501 			    load_font_now,
502 #endif
503 			    fontp,
504 			    (const char **) &font_found,
505 			    &size_found);
506 
507 #if DELAYED_MKTEXPK
508     if (!load_font_now)
509 	return True;
510 #endif
511 
512 #if FREETYPE
513     if (fontp->ft != NULL) {	/* if freetype font */
514 	fontp->timestamp = ++current_timestamp;
515 	fontp->maxchar = maxchar = 255;
516 	fontp->set_char_p = set_ft_char;
517 	fontp->glyph = xmalloc (256 * sizeof (struct glyph));
518 	memset((char *) fontp->glyph, 0, 256 * sizeof (struct glyph));
519 	fontp->flags |= FONT_LOADED;
520 	if (font_found != NULL) {
521 	    statusline_error(STATUS_MEDIUM,
522 			     "Error: Can't find font %s; using %s instead. Expect ugly output.",
523 			     fontp->fontname, font_found);
524 	    force_statusline_update();
525 	    free(fontp->fontname);
526 	    fontp->fontname = font_found; /* this has been allocated by font_open */
527 	}
528 	return True;
529     }
530 #endif /* FREETYPE */
531 
532     /* when it's not a freetype font, fontp->file == NULL means total failure */
533     if (fontp->file == NULL) {
534 	if (globals.ev.flags & EV_GE_NEWDOC)
535 	    return False;
536 	fontp->flags |= FONT_LOADED;	/* as loaded as it'll get */
537 	XDVI_ERROR((stderr, "Can't find font %s.%dpk", fontp->fontname, dpi));
538 	return False;
539     }
540     fontp->flags |= FONT_LOADED;
541 
542     if (font_found != NULL && strcmp(fontp->fontname, font_found) != 0) {
543 	/* some other font used - FIXME: is there a more efficient way than strcmp() for checking this? */
544 	statusline_error(STATUS_MEDIUM,
545 			 "Can't find pixel font %s; using %s instead at %d dpi.",
546 			 fontp->fontname, font_found, dpi);
547 	force_statusline_update();
548 	free(fontp->fontname);
549 	fontp->fontname = font_found; /* this has been allocated by font_open */
550 	hushcs = True;
551     }
552     else if (!kpse_bitmap_tolerance((double)size_found, fsize)) { /* a different size used */
553 	statusline_error(STATUS_MEDIUM,
554 			 "Can't find pixel font %s at %d dpi; using %d dpi instead.",
555 			 fontp->fontname, dpi, size_found);
556 	force_statusline_update();
557     }
558 
559     /* PK version of some font found */
560     fontp->fsize = size_found;
561     fontp->timestamp = ++current_timestamp;
562     fontp->maxchar = maxchar = 255;
563 #ifdef PTEX
564     if (iskanjifont(fontp->fontname)) {
565 	fontp->flags |= FONT_KANJI;
566 	fontp->set_char_p = set_char2;
567     } else
568 #endif /* PTEX */
569     fontp->set_char_p = set_char;
570     magic = get_bytes(fontp->file, 2);
571 
572     switch(magic) {
573     case PK_MAGIC:
574 	read_PK_index(fontp, (wide_bool)hushcs);
575 	break;
576 #ifdef USE_GF
577     case GF_MAGIC:
578 	read_GF_index(fontp, (wide_bool)hushcs);
579 	break;
580 #endif
581     case VF_MAGIC:
582 	if (resource.omega)
583 	    maxchar = read_VF_index(fontp, (wide_bool)hushcs);
584 	else
585 	    (void)read_VF_index(fontp, (wide_bool)hushcs);
586 	break;
587 #ifdef PTEX
588     case JFMS_MAGIC:
589     case JFMS_TATEMAGIC:
590 	fontp->dir = (magic == JFMS_TATEMAGIC);
591 	read_PTEXVF_index(fontp);
592 	return True;
593 #endif /* PTEX */
594     default:
595 	XDVI_FATAL((stderr, "Cannot recognize format for font file %s",
596 	  fontp->filename));
597 	break;
598     }
599 
600     if (fontp->flags & FONT_VIRTUAL) {
601 	if (!resource.omega) {
602 	    while (maxchar > 0 && fontp->macro[maxchar].pos == NULL) {
603 		--maxchar;
604 	    }
605 	    if (maxchar < 255) {
606 		realloc_virtual_font(fontp, (wide_ubyte)maxchar);
607 	    }
608 	}
609     }
610     else {
611 	while (maxchar > 0 && fontp->glyph[maxchar].addr == 0)
612 	    --maxchar;
613 	if (maxchar < 255) {
614 	    realloc_font(fontp, (wide_ubyte)maxchar);
615 	}
616     }
617     return True;
618 }
619 
620 
621 /*
622  *	MAGSTEPVALUE - If the given magnification is close to a \magstep
623  *	or a \magstephalf, then return twice the number of \magsteps.
624  *	Otherwise return NOMAGSTP.
625  */
626 
627 #define	NOMAGSTP (-29999)
628 #define	NOBUILD	29999
629 
630 static int
631 magstepvalue(float *mag)
632 {
633     int m = 0;
634     double fmag = *mag;
635     double xmag = resource.pixels_per_inch;
636     float margin = fmag * 0.002;
637 
638     if (fmag < resource.pixels_per_inch)
639 	for (;;) {
640 	    if (xmag - fmag < margin && -(xmag - fmag) < margin) {
641 		*mag = xmag;
642 		return m;
643 	    }
644 	    if (xmag < fmag)
645 		break;
646 	    xmag *= 0.9128709292;
647 	    --m;
648 	}
649     else
650 	for (;;) {
651 	    if (xmag - fmag < margin && -(xmag - fmag) < margin) {
652 		*mag = xmag;
653 		return m;
654 	    }
655 	    if (xmag > fmag)
656 		break;
657 	    xmag *= 1.095445115;
658 	    ++m;
659 	}
660     return NOMAGSTP;
661 }
662 
663 /*
664  *	reuse_font recursively sets the flags for font structures being reused.
665  */
666 
667 static void
668 reuse_font(struct font *fontp)
669 {
670     struct font **fp;
671     struct tn *tnp;
672 
673     if (fontp->flags & FONT_IN_USE)
674 	return;
675 
676     fontp->flags |= FONT_IN_USE;
677     if (resource.list_fonts)
678 	printf("xdvi: (reusing) %s at %d dpi\n", fontp->fontname,
679 	       (int)(fontp->fsize + 0.5));
680     if (fontp->flags & FONT_VIRTUAL) {
681 	for (fp = fontp->vf_table; fp < fontp->vf_table + VFTABLELEN; ++fp)
682 	    if (*fp != NULL)
683 		reuse_font(*fp);
684 	for (tnp = fontp->vf_chain; tnp != NULL; tnp = tnp->next)
685 	    reuse_font(tnp->fontp);
686     }
687 }
688 
689 
690 /*
691  *      define_font reads the rest of the fntdef command and then reads in
692  *      the specified pixel file, adding it to the global linked-list holding
693  *      all of the fonts used in the job.
694  */
695 struct font *
696 define_font(
697 #if DELAYED_MKTEXPK
698 	    Boolean read_fonts,		/* reading font definitions */
699 	    Boolean initialize_fonts,	/* also initializing internal data structures for fonts */
700 #else
701 	    Boolean load_font_now,	/* only scanning, or also loading the font? */
702 #endif
703 	    FILE *file,
704 	    wide_ubyte cmnd,
705 	    struct font *vfparent,	/* vf parent of this font, or NULL */
706 	    struct font **tntable,	/* table for low TeXnumbers */
707 	    unsigned int tn_table_len,	/* length of table for TeXnumbers */
708 	    struct tn **tn_headpp,	/* addr of head of list of TeXnumbers */
709 	    Boolean *not_found_flag)	/* signal that font hasn't been found */
710 {
711     unsigned int TeXnumber;
712     struct font *fontp;
713     float fsize;
714     double scale_dimconv;
715     long checksum;
716     int scale;
717     int design;
718     int magstepval;
719     int len;
720     char *fontname;
721     int size;
722 
723     TeXnumber = get_bytes(file, (int)cmnd - FNTDEF1 + 1);
724     checksum = get_bytes(file, 4);
725     scale = get_bytes(file, 4);
726     design = get_bytes(file, 4);
727     len = get_byte(file);
728     len += get_byte(file);	/* sequence point in the middle */
729 
730 #if DELAYED_MKTEXPK
731     if (!read_fonts) {
732 	get_bytes(file, len);
733 	return NULL;
734     }
735 #else
736     if (!load_font_now)
737 	return NULL;
738 #endif
739 
740     fontname = xmalloc((unsigned)len + 1);
741     (void)fread(fontname, sizeof(char), len, file);
742     fontname[len] = '\0';
743 
744     if (globals.debug & DBG_PK)
745 	printf("xdvi: Define font \"%s\" scale=%d design=%d number=%d\n",
746 	       fontname, scale, design, TeXnumber);
747     if (vfparent == NULL) {
748 	fsize = 0.001 * scale / design * magnification * resource.pixels_per_inch;
749 	scale_dimconv = dimconv;
750     }
751     else {
752 	/*
753 	 * The scaled size is given in units of vfparent->scale * 2 ** -20
754 	 *      SPELL units, so we convert it into SPELL units by multiplying by
755 	 *              vfparent->dimconv.
756 	 *      The design size is given in units of 2 ** -20 pt, so we convert
757 	 *      into SPELL units by multiplying by
758 	 *              (resource.pixels_per_inch * 2**16) / (72.27 * 2**20).
759 	 */
760 	fsize = (72.27 * (1 << 4)) * vfparent->dimconv * scale / design;
761 	scale_dimconv = vfparent->dimconv;
762     }
763     magstepval = magstepvalue(&fsize);
764     size = fsize + 0.5;
765     /*
766      * reuse font if possible
767      */
768     for (fontp = font_head;; fontp = fontp->next) {
769 	if (fontp == NULL) {	/* if font doesn't exist yet */
770 	    if (resource.list_fonts)
771 		printf("xdvi: %s at %d dpi\n", fontname, (int)(fsize + 0.5));
772 	    fontp = xmalloc((unsigned)sizeof(struct font));
773 	    fontp->fontname = fontname;
774 	    fontp->fsize = fsize;
775 	    fontp->magstepval = magstepval;
776 	    fontp->file = NULL;		/* needed for virtual/freetype fonts */
777 	    fontp->filename = NULL;	/* needed for freetype fonts */
778 	    fontp->checksum = checksum;
779 	    fontp->flags = FONT_IN_USE;
780 	    fontp->dimconv = scale * scale_dimconv / (1 << 20);
781 	    fontp->set_char_p = load_n_set_char;
782 #if FREETYPE
783 	    fontp->ft = NULL;
784 	    /* pixsize = scaled size of the font in pixels,
785 	     *	       = scale * [vfparent->]dimconv / (1 << 16).
786 	     */
787 	    fontp->pixsize =
788 	      (vfparent != NULL ? vfparent->dimconv : dimconv) * scale
789 	      / (1 << 16);
790 #endif
791 	    if (vfparent == NULL)
792 		if (!load_font(fontp
793 #if DELAYED_MKTEXPK
794 			       , initialize_fonts
795 #endif
796 			       )) {
797 		    if (globals.ev.flags & EV_GE_NEWDOC) {	/* if aborting */
798 			free(fontname);
799 			free(fontp);
800 			return NULL;
801 		    }
802 		    *not_found_flag = True;
803 		}
804 	    fontp->next = font_head;
805 	    font_head = fontp;
806 	    break;
807 	}
808 	if (strcmp(fontname, fontp->fontname) == 0
809 	    && size == (int)(fontp->fsize + 0.5)) {
810 	    /* if font already in use */
811 	    reuse_font(fontp);
812 	    free(fontname);
813 	    break;
814 	}
815     }
816     if (TeXnumber < tn_table_len)
817 	tntable[TeXnumber] = fontp;
818     else {
819 	struct tn *tnp;
820 	tnp = xmalloc((unsigned)sizeof(struct tn));
821 	tnp->next = *tn_headpp;
822 	*tn_headpp = tnp;
823 	tnp->TeXnumber = TeXnumber;
824 	tnp->fontp = fontp;
825     }
826     return fontp;
827 }
828 
829 
830 
831 /*
832  *      process_preamble reads the information in the preamble and stores
833  *      it into global variables for later use.
834  */
835 Boolean
836 process_preamble(FILE *fp, dviErrFlagT *errflag)
837 {
838     ubyte k;
839     static char job_id[300];
840 
841     TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d", (void *)fp, *errflag));
842 
843     if (get_byte(fp) != PRE) {
844 	*errflag = NOT_A_DVI_FILE;
845 	TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning False", (void *)fp, *errflag));
846 	return False;
847     }
848 #ifdef PTEX
849     k = get_byte(fp);
850     if (k != 2 && k != 3)
851 #else /* !PTEX */
852     if (get_byte(fp) != 2)
853 #endif /* !PTEX */
854     {
855 	*errflag = WRONG_DVI_VERSION;
856 	TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning False", (void *)fp, *errflag));
857 	return False;
858     }
859     numerator = get_bytes(fp, 4);
860     denominator = get_bytes(fp, 4);
861     magnification = get_bytes(fp, 4);
862     dimconv = (((double)numerator * magnification)
863 	       / ((double)denominator * 1000.));
864     dimconv = dimconv * (((long)resource.pixels_per_inch) << 16) / 254000;
865     tpic_conv = resource.pixels_per_inch * magnification / 1000000.0;
866     k = get_byte(fp);
867     (void)fread(job_id, sizeof(char), (int)k, fp);
868     job_id[k] = '\0';
869 
870     TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning True", (void *)fp, *errflag));
871 
872     return True;
873 }
874 
875 /*
876  *      find_postamble locates the beginning of the postamble
877  *	and leaves the file ready to start reading at that location.
878  */
879 #define	TMPSIZ	516	/* 4 trailer bytes + 512 junk bytes allowed */
880 Boolean
881 find_postamble(FILE *fp, dviErrFlagT *errflag)
882 {
883     long pos;
884     ubyte temp[TMPSIZ];
885     ubyte *p;
886     ubyte *p1;
887     ubyte byte;
888 
889     TRACE_FILES((stderr, "find_postamble on fp: %p", (void *)fp));
890 
891     fseek(fp, 0L, SEEK_END);
892     pos = ftell(fp) - TMPSIZ;
893     if (pos < 0)
894 	pos = 0;
895     fseek(fp, pos, SEEK_SET);
896     p = temp + fread((char *)temp, sizeof(char), TMPSIZ, fp);
897     for (;;) {
898 	p1 = p;
899 	while (p1 > temp && *(--p1) != TRAILER);
900 	p = p1;
901 	while (p > temp && *(--p) == TRAILER);
902 	if (p <= p1 - 4)
903 	    break;	/* found 4 TRAILER bytes */
904 	if (p <= temp) {
905 	    *errflag = DVI_CORRUPTED;
906 	    TRACE_FILES((stderr, "find_postamble: returning FALSE"));
907 	    return False;
908 	}
909     }
910     pos += p - temp;
911     byte = *p;
912     while (byte == TRAILER) {
913 	fseek(fp, --pos, SEEK_SET);
914 	byte = get_byte(fp);
915     }
916 #ifdef PTEX
917     if (byte != 2 && byte != 3)
918 #else /* !PTEX */
919     if (byte != 2)
920 #endif /* !PTEX */
921     {
922 	*errflag = WRONG_DVI_VERSION;
923 	TRACE_FILES((stderr, "find_postamble: returning FALSE"));
924 	return False;
925     }
926     fseek(fp, pos - 4, SEEK_SET);
927     fseek(fp, get_lbytes(fp, 4), SEEK_SET);
928     TRACE_FILES((stderr, "find_postamble: returning TRUE"));
929     return True;
930 }
931 
932 
933 
934 Boolean
935 set_paper_type(const char *arg)
936 {
937     const char *arg1;
938     char temp[21];
939     const char **p;
940     char *q;
941 #ifdef HAVE_LIBPAPER
942     const struct paper *pp;
943     int landscape = 0;
944 #else
945     const char **paper_types = get_paper_types();
946     size_t paper_types_size = get_paper_types_size();
947 #endif
948 
949     if (*arg == '+') {
950 	++arg;
951 	ignore_papersize_specials = True;
952     }
953     if (strlen(arg) > sizeof(temp) - 1)
954 	return False;
955     q = temp;
956     for (;;) {	/* convert to lower case */
957 	char c = *arg++;
958 	if (c >= 'A' && c <= 'Z')
959 	    c ^= ('a' ^ 'A');
960 	*q++ = c;
961 	if (c == '\0')
962 	    break;
963     }
964     arg = temp;
965 #ifdef HAVE_LIBPAPER
966     paperinit();
967     if (strcmp(temp, "libpaper") == 0) {
968 	const char *name;
969 
970 	name = systempapername();
971 	if (name == NULL)
972 		name = defaultpapername();
973 	if (strcmp(name, "libpaper") == 0)
974 		name = "a4";
975 
976 	strncpy(temp, name, sizeof(temp));
977 	temp[sizeof(temp) - 1] = '\0';
978     }
979     if (strcmp(temp, "letter") != 0 &&
980 	strcmp(temp, "ledger") != 0) {
981 	if (temp[strlen(temp) - 1] == 'r') {
982 		temp[strlen(temp) - 1] = '\0';
983 		landscape = 1;
984 	}
985     }
986     for (pp = paperfirst(); pp; pp = papernext(pp)) {
987 	if (strcmp(temp, papername(pp)) == 0) {
988 		double w, h;
989 		char wstr[256];
990 		char hstr[256];
991 
992 		if (landscape == 0) {
993 			w = paperpswidth(pp);
994 			h = paperpsheight(pp);
995 		} else {
996 			h = paperpswidth(pp);
997 			w = paperpsheight(pp);
998 		}
999 		w = w / 72.0 * 10 * 2.54;
1000 		h = h / 72.0 * 10 * 2.54;
1001 		snprintf(wstr, sizeof(wstr), "%f mm", w);
1002 		snprintf(hstr, sizeof(hstr), "%f mm", h);
1003 		wstr[sizeof(wstr) - 1] = '\0';
1004 		hstr[sizeof(hstr) - 1] = '\0';
1005 		m_paper_unshrunk_w = atopix(wstr, False);
1006 		m_paper_unshrunk_h = atopix(hstr, False);
1007     		globals.grid_paper_unit = atopixunit("mm");
1008 
1009 		break;
1010 	}
1011     }
1012     paperdone();
1013     if (pp == NULL)
1014 	return (False);
1015 #else
1016     /* perform substitutions */
1017     for (p = paper_types; p < paper_types + paper_types_size; p += 2) {
1018 	if (strcmp(temp, *p) == 0) {
1019 	    arg = p[1];
1020 	    break;
1021 	}
1022     }
1023     arg1 = strchr(arg, 'x');
1024     if (arg1 == NULL)
1025 	return False;
1026     m_paper_unshrunk_w = atopix(arg, False);
1027     m_paper_unshrunk_h = atopix(arg1 + 1, False);
1028 
1029     globals.grid_paper_unit = atopixunit(arg);
1030 #endif
1031 
1032     return (m_paper_unshrunk_w != 0 && m_paper_unshrunk_h != 0);
1033 }
1034 
1035 /*
1036  *      read_postamble reads the information in the postamble from fp,
1037  *	storing it into global variables.
1038  *      It also takes care of reading in all of the pixel files for the fonts
1039  *      used in the job.
1040  *
1041  *	FIXME: Would be better (speed up initialization when needing to generate fonts,
1042  *	and allow to open window on first page) if the font loading was done on-demand later!
1043  */
1044 Boolean
1045 read_postamble(FILE *fp, dviErrFlagT *errflag,
1046 #if DELAYED_MKTEXPK
1047 	       Boolean read_fonts, Boolean initialize_fonts
1048 #else
1049 	       Boolean load_fonts
1050 #endif
1051 	       )
1052 {
1053     ubyte cmnd;
1054     Boolean font_not_found = False;
1055     struct font	*fontp;
1056 
1057 #if DELAYED_MKTEXPK
1058     int tmp_total_pages;
1059     unsigned long tmp_numerator = numerator;
1060     unsigned long tmp_denominator = denominator;
1061     unsigned long tmp_magnification = magnification;
1062     unsigned int tmp_dvi_unshrunk_page_w, tmp_dvi_unshrunk_page_h;
1063     long tmp_last_page_offset;
1064 
1065     TRACE_FILES((stderr, "read_postamble: reading %p (%d, %d)", (void *)fp, read_fonts, initialize_fonts));
1066 
1067     if (read_fonts && initialize_fonts) {
1068 	/* clear existing font table */
1069 	memset((char *)tn_table, 0, (int)sizeof tn_table);
1070 	free_vf_chain(tn_head);
1071 	tn_head = NULL;
1072 	for (fontp = font_head; fontp != NULL; fontp = fontp->next)
1073 	    fontp->flags &= ~FONT_IN_USE;
1074     }
1075 #else /* DELAYED_MKTEXPK */
1076     TRACE_FILES((stderr, "read_postamble: reading %p (%d)", (void *)fp, load_fonts));
1077 
1078     /* clear existing font table */
1079     memset((char *)tn_table, 0, (int)sizeof tn_table);
1080     free_vf_chain(tn_head);
1081     tn_head = NULL;
1082     for (fontp = font_head; fontp != NULL; fontp = fontp->next)
1083 	fontp->flags &= ~FONT_IN_USE;
1084 #endif /* DELAYED_MKTEXPK */
1085 
1086     if (get_byte(fp) != POST) {
1087 	*errflag = POSTAMBLE_NO_POST;
1088 	TRACE_FILES((stderr, "read_postamble: returning FALSE"));
1089 	return False;
1090     }
1091 #if DELAYED_MKTEXPK
1092     tmp_last_page_offset = get_bytes(fp, 4);
1093     if (read_fonts && initialize_fonts)
1094 	m_last_page_offset = tmp_last_page_offset;
1095 
1096     if (tmp_numerator != get_bytes(fp, 4)
1097 	|| tmp_denominator != get_bytes(fp, 4)
1098 	|| tmp_magnification != get_bytes(fp, 4)) {
1099 	*errflag = POSTAMBLE_NO_MATCH;
1100 	TRACE_FILES((stderr, "read_postamble: returning FALSE"));
1101 	return False;
1102     }
1103     else if (read_fonts && initialize_fonts) {
1104 	numerator = tmp_numerator;
1105 	denominator = tmp_denominator;
1106 	magnification = tmp_magnification;
1107     }
1108 
1109     /* read largest box height and width */
1110     tmp_dvi_unshrunk_page_h = (spell_conv(get_lbytes(fp, 4)) >> 16) + resource.yoffset_int;
1111     tmp_dvi_unshrunk_page_w = (spell_conv(get_lbytes(fp, 4)) >> 16) + resource.xoffset_int;
1112     (void)get_bytes(fp, 2);	/* max stack size */
1113     tmp_total_pages = get_bytes(fp, 2);
1114 
1115     if (read_fonts && initialize_fonts) {
1116 	dvi_unshrunk_page_h = tmp_dvi_unshrunk_page_h;
1117 	if (dvi_unshrunk_page_h < m_paper_unshrunk_h)
1118 	    dvi_unshrunk_page_h = m_paper_unshrunk_h;
1119 	dvi_unshrunk_page_w = tmp_dvi_unshrunk_page_w;
1120 	if (dvi_unshrunk_page_w < m_paper_unshrunk_w)
1121 	    dvi_unshrunk_page_w = m_paper_unshrunk_w;
1122 	total_pages = tmp_total_pages;
1123     }
1124 #else /* DELAYED_MKTEXPK */
1125     m_last_page_offset = get_bytes(fp, 4);
1126     if (numerator != get_bytes(fp, 4)
1127 	|| denominator != get_bytes(fp, 4)
1128 	|| magnification != get_bytes(fp, 4)) {
1129 	*errflag = POSTAMBLE_NO_MATCH;
1130 	TRACE_FILES((stderr, "read_postamble: returning FALSE"));
1131 	return False;
1132     }
1133 
1134     /* read largest box height and width */
1135     dvi_unshrunk_page_h = (spell_conv(get_lbytes(fp, 4)) >> 16) + resource.yoffset_int;
1136     if (dvi_unshrunk_page_h < m_paper_unshrunk_h)
1137 	dvi_unshrunk_page_h = m_paper_unshrunk_h;
1138     dvi_unshrunk_page_w = (spell_conv(get_lbytes(fp, 4)) >> 16) + resource.xoffset_int;
1139     if (dvi_unshrunk_page_w < m_paper_unshrunk_w)
1140 	dvi_unshrunk_page_w = m_paper_unshrunk_w;
1141     (void)get_bytes(fp, 2);	/* max stack size */
1142     total_pages = get_bytes(fp, 2);
1143 #endif /* DELAYED_MKTEXPK */
1144 
1145     /* read font definitions */
1146     while ((cmnd = get_byte(fp)) >= FNTDEF1 && cmnd <= FNTDEF4) {
1147 	struct font *f = define_font(
1148 #if DELAYED_MKTEXPK
1149 				     read_fonts, initialize_fonts,
1150 #else
1151 				     load_fonts,
1152 #endif
1153 				     fp, cmnd, (struct font *)NULL, tn_table,
1154 				     TNTABLELEN, &tn_head, &font_not_found);
1155 	if (
1156 #if DELAYED_MKTEXPK
1157 	    read_fonts && initialize_fonts
1158 #else
1159 	    load_fonts
1160 #endif
1161 	    && f == NULL) {
1162 	    TRACE_FILES((stderr, "read_postamble: returning FALSE"));
1163 	    return False;
1164 	}
1165 #if !DELAYED_MKTEXPK
1166 	else if (!load_fonts) { /* return early */
1167 	    TRACE_FILES((stderr, "read_postamble: returning TRUE"));
1168 	    return True;
1169 	}
1170 #endif
1171     }
1172 
1173     if (cmnd != POSTPOST) {
1174 	*errflag = POSTAMBLE_NON_FNTDEF;
1175 	TRACE_FILES((stderr, "read_postamble: returning FALSE"));
1176 	return False;
1177     }
1178     if (
1179 #if DELAYED_MKTEXPK
1180 	read_fonts && initialize_fonts &&
1181 #endif
1182 	font_not_found) {
1183 	*errflag = NOT_ALL_PIXEL_FILES_FOUND;
1184 	TRACE_FILES((stderr, "read_postamble: returning FALSE"));
1185 	return False;
1186     }
1187 #if DELAYED_MKTEXPK
1188     if (read_fonts && initialize_fonts)
1189 	free_unused_fonts();
1190 #else
1191     free_unused_fonts();
1192 #endif
1193 
1194     TRACE_FILES((stderr, "read_postamble: returning TRUE"));
1195     return True;
1196 }
1197 
1198 
1199 static Boolean
1200 prepare_pages(dviErrFlagT *errflag)
1201 {
1202     int i;
1203     long offset;
1204 
1205     TRACE_FILES((stderr, "calling pageinfo_deallocate"));
1206     pageinfo_deallocate();
1207 
1208     TRACE_FILES((stderr, "pageinfo_allocate for %d pages", total_pages + 1));
1209     pageinfo_allocate(total_pages + 1);
1210     pageinfo_set_page_width(total_pages, m_paper_unshrunk_w);
1211     pageinfo_set_page_height(total_pages, m_paper_unshrunk_h);
1212     pageinfo_set_window_width(total_pages, dvi_unshrunk_page_w);
1213     pageinfo_set_window_height(total_pages, dvi_unshrunk_page_h);
1214 
1215     pageinfo_set_offset(total_pages - 1, m_last_page_offset);
1216     /*
1217      * Follow back pointers through pages in the DVI file,
1218      * storing the offsets in the pageinfo table.
1219      */
1220     for (offset = m_last_page_offset, i = total_pages; i > 0; i--) {
1221 	fseek(globals.dvi_file.bak_fp, offset, SEEK_SET);
1222 	if (get_byte(globals.dvi_file.bak_fp) != BOP) {
1223 	    *errflag = NO_BOP_AT_PAGEDESC;
1224 	    return False;
1225 	}
1226 	pageinfo_set_offset(i-1, offset);
1227 	/* from c_0, read count0, the TeX page number */
1228 	pageinfo_set_number(i-1, get_bytes(globals.dvi_file.bak_fp, 4));
1229 
1230 	/* skip c_1 to c_9 */
1231 	fseek(globals.dvi_file.bak_fp, 9*4L, SEEK_CUR);
1232 
1233 	/* next 4 byte contain offset to previous bop */
1234 	offset = get_bytes(globals.dvi_file.bak_fp, 4);
1235     }
1236     /* If not prescanning, initialize page sizes.  */
1237     if (!resource.prescan) {
1238 	for (i = 0; i < total_pages; ++i) {
1239 	    pageinfo_set_page_width(i, m_paper_unshrunk_w);
1240 	    pageinfo_set_page_height(i, m_paper_unshrunk_h);
1241 	    pageinfo_set_window_width(i, dvi_unshrunk_page_w);
1242 	    pageinfo_set_window_height(i, dvi_unshrunk_page_h);
1243 	}
1244     }
1245     return True;
1246 }
1247 
1248 void
1249 init_page(void)
1250 {
1251     if (globals.dvi_file.bak_fp == NULL)
1252 	return;
1253     globals.page.unshrunk_w = pageinfo_get_page_width(current_page);
1254     globals.page.unshrunk_h = pageinfo_get_page_height(current_page);
1255     globals.page.w = ROUNDUP(globals.page.unshrunk_w, mane.shrinkfactor) + 2;
1256     globals.page.h = ROUNDUP(globals.page.unshrunk_h, mane.shrinkfactor) + 2;
1257     TRACE_FILES((stderr, "init_page: setting globals.page.w = %d, globals.page.h = %d", globals.page.w, globals.page.h));
1258 }
1259 
1260 #ifndef	S_ISDIR
1261 #define	S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
1262 #endif
1263 
1264 static char *m_tmp_dvi_name = NULL; /* name of backup file for useTempFp */
1265 
1266 /* access function for backup file name */
1267 char *get_tmp_dvi_name(void) {
1268     return m_tmp_dvi_name;
1269 }
1270 
1271 static void
1272 remove_tmp_dvi_file(void *dummy)
1273 {
1274     UNUSED(dummy);
1275     if (m_tmp_dvi_name != NULL) {
1276 	unlink(m_tmp_dvi_name);
1277 	free(m_tmp_dvi_name);
1278     }
1279     m_tmp_dvi_name = NULL;
1280 }
1281 
1282 
1283 static FILE *
1284 make_backup_fp(FILE *source_fp, FILE *target_fp)
1285 {
1286     static Boolean first_time = True;
1287     static int tmp_fd = 0;
1288 
1289 #if !HAVE_FTRUNCATE
1290     /* in this case, we can't use ftruncate() on the existing temp file -
1291        just close the existing one, and set flag to open a new one */
1292     remove_tmp_dvi_file(NULL);
1293     if (target_fp != NULL)
1294 	fclose(target_fp);
1295     /* make sure we use a new temp file, else we'd have a race condition
1296        after closing it */
1297     first_time = True;
1298 #endif
1299 
1300     if (first_time) { /* doesn't exist yet, create it */
1301 	if ((tmp_fd = xdvi_temp_fd(&m_tmp_dvi_name)) == -1) {
1302 	    XDVI_ERROR((stderr, "error creating temporary file - disabling `useTempFp'."));
1303 	    resource.use_temp_fp = False;
1304 	    remove_tmp_dvi_file(NULL);
1305 	    return NULL;
1306 	}
1307 	/* 	fprintf(stderr, "temporary file name: |%s|, %d\n", m_tmp_dvi_name, tmp_fd); */
1308 	TRACE_EVENTS((stderr, "Created temp file: |%s|\n", m_tmp_dvi_name));
1309 	if ((target_fp = try_fdopen(tmp_fd, "wb+")) == NULL) {
1310 	    XDVI_ERROR((stderr, "error opening temporary file (%s) - disabling `useTempFp'.", strerror(errno)));
1311 	    resource.use_temp_fp = False;
1312 	    remove_tmp_dvi_file(NULL);
1313 	    return NULL;
1314 	}
1315 	first_time = False;
1316     }
1317     else { /* if not first time, truncate the existing file,
1318 	      and position both files at beginning */
1319 	ASSERT(target_fp != NULL, "");
1320 	ASSERT(source_fp != NULL, "");
1321 
1322 #if HAVE_FTRUNCATE
1323 	if (ftruncate(tmp_fd, 0) < 0) {
1324 
1325 	    XDVI_ERROR((stderr, "Couldn't truncate file %s: %s - disabling `useTempFp'; target_fp: %p.",
1326 			m_tmp_dvi_name, strerror(errno), target_fp));
1327 	    resource.use_temp_fp = False;
1328 	    remove_tmp_dvi_file(NULL);
1329 	    fclose(target_fp);
1330 	    return NULL;
1331 	}
1332 #endif
1333 	fseek(target_fp, 0L, SEEK_SET);
1334 	fseek(source_fp, 0L, SEEK_SET);
1335     }
1336 
1337     /* copy the file */
1338     if (!copy_fp(source_fp, target_fp)) {
1339 	XDVI_ERROR((stderr,
1340 		    "Error creating temporary file: %s\n"
1341 		    "- disabling `useTempFp'.",
1342 		    strerror(errno)));
1343 	remove_tmp_dvi_file(NULL);
1344 	resource.use_temp_fp = False;
1345 	fclose(target_fp);
1346 	target_fp = NULL;
1347     }
1348 
1349     /* rewind both files, else DVI parsing will fail! */
1350     if (target_fp != NULL) {
1351 	fflush(target_fp);
1352     }
1353     fseek(source_fp, 0L, SEEK_SET);
1354     if (target_fp != NULL) {
1355 	fseek(target_fp, 0L, SEEK_SET);
1356     }
1357 
1358     return target_fp;
1359 }
1360 
1361 static Boolean
1362 file_exists_p(const char *path, dviErrFlagT *errflag)
1363 {
1364     TRACE_FILES((stderr, "file_exists_p for |%s|", path));
1365     *errflag = UNKNOWN_ERROR;
1366     if ((m_dvi_fp = XFOPEN(path, OPEN_MODE)) == NULL) {
1367 	/*  	fprintf(stderr, "after internal_open_dvi1: xfopen\n"); */
1368 	*errflag = FILE_DOESNT_EXIST;
1369 	return False;
1370     }
1371     TRACE_FILES((stderr, "m_dvi_fp for |%s| = %p", path, (void *)m_dvi_fp));
1372     /*      fprintf(stderr, "after internal_open_dvi2: xfopen\n"); */
1373 
1374     /* shouldn't happen */
1375     if (fstat(fileno(m_dvi_fp), &fstatbuf) != 0 || S_ISDIR(fstatbuf.st_mode)) {	/* if it's a directory */
1376 	*errflag = FILE_IS_DIRECTORY;
1377 	fclose(m_dvi_fp);
1378 	m_dvi_fp = NULL;
1379 	return False;
1380     }
1381     /* If file has zero size, something has gone wrong with downloading
1382        it, and the user should already have been warned about that;
1383        just return in this case.
1384        TODO: can it still happen that we try to load such a file as .dvi
1385        file? (Will exit  with `draw_part: unknown op-code xyz' or some such).
1386        In this case, it would be better to look at the preamble before
1387        entering the drawing loop.
1388     */
1389     if (fstatbuf.st_size == 0) {
1390 	*errflag = FILE_HAS_ZERO_SIZE;
1391 	fclose(m_dvi_fp);
1392 	m_dvi_fp = NULL;
1393 	return False;
1394     }
1395     return True;
1396 }
1397 
1398 /*
1399  *	internal_init_dvi is the main subroutine for reading the startup
1400  *	information from the dvi file.
1401  */
1402 
1403 static Boolean
1404 internal_init_dvi(dviErrFlagT *errflag,
1405 #if DELAYED_MKTEXPK
1406 		  Boolean read_fonts, Boolean initialize_fonts
1407 #else
1408 		  Boolean load_fonts
1409 #endif
1410 		  )
1411 {
1412     char *icon_name = NULL, *title_name = NULL;
1413 
1414     have_src_specials = False;
1415 
1416     TRACE_FILES((stderr, "internal_init_dvi, globals.dvi_file.bak_fp = %p", (void *)globals.dvi_file.bak_fp));
1417 
1418     if (!process_preamble(globals.dvi_file.bak_fp, errflag)
1419 	|| !find_postamble(globals.dvi_file.bak_fp, errflag)
1420 #if DELAYED_MKTEXPK
1421 	|| !read_postamble(globals.dvi_file.bak_fp, errflag, read_fonts, initialize_fonts)
1422 #else
1423 	|| !read_postamble(globals.dvi_file.bak_fp, errflag, load_fonts)
1424 	|| !prepare_pages(errflag)
1425 #endif
1426 	) {
1427 	return False;
1428     }
1429 #if DELAYED_MKTEXPK
1430     if (!read_fonts || !initialize_fonts) /* return early */
1431 	return True;
1432 
1433     if (!prepare_pages(errflag))
1434 	return False;
1435 #endif
1436 
1437     if (current_page >= total_pages)
1438 	current_page = total_pages - 1;
1439 
1440     globals.warn_spec_now = resource.warn_spec;
1441     globals.src.fwd_box_page = -1;
1442     search_reset_info();
1443 
1444     if (globals.pausing.num_save != NULL) {
1445 	free(globals.pausing.num_save);
1446 	globals.pausing.num_save = NULL;
1447     }
1448     if (resource.pause && total_pages > 0) {
1449 	globals.pausing.num_save = xmalloc(total_pages * sizeof *globals.pausing.num_save);
1450 	memset(globals.pausing.num_save, 0, total_pages * sizeof *globals.pausing.num_save);
1451     }
1452 
1453     init_prescan();
1454     /* this allocates icon_name and title_name */
1455     get_icon_and_title(globals.dvi_name, &icon_name, &title_name);
1456     set_icon_and_title(icon_name, title_name);
1457     free(icon_name);
1458     free(title_name);
1459     icon_name = title_name = NULL;
1460 
1461 #if defined(MOTIF) && HAVE_XPM
1462     tb_check_navigation_sensitivity(current_page);
1463 #endif
1464     refresh_pagelist(total_pages, current_page);
1465 
1466     return True;
1467 }
1468 
1469 /*
1470  *	internal_open_dvi does the real opening of the dvi file, and sets
1471  *	globals.dvi_file.time.  It returns True on success, and sets m_dvi_fp and globals.dvi_file.bak_fp.
1472  */
1473 
1474 Boolean
1475 internal_open_dvi(const char *path, dviErrFlagT *errflag,
1476 #if DELAYED_MKTEXPK
1477 		  Boolean read_fonts, Boolean initialize_fonts
1478 #else
1479 		  Boolean load_fonts
1480 #endif
1481 		  )
1482 {
1483     /*     FILE *tmp_fp = NULL; */
1484     /*     static FILE *bak_fp = NULL; /\* re-use the temporary backup fp *\/ */
1485     /*      fprintf(stderr, "------------ opening: |%s|\n", path); */
1486 
1487 #if DELAYED_MKTEXPK
1488     TRACE_FILES((stderr, "internal_open_dvi for |%s|; loading fonts: %d, %d", path, read_fonts, initialize_fonts));
1489 #else
1490     TRACE_FILES((stderr, "internal_open_dvi for |%s|", path));
1491 #endif
1492     close_old_filep();
1493 
1494     if (!file_exists_p(path, errflag)) { /* this should set fstatbuf.st_mtime */
1495 	return False;
1496     }
1497 
1498     if (!resource.use_temp_fp || (globals.dvi_file.bak_fp = make_backup_fp(m_dvi_fp, globals.dvi_file.bak_fp)) == NULL) {
1499 	globals.dvi_file.bak_fp = m_dvi_fp;
1500     }
1501 
1502     register_exit_handler(remove_tmp_dvi_file, NULL);
1503 
1504     globals.dvi_file.time = fstatbuf.st_mtime;
1505 
1506     if (!internal_init_dvi(errflag,
1507 #if DELAYED_MKTEXPK
1508 			   read_fonts, initialize_fonts
1509 #else
1510 			   load_fonts
1511 #endif
1512 			   )) {
1513 	return False;
1514     }
1515 
1516 #if COLOR
1517     full_reset_colors();
1518 #endif /* COLOR */
1519     reset_papersize_special();
1520 
1521     TRACE_FILES((stderr, "internal_open_dvi: SUCCESS!"));
1522 
1523     return True;
1524 }
1525 
1526 /*
1527   check whether `filename' is a DVI file, by checking if it exists, and if so,
1528   opening it and trying to read a DVI preamble from it:
1529 */
1530 static char *
1531 is_dvi_file(const char *filename)
1532 {
1533     FILE *fp;
1534     struct stat statbuf;
1535     char *full_pathname;
1536     dviErrFlagT unused_error;
1537 
1538     TRACE_FILES((stderr, "is_dvi_file %s", filename));
1539     TRACE_HTEX((stderr, "filename: |%s|", filename));
1540 
1541     /* used to append `.dvi' if not already present, but that was a
1542        bad idea - if we have both foo.2 and foo.2.dvi, user will want
1543        to open `foo.2' (with some appropriate application) if the link
1544        points to that filename. This means that we need to have
1545        different semantics for filenames on the command-line and
1546        filenames in hyperlinks; the latter *must* specify an
1547        extension, the former may omit the extension and default to DVI
1548        files.
1549     */
1550     /* if ((full_filename = filename_append_dvi(filename)) == NULL) { */
1551     /*     free(full_filename); */
1552     /*     return NULL; */
1553     /* } */
1554     /* TRACE_HTEX((stderr, "full_filename: |%s|\n", full_filename)); */
1555 
1556     if ((full_pathname = find_file(filename, &statbuf, kpse_program_text_format)) == NULL) {
1557 	return NULL;
1558     }
1559     else {
1560 	char *tmp = canonicalize_path(full_pathname);
1561 	free(full_pathname);
1562 	full_pathname = tmp;
1563     }
1564 
1565     TRACE_HTEX((stderr, "is_dvi_file: full_pathname: |%s|", full_pathname));
1566 
1567     if ((fp = XFOPEN(full_pathname, OPEN_MODE)) == NULL) {
1568 	free(full_pathname);
1569 	return NULL;
1570     }
1571 
1572     if (!process_preamble(fp, &unused_error)) {
1573 	free(full_pathname);
1574 	fclose(fp);
1575 	return NULL;
1576     }
1577 
1578     fclose(fp);
1579     return full_pathname;
1580 }
1581 
1582 static void
1583 report_open_error(const char *msg, const char *filename, dviErrFlagT errflag)
1584 {
1585     const char *errmsg;
1586     switch(errflag) {
1587     case FILE_HAS_ZERO_SIZE:
1588 	errmsg = "File has zero size";
1589 	break;
1590     case FILE_DOESNT_EXIST:
1591 	errmsg = "No such file";
1592 	break;
1593     case FILE_IS_DIRECTORY:
1594 	errmsg = "Is a directory";
1595 	break;
1596     default:
1597 	errmsg = "An unknown error occurred";
1598 	break;
1599     }
1600     XDVI_ERROR((stderr, "%s: %s: %s", msg, filename, errmsg));
1601 }
1602 
1603 /*
1604   Implements the algorithm for opening a DVI file from the command line.
1605   This is similar to `open_dvi_file()' in non-k xdvi.
1606 
1607   If the file does not already have `.dvi' extension, append `.dvi'
1608   and set tried_dvi_ext to True. Try to open this file. If the file
1609   doesn't exist, try the original file name. If this file doesn't
1610   exist either, exit with an error message `No such file or directory'.
1611   If tried_dvi_ext == True, also report that file.dvi didn't exist
1612   either.
1613 
1614   (A later function will check if the file really is a DVI file, and
1615   will use tried_dvi_ext for the same purpose).
1616 */
1617 char *
1618 find_dvi_file(const char *filename, Boolean *tried_dvi_ext, Boolean from_file_history)
1619 {
1620     char *new_filename;
1621     size_t len;
1622     dviErrFlagT errflag;
1623 
1624     ASSERT(filename != NULL, "Filename argument in find_dvi_file() musn't be NULL");
1625     len = strlen(filename);
1626 
1627     if (len < sizeof(".dvi") || strcmp(filename + len - sizeof(".dvi") + 1, ".dvi") != 0) {
1628 	/* doesn't already have .dvi extension */
1629 	TRACE_HTEX((stderr, "|%s| doesn't have .dvi extension, appending ...", filename));
1630 	new_filename = xstrdup(filename);
1631 	new_filename = xstrcat(new_filename, ".dvi");
1632 	*tried_dvi_ext = True;
1633 
1634 	if (file_exists_p(new_filename, &errflag)) { /* file exists */
1635 	    char *expanded_filename = expand_filename(new_filename, USE_CWD_PATH);
1636 	    free(new_filename);
1637 	    return expanded_filename;
1638 	}
1639 	else { /* don't report an error; will try verbatim filename next */
1640 	    free(new_filename);
1641 	}
1642     }
1643 
1644     /* try verbatim filename (might be strange things like `foo.wdvi') */
1645     if (file_exists_p(filename, &errflag)) {
1646 	char *expanded_filename = expand_filename(filename, USE_CWD_PATH);
1647 	return expanded_filename;
1648     }
1649     else {
1650 	if (*tried_dvi_ext) {
1651 	    if (!from_file_history) {
1652 		XDVI_FATAL((stderr, "%s: %s, and %s.dvi doesn't exist either.",
1653 			    filename, get_dvi_error(errflag), filename));
1654 	    }
1655 	    else {
1656 		popup_message(globals.widgets.top_level,
1657 			      MSG_ERR,
1658 			      NULL,
1659 			      "Could not open \"%s\": %s.\n", filename, get_dvi_error(errflag));
1660 	    }
1661 	}
1662 	else {
1663 	    if (!from_file_history) {
1664 		XDVI_FATAL((stderr, "%s: %s.", filename, get_dvi_error(errflag)));
1665 	    }
1666 	    /* else: file is from history; this is at startup, where we may
1667 	       loop through the history until we find a usable file. Don't report
1668 	       an error in this case. */
1669 	}
1670     }
1671     return NULL;
1672 }
1673 
1674 
1675 
1676 /*
1677  * A wrapper for open_dvi_file that can also deal with remote files/URLs, and other
1678  * file types. Returns the (newly malloc'ed) new dvi file name if it succeeds, NULL else.
1679  */
1680 char *
1681 open_dvi_file_wrapper(const char *filename,
1682 		      Boolean from_command_line,
1683 		      Boolean open_new_instance,
1684 		      Boolean *tried_dvi_ext,
1685 		      Boolean from_file_history)
1686 {
1687     char *real_filename = NULL;
1688     char *new_dvi_name = NULL;
1689     char canonical_path[MAXPATHLEN + 1];
1690 
1691     if (from_command_line) {
1692 	TRACE_HTEX((stderr, "filename IS from commandline"));
1693 	/*
1694 	  if filename is from command-line, we want to treat the file as a DVI file
1695 	  always (and NOT launch the browser or other programs; that'd just confuse
1696 	  people, who meant to launch *xdvi*). `find_dvi_file' tries to locate the
1697 	  file and does all error handling; on success, it returns a fully expanded
1698 	  filename.
1699 	*/
1700 	real_filename = find_dvi_file(filename, tried_dvi_ext, from_file_history); /* this allocates real_filename */
1701 	if (real_filename == NULL)
1702 	    return False;
1703 
1704 	TRACE_HTEX((stderr, "filename |%s| %p from commandline;\ndvi_name: |%s|,\nfilename: |%s|%p",
1705 		    real_filename, real_filename, globals.dvi_name, filename, (void *)filename));
1706 	new_dvi_name = xstrdup(REALPATH(real_filename, canonical_path));
1707 	free(real_filename);
1708 	TRACE_FILES((stderr, "new_dvi_name: |%s|", new_dvi_name));
1709 	return new_dvi_name;
1710     }
1711     else {
1712 	/*
1713 	  if it's not from the command line (e.g. result of clicking Mouse-1 on a link);
1714 	  in this case we might fall back to using the browser.
1715 	  Check whether it's a local file:
1716 	*/
1717 	const char *filename_no_prefix;
1718 	char *expanded_filename;
1719 	TRACE_HTEX((stderr, "filename NOT from commandline"));
1720 	if ((filename_no_prefix = is_local_file(filename)) != NULL) {
1721 	    /* if it's a local file, check whether it's a DVI file: */
1722 	    if ((expanded_filename = is_dvi_file(filename_no_prefix)) != NULL) {
1723 		/* yes, open it */
1724 		if (open_dvi_file(expanded_filename, open_new_instance)) {
1725 		    TRACE_FILES((stderr, "success: %p |%s|", expanded_filename, expanded_filename));
1726 		    if (!open_new_instance) {
1727 			new_dvi_name = expand_filename_append_dvi(expanded_filename, USE_DVI_PATH, True);
1728 			TRACE_FILES((stderr, "new_dvi_name: %p |%s|", (void*)new_dvi_name, new_dvi_name));
1729 		    }
1730 		}
1731 		free(expanded_filename);
1732 		return new_dvi_name;
1733 	    }
1734 	    else {
1735 		/*
1736 		  local file, but not a DVI file;
1737 		  try other viewers for this MIME type:
1738 		*/
1739 		TRACE_HTEX((stderr, "%s is NOT a DVI file", filename_no_prefix));
1740 		launch_program(filename);
1741 		return NULL;
1742 	    }
1743 	}
1744 	else {
1745 	    /* not a local file, retrieve it with the browser: */
1746 	    launch_browser(filename);
1747 	    return NULL;
1748 	}
1749     }
1750 }
1751 
1752 
1753 static Boolean
1754 open_dvi_file(const char *filename, Boolean open_new_instance)
1755 {
1756     Boolean retval = True;
1757 
1758     char *anchor_name = resource.anchor_pos;
1759 
1760     TRACE_HTEX((stderr, "open_dvi_file: |%s| + |%s|",
1761 		filename, anchor_name == NULL ? "<no anchor>" : anchor_name));
1762 
1763     if (open_new_instance) {
1764 	launch_xdvi(filename, anchor_name);
1765     }
1766     else {
1767 	dviErrFlagT errflag = NO_ERROR;
1768 	TRACE_HTEX((stderr, "internal_open_dvi: |%s|", filename));
1769 	if (!internal_open_dvi(filename, &errflag, True
1770 #if DELAYED_MKTEXPK
1771 			       , TRUE
1772 #endif
1773 			       )) {
1774 	    report_open_error("Cannot open DVI file", filename, errflag);
1775 	    retval = False;
1776 	}
1777     }
1778     return retval;
1779 }
1780 
1781 /**
1782  **	form_dvi_property forms the property used to exhibit the dvi file name
1783  **	used as a window property (used for source specials).
1784  **/
1785 
1786 void
1787 form_dvi_property(void)
1788 {
1789 #if 0
1790     size_t len;
1791     unsigned long ino;
1792     int i;
1793 #endif
1794 
1795     if (m_dvi_fp == NULL)
1796 	return;
1797 
1798     if (dvi_property != NULL)
1799 	free(dvi_property);
1800 
1801     dvi_property_length = strlen(globals.dvi_name) + 1; /* also copy the terminating 0 */
1802     dvi_property = xmalloc(dvi_property_length);
1803 
1804     /* NOTE: we don't use dvi_inode like non-k xdvi, since xdvik keeps closer
1805        track of when the path points to a different inode. */
1806     strcpy(dvi_property, globals.dvi_name);
1807 }
1808 
1809 
1810 /* access for m_dvi_fp */
1811 void
1812 close_old_filep(void)
1813 {
1814     if (m_dvi_fp != NULL) {
1815 	fclose(m_dvi_fp);
1816 	m_dvi_fp = NULL;
1817 	if (!resource.use_temp_fp)
1818 	    globals.dvi_file.bak_fp = NULL;
1819     }
1820 }
1821 
1822 
1823 
1824 /**
1825  **	Check for changes in dvi file.
1826  **	Return True if file has changed, False else.
1827  **/
1828 
1829 Boolean
1830 dvi_file_changed(void)
1831 {
1832     TRACE_FILES((stderr, "dvi_file_changed: fp = %p?", (void *)m_dvi_fp));
1833 
1834     /*     fprintf(stderr, "m_dvi_fp3: %p (%s)\n", m_dvi_fp, globals.dvi_name); */
1835     if (m_dvi_fp == NULL) {
1836 	TRACE_FILES((stderr, "m_dvi_fp == NULL"));
1837 	if (stat(globals.dvi_name, &fstatbuf) == 0 && fstatbuf.st_mtime != globals.dvi_file.time) {
1838 	    TRACE_FILES((stderr, "file changed"));
1839 	    if (resource.use_temp_fp) {
1840 		dviErrFlagT errflag = NO_ERROR;
1841 #if !DELAYED_MKTEXPK
1842 		if (resource.watch_file == 0.0)
1843 		    statusline_info(STATUS_MEDIUM, "File changed ...");
1844 		TRACE_FILES((stderr, "returning FALSE"));
1845 #endif
1846 		if (file_exists_p(globals.dvi_name, &errflag)
1847 		    && process_preamble(m_dvi_fp, &errflag)
1848 		    && find_postamble(m_dvi_fp, &errflag)
1849 		    && read_postamble(m_dvi_fp, &errflag, False
1850 #if DELAYED_MKTEXPK
1851 				      , False
1852 #endif
1853 				      )) {
1854 		    TRACE_FILES((stderr, "File OK, reloading ..."));
1855 
1856 		    globals.ev.flags |= EV_RELOAD;
1857 		    return True;
1858 		}
1859 		else {
1860 #if DELAYED_MKTEXPK
1861 		    if (resource.watch_file == 0.0)
1862 			statusline_info(STATUS_MEDIUM, "File corrupted (click on window to reload) ...");
1863 		    TRACE_FILES((stderr, "returning FALSE"));
1864 #endif
1865 		    return False;
1866 		}
1867 	    }
1868 	    /* Bug alert: Don't set EV_RELOAD again here, else xdvi
1869 	       can go into a stretch of time where it again and again
1870 	       tries to reload a file even if the user doesn't click
1871 	       on the canvas.
1872 	    */
1873 	    /*
1874 	      else {
1875 	      globals.ev.flags |= EV_RELOAD;
1876 	      }
1877 	    */
1878 	    TRACE_FILES((stderr, "returning TRUE"));
1879 	    return True;
1880 	}
1881 	else {
1882 	    TRACE_FILES((stderr, "file not changed"));
1883 	}
1884     }
1885     /* BUG ALERT: Don't use fstat(fileno(m_dvi_fp) here; if file hase
1886        disappeared, this won't report an error! */
1887     else if (stat(globals.dvi_name, &fstatbuf) != 0 /* stat failed ... */
1888 	     || fstatbuf.st_mtime != globals.dvi_file.time /* ... or different timestamp, reload: */) {
1889 	dviErrFlagT errflag = NO_ERROR;
1890 
1891 	TRACE_FILES((stderr, "Stat failed, or different timestamp ..."));
1892 	globals.dvi_file.time = 0; /* force reload next time also if stat failed */
1893 
1894 	if (resource.use_temp_fp) { /* in this case, reload only if file has been written completely */
1895 	    if (resource.watch_file == 0.0) {
1896 		statusline_info(STATUS_MEDIUM, "File corrupted (click on window to reload) ...");
1897 		globals.cursor.flags |= CURSOR_CORRUPTED;
1898 		globals.ev.flags |= EV_CURSOR;
1899 	    }
1900 	    else {
1901 		statusline_info(STATUS_MEDIUM, "File corrupted (will try to reload) ...");
1902 	    }
1903 	    close_old_filep();
1904 	    if (file_exists_p(globals.dvi_name, &errflag)
1905 		&& process_preamble(m_dvi_fp, &errflag)
1906 		&& find_postamble(m_dvi_fp, &errflag)
1907 		&& read_postamble(m_dvi_fp, &errflag, False
1908 #if DELAYED_MKTEXPK
1909 				  , False
1910 #endif
1911 				  )) {
1912 		TRACE_FILES((stderr, "File OK, reloading ..."));
1913 
1914 		globals.ev.flags |= EV_RELOAD;
1915 		return True;
1916 	    }
1917 	    else {
1918 		TRACE_FILES((stderr, "NO successful load: %s", get_dvi_error(errflag)));
1919 		/*  		fprintf(stderr, "=========== NO successful load: %s\n", get_dvi_error(errflag)); */
1920 		return False;
1921 	    }
1922 	}
1923 	else {
1924 	    TRACE_FILES((stderr, "Not using temp fp, reloading..."));
1925 	    globals.ev.flags |= EV_RELOAD;
1926 	    return True;
1927 	}
1928     }
1929     return False;
1930 }
1931 
1932 /**
1933  **	Reload the dvi file (unconditionally). Return True on success, False else.
1934  **/
1935 
1936 Boolean
1937 load_dvi_file(
1938 #if !DELAYED_MKTEXPK
1939 	      Boolean load_fonts,
1940 #endif
1941 	      dviErrFlagT *errflag)
1942 {
1943     unsigned int old_page_w, old_page_h;
1944     static ino_t dvi_inode = 0;
1945 
1946     TRACE_FILES((stderr, "load_dvi_file: going to read %p", (void *)m_dvi_fp));
1947 
1948     if (resource.use_temp_fp && m_dvi_fp != NULL) {
1949 	/* in this case, reload only if file has been written completely */
1950 	*errflag = NO_ERROR;
1951 	fseek(m_dvi_fp, 0L, SEEK_SET);
1952 	if (!process_preamble(m_dvi_fp, errflag)
1953 	    || !find_postamble(m_dvi_fp, errflag)
1954 	    || !read_postamble(m_dvi_fp, errflag,
1955 #if DELAYED_MKTEXPK
1956 			       False, False
1957 #else
1958 			       True
1959 #endif
1960 			       )) {
1961 	    TRACE_FILES((stderr, "reading of %p failed: %s!",
1962 			 (void *)m_dvi_fp,
1963 			 get_dvi_error(*errflag)));
1964 	    return False;
1965 	}
1966     }
1967 
1968     old_page_w = globals.page.w;
1969     old_page_h = globals.page.h;
1970 
1971     *errflag = NO_ERROR;
1972 
1973 #if DELAYED_MKTEXPK
1974     /* use same trick with reading postamble twice to first find names of PK fonts
1975        that need to be created. */
1976     reset_missing_font_count();
1977     kpse_set_program_enabled(kpse_any_glyph_format, False, kpse_src_compile);
1978 #endif
1979 
1980     if (!internal_open_dvi(globals.dvi_name, errflag,
1981 #if DELAYED_MKTEXPK
1982 			   True, False
1983 #else
1984 			   load_fonts
1985 #endif
1986 			   )) {
1987 	XClearWindow(DISP, mane.win);
1988 	xdvi_bell();
1989 	statusline_info(STATUS_MEDIUM, "%s: %s%s", globals.dvi_name, get_dvi_error(*errflag),
1990 			 resource.watch_file > 0.0 ? "; will try to reload ..." : " (click on window to reload)");
1991 	close_old_filep();
1992 
1993 	return False;
1994     }
1995 #if DELAYED_MKTEXPK
1996     /* second time */
1997     kpse_set_program_enabled(kpse_any_glyph_format, True, kpse_src_compile);
1998 
1999     if (!internal_open_dvi(globals.dvi_name, errflag, True, True)) {
2000 	XClearWindow(DISP, mane.win);
2001 	xdvi_bell();
2002 	statusline_info(STATUS_MEDIUM, "%s: %s%s", globals.dvi_name, get_dvi_error(*errflag),
2003 			 resource.watch_file > 0.0 ? "; will try to reload ..." : " (click on window to reload)");
2004 	close_old_filep();
2005 	return False;
2006     }
2007 #endif
2008     else { /* success */
2009 	if (fstatbuf.st_ino != dvi_inode) {
2010 	    dvi_inode = fstatbuf.st_ino;
2011 	    form_dvi_property();
2012 	    set_dvi_property();
2013 	}
2014 	if (globals.page.w != old_page_w || globals.page.h != old_page_h)
2015 	    reconfig();
2016 
2017 	htex_reinit();
2018 
2019 	globals.cursor.flags &= ~CURSOR_CORRUPTED;
2020 	return True;
2021     }
2022 }
2023