Back to index

tetex-bin  3.0
dvi-init.c
Go to the documentation of this file.
00001 /*========================================================================*\
00002 
00003 Copyright (c) 1990-2004  Paul Vojta
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to
00007 deal in the Software without restriction, including without limitation the
00008 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00009 sell copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011 
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00018 PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
00019 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00020 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00021 OTHER DEALINGS IN THE SOFTWARE.
00022 
00023 NOTE:
00024        xdvi is based on prior work, as noted in the modification history
00025        in xdvi.c.
00026 
00027 \*========================================================================*/
00028 
00029 #include "xdvi-config.h"
00030 #include "xdvi.h"
00031 
00032 #include "dvi-init.h"
00033 #include "dvi-draw.h"
00034 #include "util.h"
00035 #include "x_util.h"
00036 #include "mime.h"
00037 #include "pagesel.h"
00038 #include "special.h"
00039 #include "hypertex.h"
00040 #include "kpathsea/c-fopen.h"
00041 #include "kpathsea/c-stat.h"
00042 #include "kpathsea/magstep.h"
00043 #include "kpathsea/tex-glyph.h"
00044 #include "dvi.h"
00045 #include "string-utils.h"
00046 #include "browser.h"
00047 #include "sfSelFile.h"
00048 #include "xm_toolbar.h"
00049 #include "pagehist.h"
00050 
00051 #ifdef T1LIB
00052 #include "t1lib.h"
00053 #endif
00054 
00055 #include "message-window.h"
00056 #include "search-internal.h"
00057 #include "statusline.h"
00058 #include "events.h"
00059 #include "font-open.h"
00060 
00061 #define       PK_PRE        247
00062 #define       PK_ID         89
00063 #define       PK_MAGIC      ((PK_PRE << 8) | PK_ID)
00064 #define       GF_PRE        247
00065 #define       GF_ID         131
00066 #define       GF_MAGIC      ((GF_PRE << 8) | GF_ID)
00067 #define       VF_PRE        247
00068 #define       VF_ID_BYTE    202
00069 #define       VF_MAGIC      ((VF_PRE << 8) | VF_ID_BYTE)
00070 
00071 /* font stuff */
00072 struct font *tn_table[TNTABLELEN];
00073 struct font *font_head = NULL;
00074 struct tn *tn_head = NULL;
00075 wide_ubyte maxchar;
00076 unsigned short       current_timestamp = 0;
00077 
00078 
00079 unsigned long magnification;
00080 double dimconv;
00081 double tpic_conv;
00082 
00083 /* Curently processed page number (starting at 0). */
00084 int current_page = 0;
00085 int total_pages = 0;
00086 
00087 /* postamble offset is saved in this global variable */
00088 long g_postamble_offset;
00089 
00090 
00091 static struct stat fstatbuf;
00092 
00093 static FILE *m_dvi_fp = NULL; /* original user's file */
00094 
00095 
00096 static Boolean open_dvi_file(const char *filename, Boolean open_new_instance);
00097 
00098 /*
00099  * DVI preamble and postamble information.
00100  */
00101 static unsigned long numerator, denominator;
00102 static unsigned int dvi_unshrunk_page_w, dvi_unshrunk_page_h;
00103 static unsigned int m_paper_unshrunk_w, m_paper_unshrunk_h;
00104 
00105 
00106 /*
00107  * Offset in DVI file of last page, set in read_postamble().
00108  */
00109 static long m_last_page_offset;
00110 
00111 static const char *dvi_err_list[] = {
00112     /* NO_ERROR                  */       "No Error",
00113     /* WRONG_DVI_VERSION         */       "Wrong version of DVI output for this program",
00114     /* DVI_CORRUPTED             */       "DVI file corrupted",
00115     /* NOT_A_DVI_FILE            */       "Not a DVI file",
00116     /* POSTAMBLE_NO_POST         */       "Postamble doesn't begin with POST",
00117     /* POSTAMBLE_NO_MATCH        */       "Postamble doesn't match preamble",
00118     /* POSTAMBLE_NON_FNTDEF      */       "Non-fntdef command found in postamble",
00119     /* NOT_ALL_PIXEL_FILES_FOUND */       "Not all pixel files were found",
00120     /* NO_BOP_AT_PAGEDESC        */       "Page description doesn't begin with BOP",
00121     /* FILE_HAS_ZERO_SIZE        */       "File has zero size",
00122     /* FILE_DOESNT_EXIST         */       "No such file",
00123     /* FILE_IS_DIRECTORY         */       "Is a directory",
00124     /* UNKNOWN_ERROR             */       "An unknown error occurred"
00125 };
00126 
00127 /*
00128  * access method for above list
00129  */
00130 const char *
00131 get_dvi_error(dviErrFlagT flag) {
00132     ASSERT(flag < XtNumber(dvi_err_list), "Flag out of range");
00133     return dvi_err_list[flag];
00134 }
00135 
00136 /*
00137  *     free_vf_chain frees the vf_chain structure.
00138  */
00139 
00140 static void
00141 free_vf_chain(struct tn *tnp)
00142 {
00143     while (tnp != NULL) {
00144        struct tn *tnp1 = tnp->next;
00145        free((char *)tnp);
00146        tnp = tnp1;
00147     }
00148 }
00149 
00150 /*
00151  *     delete glyph information in a font.
00152  */
00153 
00154 static void
00155 delete_glyphs(struct font *fontp)
00156 {
00157     struct glyph *g;
00158 
00159     for (g = fontp->glyph; g <= fontp->glyph + fontp->maxchar; ++g) {
00160        if (g->bitmap2.bits) {
00161            free(g->bitmap2.bits);
00162            g->bitmap2.bits = NULL;
00163        }
00164 #ifdef GREY
00165        if (g->pixmap2) {
00166            XDestroyImage(g->image2);
00167            g->pixmap2 = NULL;
00168            if (g->pixmap2_gc2 != NULL) {
00169               free(g->pixmap2_gc2);
00170               g->pixmap2_gc2 = NULL;
00171            }
00172        }
00173 #if COLOR
00174        g->fg = NULL;
00175 #endif
00176 #endif
00177     }
00178 }
00179 
00180 /*
00181  *     Release all shrunken bitmaps for all fonts.
00182  */
00183 
00184 void
00185 reset_fonts(void)
00186 {
00187     struct font *f;
00188 
00189     for (f = font_head; f != NULL; f = f->next) {
00190        if ((f->flags & FONT_LOADED) && !(f->flags & FONT_VIRTUAL)) {
00191            delete_glyphs(f);
00192        }
00193     }
00194 }
00195 
00196 /*
00197  * free up fonts no longer in use.
00198  */
00199 static void
00200 free_unused_fonts(void)
00201 {
00202     struct font *fontp;
00203     struct font **fontpp;
00204 
00205     fontpp = &font_head;
00206     while ((fontp = *fontpp) != NULL) {
00207        if (fontp->flags & FONT_IN_USE)
00208            fontpp = &fontp->next;
00209        else {
00210            if (globals.debug & DBG_PK)
00211               printf("xdvi: Discarding font \"%s\" at %d dpi\n",
00212                      fontp->fontname, (int)(fontp->fsize + 0.5));
00213            *fontpp = fontp->next;  /* remove from list */
00214            free(fontp->fontname);
00215            if (fontp->flags & FONT_LOADED) {
00216               if (fontp->file != NULL) {
00217                   fclose(fontp->file);
00218               }
00219               free(fontp->filename);
00220               if (fontp->flags & FONT_VIRTUAL) {
00221                   struct macro *m;
00222 
00223                   for (m = fontp->macro;
00224                       m <= fontp->macro + fontp->maxchar; ++m)
00225                          if (m->free_me) free((char *)m->pos);
00226                   free((char *)fontp->macro);
00227                   free((char *)fontp->vf_table);
00228                   free_vf_chain(fontp->vf_chain);
00229               }
00230               else {
00231                   delete_glyphs(fontp);
00232                   free((char *)fontp->glyph);
00233               }
00234               free((char *)fontp);
00235            }
00236        }
00237     }
00238 }
00239 
00240 #if COLOR
00241 
00242 /*
00243  *     Release all allocated pixels, and (in greyscale mode) invalidate
00244  *     all shrunken glyphs.
00245  */
00246 
00247 void
00248 reset_colors(void)
00249 {
00250     if (color_list_len != 0) {
00251        XFreeColors(DISP, G_colormap, color_list, color_list_len, 0);
00252        color_list_len = 0;
00253     }
00254     while (bg_head != NULL) {
00255        struct bgrec *bgp;
00256        struct fgrec *fgp;
00257 
00258        for (fgp = bg_head->fg_head; fgp != NULL;) {
00259            struct fgrec *fgp1 = fgp->next;
00260            free(fgp);
00261            fgp = fgp1;
00262        }
00263        bgp = bg_head->next;
00264        free(bg_head);
00265        bg_head = bgp;
00266     }
00267 #if GREY
00268     if (resource.use_grey) {
00269        struct font *f;
00270        struct glyph *g;
00271 
00272        for (f = font_head; f != NULL; f = f->next)
00273            if ((f->flags & FONT_LOADED) && !(f->flags & FONT_VIRTUAL))
00274               for (g = f->glyph; g <= f->glyph + f->maxchar; ++g)
00275                   g->fg = NULL;
00276     }
00277 #endif /* GREY */
00278     bg_current = NULL;
00279     fg_active = NULL;
00280     color_warned = False;
00281 }
00282 
00283 /*
00284  *     All of the above, plus discard all scanned information.
00285  */
00286 
00287 void
00288 full_reset_colors(void)
00289 {
00290     if (page_colors.stack != NULL) {
00291        size_t i;
00292        struct rgb *last_freed = &fg_initial;
00293 
00294        /* fprintf(stderr, "i: %d; last freed: %p\n", page_colors.size, &fg_initial); */
00295        for (i = 0; i < page_colors.size; ++i) {
00296            if (page_colors.stack[i].colorstack != last_freed) {
00297               last_freed = page_colors.stack[i].colorstack;
00298               /* BUG ALERT: don't free &fg_initial, else segfault with changing
00299                  foreground in xm_colorsel.c! */
00300               if (last_freed != NULL && last_freed != &fg_initial) {
00301                   /* fprintf(stderr, "freeing %d: %p\n", i, last_freed); */
00302                   free(last_freed);
00303               }
00304            }
00305        }
00306        free(page_colors.stack);
00307        page_colors.stack = NULL;
00308     }
00309     reset_colors();
00310 }
00311 
00312 #endif /* COLOR */
00313 
00314 
00315 
00316 /*
00317  *     realloc_font allocates the font structure to contain (newsize + 1)
00318  *     characters.
00319  */
00320 
00321 void
00322 realloc_font(struct font *fontp, wide_ubyte newsize)
00323 {
00324     struct glyph *glyph;
00325 
00326     glyph = fontp->glyph = xrealloc(fontp->glyph,
00327                                 (unsigned int)(newsize + 1) * sizeof(struct glyph));
00328     if (newsize > fontp->maxchar)
00329        memset((char *)(glyph + fontp->maxchar + 1), 0,
00330              (int)(newsize - fontp->maxchar) * sizeof(struct glyph));
00331     maxchar = fontp->maxchar = newsize;
00332 }
00333 
00334 
00335 /*
00336  *     realloc_virtual_font does the same thing for virtual fonts.
00337  */
00338 
00339 void
00340 realloc_virtual_font(struct font *fontp, wide_ubyte newsize)
00341 {
00342     struct macro *macro;
00343 
00344     macro = fontp->macro = xrealloc(fontp->macro,
00345                                 (unsigned int)(newsize + 1) * sizeof(struct macro));
00346     if (newsize > fontp->maxchar)
00347        memset((char *)(macro + fontp->maxchar + 1), 0,
00348              (int)(newsize - fontp->maxchar) * sizeof(struct macro));
00349     maxchar = fontp->maxchar = newsize;
00350 }
00351 
00352 
00353 /*
00354  * load_font locates the t1 font or raster file and reads the index of
00355  * characters, plus whatever other preprocessing is done (depending on
00356  * the format).
00357  *
00358  * Returns True if sucessful, False if not.
00359  */
00360 
00361 Boolean
00362 load_font(struct font *fontp, Boolean use_t1lib)
00363 {
00364     double fsize = fontp->fsize;
00365     int dpi = fsize + 0.5;
00366     char *font_found;
00367     int size_found;
00368     int magic;
00369     Boolean hushcs = resource.hush_chk;
00370 
00371     fontp->file = NULL;
00372 
00373     /* BUG ALERT: This used to be:
00374      *
00375      * if (--globals.ev.ctr == 0) {
00376      *     read_events(EV_GE_IDLE);
00377      * }
00378      * force_statusline_update();
00379      * XSync(DISP, False);
00380      *
00381      * The idea was to update the `loading fonts ...' popup. However,
00382      * calling read_events() here may call dvi_file_changed() if the
00383      * user clicks on the window, which calls file_exists_p(), and
00384      * that changes m_dvi_fp while it's still being used to read the
00385      * postamble (where load_font() is called from), which will cause
00386      * xdvi to crash! (bug #968127).
00387      *
00388      * Sadly, without this update, the `loading fonts' popup doesn't
00389      * appear before the main window comes up ...
00390      */
00391 
00392 #ifdef T1LIB
00393     fontp->file = font_open(fontp->fontname, &font_found,
00394                          fsize, &size_found,
00395                          &fontp->filename, &fontp->t1id);
00396 #else
00397     fontp->file = font_open(fontp->fontname, &font_found,
00398                          fsize, &size_found,
00399                          &fontp->filename);
00400 #endif /* T1LIB */
00401 
00402 #ifdef T1LIB
00403     if (fontp->t1id >= 0 && use_t1lib) {
00404        /* It's a type1 font */
00405        fontp->fsize = fsize;       /* It comes in all sizes */
00406        fontp->timestamp = ++current_timestamp;
00407        fontp->maxchar = maxchar = 255;
00408        fontp->set_char_p = set_t1_char;
00409        /* read_T1_char is a dummy */
00410        fontp->read_char = read_T1_char;
00411        fontp->glyph = xmalloc (256 * sizeof (struct glyph));
00412        memset((char *) fontp->glyph, 0, 256 * sizeof (struct glyph));
00413        fontp->flags |= FONT_LOADED;
00414        if (font_found != NULL) {
00415            statusline_print(STATUS_MEDIUM,
00416                           "Error: Can't find font %s; using %s instead. Expect ugly output.",
00417                           fontp->fontname, font_found);
00418            force_statusline_update();
00419            free(fontp->fontname);
00420            fontp->fontname = font_found; /* this has been allocated by font_open */
00421        }
00422        return True;
00423     }
00424 #endif /* T1LIB */
00425     /* when not using T1lib, fontp->file == NULL means total failure */
00426     if (fontp->file == NULL) {
00427        if (globals.ev.flags & EV_GE_NEWDOC)
00428            return False;
00429        fontp->flags |= FONT_LOADED;       /* as loaded as it'll get */
00430        XDVI_ERROR((stderr, "Can't find font %s.%dpk", fontp->fontname, dpi));
00431        return False;
00432     }
00433     fontp->flags |= FONT_LOADED;
00434 
00435     if (font_found != NULL  && strcmp(fontp->fontname, font_found) != 0) {
00436        /* some other font used - FIXME: is there a more efficient way than strcmp() for checking this? */
00437        statusline_print(STATUS_MEDIUM,
00438                       "Can't find pixel font %s; using %s instead at %d dpi.",
00439                       fontp->fontname, font_found, dpi);
00440        force_statusline_update();
00441        free(fontp->fontname);
00442        fontp->fontname = font_found; /* this has been allocated by font_open */
00443        hushcs = True;
00444     }
00445     else if (!kpse_bitmap_tolerance((double)size_found, fsize)) { /* a different size used */
00446        statusline_print(STATUS_MEDIUM,
00447                       "Can't find pixel font %s at %d dpi; using %d dpi instead.",
00448                       fontp->fontname, dpi, size_found);
00449        force_statusline_update();
00450     }
00451 
00452     /* PK version of some font found */
00453     fontp->fsize = size_found;
00454     fontp->timestamp = ++current_timestamp;
00455     fontp->maxchar = maxchar = 255;
00456     fontp->set_char_p = set_char;
00457     magic = get_bytes(fontp->file, 2);
00458 
00459     switch(magic) {
00460     case PK_MAGIC:
00461        read_PK_index(fontp, (wide_bool)hushcs);
00462        break;
00463 #ifdef USE_GF
00464     case GF_MAGIC:
00465        read_GF_index(fontp, (wide_bool)hushcs);
00466        break;
00467 #endif
00468     case VF_MAGIC:
00469        if (resource.omega)
00470            maxchar = read_VF_index(fontp, (wide_bool)hushcs);
00471        else
00472            (void)read_VF_index(fontp, (wide_bool)hushcs);
00473        break;
00474     default:
00475        XDVI_FATAL((stderr, "Cannot recognize format for font file %s", fontp->filename));
00476        break;
00477     }
00478     
00479     if (fontp->flags & FONT_VIRTUAL) {
00480        if (!resource.omega) {
00481            while (maxchar > 0 && fontp->macro[maxchar].pos == NULL) {
00482               --maxchar;
00483            }
00484            if (maxchar < 255) {
00485               realloc_virtual_font(fontp, (wide_ubyte)maxchar);
00486            }
00487        }
00488     }
00489     else {
00490        while (maxchar > 0 && fontp->glyph[maxchar].addr == 0)
00491            --maxchar;
00492        if (maxchar < 255)
00493            realloc_font(fontp, (wide_ubyte)maxchar);
00494     }
00495     return True;
00496 }
00497 
00498 
00499 /*
00500  *     MAGSTEPVALUE - If the given magnification is close to a \magstep
00501  *     or a \magstephalf, then return twice the number of \magsteps.
00502  *     Otherwise return NOMAGSTP.
00503  */
00504 
00505 #define       NOMAGSTP (-29999)
00506 #define       NOBUILD       29999
00507 
00508 static int
00509 magstepvalue(float *mag)
00510 {
00511     int m = 0;
00512     double fmag = *mag;
00513     double xmag = resource.pixels_per_inch;
00514     float margin = fmag * 0.002;
00515 
00516     if (fmag < resource.pixels_per_inch)
00517        for (;;) {
00518            if (xmag - fmag < margin && -(xmag - fmag) < margin) {
00519               *mag = xmag;
00520               return m;
00521            }
00522            if (xmag < fmag)
00523               break;
00524            xmag *= 0.9128709292;
00525            --m;
00526        }
00527     else
00528        for (;;) {
00529            if (xmag - fmag < margin && -(xmag - fmag) < margin) {
00530               *mag = xmag;
00531               return m;
00532            }
00533            if (xmag > fmag)
00534               break;
00535            xmag *= 1.095445115;
00536            ++m;
00537        }
00538     return NOMAGSTP;
00539 }
00540 
00541 /*
00542  *     reuse_font recursively sets the flags for font structures being reused.
00543  */
00544 
00545 static void
00546 reuse_font(struct font *fontp)
00547 {
00548     struct font **fp;
00549     struct tn *tnp;
00550 
00551     if (fontp->flags & FONT_IN_USE)
00552        return;
00553 
00554     fontp->flags |= FONT_IN_USE;
00555     if (resource.list_fonts)
00556        printf("xdvi: (reusing) %s at %d dpi\n", fontp->fontname,
00557               (int)(fontp->fsize + 0.5));
00558     if (fontp->flags & FONT_VIRTUAL) {
00559        for (fp = fontp->vf_table; fp < fontp->vf_table + VFTABLELEN; ++fp)
00560            if (*fp != NULL)
00561               reuse_font(*fp);
00562        for (tnp = fontp->vf_chain; tnp != NULL; tnp = tnp->next)
00563            reuse_font(tnp->fontp);
00564     }
00565 }
00566 
00567 
00568 /*
00569  *      define_font reads the rest of the fntdef command and then reads in
00570  *      the specified pixel file, adding it to the global linked-list holding
00571  *      all of the fonts used in the job.
00572  */
00573 struct font *
00574 define_font(Boolean load_font_now, /* only scanning, or also loading the font? */
00575            FILE *file, wide_ubyte cmnd,
00576            struct font *vfparent,  /* vf parent of this font, or NULL */
00577            struct font **tntable,  /* table for low TeXnumbers */
00578            unsigned int tn_table_len,     /* length of table for TeXnumbers */
00579            struct tn **tn_headpp,  /* addr of head of list of TeXnumbers */
00580            Boolean *not_found_flag)       /* signal that font hasn't been found */
00581 {
00582     unsigned int TeXnumber;
00583     struct font *fontp;
00584     float fsize;
00585     double scale_dimconv;
00586     long checksum;
00587     int scale, orig_scale;
00588     int design;
00589     int magstepval;
00590     int len;
00591     char *fontname;
00592     int size;
00593 
00594     TeXnumber = get_bytes(file, (int)cmnd - FNTDEF1 + 1);
00595     checksum = get_bytes(file, 4);
00596     scale = orig_scale = get_bytes(file, 4);
00597     design = get_bytes(file, 4);
00598     len = get_byte(file);
00599     len += get_byte(file);  /* sequence point in the middle */
00600 
00601     if (!load_font_now)
00602        return NULL;
00603     
00604     fontname = xmalloc((unsigned)len + 1);
00605     fread(fontname, sizeof(char), len, file);
00606     fontname[len] = '\0';
00607     if (globals.debug & DBG_PK)
00608        printf("xdvi: Define font \"%s\" scale=%d design=%d number=%d\n",
00609               fontname, scale, design, TeXnumber);
00610     if (vfparent == NULL) {
00611        fsize = 0.001 * scale / design * magnification * resource.pixels_per_inch;
00612        scale_dimconv = dimconv;
00613     }
00614     else {
00615        /*
00616         * The scaled size is given in units of vfparent->scale * 2 ** -20
00617         *      SPELL units, so we convert it into SPELL units by multiplying by
00618         *              vfparent->dimconv.
00619         *      The design size is given in units of 2 ** -20 pt, so we convert
00620         *      into SPELL units by multiplying by
00621         *              (resource.pixels_per_inch * 2**16) / (72.27 * 2**20).
00622         */
00623        fsize = (72.27 * (1 << 4)) * vfparent->dimconv * scale / design;
00624        scale_dimconv = vfparent->dimconv;
00625        /* Inherit the scale from the virtual parent */
00626        scale = vfparent->scale * ((orig_scale * scale_dimconv / (1 << 20)) / vfparent->dimconv);
00627     }
00628     magstepval = magstepvalue(&fsize);
00629     size = fsize + 0.5;
00630     /*
00631      * reuse font if possible
00632      */
00633     for (fontp = font_head;; fontp = fontp->next) {
00634        if (fontp == NULL) { /* if font doesn't exist yet */
00635            if (resource.list_fonts)
00636               printf("xdvi: %s at %d dpi\n", fontname, (int)(fsize + 0.5));
00637            fontp = xmalloc((unsigned)sizeof(struct font));
00638            fontp->fontname = fontname;
00639            fontp->fsize = fsize;
00640            fontp->magstepval = magstepval;
00641            fontp->file = NULL;     /* needed if it's a virtual font */
00642            fontp->checksum = checksum;
00643            fontp->flags = FONT_IN_USE;
00644            fontp->dimconv =  orig_scale * scale_dimconv / (1 << 20);
00645            fontp->set_char_p = load_n_set_char;
00646            fontp->scale = scale;
00647            if (vfparent == NULL)
00648               if (!load_font(fontp, resource.t1lib)) {
00649                   if (globals.ev.flags & EV_GE_NEWDOC) {       /* if aborting */
00650                      free(fontname);
00651                      free(fontp);
00652                      return NULL;
00653                   }
00654                   *not_found_flag = True;
00655               }
00656            fontp->next = font_head;
00657            font_head = fontp;
00658            break;
00659        }
00660        if (strcmp(fontname, fontp->fontname) == 0
00661            && size == (int)(fontp->fsize + 0.5)) {
00662            /* if font already in use */
00663            reuse_font(fontp);
00664            free(fontname);
00665            break;
00666        }
00667     }
00668     if (TeXnumber < tn_table_len)
00669        tntable[TeXnumber] = fontp;
00670     else {
00671        struct tn *tnp;
00672        tnp = xmalloc((unsigned)sizeof(struct tn));
00673        tnp->next = *tn_headpp;
00674        *tn_headpp = tnp;
00675        tnp->TeXnumber = TeXnumber;
00676        tnp->fontp = fontp;
00677     }
00678     return fontp;
00679 }
00680 
00681        
00682 
00683 
00684 /*
00685  *      process_preamble reads the information in the preamble and stores
00686  *      it into global variables for later use.
00687  */
00688 Boolean
00689 process_preamble(FILE *fp, dviErrFlagT *errflag)
00690 {
00691     ubyte k;
00692     static char job_id[300];
00693 
00694     TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d", (void *)fp, *errflag));
00695     
00696     if (get_byte(fp) != PRE) {
00697        *errflag = NOT_A_DVI_FILE;
00698        TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning False", (void *)fp, *errflag));
00699        return False;
00700     }
00701     if (get_byte(fp) != 2) {
00702        *errflag = WRONG_DVI_VERSION;
00703        TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning False", (void *)fp, *errflag));
00704        return False;
00705     }
00706     numerator = get_bytes(fp, 4);
00707     denominator = get_bytes(fp, 4);
00708     magnification = get_bytes(fp, 4);
00709     dimconv = (((double)numerator * magnification)
00710               / ((double)denominator * 1000.));
00711     dimconv = dimconv * (((long)resource.pixels_per_inch) << 16) / 254000;
00712     tpic_conv = resource.pixels_per_inch * magnification / 1000000.0;
00713     k = get_byte(fp);
00714     fread(job_id, sizeof(char), (int)k, fp);
00715     job_id[k] = '\0';
00716 
00717     TRACE_FILES((stderr, "process_preamble: fp = %p, errflag = %d, returning True", (void *)fp, *errflag));
00718     
00719     return True;
00720 }
00721 
00722 /*
00723  *      find_postamble locates the beginning of the postamble
00724  *     and leaves the file ready to start reading at that location.
00725  */
00726 #define       TMPSIZ 516    /* 4 trailer bytes + 512 junk bytes allowed */
00727 Boolean
00728 find_postamble(FILE *fp, dviErrFlagT *errflag)
00729 {
00730     long pos;
00731     ubyte temp[TMPSIZ];
00732     ubyte *p;
00733     ubyte *p1;
00734     ubyte byte;
00735 
00736     TRACE_FILES((stderr, "find_postamble on fp: %p", (void *)fp));
00737     
00738     fseek(fp, 0L, SEEK_END);
00739     pos = ftell(fp) - TMPSIZ;
00740     if (pos < 0)
00741        pos = 0;
00742     fseek(fp, pos, SEEK_SET);
00743     p = temp + fread((char *)temp, sizeof(char), TMPSIZ, fp);
00744     for (;;) {
00745        p1 = p;
00746        while (p1 > temp && *(--p1) != TRAILER);
00747        p = p1;
00748        while (p > temp && *(--p) == TRAILER);
00749        if (p <= p1 - 4)
00750            break;    /* found 4 TRAILER bytes */
00751        if (p <= temp) {
00752            *errflag = DVI_CORRUPTED;
00753            TRACE_FILES((stderr, "find_postamble: returning FALSE"));
00754            return False;
00755        }
00756     }
00757     pos += p - temp;
00758     byte = *p;
00759     while (byte == TRAILER) {
00760        fseek(fp, --pos, SEEK_SET);
00761        byte = get_byte(fp);
00762     }
00763     if (byte != 2) {
00764        *errflag = WRONG_DVI_VERSION;
00765        TRACE_FILES((stderr, "find_postamble: returning FALSE"));
00766        return False;
00767     }
00768     fseek(fp, pos - 4, SEEK_SET);
00769     fseek(fp, get_lbytes(fp, 4), SEEK_SET);
00770     TRACE_FILES((stderr, "find_postamble: returning TRUE"));
00771     return True;
00772 }
00773 
00774 
00775 
00776 Boolean
00777 set_paper_type(const char *arg)
00778 {
00779     const char *arg1;
00780     char temp[21];
00781     const char **p;
00782     char *q;
00783     const char **paper_types = get_paper_types();
00784     size_t paper_types_size = get_paper_types_size();
00785     
00786     if (*arg == '+') {
00787        ++arg;
00788        ignore_papersize_specials = True;
00789     }
00790     if (strlen(arg) > sizeof(temp) - 1)
00791        return False;
00792     q = temp;
00793     for (;;) {       /* convert to lower case */
00794        char c = *arg++;
00795        if (c >= 'A' && c <= 'Z')
00796            c ^= ('a' ^ 'A');
00797        *q++ = c;
00798        if (c == '\0')
00799            break;
00800     }
00801     arg = temp;
00802     /* perform substitutions */
00803     for (p = paper_types; p < paper_types + paper_types_size; p += 2) {
00804        if (strcmp(temp, *p) == 0) {
00805            arg = p[1];
00806            break;
00807        }
00808     }
00809     arg1 = strchr(arg, 'x');
00810     if (arg1 == NULL)
00811        return False;
00812     m_paper_unshrunk_w = atopix(arg, False);
00813     m_paper_unshrunk_h = atopix(arg1 + 1, False);
00814 
00815     return (m_paper_unshrunk_w != 0 && m_paper_unshrunk_h != 0);
00816 }
00817 
00818 /*
00819  *      read_postamble reads the information in the postamble from fp,
00820  *     storing it into global variables.
00821  *      It also takes care of reading in all of the pixel files for the fonts
00822  *      used in the job.
00823  *
00824  *     FIXME: Would be better (speed up initialization when needing to generate fonts,
00825  *     and allow to open window on first page) if the font loading was done on-demand later!
00826  */
00827 Boolean
00828 read_postamble(FILE *fp, dviErrFlagT *errflag, Boolean load_fonts)
00829 {
00830     ubyte cmnd;
00831     Boolean font_not_found = False;
00832     struct font      *fontp;
00833 
00834     TRACE_FILES((stderr, "read_postamble: reading %p (%d)", (void *)fp, load_fonts));
00835 
00836     /* clear existing font table */
00837     memset((char *)tn_table, 0, (int)sizeof tn_table);
00838     free_vf_chain(tn_head);
00839     tn_head = NULL;
00840     for (fontp = font_head; fontp != NULL; fontp = fontp->next)
00841        fontp->flags &= ~FONT_IN_USE;
00842 
00843     
00844     if (get_byte(fp) != POST) {
00845        *errflag = POSTAMBLE_NO_POST;
00846        TRACE_FILES((stderr, "read_postamble: returning FALSE"));
00847        return False;
00848     }
00849     m_last_page_offset = get_bytes(fp, 4);
00850     if (numerator != get_bytes(fp, 4)
00851        || denominator != get_bytes(fp, 4)
00852        || magnification != get_bytes(fp, 4)) {
00853        *errflag = POSTAMBLE_NO_MATCH;
00854        TRACE_FILES((stderr, "read_postamble: returning FALSE"));
00855        return False;
00856     }
00857 
00858     /* read largest box height and width */
00859     dvi_unshrunk_page_h = (spell_conv(get_lbytes(fp, 4)) >> 16) + resource.yoffset_int;
00860     if (dvi_unshrunk_page_h < m_paper_unshrunk_h)
00861        dvi_unshrunk_page_h = m_paper_unshrunk_h;
00862     dvi_unshrunk_page_w = (spell_conv(get_lbytes(fp, 4)) >> 16) + resource.xoffset_int;
00863     if (dvi_unshrunk_page_w < m_paper_unshrunk_w)
00864        dvi_unshrunk_page_w = m_paper_unshrunk_w;
00865     (void)get_bytes(fp, 2); /* max stack size */
00866     total_pages = get_bytes(fp, 2);
00867 
00868     /* read font definitions */
00869     while ((cmnd = get_byte(fp)) >= FNTDEF1 && cmnd <= FNTDEF4) {
00870        struct font *f = define_font(load_fonts, fp, cmnd, (struct font *)NULL, tn_table,
00871                                  TNTABLELEN, &tn_head, &font_not_found);
00872        if (load_fonts && f == NULL) {
00873            TRACE_FILES((stderr, "read_postamble: returning FALSE"));
00874            return False;
00875        }
00876        else if (!load_fonts) { /* return early */
00877            TRACE_FILES((stderr, "read_postamble: returning TRUE"));
00878            return True;
00879        }
00880     }
00881     if (cmnd != POSTPOST) {
00882        *errflag = POSTAMBLE_NON_FNTDEF;
00883        TRACE_FILES((stderr, "read_postamble: returning FALSE"));
00884        return False;
00885     }
00886     if (font_not_found) {
00887        *errflag = NOT_ALL_PIXEL_FILES_FOUND;
00888        TRACE_FILES((stderr, "read_postamble: returning FALSE"));
00889        return False;
00890     }
00891     free_unused_fonts();
00892 
00893     TRACE_FILES((stderr, "read_postamble: returning TRUE"));
00894     return True;
00895 }
00896 
00897 
00898 static Boolean
00899 prepare_pages(dviErrFlagT *errflag)
00900 {
00901     int i;
00902     long offset;
00903 
00904     TRACE_FILES((stderr, "calling pageinfo_deallocate"));
00905     pageinfo_deallocate();
00906 
00907     TRACE_FILES((stderr, "pageinfo_allocate for %d pages", total_pages + 1));
00908     pageinfo_allocate(total_pages + 1);
00909     pageinfo_set_page_width(total_pages, m_paper_unshrunk_w);
00910     pageinfo_set_page_height(total_pages, m_paper_unshrunk_h);
00911     pageinfo_set_window_width(total_pages, dvi_unshrunk_page_w);
00912     pageinfo_set_window_height(total_pages, dvi_unshrunk_page_h);
00913 
00914     pageinfo_set_offset(total_pages - 1, m_last_page_offset);
00915     /*
00916      * Follow back pointers through pages in the DVI file,
00917      * storing the offsets in the pageinfo table.
00918      */
00919     for (offset = m_last_page_offset, i = total_pages; i > 0; i--) {
00920        fseek(globals.dvi_file.bak_fp, offset, SEEK_SET);
00921        if (get_byte(globals.dvi_file.bak_fp) != BOP) {
00922            *errflag = NO_BOP_AT_PAGEDESC;
00923            return False;
00924        }
00925        pageinfo_set_offset(i-1, offset);
00926        /* from c_0, read count0, the TeX page number */
00927        pageinfo_set_number(i-1, get_bytes(globals.dvi_file.bak_fp, 4));
00928 
00929        /* skip c_1 to c_9 */
00930        fseek(globals.dvi_file.bak_fp, 9*4L, SEEK_CUR);
00931 
00932        /* next 4 byte contain offset to previous bop */
00933        offset = get_bytes(globals.dvi_file.bak_fp, 4);
00934     }
00935     /* If not prescanning, initialize page sizes.  */
00936     if (!resource.prescan) {
00937        for (i = 0; i < total_pages; ++i) {
00938            pageinfo_set_page_width(i, m_paper_unshrunk_w);
00939            pageinfo_set_page_height(i, m_paper_unshrunk_h);
00940            pageinfo_set_window_width(i, dvi_unshrunk_page_w);
00941            pageinfo_set_window_height(i, dvi_unshrunk_page_h);
00942        }
00943     }
00944     return True;
00945 }
00946 
00947 void
00948 init_page(void)
00949 {
00950     if (globals.dvi_file.bak_fp == NULL)
00951        return;
00952     globals.page.unshrunk_w = pageinfo_get_page_width(current_page);
00953     globals.page.unshrunk_h = pageinfo_get_page_height(current_page);
00954     globals.page.w = ROUNDUP(globals.page.unshrunk_w, mane.shrinkfactor) + 2;
00955     globals.page.h = ROUNDUP(globals.page.unshrunk_h, mane.shrinkfactor) + 2;
00956     TRACE_FILES((stderr, "init_page: setting globals.page.w = %d, globals.page.h = %d", globals.page.w, globals.page.h));
00957 }
00958 
00959 #ifndef       S_ISDIR
00960 #define       S_ISDIR(m)    (((m) & S_IFMT) == S_IFDIR)
00961 #endif
00962 
00963 static char *tmp_dvi_name = NULL; /* name of backup file for useTempFp */
00964 
00965 /* access function for backup file name */
00966 char *get_tmp_dvi_name() {
00967     return tmp_dvi_name;
00968 }
00969 
00970 void
00971 remove_tmp_dvi_file(void)
00972 {
00973     if (tmp_dvi_name != NULL)
00974        unlink(tmp_dvi_name);
00975 }
00976 
00977 
00978 static FILE *
00979 make_backup_fp(FILE *source_fp, FILE *target_fp)
00980 {
00981     static Boolean first_time = True;
00982     static int tmp_fd = 0;
00983 
00984 #if !HAVE_FTRUNCATE
00985     /* in this case, we can't use ftruncate() on the existing temp file -
00986        just close the existing one, and set flag to open a new one */
00987     if (tmp_dvi_name != NULL)
00988        unlink(tmp_dvi_name);
00989     if (target_fp != NULL)
00990        fclose(target_fp);
00991     /* make sure we use a new temp file, else we'd have a race condition
00992        after closing it */
00993     free(tmp_dvi_name);
00994     tmp_dvi_name = NULL;
00995     first_time = True;
00996 #endif
00997     
00998     if (first_time) { /* doesn't exist yet, create it */
00999        if ((tmp_fd = xdvi_temp_fd(&tmp_dvi_name)) == -1) {
01000            XDVI_ERROR((stderr, "error creating temporary file - disabling `useTempFp'."));
01001            return NULL;
01002        }
01003 /*     fprintf(stderr, "temporary file name: |%s|, %d\n", tmp_dvi_name, tmp_fd); */
01004        TRACE_EVENTS((stderr, "Created temp file: |%s|\n", tmp_dvi_name));
01005        if ((target_fp = try_fdopen(tmp_fd, "wb+")) == NULL) {
01006            XDVI_ERROR((stderr, "error opening temporary file (%s) - disabling `useTempFp'.", strerror(errno)));
01007            return NULL;
01008        }
01009        first_time = False;
01010     }
01011     else { /* if not first time, truncate the existing file,
01012              and position both files at beginning */
01013        ASSERT(target_fp != NULL, "");
01014        ASSERT(source_fp != NULL, "");
01015        
01016 #if HAVE_FTRUNCATE
01017        if (ftruncate(tmp_fd, 0) < 0) {
01018            XDVI_ERROR((stderr, "Couldn't truncate file %s: %s - disabling `useTempFp'.",
01019                      tmp_dvi_name, strerror(errno)));
01020            unlink(tmp_dvi_name);
01021            fclose(target_fp);
01022            return NULL;
01023        }
01024 #endif
01025        fseek(target_fp, 0L, SEEK_SET);
01026        fseek(source_fp, 0L, SEEK_SET);
01027     }
01028 
01029     /* copy the file */
01030     if (!copy_fp(source_fp, target_fp)) {
01031        XDVI_ERROR((stderr,
01032                   "Error creating temporary file: %s\n"
01033                   "- disabling `useTempFp'.",
01034                   strerror(errno)));
01035        fclose(target_fp);
01036        target_fp = NULL;
01037     }
01038     
01039     /* rewind both files, else DVI parsing will fail! */
01040     fflush(target_fp);
01041     fseek(source_fp, 0L, SEEK_SET);
01042     if (target_fp != NULL) {
01043        fseek(target_fp, 0L, SEEK_SET);
01044     }
01045     
01046     return target_fp;
01047 }
01048 
01049 static Boolean
01050 file_exists_p(const char *path, dviErrFlagT *errflag)
01051 {
01052     TRACE_FILES((stderr, "file_exists_p for |%s|", path));
01053     *errflag = UNKNOWN_ERROR;
01054     if ((m_dvi_fp = XFOPEN(path, OPEN_MODE)) == NULL) {
01055 /*     fprintf(stderr, "after internal_open_dvi1: xfopen\n"); */
01056        *errflag = FILE_DOESNT_EXIST;
01057        return False;
01058     }
01059     TRACE_FILES((stderr, "m_dvi_fp for |%s| = %p", path, (void *)m_dvi_fp));
01060 /*      fprintf(stderr, "after internal_open_dvi2: xfopen\n"); */
01061     
01062     /* shouldn't happen */
01063     if (fstat(fileno(m_dvi_fp), &fstatbuf) != 0 || S_ISDIR(fstatbuf.st_mode)) {     /* if it's a directory */
01064        *errflag = FILE_IS_DIRECTORY;
01065        fclose(m_dvi_fp);
01066        m_dvi_fp = NULL;
01067        return False;
01068     }
01069     /* If file has zero size, something has gone wrong with downloading
01070        it, and the user should already have been warned about that;
01071        just return in this case.
01072        TODO: can it still happen that we try to load such a file as .dvi
01073        file? (Will exit  with `draw_part: unknown op-code xyz' or some such).
01074        In this case, it would be better to look at the preamble before
01075        entering the drawing loop.
01076     */
01077     if (fstatbuf.st_size == 0) {
01078        *errflag = FILE_HAS_ZERO_SIZE;
01079        fclose(m_dvi_fp);
01080        m_dvi_fp = NULL;
01081        return False;
01082     }
01083     return True;
01084 }
01085 
01086 /*
01087  *     internal_init_dvi is the main subroutine for reading the startup
01088  *     information from the dvi file.
01089  */
01090 
01091 static Boolean
01092 internal_init_dvi(dviErrFlagT *errflag, Boolean load_fonts)
01093 {
01094     char *icon_name = NULL, *title_name = NULL;
01095 
01096     have_src_specials = False;
01097 
01098     TRACE_FILES((stderr, "internal_init_dvi, globals.dvi_file.bak_fp = %p", (void *)globals.dvi_file.bak_fp));
01099     
01100     if (!process_preamble(globals.dvi_file.bak_fp, errflag)
01101        || !find_postamble(globals.dvi_file.bak_fp, errflag)
01102        || !read_postamble(globals.dvi_file.bak_fp, errflag, load_fonts)
01103        || !prepare_pages(errflag))
01104        return False;
01105 
01106     if (current_page >= total_pages)
01107        current_page = total_pages - 1;
01108 
01109     globals.warn_spec_now = resource.warn_spec;
01110     globals.src.fwd_box_page = -1;
01111     search_reset_info();
01112     
01113     if (globals.pausing.num_save != NULL) {
01114        free(globals.pausing.num_save);
01115        globals.pausing.num_save = NULL;
01116     }
01117     if (resource.pause && total_pages > 0) {
01118        globals.pausing.num_save = xmalloc(total_pages * sizeof *globals.pausing.num_save);
01119        memset(globals.pausing.num_save, 0, total_pages * sizeof *globals.pausing.num_save);
01120     }
01121     
01122     init_prescan();
01123     /* this allocates icon_name and title_name */
01124     get_icon_and_title(globals.dvi_name, &icon_name, &title_name);
01125     set_icon_and_title(icon_name, title_name);
01126     free(icon_name);
01127     free(title_name);
01128     icon_name = title_name = NULL;
01129     
01130 #if defined(MOTIF) && HAVE_XPM
01131     tb_check_navigation_sensitivity(current_page);
01132 #endif
01133     refresh_pagelist(total_pages, current_page);
01134 
01135     return True;
01136 }
01137 
01138 /*
01139  *     internal_open_dvi does the real opening of the dvi file, and sets
01140  *     globals.dvi_file.time.  It returns True on success, and sets m_dvi_fp and globals.dvi_file.bak_fp.
01141  */
01142 
01143 Boolean
01144 internal_open_dvi(const char *path, dviErrFlagT *errflag, Boolean load_fonts)
01145 {
01146 /*     FILE *tmp_fp = NULL; */
01147 /*     static FILE *bak_fp = NULL; /\* re-use the temporary backup fp *\/ */
01148 /*      fprintf(stderr, "------------ opening: |%s|\n", path); */
01149 
01150     TRACE_FILES((stderr, "internal_open_dvi for |%s|", path));
01151     close_old_filep();
01152 
01153     if (!file_exists_p(path, errflag)) { /* this should set fstatbuf.st_mtime */
01154        return False;
01155     }
01156 
01157     if (!resource.use_temp_fp || (globals.dvi_file.bak_fp = make_backup_fp(m_dvi_fp, globals.dvi_file.bak_fp)) == NULL) {
01158        globals.dvi_file.bak_fp = m_dvi_fp;
01159     }
01160     globals.dvi_file.time = fstatbuf.st_mtime;
01161     
01162     if (!internal_init_dvi(errflag, load_fonts)) {
01163        return False;
01164     }
01165     
01166 #if COLOR
01167     full_reset_colors();
01168 #endif /* COLOR */
01169     reset_papersize_special();
01170     
01171     TRACE_FILES((stderr, "internal_open_dvi: SUCCESS!"));
01172 
01173     return True;
01174 }
01175 
01176 /*
01177   check whether `filename' is a DVI file, by checking if it exists, and if so,
01178   opening it and trying to read a DVI preamble from it:
01179 */
01180 static char *
01181 is_dvi_file(const char *filename)
01182 {
01183     FILE *fp;
01184     struct stat statbuf;
01185     char *full_pathname;
01186     dviErrFlagT unused_error;
01187 
01188     TRACE_FILES((stderr, "is_dvi_file %s", filename));
01189     TRACE_HTEX((stderr, "filename: |%s|", filename));
01190 
01191     /* used to append `.dvi' if not already present, but that was a
01192        bad idea - if we have both foo.2 and foo.2.dvi, user will want
01193        to open `foo.2' (with some appropriate application) if the link
01194        points to that filename. This means that we need to have
01195        different semantics for filenames on the command-line and
01196        filenames in hyperlinks; the latter *must* specify an
01197        extension, the former may omit the extension and default to DVI
01198        files.
01199     */
01200     /* if ((full_filename = filename_append_dvi(filename)) == NULL) { */
01201     /*     free(full_filename); */
01202     /*     return NULL; */
01203     /* } */
01204     /* TRACE_HTEX((stderr, "full_filename: |%s|\n", full_filename)); */
01205 
01206     if ((full_pathname = find_file(filename, &statbuf, kpse_program_text_format)) == NULL) {
01207        return NULL;
01208     }
01209     else {
01210        char *tmp = canonicalize_path(full_pathname);
01211        free(full_pathname);
01212        full_pathname = tmp;
01213     }
01214     
01215     TRACE_HTEX((stderr, "is_dvi_file: full_pathname: |%s|", full_pathname));
01216 
01217     if ((fp = XFOPEN(full_pathname, OPEN_MODE)) == NULL) {
01218        free(full_pathname);
01219        return NULL;
01220     }
01221 
01222     if (!process_preamble(fp, &unused_error)) {
01223        free(full_pathname);
01224        fclose(fp);
01225        return NULL;
01226     }
01227 
01228     fclose(fp);
01229     return full_pathname;
01230 }
01231 
01232 static void
01233 report_open_error(const char *msg, const char *filename, dviErrFlagT errflag)
01234 {
01235     const char *errmsg;
01236     switch(errflag) {
01237     case FILE_HAS_ZERO_SIZE:
01238        errmsg = "File has zero size";
01239        break;
01240     case FILE_DOESNT_EXIST:
01241        errmsg = "No such file";
01242        break;
01243     case FILE_IS_DIRECTORY:
01244        errmsg = "Is a directory";
01245        break;
01246     default:
01247        errmsg = "An unknown error occurred";
01248        break;
01249     }
01250     XDVI_ERROR((stderr, "%s: %s: %s", msg, filename, errmsg));
01251 }
01252 
01253 /*
01254   Implements the algorithm for opening a DVI file from the command line.
01255   This is similar to `open_dvi_file()' in non-k xdvi.
01256   
01257   If the file does not already have `.dvi' extension, append `.dvi'
01258   and set tried_dvi_ext to True. Try to open this file. If the file
01259   doesn't exist, try the original file name. If this file doesn't
01260   exist either, exit with an error message `No such file or directory'.
01261   If tried_dvi_ext == True, also report that file.dvi didn't exist
01262   either.
01263 
01264   (A later function will check if the file really is a DVI file, and
01265   will use tried_dvi_ext for the same purpose).
01266 */
01267 char *
01268 find_dvi_file(const char *filename, Boolean *tried_dvi_ext, Boolean from_file_history)
01269 {
01270     char *new_filename;
01271     size_t len;
01272     dviErrFlagT errflag;
01273 
01274     ASSERT(filename != NULL, "Filename argument in find_dvi_file() musn't be NULL");
01275     len = strlen(filename);
01276 
01277     if (len < sizeof(".dvi") || strcmp(filename + len - sizeof(".dvi") + 1, ".dvi") != 0) {
01278        /* doesn't already have .dvi extension */
01279        TRACE_HTEX((stderr, "|%s| doesn't have .dvi extension, appending ...", filename));
01280        new_filename = xstrdup(filename);
01281        new_filename = xstrcat(new_filename, ".dvi");
01282        *tried_dvi_ext = True;
01283        
01284        if (file_exists_p(new_filename, &errflag)) { /* file exists */
01285            char *expanded_filename = expand_filename(new_filename, USE_CWD_PATH);
01286            free(new_filename);
01287            return expanded_filename;
01288        }
01289        else { /* don't report an error; will try verbatim filename next */
01290            free(new_filename);
01291        }
01292     }
01293 
01294     /* try verbatim filename (might be strange things like `foo.wdvi') */
01295     if (file_exists_p(filename, &errflag)) {
01296        char *expanded_filename = expand_filename(filename, USE_CWD_PATH);
01297        return expanded_filename;
01298     }
01299     else {
01300        if (*tried_dvi_ext) {
01301            if (!from_file_history) {
01302               XDVI_FATAL((stderr, "%s: %s, and %s.dvi doesn't exist either.",
01303                          filename, get_dvi_error(errflag), filename));
01304            }
01305            else {
01306               popup_message(globals.widgets.top_level,
01307                            MSG_ERR,
01308                            NULL,
01309                            "Could not open \"%s\": %s.\n", filename, get_dvi_error(errflag));
01310            }
01311        }
01312        else {
01313            if (!from_file_history) {
01314               XDVI_FATAL((stderr, "%s: %s.", filename, get_dvi_error(errflag)));
01315            }
01316            /* else: file is from history; this is at startup, where we may
01317               loop through the history until we find a usable file. Don't report
01318               an error in this case. */
01319        }
01320     }
01321     return NULL;
01322 }
01323 
01324 
01325 
01326 /*
01327  * A wrapper for open_dvi_file that can also deal with remote files/URLs, and other
01328  * file types. Returns the (newly malloc'ed) new dvi file name if it succeeds, NULL else.
01329  */
01330 char *
01331 open_dvi_file_wrapper(const char *filename,
01332                     Boolean from_command_line,
01333                     Boolean open_new_instance,
01334                     Boolean *tried_dvi_ext,
01335                     Boolean from_file_history)
01336 {
01337     char *real_filename = NULL;
01338     char *new_dvi_name = NULL;
01339     char canonical_path[MAXPATHLEN + 1];
01340     
01341     if (from_command_line) {
01342        TRACE_HTEX((stderr, "filename IS from commandline"));
01343        /*
01344          if filename is from command-line, we want to treat the file as a DVI file
01345          always (and NOT launch the browser or other programs; that'd just confuse
01346          people, who meant to launch *xdvi*). `find_dvi_file' tries to locate the
01347          file and does all error handling; on success, it returns a fully expanded
01348          filename.
01349         */
01350        real_filename = find_dvi_file(filename, tried_dvi_ext, from_file_history); /* this allocates real_filename */
01351        if (real_filename == NULL)
01352            return False;
01353        
01354        TRACE_HTEX((stderr, "filename |%s| %p from commandline;\ndvi_name: |%s|,\nfilename: |%s|%p",
01355                   real_filename, real_filename, globals.dvi_name, filename, (void *)filename));
01356        new_dvi_name = xstrdup(REALPATH(real_filename, canonical_path));
01357        free(real_filename);
01358        TRACE_FILES((stderr, "new_dvi_name: |%s|", new_dvi_name));
01359        return new_dvi_name;
01360     }
01361     else {
01362        /*
01363          if it's not from the command line (e.g. result of clicking Mouse-1 on a link);
01364          in this case we might fall back to using the browser.
01365          Check whether it's a local file:
01366         */
01367        const char *filename_no_prefix;
01368        char *expanded_filename;
01369        TRACE_HTEX((stderr, "filename NOT from commandline"));
01370        if ((filename_no_prefix = is_local_file(filename)) != NULL) {
01371            /* if it's a local file, check whether it's a DVI file: */
01372            if ((expanded_filename = is_dvi_file(filename_no_prefix)) != NULL) {
01373               /* yes, open it */
01374               if (open_dvi_file(expanded_filename, open_new_instance)) {
01375                   TRACE_FILES((stderr, "success: %p |%s|", expanded_filename, expanded_filename));
01376                   if (!open_new_instance) {
01377                      new_dvi_name = expand_filename_append_dvi(expanded_filename, USE_DVI_PATH, True);
01378                      TRACE_FILES((stderr, "new_dvi_name: %p |%s|", (void*)new_dvi_name, new_dvi_name));
01379                   }
01380               }
01381               free(expanded_filename);
01382               return new_dvi_name;
01383            }
01384            else {
01385               /*
01386                 local file, but not a DVI file;
01387                 try other viewers for this MIME type:
01388               */
01389               TRACE_HTEX((stderr, "%s is NOT a DVI file", filename_no_prefix));
01390               launch_program(filename);
01391               return NULL;
01392            }
01393        }
01394        else {
01395            /* not a local file, retrieve it with the browser: */
01396            launch_browser(filename);
01397            return NULL;
01398        }
01399     }
01400 }
01401 
01402 
01403 static Boolean
01404 open_dvi_file(const char *filename, Boolean open_new_instance)
01405 {
01406     Boolean retval = True;
01407 
01408     char *anchor_name = resource.anchor_pos;
01409 
01410     TRACE_HTEX((stderr, "open_dvi_file: |%s| + |%s|",
01411               filename, anchor_name == NULL ? "<no anchor>" : anchor_name));
01412 
01413     if (open_new_instance) {
01414        launch_xdvi(filename, anchor_name);
01415     }
01416     else {
01417        dviErrFlagT errflag = NO_ERROR;
01418        TRACE_HTEX((stderr, "internal_open_dvi: |%s|", filename));
01419        if (!internal_open_dvi(filename, &errflag, True)) {
01420 /*         || !internal_init_dvi(&errflag, True)) { */
01421            report_open_error("Cannot open DVI file", filename, errflag);
01422            retval = False;
01423        }
01424     }
01425     return retval;
01426 }
01427 
01433 void
01434 form_dvi_property(void)
01435 {
01436 #if 0
01437     size_t len;
01438     unsigned long ino;
01439     int i;
01440 #endif
01441 
01442     if (m_dvi_fp == NULL)
01443        return;
01444 
01445     if (dvi_property != NULL)
01446        free(dvi_property);
01447 
01448     dvi_property_length = strlen(globals.dvi_name) + 1; /* also copy the terminating 0 */
01449     dvi_property = xmalloc(dvi_property_length);
01450 
01451     /* NOTE: we don't use dvi_inode like non-k xdvi, since dvi_name is
01452        always fully expanded with xdvik. */
01453     strcpy(dvi_property, globals.dvi_name);
01454 }
01455 
01456 
01457 /* access for m_dvi_fp */
01458 void
01459 close_old_filep(void)
01460 {
01461     if (m_dvi_fp != NULL) {
01462        fclose(m_dvi_fp);
01463        m_dvi_fp = NULL;
01464        if (!resource.use_temp_fp)
01465            globals.dvi_file.bak_fp = NULL;
01466     }
01467 }
01468 
01469 
01470 
01476 Boolean
01477 dvi_file_changed(void)
01478 {
01479     TRACE_FILES((stderr, "dvi_file_changed: fp = %p?", (void *)m_dvi_fp));
01480 
01481 /*     fprintf(stderr, "m_dvi_fp3: %p (%s)\n", m_dvi_fp, globals.dvi_name); */
01482     if (m_dvi_fp == NULL) {
01483        TRACE_FILES((stderr, "m_dvi_fp == NULL"));
01484        if (stat(globals.dvi_name, &fstatbuf) == 0 && fstatbuf.st_mtime != globals.dvi_file.time) {
01485            TRACE_FILES((stderr, "file changed"));
01486            if (resource.use_temp_fp) {
01487               dviErrFlagT errflag = NO_ERROR;
01488 
01489               if (resource.watch_file == 0.0)
01490                   statusline_print(STATUS_MEDIUM, "File changed ...");
01491               TRACE_FILES((stderr, "returning FALSE"));
01492 
01493               if (file_exists_p(globals.dvi_name, &errflag)
01494                   && process_preamble(m_dvi_fp, &errflag)
01495                   && find_postamble(m_dvi_fp, &errflag)
01496                   && read_postamble(m_dvi_fp, &errflag, False)) {
01497                   TRACE_FILES((stderr, "File OK, reloading ..."));
01498                   
01499                   globals.ev.flags |= EV_RELOAD;
01500                   return True;
01501               }
01502               else {
01503                   return False;
01504               }
01505            }
01506            /* Bug alert: Don't set EV_RELOAD again here, else xdvi
01507               can go into a stretch of time where it again and again
01508               tries to reload a file even if the user doesn't click
01509               on the canvas.
01510            */
01511            /*
01512            else {
01513               globals.ev.flags |= EV_RELOAD;
01514            }
01515            */
01516            TRACE_FILES((stderr, "returning TRUE"));
01517            return True;
01518        }
01519        else {
01520            TRACE_FILES((stderr, "file not changed"));
01521        }
01522     }
01523     /* BUG ALERT: Don't use fstat(fileno(m_dvi_fp) here; if file hase
01524        disappeared, this won't report an error! */
01525     else if (stat(globals.dvi_name, &fstatbuf) != 0 /* stat failed ... */
01526             || fstatbuf.st_mtime != globals.dvi_file.time /* ... or different timestamp, reload: */) {
01527        dviErrFlagT errflag = NO_ERROR;
01528 
01529        TRACE_FILES((stderr, "Stat failed, or different timestamp ..."));
01530        globals.dvi_file.time = 0; /* force reload next time also if stat failed */
01531        
01532        if (resource.use_temp_fp) { /* in this case, reload only if file has been written completely */
01533            if (resource.watch_file == 0.0) {
01534               statusline_print(STATUS_MEDIUM, "File corrupted (click on window to reload) ...");
01535               globals.cursor.flags |= CURSOR_CORRUPTED;
01536               globals.ev.flags |= EV_CURSOR;
01537            }
01538            else {
01539               statusline_print(STATUS_MEDIUM, "File corrupted (will try to reload) ...");
01540            }
01541            close_old_filep();
01542            if (file_exists_p(globals.dvi_name, &errflag)
01543               && process_preamble(m_dvi_fp, &errflag)
01544               && find_postamble(m_dvi_fp, &errflag)
01545               && read_postamble(m_dvi_fp, &errflag, False)) {
01546               TRACE_FILES((stderr, "File OK, reloading ..."));
01547               
01548               globals.ev.flags |= EV_RELOAD;
01549               return True;
01550            }
01551            else {
01552               TRACE_FILES((stderr, "NO successful load: %s", get_dvi_error(errflag)));
01553 /*            fprintf(stderr, "=========== NO successful load: %s\n", get_dvi_error(errflag)); */
01554               return False;
01555            }
01556        }
01557        else {
01558            TRACE_FILES((stderr, "Not using temp fp, reloading..."));
01559            globals.ev.flags |= EV_RELOAD;
01560            return True;
01561        }
01562     }
01563     return False;
01564 }
01565 
01570 Boolean
01571 load_dvi_file(Boolean load_fonts, dviErrFlagT *errflag)
01572 {
01573     unsigned int old_page_w, old_page_h;
01574     static ino_t dvi_inode = 0;
01575 
01576     TRACE_FILES((stderr, "load_dvi_file: going to read %p", (void *)m_dvi_fp));
01577     
01578     if (resource.use_temp_fp && m_dvi_fp != NULL) {
01579        /* in this case, reload only if file has been written completely */
01580        *errflag = NO_ERROR;
01581        fseek(m_dvi_fp, 0L, SEEK_SET);
01582        if (!process_preamble(m_dvi_fp, errflag)
01583            || !find_postamble(m_dvi_fp, errflag)
01584            || !read_postamble(m_dvi_fp, errflag, True)) {
01585            TRACE_FILES((stderr, "reading of %p failed: %s!",
01586                       (void *)m_dvi_fp,
01587                       get_dvi_error(*errflag)));
01588            return False;
01589        }
01590     }
01591 
01592     old_page_w = globals.page.w;
01593     old_page_h = globals.page.h;
01594 
01595     *errflag = NO_ERROR;
01596     if (!internal_open_dvi(globals.dvi_name, errflag, load_fonts)) {
01597 /*     || !internal_init_dvi(errflag, load_fonts)) { */
01598        XClearWindow(DISP, mane.win);
01599        XBell(DISP, 0);
01600        statusline_print(STATUS_MEDIUM, "%s: %s%s", globals.dvi_name, get_dvi_error(*errflag),
01601                       resource.watch_file > 0.0 ? "; will try to reload ..." : " (click on window to reload)");
01602        close_old_filep();
01603 
01604        return False;
01605     }
01606     else { /* success */
01607        if (fstatbuf.st_ino != dvi_inode) {
01608            dvi_inode = fstatbuf.st_ino;
01609            form_dvi_property();
01610            set_dvi_property();
01611        }
01612        if (globals.page.w != old_page_w || globals.page.h != old_page_h)
01613            reconfig();
01614 
01615        htex_reinit();
01616 
01617        globals.cursor.flags &= ~CURSOR_CORRUPTED;
01618        return True;
01619     }
01620 }