diff options
Diffstat (limited to 'Build/source/texk/xdvik/dvi-init.c')
-rw-r--r-- | Build/source/texk/xdvik/dvi-init.c | 1620 |
1 files changed, 1620 insertions, 0 deletions
diff --git a/Build/source/texk/xdvik/dvi-init.c b/Build/source/texk/xdvik/dvi-init.c new file mode 100644 index 00000000000..d62b170f620 --- /dev/null +++ b/Build/source/texk/xdvik/dvi-init.c @@ -0,0 +1,1620 @@ +/*========================================================================*\ + +Copyright (c) 1990-2004 Paul Vojta + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +NOTE: + xdvi is based on prior work, as noted in the modification history + in xdvi.c. + +\*========================================================================*/ + +#include "xdvi-config.h" +#include "xdvi.h" + +#include "dvi-init.h" +#include "dvi-draw.h" +#include "util.h" +#include "x_util.h" +#include "mime.h" +#include "pagesel.h" +#include "special.h" +#include "hypertex.h" +#include "kpathsea/c-fopen.h" +#include "kpathsea/c-stat.h" +#include "kpathsea/magstep.h" +#include "kpathsea/tex-glyph.h" +#include "dvi.h" +#include "string-utils.h" +#include "browser.h" +#include "sfSelFile.h" +#include "xm_toolbar.h" +#include "pagehist.h" + +#ifdef T1LIB +#include "t1lib.h" +#endif + +#include "message-window.h" +#include "search-internal.h" +#include "statusline.h" +#include "events.h" +#include "font-open.h" + +#define PK_PRE 247 +#define PK_ID 89 +#define PK_MAGIC ((PK_PRE << 8) | PK_ID) +#define GF_PRE 247 +#define GF_ID 131 +#define GF_MAGIC ((GF_PRE << 8) | GF_ID) +#define VF_PRE 247 +#define VF_ID_BYTE 202 +#define VF_MAGIC ((VF_PRE << 8) | VF_ID_BYTE) + +/* font stuff */ +struct font *tn_table[TNTABLELEN]; +struct font *font_head = NULL; +struct tn *tn_head = NULL; +wide_ubyte maxchar; +unsigned short current_timestamp = 0; + + +unsigned long magnification; +double dimconv; +double tpic_conv; + +/* Curently processed page number (starting at 0). */ +int current_page = 0; +int total_pages = 0; + +/* postamble offset is saved in this global variable */ +long g_postamble_offset; + + +static struct stat fstatbuf; + +static FILE *m_dvi_fp = NULL; /* original user's file */ + + +static Boolean open_dvi_file(const char *filename, Boolean open_new_instance); + +/* + * DVI preamble and postamble information. + */ +static unsigned long numerator, denominator; +static unsigned int dvi_unshrunk_page_w, dvi_unshrunk_page_h; +static unsigned int m_paper_unshrunk_w, m_paper_unshrunk_h; + + +/* + * Offset in DVI file of last page, set in read_postamble(). + */ +static long m_last_page_offset; + +static const char *dvi_err_list[] = { + /* NO_ERROR */ "No Error", + /* WRONG_DVI_VERSION */ "Wrong version of DVI output for this program", + /* DVI_CORRUPTED */ "DVI file corrupted", + /* NOT_A_DVI_FILE */ "Not a DVI file", + /* POSTAMBLE_NO_POST */ "Postamble doesn't begin with POST", + /* POSTAMBLE_NO_MATCH */ "Postamble doesn't match preamble", + /* POSTAMBLE_NON_FNTDEF */ "Non-fntdef command found in postamble", + /* NOT_ALL_PIXEL_FILES_FOUND */ "Not all pixel files were found", + /* NO_BOP_AT_PAGEDESC */ "Page description doesn't begin with BOP", + /* FILE_HAS_ZERO_SIZE */ "File has zero size", + /* FILE_DOESNT_EXIST */ "No such file", + /* FILE_IS_DIRECTORY */ "Is a directory", + /* UNKNOWN_ERROR */ "An unknown error occurred" +}; + +/* + * access method for above list + */ +const char * +get_dvi_error(dviErrFlagT flag) { + ASSERT(flag < XtNumber(dvi_err_list), "Flag out of range"); + return dvi_err_list[flag]; +} + +/* + * free_vf_chain frees the vf_chain structure. + */ + +static void +free_vf_chain(struct tn *tnp) +{ + while (tnp != NULL) { + struct tn *tnp1 = tnp->next; + free((char *)tnp); + tnp = tnp1; + } +} + +/* + * delete glyph information in a font. + */ + +static void +delete_glyphs(struct font *fontp) +{ + struct glyph *g; + + for (g = fontp->glyph; g <= fontp->glyph + fontp->maxchar; ++g) { + if (g->bitmap2.bits) { + free(g->bitmap2.bits); + g->bitmap2.bits = NULL; + } +#ifdef GREY + if (g->pixmap2) { + XDestroyImage(g->image2); + g->pixmap2 = NULL; + if (g->pixmap2_gc2 != NULL) { + free(g->pixmap2_gc2); + g->pixmap2_gc2 = NULL; + } + } +#if COLOR + g->fg = NULL; +#endif +#endif + } +} + +/* + * Release all shrunken bitmaps for all fonts. + */ + +void +reset_fonts(void) +{ + struct font *f; + + for (f = font_head; f != NULL; f = f->next) { + if ((f->flags & FONT_LOADED) && !(f->flags & FONT_VIRTUAL)) { + delete_glyphs(f); + } + } +} + +/* + * free up fonts no longer in use. + */ +static void +free_unused_fonts(void) +{ + struct font *fontp; + struct font **fontpp; + + fontpp = &font_head; + while ((fontp = *fontpp) != NULL) { + if (fontp->flags & FONT_IN_USE) + fontpp = &fontp->next; + else { + if (globals.debug & DBG_PK) + printf("xdvi: Discarding font \"%s\" at %d dpi\n", + fontp->fontname, (int)(fontp->fsize + 0.5)); + *fontpp = fontp->next; /* remove from list */ + free(fontp->fontname); + if (fontp->flags & FONT_LOADED) { + if (fontp->file != NULL) { + fclose(fontp->file); + } + free(fontp->filename); + if (fontp->flags & FONT_VIRTUAL) { + struct macro *m; + + for (m = fontp->macro; + m <= fontp->macro + fontp->maxchar; ++m) + if (m->free_me) free((char *)m->pos); + free((char *)fontp->macro); + free((char *)fontp->vf_table); + free_vf_chain(fontp->vf_chain); + } + else { + delete_glyphs(fontp); + free((char *)fontp->glyph); + } + free((char *)fontp); + } + } + } +} + +#if COLOR + +/* + * Release all allocated pixels, and (in greyscale mode) invalidate + * all shrunken glyphs. + */ + +void +reset_colors(void) +{ + if (color_list_len != 0) { + XFreeColors(DISP, G_colormap, color_list, color_list_len, 0); + color_list_len = 0; + } + while (bg_head != NULL) { + struct bgrec *bgp; + struct fgrec *fgp; + + for (fgp = bg_head->fg_head; fgp != NULL;) { + struct fgrec *fgp1 = fgp->next; + free(fgp); + fgp = fgp1; + } + bgp = bg_head->next; + free(bg_head); + bg_head = bgp; + } +#if GREY + if (resource.use_grey) { + struct font *f; + struct glyph *g; + + for (f = font_head; f != NULL; f = f->next) + if ((f->flags & FONT_LOADED) && !(f->flags & FONT_VIRTUAL)) + for (g = f->glyph; g <= f->glyph + f->maxchar; ++g) + g->fg = NULL; + } +#endif /* GREY */ + bg_current = NULL; + fg_active = NULL; + color_warned = False; +} + +/* + * All of the above, plus discard all scanned information. + */ + +void +full_reset_colors(void) +{ + if (page_colors.stack != NULL) { + size_t i; + struct rgb *last_freed = &fg_initial; + + /* fprintf(stderr, "i: %d; last freed: %p\n", page_colors.size, &fg_initial); */ + for (i = 0; i < page_colors.size; ++i) { + if (page_colors.stack[i].colorstack != last_freed) { + last_freed = page_colors.stack[i].colorstack; + /* BUG ALERT: don't free &fg_initial, else segfault with changing + foreground in xm_colorsel.c! */ + if (last_freed != NULL && last_freed != &fg_initial) { + /* fprintf(stderr, "freeing %d: %p\n", i, last_freed); */ + free(last_freed); + } + } + } + free(page_colors.stack); + page_colors.stack = NULL; + } + reset_colors(); +} + +#endif /* COLOR */ + + + +/* + * realloc_font allocates the font structure to contain (newsize + 1) + * characters. + */ + +void +realloc_font(struct font *fontp, wide_ubyte newsize) +{ + struct glyph *glyph; + + glyph = fontp->glyph = xrealloc(fontp->glyph, + (unsigned int)(newsize + 1) * sizeof(struct glyph)); + if (newsize > fontp->maxchar) + memset((char *)(glyph + fontp->maxchar + 1), 0, + (int)(newsize - fontp->maxchar) * sizeof(struct glyph)); + maxchar = fontp->maxchar = newsize; +} + + +/* + * realloc_virtual_font does the same thing for virtual fonts. + */ + +void +realloc_virtual_font(struct font *fontp, wide_ubyte newsize) +{ + struct macro *macro; + + macro = fontp->macro = xrealloc(fontp->macro, + (unsigned int)(newsize + 1) * sizeof(struct macro)); + if (newsize > fontp->maxchar) + memset((char *)(macro + fontp->maxchar + 1), 0, + (int)(newsize - fontp->maxchar) * sizeof(struct macro)); + maxchar = fontp->maxchar = newsize; +} + + +/* + * load_font locates the t1 font or raster file and reads the index of + * characters, plus whatever other preprocessing is done (depending on + * the format). + * + * Returns True if sucessful, False if not. + */ + +Boolean +load_font(struct font *fontp, Boolean use_t1lib) +{ + double fsize = fontp->fsize; + int dpi = fsize + 0.5; + char *font_found; + int size_found; + int magic; + Boolean hushcs = resource.hush_chk; + + fontp->file = NULL; + + /* BUG ALERT: This used to be: + * + * if (--globals.ev.ctr == 0) { + * read_events(EV_GE_IDLE); + * } + * force_statusline_update(); + * XSync(DISP, False); + * + * The idea was to update the `loading fonts ...' popup. However, + * calling read_events() here may call dvi_file_changed() if the + * user clicks on the window, which calls file_exists_p(), and + * that changes m_dvi_fp while it's still being used to read the + * postamble (where load_font() is called from), which will cause + * xdvi to crash! (bug #968127). + * + * Sadly, without this update, the `loading fonts' popup doesn't + * appear before the main window comes up ... + */ + +#ifdef T1LIB + fontp->file = font_open(fontp->fontname, &font_found, + fsize, &size_found, + &fontp->filename, &fontp->t1id); +#else + fontp->file = font_open(fontp->fontname, &font_found, + fsize, &size_found, + &fontp->filename); +#endif /* T1LIB */ + +#ifdef T1LIB + if (fontp->t1id >= 0 && use_t1lib) { + /* It's a type1 font */ + fontp->fsize = fsize; /* It comes in all sizes */ + fontp->timestamp = ++current_timestamp; + fontp->maxchar = maxchar = 255; + fontp->set_char_p = set_t1_char; + /* read_T1_char is a dummy */ + fontp->read_char = read_T1_char; + fontp->glyph = xmalloc (256 * sizeof (struct glyph)); + memset((char *) fontp->glyph, 0, 256 * sizeof (struct glyph)); + fontp->flags |= FONT_LOADED; + if (font_found != NULL) { + statusline_print(STATUS_MEDIUM, + "Error: Can't find font %s; using %s instead. Expect ugly output.", + fontp->fontname, font_found); + force_statusline_update(); + free(fontp->fontname); + fontp->fontname = font_found; /* this has been allocated by font_open */ + } + return True; + } +#endif /* T1LIB */ + /* when not using T1lib, fontp->file == NULL means total failure */ + if (fontp->file == NULL) { + if (globals.ev.flags & EV_GE_NEWDOC) + return False; + fontp->flags |= FONT_LOADED; /* as loaded as it'll get */ + XDVI_ERROR((stderr, "Can't find font %s.%dpk", fontp->fontname, dpi)); + return False; + } + fontp->flags |= FONT_LOADED; + + if (font_found != NULL && strcmp(fontp->fontname, font_found) != 0) { + /* some other font used - FIXME: is there a more efficient way than strcmp() for checking this? */ + statusline_print(STATUS_MEDIUM, + "Can't find pixel font %s; using %s instead at %d dpi.", + fontp->fontname, font_found, dpi); + force_statusline_update(); + free(fontp->fontname); + fontp->fontname = font_found; /* this has been allocated by font_open */ + hushcs = True; + } + else if (!kpse_bitmap_tolerance((double)size_found, fsize)) { /* a different size used */ + statusline_print(STATUS_MEDIUM, + "Can't find pixel font %s at %d dpi; using %d dpi instead.", + fontp->fontname, dpi, size_found); + force_statusline_update(); + } + + /* PK version of some font found */ + fontp->fsize = size_found; + fontp->timestamp = ++current_timestamp; + fontp->maxchar = maxchar = 255; + fontp->set_char_p = set_char; + magic = get_bytes(fontp->file, 2); + + switch(magic) { + case PK_MAGIC: + read_PK_index(fontp, (wide_bool)hushcs); + break; +#ifdef USE_GF + case GF_MAGIC: + read_GF_index(fontp, (wide_bool)hushcs); + break; +#endif + case VF_MAGIC: + if (resource.omega) + maxchar = read_VF_index(fontp, (wide_bool)hushcs); + else + (void)read_VF_index(fontp, (wide_bool)hushcs); + break; + default: + XDVI_FATAL((stderr, "Cannot recognize format for font file %s", fontp->filename)); + break; + } + + if (fontp->flags & FONT_VIRTUAL) { + if (!resource.omega) { + while (maxchar > 0 && fontp->macro[maxchar].pos == NULL) { + --maxchar; + } + if (maxchar < 255) { + realloc_virtual_font(fontp, (wide_ubyte)maxchar); + } + } + } + else { + while (maxchar > 0 && fontp->glyph[maxchar].addr == 0) + --maxchar; + if (maxchar < 255) + realloc_font(fontp, (wide_ubyte)maxchar); + } + return True; +} + + +/* + * MAGSTEPVALUE - If the given magnification is close to a \magstep + * or a \magstephalf, then return twice the number of \magsteps. + * Otherwise return NOMAGSTP. + */ + +#define NOMAGSTP (-29999) +#define NOBUILD 29999 + +static int +magstepvalue(float *mag) +{ + int m = 0; + double fmag = *mag; + double xmag = resource.pixels_per_inch; + float margin = fmag * 0.002; + + if (fmag < resource.pixels_per_inch) + for (;;) { + if (xmag - fmag < margin && -(xmag - fmag) < margin) { + *mag = xmag; + return m; + } + if (xmag < fmag) + break; + xmag *= 0.9128709292; + --m; + } + else + for (;;) { + if (xmag - fmag < margin && -(xmag - fmag) < margin) { + *mag = xmag; + return m; + } + if (xmag > fmag) + break; + xmag *= 1.095445115; + ++m; + } + return NOMAGSTP; +} + +/* + * reuse_font recursively sets the flags for font structures being reused. + */ + +static void +reuse_font(struct font *fontp) +{ + struct font **fp; + struct tn *tnp; + + if (fontp->flags & FONT_IN_USE) + return; + + fontp->flags |= FONT_IN_USE; + if (resource.list_fonts) + printf("xdvi: (reusing) %s at %d dpi\n", fontp->fontname, + (int)(fontp->fsize + 0.5)); + if (fontp->flags & FONT_VIRTUAL) { + for (fp = fontp->vf_table; fp < fontp->vf_table + VFTABLELEN; ++fp) + if (*fp != NULL) + reuse_font(*fp); + for (tnp = fontp->vf_chain; tnp != NULL; tnp = tnp->next) + reuse_font(tnp->fontp); + } +} + + +/* + * define_font reads the rest of the fntdef command and then reads in + * the specified pixel file, adding it to the global linked-list holding + * all of the fonts used in the job. + */ +struct font * +define_font(Boolean load_font_now, /* only scanning, or also loading the font? */ + FILE *file, wide_ubyte cmnd, + struct font *vfparent, /* vf parent of this font, or NULL */ + struct font **tntable, /* table for low TeXnumbers */ + unsigned int tn_table_len, /* length of table for TeXnumbers */ + struct tn **tn_headpp, /* addr of head of list of TeXnumbers */ + Boolean *not_found_flag) /* signal that font hasn't been found */ +{ + unsigned int TeXnumber; + struct font *fontp; + float fsize; + double scale_dimconv; + long checksum; + int scale, orig_scale; + int design; + int magstepval; + int len; + char *fontname; + int size; + + TeXnumber = get_bytes(file, (int)cmnd - FNTDEF1 + 1); + checksum = get_bytes(file, 4); + scale = orig_scale = get_bytes(file, 4); + design = get_bytes(file, 4); + len = get_byte(file); + len += get_byte(file); /* sequence point in the middle */ + + if (!load_font_now) + return NULL; + + fontname = xmalloc((unsigned)len + 1); + fread(fontname, sizeof(char), len, file); + fontname[len] = '\0'; + if (globals.debug & DBG_PK) + printf("xdvi: Define font \"%s\" scale=%d design=%d number=%d\n", + fontname, scale, design, TeXnumber); + if (vfparent == NULL) { + fsize = 0.001 * scale / design * magnification * resource.pixels_per_inch; + scale_dimconv = dimconv; + } + else { + /* + * The scaled size is given in units of vfparent->scale * 2 ** -20 + * SPELL units, so we convert it into SPELL units by multiplying by + * vfparent->dimconv. + * The design size is given in units of 2 ** -20 pt, so we convert + * into SPELL units by multiplying by + * (resource.pixels_per_inch * 2**16) / (72.27 * 2**20). + */ + fsize = (72.27 * (1 << 4)) * vfparent->dimconv * scale / design; + scale_dimconv = vfparent->dimconv; + /* Inherit the scale from the virtual parent */ + scale = vfparent->scale * ((orig_scale * scale_dimconv / (1 << 20)) / vfparent->dimconv); + } + magstepval = magstepvalue(&fsize); + size = fsize + 0.5; + /* + * reuse font if possible + */ + for (fontp = font_head;; fontp = fontp->next) { + if (fontp == NULL) { /* if font doesn't exist yet */ + if (resource.list_fonts) + printf("xdvi: %s at %d dpi\n", fontname, (int)(fsize + 0.5)); + fontp = xmalloc((unsigned)sizeof(struct font)); + fontp->fontname = fontname; + fontp->fsize = fsize; + fontp->magstepval = magstepval; + fontp->file = NULL; /* needed if it's a virtual font */ + fontp->checksum = checksum; + fontp->flags = FONT_IN_USE; + fontp->dimconv = orig_scale * scale_dimconv / (1 << 20); + fontp->set_char_p = load_n_set_char; + fontp->scale = scale; + if (vfparent == NULL) + if (!load_font(fontp, resource.t1lib)) { + if (globals.ev.flags & EV_GE_NEWDOC) { /* if aborting */ + free(fontname); + free(fontp); + return NULL; + } + *not_found_flag = True; + } + fontp->next = font_head; + font_head = fontp; + break; + } + if (strcmp(fontname, fontp->fontname) == 0 + && size == (int)(fontp->fsize + 0.5)) { + /* if font already in use */ + reuse_font(fontp); + free(fontname); + break; + } + } + if (TeXnumber < tn_table_len) + tntable[TeXnumber] = fontp; + else { + struct tn *tnp; + tnp = xmalloc((unsigned)sizeof(struct tn)); + tnp->next = *tn_headpp; + *tn_headpp = tnp; + tnp->TeXnumber = TeXnumber; + tnp->fontp = fontp; + } + return fontp; +} + + + + +/* + * process_preamble reads the information in the preamble and stores + * it into global variables for later use. + */ +Boolean +process_preamble(FILE *fp, dviErrFlagT *errflag) +{ + ubyte k; + static char job_id[300]; + + TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d", (void *)fp, *errflag)); + + if (get_byte(fp) != PRE) { + *errflag = NOT_A_DVI_FILE; + TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning False", (void *)fp, *errflag)); + return False; + } + if (get_byte(fp) != 2) { + *errflag = WRONG_DVI_VERSION; + TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning False", (void *)fp, *errflag)); + return False; + } + numerator = get_bytes(fp, 4); + denominator = get_bytes(fp, 4); + magnification = get_bytes(fp, 4); + dimconv = (((double)numerator * magnification) + / ((double)denominator * 1000.)); + dimconv = dimconv * (((long)resource.pixels_per_inch) << 16) / 254000; + tpic_conv = resource.pixels_per_inch * magnification / 1000000.0; + k = get_byte(fp); + fread(job_id, sizeof(char), (int)k, fp); + job_id[k] = '\0'; + + TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning True", (void *)fp, *errflag)); + + return True; +} + +/* + * find_postamble locates the beginning of the postamble + * and leaves the file ready to start reading at that location. + */ +#define TMPSIZ 516 /* 4 trailer bytes + 512 junk bytes allowed */ +Boolean +find_postamble(FILE *fp, dviErrFlagT *errflag) +{ + long pos; + ubyte temp[TMPSIZ]; + ubyte *p; + ubyte *p1; + ubyte byte; + + TRACE_FILES((stderr, "find_postamble on fp: %p", (void *)fp)); + + fseek(fp, 0L, SEEK_END); + pos = ftell(fp) - TMPSIZ; + if (pos < 0) + pos = 0; + fseek(fp, pos, SEEK_SET); + p = temp + fread((char *)temp, sizeof(char), TMPSIZ, fp); + for (;;) { + p1 = p; + while (p1 > temp && *(--p1) != TRAILER); + p = p1; + while (p > temp && *(--p) == TRAILER); + if (p <= p1 - 4) + break; /* found 4 TRAILER bytes */ + if (p <= temp) { + *errflag = DVI_CORRUPTED; + TRACE_FILES((stderr, "find_postamble: returning FALSE")); + return False; + } + } + pos += p - temp; + byte = *p; + while (byte == TRAILER) { + fseek(fp, --pos, SEEK_SET); + byte = get_byte(fp); + } + if (byte != 2) { + *errflag = WRONG_DVI_VERSION; + TRACE_FILES((stderr, "find_postamble: returning FALSE")); + return False; + } + fseek(fp, pos - 4, SEEK_SET); + fseek(fp, get_lbytes(fp, 4), SEEK_SET); + TRACE_FILES((stderr, "find_postamble: returning TRUE")); + return True; +} + + + +Boolean +set_paper_type(const char *arg) +{ + const char *arg1; + char temp[21]; + const char **p; + char *q; + const char **paper_types = get_paper_types(); + size_t paper_types_size = get_paper_types_size(); + + if (*arg == '+') { + ++arg; + ignore_papersize_specials = True; + } + if (strlen(arg) > sizeof(temp) - 1) + return False; + q = temp; + for (;;) { /* convert to lower case */ + char c = *arg++; + if (c >= 'A' && c <= 'Z') + c ^= ('a' ^ 'A'); + *q++ = c; + if (c == '\0') + break; + } + arg = temp; + /* perform substitutions */ + for (p = paper_types; p < paper_types + paper_types_size; p += 2) { + if (strcmp(temp, *p) == 0) { + arg = p[1]; + break; + } + } + arg1 = strchr(arg, 'x'); + if (arg1 == NULL) + return False; + m_paper_unshrunk_w = atopix(arg, False); + m_paper_unshrunk_h = atopix(arg1 + 1, False); + + return (m_paper_unshrunk_w != 0 && m_paper_unshrunk_h != 0); +} + +/* + * read_postamble reads the information in the postamble from fp, + * storing it into global variables. + * It also takes care of reading in all of the pixel files for the fonts + * used in the job. + * + * FIXME: Would be better (speed up initialization when needing to generate fonts, + * and allow to open window on first page) if the font loading was done on-demand later! + */ +Boolean +read_postamble(FILE *fp, dviErrFlagT *errflag, Boolean load_fonts) +{ + ubyte cmnd; + Boolean font_not_found = False; + struct font *fontp; + + TRACE_FILES((stderr, "read_postamble: reading %p (%d)", (void *)fp, load_fonts)); + + /* clear existing font table */ + memset((char *)tn_table, 0, (int)sizeof tn_table); + free_vf_chain(tn_head); + tn_head = NULL; + for (fontp = font_head; fontp != NULL; fontp = fontp->next) + fontp->flags &= ~FONT_IN_USE; + + + if (get_byte(fp) != POST) { + *errflag = POSTAMBLE_NO_POST; + TRACE_FILES((stderr, "read_postamble: returning FALSE")); + return False; + } + m_last_page_offset = get_bytes(fp, 4); + if (numerator != get_bytes(fp, 4) + || denominator != get_bytes(fp, 4) + || magnification != get_bytes(fp, 4)) { + *errflag = POSTAMBLE_NO_MATCH; + TRACE_FILES((stderr, "read_postamble: returning FALSE")); + return False; + } + + /* read largest box height and width */ + dvi_unshrunk_page_h = (spell_conv(get_lbytes(fp, 4)) >> 16) + resource.yoffset_int; + if (dvi_unshrunk_page_h < m_paper_unshrunk_h) + dvi_unshrunk_page_h = m_paper_unshrunk_h; + dvi_unshrunk_page_w = (spell_conv(get_lbytes(fp, 4)) >> 16) + resource.xoffset_int; + if (dvi_unshrunk_page_w < m_paper_unshrunk_w) + dvi_unshrunk_page_w = m_paper_unshrunk_w; + (void)get_bytes(fp, 2); /* max stack size */ + total_pages = get_bytes(fp, 2); + + /* read font definitions */ + while ((cmnd = get_byte(fp)) >= FNTDEF1 && cmnd <= FNTDEF4) { + struct font *f = define_font(load_fonts, fp, cmnd, (struct font *)NULL, tn_table, + TNTABLELEN, &tn_head, &font_not_found); + if (load_fonts && f == NULL) { + TRACE_FILES((stderr, "read_postamble: returning FALSE")); + return False; + } + else if (!load_fonts) { /* return early */ + TRACE_FILES((stderr, "read_postamble: returning TRUE")); + return True; + } + } + if (cmnd != POSTPOST) { + *errflag = POSTAMBLE_NON_FNTDEF; + TRACE_FILES((stderr, "read_postamble: returning FALSE")); + return False; + } + if (font_not_found) { + *errflag = NOT_ALL_PIXEL_FILES_FOUND; + TRACE_FILES((stderr, "read_postamble: returning FALSE")); + return False; + } + free_unused_fonts(); + + TRACE_FILES((stderr, "read_postamble: returning TRUE")); + return True; +} + + +static Boolean +prepare_pages(dviErrFlagT *errflag) +{ + int i; + long offset; + + TRACE_FILES((stderr, "calling pageinfo_deallocate")); + pageinfo_deallocate(); + + TRACE_FILES((stderr, "pageinfo_allocate for %d pages", total_pages + 1)); + pageinfo_allocate(total_pages + 1); + pageinfo_set_page_width(total_pages, m_paper_unshrunk_w); + pageinfo_set_page_height(total_pages, m_paper_unshrunk_h); + pageinfo_set_window_width(total_pages, dvi_unshrunk_page_w); + pageinfo_set_window_height(total_pages, dvi_unshrunk_page_h); + + pageinfo_set_offset(total_pages - 1, m_last_page_offset); + /* + * Follow back pointers through pages in the DVI file, + * storing the offsets in the pageinfo table. + */ + for (offset = m_last_page_offset, i = total_pages; i > 0; i--) { + fseek(globals.dvi_file.bak_fp, offset, SEEK_SET); + if (get_byte(globals.dvi_file.bak_fp) != BOP) { + *errflag = NO_BOP_AT_PAGEDESC; + return False; + } + pageinfo_set_offset(i-1, offset); + /* from c_0, read count0, the TeX page number */ + pageinfo_set_number(i-1, get_bytes(globals.dvi_file.bak_fp, 4)); + + /* skip c_1 to c_9 */ + fseek(globals.dvi_file.bak_fp, 9*4L, SEEK_CUR); + + /* next 4 byte contain offset to previous bop */ + offset = get_bytes(globals.dvi_file.bak_fp, 4); + } + /* If not prescanning, initialize page sizes. */ + if (!resource.prescan) { + for (i = 0; i < total_pages; ++i) { + pageinfo_set_page_width(i, m_paper_unshrunk_w); + pageinfo_set_page_height(i, m_paper_unshrunk_h); + pageinfo_set_window_width(i, dvi_unshrunk_page_w); + pageinfo_set_window_height(i, dvi_unshrunk_page_h); + } + } + return True; +} + +void +init_page(void) +{ + if (globals.dvi_file.bak_fp == NULL) + return; + globals.page.unshrunk_w = pageinfo_get_page_width(current_page); + globals.page.unshrunk_h = pageinfo_get_page_height(current_page); + globals.page.w = ROUNDUP(globals.page.unshrunk_w, mane.shrinkfactor) + 2; + globals.page.h = ROUNDUP(globals.page.unshrunk_h, mane.shrinkfactor) + 2; + TRACE_FILES((stderr, "init_page: setting globals.page.w = %d, globals.page.h = %d", globals.page.w, globals.page.h)); +} + +#ifndef S_ISDIR +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +static char *tmp_dvi_name = NULL; /* name of backup file for useTempFp */ + +/* access function for backup file name */ +char *get_tmp_dvi_name() { + return tmp_dvi_name; +} + +void +remove_tmp_dvi_file(void) +{ + if (tmp_dvi_name != NULL) + unlink(tmp_dvi_name); +} + + +static FILE * +make_backup_fp(FILE *source_fp, FILE *target_fp) +{ + static Boolean first_time = True; + static int tmp_fd = 0; + +#if !HAVE_FTRUNCATE + /* in this case, we can't use ftruncate() on the existing temp file - + just close the existing one, and set flag to open a new one */ + if (tmp_dvi_name != NULL) + unlink(tmp_dvi_name); + if (target_fp != NULL) + fclose(target_fp); + /* make sure we use a new temp file, else we'd have a race condition + after closing it */ + free(tmp_dvi_name); + tmp_dvi_name = NULL; + first_time = True; +#endif + + if (first_time) { /* doesn't exist yet, create it */ + if ((tmp_fd = xdvi_temp_fd(&tmp_dvi_name)) == -1) { + XDVI_ERROR((stderr, "error creating temporary file - disabling `useTempFp'.")); + return NULL; + } +/* fprintf(stderr, "temporary file name: |%s|, %d\n", tmp_dvi_name, tmp_fd); */ + TRACE_EVENTS((stderr, "Created temp file: |%s|\n", tmp_dvi_name)); + if ((target_fp = try_fdopen(tmp_fd, "wb+")) == NULL) { + XDVI_ERROR((stderr, "error opening temporary file (%s) - disabling `useTempFp'.", strerror(errno))); + return NULL; + } + first_time = False; + } + else { /* if not first time, truncate the existing file, + and position both files at beginning */ + ASSERT(target_fp != NULL, ""); + ASSERT(source_fp != NULL, ""); + +#if HAVE_FTRUNCATE + if (ftruncate(tmp_fd, 0) < 0) { + XDVI_ERROR((stderr, "Couldn't truncate file %s: %s - disabling `useTempFp'.", + tmp_dvi_name, strerror(errno))); + unlink(tmp_dvi_name); + fclose(target_fp); + return NULL; + } +#endif + fseek(target_fp, 0L, SEEK_SET); + fseek(source_fp, 0L, SEEK_SET); + } + + /* copy the file */ + if (!copy_fp(source_fp, target_fp)) { + XDVI_ERROR((stderr, + "Error creating temporary file: %s\n" + "- disabling `useTempFp'.", + strerror(errno))); + fclose(target_fp); + target_fp = NULL; + } + + /* rewind both files, else DVI parsing will fail! */ + fflush(target_fp); + fseek(source_fp, 0L, SEEK_SET); + if (target_fp != NULL) { + fseek(target_fp, 0L, SEEK_SET); + } + + return target_fp; +} + +static Boolean +file_exists_p(const char *path, dviErrFlagT *errflag) +{ + TRACE_FILES((stderr, "file_exists_p for |%s|", path)); + *errflag = UNKNOWN_ERROR; + if ((m_dvi_fp = XFOPEN(path, OPEN_MODE)) == NULL) { +/* fprintf(stderr, "after internal_open_dvi1: xfopen\n"); */ + *errflag = FILE_DOESNT_EXIST; + return False; + } + TRACE_FILES((stderr, "m_dvi_fp for |%s| = %p", path, (void *)m_dvi_fp)); +/* fprintf(stderr, "after internal_open_dvi2: xfopen\n"); */ + + /* shouldn't happen */ + if (fstat(fileno(m_dvi_fp), &fstatbuf) != 0 || S_ISDIR(fstatbuf.st_mode)) { /* if it's a directory */ + *errflag = FILE_IS_DIRECTORY; + fclose(m_dvi_fp); + m_dvi_fp = NULL; + return False; + } + /* If file has zero size, something has gone wrong with downloading + it, and the user should already have been warned about that; + just return in this case. + TODO: can it still happen that we try to load such a file as .dvi + file? (Will exit with `draw_part: unknown op-code xyz' or some such). + In this case, it would be better to look at the preamble before + entering the drawing loop. + */ + if (fstatbuf.st_size == 0) { + *errflag = FILE_HAS_ZERO_SIZE; + fclose(m_dvi_fp); + m_dvi_fp = NULL; + return False; + } + return True; +} + +/* + * internal_init_dvi is the main subroutine for reading the startup + * information from the dvi file. + */ + +static Boolean +internal_init_dvi(dviErrFlagT *errflag, Boolean load_fonts) +{ + char *icon_name = NULL, *title_name = NULL; + + have_src_specials = False; + + TRACE_FILES((stderr, "internal_init_dvi, globals.dvi_file.bak_fp = %p", (void *)globals.dvi_file.bak_fp)); + + if (!process_preamble(globals.dvi_file.bak_fp, errflag) + || !find_postamble(globals.dvi_file.bak_fp, errflag) + || !read_postamble(globals.dvi_file.bak_fp, errflag, load_fonts) + || !prepare_pages(errflag)) + return False; + + if (current_page >= total_pages) + current_page = total_pages - 1; + + globals.warn_spec_now = resource.warn_spec; + globals.src.fwd_box_page = -1; + search_reset_info(); + + if (globals.pausing.num_save != NULL) { + free(globals.pausing.num_save); + globals.pausing.num_save = NULL; + } + if (resource.pause && total_pages > 0) { + globals.pausing.num_save = xmalloc(total_pages * sizeof *globals.pausing.num_save); + memset(globals.pausing.num_save, 0, total_pages * sizeof *globals.pausing.num_save); + } + + init_prescan(); + /* this allocates icon_name and title_name */ + get_icon_and_title(globals.dvi_name, &icon_name, &title_name); + set_icon_and_title(icon_name, title_name); + free(icon_name); + free(title_name); + icon_name = title_name = NULL; + +#if defined(MOTIF) && HAVE_XPM + tb_check_navigation_sensitivity(current_page); +#endif + refresh_pagelist(total_pages, current_page); + + return True; +} + +/* + * internal_open_dvi does the real opening of the dvi file, and sets + * globals.dvi_file.time. It returns True on success, and sets m_dvi_fp and globals.dvi_file.bak_fp. + */ + +Boolean +internal_open_dvi(const char *path, dviErrFlagT *errflag, Boolean load_fonts) +{ +/* FILE *tmp_fp = NULL; */ +/* static FILE *bak_fp = NULL; /\* re-use the temporary backup fp *\/ */ +/* fprintf(stderr, "------------ opening: |%s|\n", path); */ + + TRACE_FILES((stderr, "internal_open_dvi for |%s|", path)); + close_old_filep(); + + if (!file_exists_p(path, errflag)) { /* this should set fstatbuf.st_mtime */ + return False; + } + + if (!resource.use_temp_fp || (globals.dvi_file.bak_fp = make_backup_fp(m_dvi_fp, globals.dvi_file.bak_fp)) == NULL) { + globals.dvi_file.bak_fp = m_dvi_fp; + } + globals.dvi_file.time = fstatbuf.st_mtime; + + if (!internal_init_dvi(errflag, load_fonts)) { + return False; + } + +#if COLOR + full_reset_colors(); +#endif /* COLOR */ + reset_papersize_special(); + + TRACE_FILES((stderr, "internal_open_dvi: SUCCESS!")); + + return True; +} + +/* + check whether `filename' is a DVI file, by checking if it exists, and if so, + opening it and trying to read a DVI preamble from it: +*/ +static char * +is_dvi_file(const char *filename) +{ + FILE *fp; + struct stat statbuf; + char *full_pathname; + dviErrFlagT unused_error; + + TRACE_FILES((stderr, "is_dvi_file %s", filename)); + TRACE_HTEX((stderr, "filename: |%s|", filename)); + + /* used to append `.dvi' if not already present, but that was a + bad idea - if we have both foo.2 and foo.2.dvi, user will want + to open `foo.2' (with some appropriate application) if the link + points to that filename. This means that we need to have + different semantics for filenames on the command-line and + filenames in hyperlinks; the latter *must* specify an + extension, the former may omit the extension and default to DVI + files. + */ + /* if ((full_filename = filename_append_dvi(filename)) == NULL) { */ + /* free(full_filename); */ + /* return NULL; */ + /* } */ + /* TRACE_HTEX((stderr, "full_filename: |%s|\n", full_filename)); */ + + if ((full_pathname = find_file(filename, &statbuf, kpse_program_text_format)) == NULL) { + return NULL; + } + else { + char *tmp = canonicalize_path(full_pathname); + free(full_pathname); + full_pathname = tmp; + } + + TRACE_HTEX((stderr, "is_dvi_file: full_pathname: |%s|", full_pathname)); + + if ((fp = XFOPEN(full_pathname, OPEN_MODE)) == NULL) { + free(full_pathname); + return NULL; + } + + if (!process_preamble(fp, &unused_error)) { + free(full_pathname); + fclose(fp); + return NULL; + } + + fclose(fp); + return full_pathname; +} + +static void +report_open_error(const char *msg, const char *filename, dviErrFlagT errflag) +{ + const char *errmsg; + switch(errflag) { + case FILE_HAS_ZERO_SIZE: + errmsg = "File has zero size"; + break; + case FILE_DOESNT_EXIST: + errmsg = "No such file"; + break; + case FILE_IS_DIRECTORY: + errmsg = "Is a directory"; + break; + default: + errmsg = "An unknown error occurred"; + break; + } + XDVI_ERROR((stderr, "%s: %s: %s", msg, filename, errmsg)); +} + +/* + Implements the algorithm for opening a DVI file from the command line. + This is similar to `open_dvi_file()' in non-k xdvi. + + If the file does not already have `.dvi' extension, append `.dvi' + and set tried_dvi_ext to True. Try to open this file. If the file + doesn't exist, try the original file name. If this file doesn't + exist either, exit with an error message `No such file or directory'. + If tried_dvi_ext == True, also report that file.dvi didn't exist + either. + + (A later function will check if the file really is a DVI file, and + will use tried_dvi_ext for the same purpose). +*/ +char * +find_dvi_file(const char *filename, Boolean *tried_dvi_ext, Boolean from_file_history) +{ + char *new_filename; + size_t len; + dviErrFlagT errflag; + + ASSERT(filename != NULL, "Filename argument in find_dvi_file() musn't be NULL"); + len = strlen(filename); + + if (len < sizeof(".dvi") || strcmp(filename + len - sizeof(".dvi") + 1, ".dvi") != 0) { + /* doesn't already have .dvi extension */ + TRACE_HTEX((stderr, "|%s| doesn't have .dvi extension, appending ...", filename)); + new_filename = xstrdup(filename); + new_filename = xstrcat(new_filename, ".dvi"); + *tried_dvi_ext = True; + + if (file_exists_p(new_filename, &errflag)) { /* file exists */ + char *expanded_filename = expand_filename(new_filename, USE_CWD_PATH); + free(new_filename); + return expanded_filename; + } + else { /* don't report an error; will try verbatim filename next */ + free(new_filename); + } + } + + /* try verbatim filename (might be strange things like `foo.wdvi') */ + if (file_exists_p(filename, &errflag)) { + char *expanded_filename = expand_filename(filename, USE_CWD_PATH); + return expanded_filename; + } + else { + if (*tried_dvi_ext) { + if (!from_file_history) { + XDVI_FATAL((stderr, "%s: %s, and %s.dvi doesn't exist either.", + filename, get_dvi_error(errflag), filename)); + } + else { + popup_message(globals.widgets.top_level, + MSG_ERR, + NULL, + "Could not open \"%s\": %s.\n", filename, get_dvi_error(errflag)); + } + } + else { + if (!from_file_history) { + XDVI_FATAL((stderr, "%s: %s.", filename, get_dvi_error(errflag))); + } + /* else: file is from history; this is at startup, where we may + loop through the history until we find a usable file. Don't report + an error in this case. */ + } + } + return NULL; +} + + + +/* + * A wrapper for open_dvi_file that can also deal with remote files/URLs, and other + * file types. Returns the (newly malloc'ed) new dvi file name if it succeeds, NULL else. + */ +char * +open_dvi_file_wrapper(const char *filename, + Boolean from_command_line, + Boolean open_new_instance, + Boolean *tried_dvi_ext, + Boolean from_file_history) +{ + char *real_filename = NULL; + char *new_dvi_name = NULL; + char canonical_path[MAXPATHLEN + 1]; + + if (from_command_line) { + TRACE_HTEX((stderr, "filename IS from commandline")); + /* + if filename is from command-line, we want to treat the file as a DVI file + always (and NOT launch the browser or other programs; that'd just confuse + people, who meant to launch *xdvi*). `find_dvi_file' tries to locate the + file and does all error handling; on success, it returns a fully expanded + filename. + */ + real_filename = find_dvi_file(filename, tried_dvi_ext, from_file_history); /* this allocates real_filename */ + if (real_filename == NULL) + return False; + + TRACE_HTEX((stderr, "filename |%s| %p from commandline;\ndvi_name: |%s|,\nfilename: |%s|%p", + real_filename, real_filename, globals.dvi_name, filename, (void *)filename)); + new_dvi_name = xstrdup(REALPATH(real_filename, canonical_path)); + free(real_filename); + TRACE_FILES((stderr, "new_dvi_name: |%s|", new_dvi_name)); + return new_dvi_name; + } + else { + /* + if it's not from the command line (e.g. result of clicking Mouse-1 on a link); + in this case we might fall back to using the browser. + Check whether it's a local file: + */ + const char *filename_no_prefix; + char *expanded_filename; + TRACE_HTEX((stderr, "filename NOT from commandline")); + if ((filename_no_prefix = is_local_file(filename)) != NULL) { + /* if it's a local file, check whether it's a DVI file: */ + if ((expanded_filename = is_dvi_file(filename_no_prefix)) != NULL) { + /* yes, open it */ + if (open_dvi_file(expanded_filename, open_new_instance)) { + TRACE_FILES((stderr, "success: %p |%s|", expanded_filename, expanded_filename)); + if (!open_new_instance) { + new_dvi_name = expand_filename_append_dvi(expanded_filename, USE_DVI_PATH, True); + TRACE_FILES((stderr, "new_dvi_name: %p |%s|", (void*)new_dvi_name, new_dvi_name)); + } + } + free(expanded_filename); + return new_dvi_name; + } + else { + /* + local file, but not a DVI file; + try other viewers for this MIME type: + */ + TRACE_HTEX((stderr, "%s is NOT a DVI file", filename_no_prefix)); + launch_program(filename); + return NULL; + } + } + else { + /* not a local file, retrieve it with the browser: */ + launch_browser(filename); + return NULL; + } + } +} + + +static Boolean +open_dvi_file(const char *filename, Boolean open_new_instance) +{ + Boolean retval = True; + + char *anchor_name = resource.anchor_pos; + + TRACE_HTEX((stderr, "open_dvi_file: |%s| + |%s|", + filename, anchor_name == NULL ? "<no anchor>" : anchor_name)); + + if (open_new_instance) { + launch_xdvi(filename, anchor_name); + } + else { + dviErrFlagT errflag = NO_ERROR; + TRACE_HTEX((stderr, "internal_open_dvi: |%s|", filename)); + if (!internal_open_dvi(filename, &errflag, True)) { +/* || !internal_init_dvi(&errflag, True)) { */ + report_open_error("Cannot open DVI file", filename, errflag); + retval = False; + } + } + return retval; +} + +/** + ** form_dvi_property forms the property used to exhibit the dvi file name + ** used as a window property (used for source specials). + **/ + +void +form_dvi_property(void) +{ +#if 0 + size_t len; + unsigned long ino; + int i; +#endif + + if (m_dvi_fp == NULL) + return; + + if (dvi_property != NULL) + free(dvi_property); + + dvi_property_length = strlen(globals.dvi_name) + 1; /* also copy the terminating 0 */ + dvi_property = xmalloc(dvi_property_length); + + /* NOTE: we don't use dvi_inode like non-k xdvi, since dvi_name is + always fully expanded with xdvik. */ + strcpy(dvi_property, globals.dvi_name); +} + + +/* access for m_dvi_fp */ +void +close_old_filep(void) +{ + if (m_dvi_fp != NULL) { + fclose(m_dvi_fp); + m_dvi_fp = NULL; + if (!resource.use_temp_fp) + globals.dvi_file.bak_fp = NULL; + } +} + + + +/** + ** Check for changes in dvi file. + ** Return True if file has changed, False else. + **/ + +Boolean +dvi_file_changed(void) +{ + TRACE_FILES((stderr, "dvi_file_changed: fp = %p?", (void *)m_dvi_fp)); + +/* fprintf(stderr, "m_dvi_fp3: %p (%s)\n", m_dvi_fp, globals.dvi_name); */ + if (m_dvi_fp == NULL) { + TRACE_FILES((stderr, "m_dvi_fp == NULL")); + if (stat(globals.dvi_name, &fstatbuf) == 0 && fstatbuf.st_mtime != globals.dvi_file.time) { + TRACE_FILES((stderr, "file changed")); + if (resource.use_temp_fp) { + dviErrFlagT errflag = NO_ERROR; + + if (resource.watch_file == 0.0) + statusline_print(STATUS_MEDIUM, "File changed ..."); + TRACE_FILES((stderr, "returning FALSE")); + + if (file_exists_p(globals.dvi_name, &errflag) + && process_preamble(m_dvi_fp, &errflag) + && find_postamble(m_dvi_fp, &errflag) + && read_postamble(m_dvi_fp, &errflag, False)) { + TRACE_FILES((stderr, "File OK, reloading ...")); + + globals.ev.flags |= EV_RELOAD; + return True; + } + else { + return False; + } + } + /* Bug alert: Don't set EV_RELOAD again here, else xdvi + can go into a stretch of time where it again and again + tries to reload a file even if the user doesn't click + on the canvas. + */ + /* + else { + globals.ev.flags |= EV_RELOAD; + } + */ + TRACE_FILES((stderr, "returning TRUE")); + return True; + } + else { + TRACE_FILES((stderr, "file not changed")); + } + } + /* BUG ALERT: Don't use fstat(fileno(m_dvi_fp) here; if file hase + disappeared, this won't report an error! */ + else if (stat(globals.dvi_name, &fstatbuf) != 0 /* stat failed ... */ + || fstatbuf.st_mtime != globals.dvi_file.time /* ... or different timestamp, reload: */) { + dviErrFlagT errflag = NO_ERROR; + + TRACE_FILES((stderr, "Stat failed, or different timestamp ...")); + globals.dvi_file.time = 0; /* force reload next time also if stat failed */ + + if (resource.use_temp_fp) { /* in this case, reload only if file has been written completely */ + if (resource.watch_file == 0.0) { + statusline_print(STATUS_MEDIUM, "File corrupted (click on window to reload) ..."); + globals.cursor.flags |= CURSOR_CORRUPTED; + globals.ev.flags |= EV_CURSOR; + } + else { + statusline_print(STATUS_MEDIUM, "File corrupted (will try to reload) ..."); + } + close_old_filep(); + if (file_exists_p(globals.dvi_name, &errflag) + && process_preamble(m_dvi_fp, &errflag) + && find_postamble(m_dvi_fp, &errflag) + && read_postamble(m_dvi_fp, &errflag, False)) { + TRACE_FILES((stderr, "File OK, reloading ...")); + + globals.ev.flags |= EV_RELOAD; + return True; + } + else { + TRACE_FILES((stderr, "NO successful load: %s", get_dvi_error(errflag))); +/* fprintf(stderr, "=========== NO successful load: %s\n", get_dvi_error(errflag)); */ + return False; + } + } + else { + TRACE_FILES((stderr, "Not using temp fp, reloading...")); + globals.ev.flags |= EV_RELOAD; + return True; + } + } + return False; +} + +/** + ** Reload the dvi file (unconditionally). Return True on success, False else. + **/ + +Boolean +load_dvi_file(Boolean load_fonts, dviErrFlagT *errflag) +{ + unsigned int old_page_w, old_page_h; + static ino_t dvi_inode = 0; + + TRACE_FILES((stderr, "load_dvi_file: going to read %p", (void *)m_dvi_fp)); + + if (resource.use_temp_fp && m_dvi_fp != NULL) { + /* in this case, reload only if file has been written completely */ + *errflag = NO_ERROR; + fseek(m_dvi_fp, 0L, SEEK_SET); + if (!process_preamble(m_dvi_fp, errflag) + || !find_postamble(m_dvi_fp, errflag) + || !read_postamble(m_dvi_fp, errflag, True)) { + TRACE_FILES((stderr, "reading of %p failed: %s!", + (void *)m_dvi_fp, + get_dvi_error(*errflag))); + return False; + } + } + + old_page_w = globals.page.w; + old_page_h = globals.page.h; + + *errflag = NO_ERROR; + if (!internal_open_dvi(globals.dvi_name, errflag, load_fonts)) { +/* || !internal_init_dvi(errflag, load_fonts)) { */ + XClearWindow(DISP, mane.win); + XBell(DISP, 0); + statusline_print(STATUS_MEDIUM, "%s: %s%s", globals.dvi_name, get_dvi_error(*errflag), + resource.watch_file > 0.0 ? "; will try to reload ..." : " (click on window to reload)"); + close_old_filep(); + + return False; + } + else { /* success */ + if (fstatbuf.st_ino != dvi_inode) { + dvi_inode = fstatbuf.st_ino; + form_dvi_property(); + set_dvi_property(); + } + if (globals.page.w != old_page_w || globals.page.h != old_page_h) + reconfig(); + + htex_reinit(); + + globals.cursor.flags &= ~CURSOR_CORRUPTED; + return True; + } +} |