Back to index

tetex-bin  3.0
font-open.c
Go to the documentation of this file.
00001 /*
00002    font_open.c: find font filenames.  This bears no relation (but the
00003    interface) to the original font_open.c.
00004 
00005 Copyright (c) 1999-2004  The texk project
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a copy
00008 of this software and associated documentation files (the "Software"), to
00009 deal in the Software without restriction, including without limitation the
00010 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00011 sell copies of the Software, and to permit persons to whom the Software is
00012 furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00018 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00019 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00020 IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE
00021 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00022 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00023 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00024 
00025  */
00026 
00027 #include "xdvi-config.h"
00028 #include "xdvi.h"
00029 #include "dvi-draw.h"
00030 #include "util.h"
00031 #include "events.h"
00032 #include "my-snprintf.h"
00033 #include "print-log.h"
00034 
00035 #include "statusline.h"
00036 #include "font-open.h"
00037 
00038 #include "kpathsea/c-fopen.h"
00039 #include "kpathsea/tex-glyph.h"
00040 
00041 #include <stdlib.h>
00042 #include <ctype.h>
00043 
00044 #if HAVE_SYS_WAIT_H
00045 # include <sys/wait.h>
00046 #endif
00047 #ifndef WIFEXITED
00048 # define WIFEXITED(status)  (((status) & 255) == 0)
00049 #endif
00050 #ifndef WEXITSTATUS
00051 # define WEXITSTATUS(status)       ((unsigned)(status) >> 8)
00052 #endif
00053 #ifndef WIFSIGNALED
00054 # ifndef WIFSTOPPED
00055 #  define WIFSTOPPED(status)       (((status) & 0xff) == 0x7f)
00056 # endif
00057 # define WIFSIGNALED(status)       (!WIFSTOPPED(status) && !WIFEXITED(status))
00058 #endif
00059 #ifndef WTERMSIG
00060 # define WTERMSIG(status)   ((status) & 0x7f)
00061 #endif
00062 
00063 /* if POSIX O_NONBLOCK is not available, use O_NDELAY */
00064 #if !defined(O_NONBLOCK) && defined(O_NDELAY)
00065 # define O_NONBLOCK O_NDELAY
00066 #endif
00067 
00068 #ifdef EWOULDBLOCK
00069 # ifdef EAGAIN
00070 #  define AGAIN_CONDITION   (errno == EWOULDBLOCK || errno == EAGAIN)
00071 # else
00072 #  define AGAIN_CONDITION   (errno == EWOULDBLOCK)
00073 # endif
00074 #else /* EWOULDBLOCK */
00075 # ifdef EAGAIN
00076 #  define AGAIN_CONDITION   (errno == EAGAIN)
00077 # endif
00078 #endif /* EWOULDBLOCK */
00079 
00080 #if HAVE_POLL
00081 # include <poll.h>
00082 # define XIO_IN POLLIN
00083 # define XIO_OUT POLLOUT
00084 #else
00085 # define XIO_IN 1
00086 # define XIO_OUT 2
00087 #endif /* HAVE_POLL */
00088 
00089 #if 0
00090 // static int mktexpk_io[2];
00091 // static struct xchild mktexpk_child = { NULL, 0, True, "font creation", NULL, NULL, mktexpk_ended };
00092 // 
00093 // static char *read_from_mktexpk(int ignored);
00094 // static void write_to_mktexpk(int ignored);
00095 // 
00096 // static struct xio mktexpk_xio = { NULL, 0, XIO_IN,
00097 // #if HAVE_POLL
00098 //                            NULL,
00099 // #endif
00100 //                            read_from_mktexpk,
00101 //                            NULL};
00102 // 
00103 
00104 static void
00105 mktexpk_ended(int status, struct xchild *this)
00106 {
00107     char str[1024] = "";
00108     char *err_msg = NULL;
00109 
00110     fprintf(stderr, "------- MKTEXPK_ENDED!\n");
00111     if (this->io != NULL && WIFEXITED(status)) {
00112        err_msg = (this->io->read_proc)(this->io->fd);
00113        SNPRINTF(str, 1024, "\nProcess `%s' returned exit code %d.\n",
00114               this->name, WEXITSTATUS(status));
00115        str[1024 - 1] = '\0';
00116        printlog_append_str(str);
00117        if (err_msg != NULL) {
00118            fprintf(stderr, "FROM MKTEXPK: |%s|\n", err_msg);
00119            printlog_append_str(err_msg);
00120        }
00121     }
00122     printlog_enable_closebutton();
00123 /*     free(this->name); */
00124 /*     free(this->io); */
00125 /*     free(this); */
00126     
00127 //     read_from_mktexpk(0);
00128 //     clear_io(this->io);
00129 //     (void)close(mktexpk_xio.fd);
00130 // 
00131 //     if (WIFEXITED(status)) {
00132 //     if (WEXITSTATUS(status) == 0) {
00133 //         printlog_append("Done.\n", strlen("Done.\n"));
00134 //     }
00135 //     else
00136 //         sprintf(str, "\nPrint process returned exit code %d.\n",
00137 //                WEXITSTATUS(status));
00138 //     }
00139 //     else if (WIFSIGNALED(status))
00140 //     sprintf(str, "\nPrint process terminated by signal %d.\n",
00141 //            WTERMSIG(status));
00142 //     else
00143 //     sprintf(str, "\nPrint process returned unknown status 0x%x.\n",
00144 //            status);
00145 // 
00146 
00147 }
00148 
00149 static char *
00150 read_from_mktexpk(int fd)
00151 {
00152     int bytes;
00153     char line[80];
00154     char *buf;
00155 
00156     fprintf(stderr, "------- READ_FROM_MKTEXPK!\n");
00157     for (;;) {
00158 #ifndef MOTIF
00159        bytes = read(fd, line, sizeof line);
00160 #else
00161        bytes = read(fd, line, sizeof line - 1);
00162 #endif
00163        if (bytes < 0) {
00164            if (AGAIN_CONDITION)
00165               break;
00166            perror("xdvi: read_from_mktexpk");
00167            break;
00168        }
00169 
00170        if (bytes == 0)
00171            break;
00172        else {
00173 #ifdef MOTIF
00174            line[bytes] = '\0';
00175 #endif
00176            //     fprintf(stderr, "------- READ_FROM_MKTEXPK:|%s|\n", line);
00177            printlog_append(line, bytes);
00178        }
00179     }
00180     buf = xmalloc(bytes + 1);
00181     memcpy(buf, line, bytes);
00182     buf[bytes] = '\0';
00183     return buf;
00184 }
00185 
00186 // static void
00187 // write_to_mktexpk(int ignored)
00188 // {
00189 //     UNUSED(ignored);
00190 //     
00191 //     return;
00192 // }
00193 #endif /* 0 */
00194 
00195 
00196 
00197 /* We try for a VF first because that's what dvips does.  Also, it's
00198    easier to avoid running mktexpk if we have a VF this way.  */
00199 
00200 FILE *
00201 font_open(char *font, char **font_ret,
00202          double dpi, int *dpi_ret,
00203          char **filename_ret
00204 #ifdef T1LIB
00205          , int *t1id
00206 #endif
00207          )
00208 {
00209     char *name;
00210     kpse_glyph_file_type file_ret;
00211 
00212     /* defaults in case of success; filename_ret will be
00213        non-NULL iff the fallback font is used.
00214     */
00215     *font_ret = NULL;
00216     /* filename_ret is NULL iff a T1 version of a font has been used */
00217     *filename_ret = NULL;
00218     *dpi_ret = dpi;
00219 
00220     if (resource.omega) { /* for omega, first try 16-bit ovf's, then 8-bit vf's. */
00221        name = kpse_find_ovf(font);
00222        if (name == NULL)
00223            name = kpse_find_vf(font);
00224     }
00225     else {
00226        name = kpse_find_vf(font);
00227     }
00228     
00229 #ifdef T1LIB
00230     if (resource.t1lib) {
00231        *t1id = -1;
00232     }
00233 #endif /* T1LIB */
00234 
00235     if (name) { /* found a vf font */
00236        /* pretend it has the expected dpi value, else caller will complain */
00237        *dpi_ret = dpi;
00238        *filename_ret = name;
00239        return XFOPEN(name, FOPEN_R_MODE);
00240     }
00241 
00242 #ifdef T1LIB
00243     if (resource.t1lib) {
00244        /* First attempt: T1 font of correct size */
00245        *t1id = find_T1_font(font);
00246        if (*t1id >= 0) {
00247            TRACE_T1((stderr, "found T1 font %s", font));
00248            return NULL;
00249        }
00250        TRACE_T1((stderr,
00251                 "T1 version of font %s not found, trying pixel version next, then fallback",
00252                 font));
00253     }
00254 #endif /* T1LIB */
00255     
00256 #ifdef EXPERIMENTAL_DELAYED_MTKEXPK
00257     /*
00258       From this point on, kpathsea might create some fonts (and fail horribly ...)
00259       We want to catch its error messages and present them to the user in a window,
00260       so fork and collect all output of the child into a pipe, similar to what's done for
00261       dvips.
00262 
00263       Actually, the approach outlined here is bogus, since it still
00264       ignores the main issue of knowing, in the parent, when all the
00265       font creation commands have finished (so that we can start
00266       drawing the pages). What is needed here is a child procedure
00267       that works through a stack of font names, creating the fonts if
00268       needed, and the parent checking the return values from these
00269       font creation processes. Only after the child is finished,
00270       xdvi can go on drawing the page, by calling the drawing routine
00271       *from within* mktexpk_ended().
00272     */
00273     {
00274        struct xchild *mktexpk_child = xmalloc(sizeof *mktexpk_child);
00275        struct xio *mktexpk_xio = xmalloc(sizeof *mktexpk_xio);
00276        int mktexpk_io[2];
00277        int pid;
00278        
00279        fprintf(stderr, "BEFORE CREATING PIPE\n");
00280        
00281        if (xpipe(mktexpk_io) != 0) {
00282            perror("[xdvi] pipe");
00283            return NULL;
00284        }
00285 
00286        /* flush output buffers to avoid double buffering (i.e. data
00287           waiting in the output buffer being written twice, by the parent
00288           and the child) */
00289        fflush(stderr);
00290        fflush(stdout);
00291 
00292        switch (pid = fork()) {
00293        case -1:      /* forking error */
00294            perror("fork");
00295            close(mktexpk_io[0]);
00296            close(mktexpk_io[1]);
00297            return NULL;
00298        case 0:       /* child */
00299            fprintf(stderr, "CHILD\n");
00300            close(mktexpk_io[0]); /* no reading from io */
00301            
00302            /* make stdout and stderr of child go to mktexpk_io[1] */
00303            if (mktexpk_io[1] == STDOUT_FILENO)
00304               XDVI_ABORT((stderr, "mktexpk_io[1] shouldn't be STDOUT_FILENO"));
00305            if (dup2(mktexpk_io[1], STDOUT_FILENO) != STDOUT_FILENO)
00306               XDVI_ABORT((stderr, "dup2: mktexpk_io[1], STDOUT_FILENO: %s", strerror(errno)));
00307 
00308            if (mktexpk_io[1] == STDERR_FILENO)
00309               XDVI_ABORT((stderr, "mktexpk_io[1] shouldn't be STDERR_FILENO"));
00310            if (dup2(mktexpk_io[1], STDERR_FILENO) != STDERR_FILENO)
00311               XDVI_ABORT((stderr, "dup2: mktexpk_io[1], STDERR_FILENO: %s", strerror(errno)));
00312            close(mktexpk_io[1]);
00313 
00314            fprintf(stderr, "Running ...\n");
00315            fprintf(stdout, "Running to stdout ...\n");
00316 
00317            /* TODO: We could use a convenience routine from kpathsea (which we'd need to create first though)
00318               like
00319               kpse_find_glyph_nocreate()
00320               that just returns NULL instead of invoking mktexpk. However this still doesn't give us
00321               access to error messages from mktexpk etc.
00322               Maybe it would be better to collect all output from mktexpk into a `log' window, and at
00323               the same time filter the output for (shorter) messages in the statusline, a la:
00324               `generating font %s (n of m) ...'
00325               How is the `n of m' part done in e.g. kdvi? Investigate.
00326            */
00327     
00328            /* Second attempt: PK/GF/... font within allowable size range */
00329            name = kpse_find_glyph(font, (unsigned)(dpi + .5),
00330                                kpse_any_glyph_format, &file_ret);
00331     
00332            if (name) { /* success */
00333               fprintf(stderr, "\n1 DPI: %d\nFONTNAME: %s\n", file_ret.dpi, name);
00334               *dpi_ret = file_ret.dpi;
00335               *filename_ret = name;
00336               _exit(0);
00337               /* ?          return XFOPEN(name, FOPEN_R_MODE); */
00338            }
00339            else if (resource.alt_font != NULL) {
00340               /* The strange thing about kpse_find_glyph() is that it
00341                  won't create a PK version of alt_font if it doesn't
00342                  already exist. So we invoke it explicitly a second time
00343                  for that one.
00344               */
00345               TRACE_T1((stderr, "Trying fallback"));
00346 #ifdef T1LIB
00347               if (resource.t1lib) {
00348                   /* Third attempt: T1 version of fallback font */
00349                   *t1id = find_T1_font(resource.alt_font);
00350                   if (*t1id >= 0) {
00351                      TRACE_T1((stderr, "found fallback font for %s: %s", font, resource.alt_font));
00352                      *font_ret = xstrdup(resource.alt_font);
00353                      _exit(0);
00354                   }
00355                   TRACE_T1((stderr,
00356                            "Type1 version of fallback font %s not found, trying pixel version",
00357                            resource.alt_font));
00358               }
00359 #endif /* T1LIB */
00360               /* Forth attempt: PK version of fallback font */
00361               name = kpse_find_glyph(resource.alt_font, (unsigned)(dpi + .5),
00362                                    kpse_any_glyph_format, &file_ret);
00363               if (name) { /* success */
00364                   fprintf(stderr, "\n2 DPI: %d\nFONTNAME: %s\nRET_FONT: %s\n", file_ret.dpi, name, resource.alt_font);
00365                   *dpi_ret = file_ret.dpi;
00366                   *filename_ret = name;
00367                   *font_ret = xstrdup(resource.alt_font);
00368                   _exit(0);
00369                   /* ? return XFOPEN(name, FOPEN_R_MODE); */
00370               }
00371            }
00372            _exit(1);
00373        default: /* parent */
00374            close(mktexpk_io[1]); /* no writing to io */
00375 
00376            mktexpk_xio->next = NULL;
00377            mktexpk_xio->fd = mktexpk_io[0];
00378            mktexpk_xio->xio_events = XIO_IN;
00379 #if HAVE_POLL
00380            mktexpk_xio->pfd = NULL;
00381 #endif
00382            mktexpk_xio->read_proc = read_from_mktexpk;
00383            mktexpk_xio->write_proc = NULL;
00384            
00385            mktexpk_child->next = NULL;
00386            mktexpk_child->pid = pid;
00387            mktexpk_child->name = xstrdup(font);
00388            mktexpk_child->data = NULL;
00389            mktexpk_child->proc = mktexpk_ended;
00390            mktexpk_child->io = mktexpk_xio;
00391            
00392            set_chld(mktexpk_child);
00393 
00394            /* TODO: get DPI and FONTNAME from the log window, save to *dpi_ret, *filename_ret and *font_ret
00395               and return XFOPEN(name, FOPEN_R_MODE);
00396            */
00397            
00398            return NULL;
00399        }
00400     }
00401     
00402 #else /* EXPERIMENTAL_DELAYED_MTKEXPK */
00403     
00404     /*
00405       TODO:
00406 
00407       Probably a better approach would be as follows:
00408 
00409       1. Read the postamble to get all font definitions. Then, set:
00410       
00411        kpse_set_program_enabled(kpse_any_glyph_format, False, kpse_src_compile);
00412 
00413        and run load_font() on all of the fonts, with an array in which to save
00414        the names that don't exist (that returned NULL).
00415 
00416       2. Run load_font() again on the fonts that didn't exist in step
00417          (1) and display the output in a window. This somehow needs to
00418          be fork()ed so that the window itself remains responsive.
00419         (Maybe it's easier to call mktexpk directly on the command-line?)
00420 
00421          _________________________________________________________
00422          |                                                       |
00423          |   Xdvi is creating fonts, please be patient ...       |
00424          |                                                       |
00425          |   Font xyz (n of m)                                   |
00426          |                                                       |
00427          |   Errors: 0          [ Show Details ... ]             |
00428          |                                                       |
00429          |   [ ... some progress meter or busy indicator ... ]   |
00430          |                                                       |
00431          |                                                       |
00432          |   [ Exit xdvi ]                            [ Help ]   |
00433          |                                                       |
00434          ---------------------------------------------------------
00435         
00436       This window can be shown before the main window is opened.
00437 
00438     */
00439 
00440     /* Second try: PK/GF/... font within allowable size range */
00441     /*
00442       NOTE SU: The problem with this is that it will already use the PK version
00443       of the fallback font (e.g. cmr10.600pk) if the PK version exists, so the
00444       Type1 version of the fallback won't get used at all. But maybe this isn't
00445       that severe, given that the font is grossly wrong anyway.
00446      */
00447     name = kpse_find_glyph(font, (unsigned)(dpi + .5),
00448                         kpse_any_glyph_format, &file_ret);
00449     
00450     if (name) { /* success */
00451        *dpi_ret = file_ret.dpi;
00452        *filename_ret = name;
00453        *font_ret = file_ret.name;
00454        TRACE_T1((stderr, "Found pixel version: %s at %d dpi", file_ret.name, *dpi_ret));
00455        return XFOPEN(name, FOPEN_R_MODE);
00456     }
00457     else if (resource.alt_font != NULL) {
00458        /* The strange thing about kpse_find_glyph() is that it
00459           won't create a PK version of alt_font if it doesn't
00460           already exist. So we invoke it explicitly a second time
00461           for that one.
00462        */
00463        TRACE_T1((stderr, "Trying fallback"));
00464 #ifdef T1LIB
00465        if (resource.t1lib) {
00466            /* Third attempt: T1 version of fallback font */
00467            *t1id = find_T1_font(resource.alt_font);
00468            if (*t1id >= 0) {
00469               TRACE_T1((stderr, "found fallback font for %s: %s", font, resource.alt_font));
00470               *font_ret = xstrdup(resource.alt_font);
00471               return NULL;
00472            }
00473            TRACE_T1((stderr,
00474                     "Type1 version of fallback font %s not found, trying pixel version",
00475                     resource.alt_font));
00476        }
00477 #endif /* T1LIB */
00478        /* Forth attempt: PK version of fallback font */
00479        name = kpse_find_glyph(resource.alt_font, (unsigned)(dpi + .5),
00480                             kpse_any_glyph_format, &file_ret);
00481        if (name) { /* success */
00482            TRACE_T1((stderr, "Success for PK version of fallback"));
00483            *dpi_ret = file_ret.dpi;
00484            *filename_ret = name;
00485            *font_ret = xstrdup(resource.alt_font);
00486            return XFOPEN(name, FOPEN_R_MODE);
00487        }
00488        else {
00489            TRACE_T1((stderr, "Failure for PK version of fallback"));
00490        }
00491     }
00492 #endif /* EXPERIMENTAL_DELAYED_MTKEXPK */
00493     /* all other cases are failure */
00494     TRACE_T1((stderr, "Failure"));
00495     return NULL;
00496 }