home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / s / stex2-18.zip / SeeTeX / libtex / font.c < prev    next >
C/C++ Source or Header  |  1990-07-10  |  12KB  |  538 lines

  1. /*
  2.  * Copyright (c) 1987, 1989 University of Maryland
  3.  * Department of Computer Science.  All rights reserved.
  4.  * Permission to copy for any purpose is hereby granted
  5.  * so long as this copyright notice remains intact.
  6.  */
  7.  
  8. #ifndef lint
  9. static char rcsid[] = "$Header: /usr/src/local/tex/local/mctex/lib/RCS/font.c,v 2.12 89/11/06 15:00:47 chris Exp $";
  10. #endif
  11.  
  12. /*
  13.  * Routines for working with fonts.  In particular, the configuration
  14.  * dependent code is here.
  15.  *
  16.  * Specific fonts (GF, PXL, etc.) have functions in separate files.
  17.  */
  18.  
  19. #include <stdio.h>
  20. #include <errno.h>
  21. #include <ctype.h>
  22. #include "types.h"
  23. #include "conv.h"
  24. #include "error.h"
  25. #include "font.h"
  26.  
  27. /*
  28.  * Define the default configuration file.
  29.  * Also define the maximum path name length.
  30.  */
  31. #ifndef FONTDESC
  32. /* #define FONTDESC "/usr/local/lib/tex/fontdesc" */
  33.     you must define FONTDESC in the Makefile
  34. #endif
  35.  
  36. #define    PATHLEN    1024
  37.  
  38. /*
  39.  * A font configuration.  The font list is ordered.
  40.  *
  41.  * A specifier is typically a particular print engine, since
  42.  * different engines need slightly different fonts.
  43.  */
  44. struct fontconf {
  45.     struct    fontconf *fc_next;
  46.     struct    fontops *fc_ops;
  47.     char    *fc_path;    /* path, with metacharacters */
  48.     char    *fc_spec;    /* specifier */
  49.     int    fc_slop;    /* slop value */
  50. };
  51.  
  52. /*
  53.  * EQ is a fast way to check for string equivalence.
  54.  */
  55. #define    EQ(a, b) (*(a) == *(b) && strcmp(a, b) == 0)
  56.  
  57. /*
  58.  * Private variables and functions.
  59.  */
  60. static    int didinit;        /* true => initialised already */
  61. static    char *cfname;        /* config file name, for errors */
  62. static    int cfline;        /* config file line, likewise */
  63. static    struct fontops *fontops;/* font operations code: list head */
  64. static    struct fontconf *fonts;    /* font list */
  65. static    struct fontconf **nextfc;/* used during initialisation */
  66. static    char spec_any[] = "*";    /* the `anything' specifier */
  67.  
  68. static void readconf(), badcf(), setfenv(), setfont();
  69. static struct font *getafont();
  70.  
  71. /*
  72.  * Imports.
  73.  */
  74. extern    int errno;
  75. char    *getenv(), *malloc(), *strncpy(), *strsave();
  76.  
  77. /*
  78.  * You may get warnings from lint about sprintf(), which is of type
  79.  * `char *' in early 4BSD releases.  Ignore the warning.
  80.  */
  81.  
  82. /*
  83.  * Here, alas, we know about all the kinds of fonts.
  84.  * This also means that every DVI interpreter pulls in
  85.  * the full set of font manipulation routines.
  86.  *
  87.  * PERHAPS THIS SHOULD BE CONFIGURABLE.
  88.  */
  89. #define    ADDFONT(x) { \
  90.     extern struct fontops x; \
  91.     x.fo_next = fontops; \
  92.     fontops = &x; \
  93. }
  94.  
  95. void
  96. fontinit(file)
  97.     char *file;
  98. {
  99.  
  100.     if (didinit) {
  101.         /*
  102.          * Could free the old configuration and fire up
  103.          * a new one, but for now . . .
  104.          */
  105.         error(1, 0, "attempt to reinit fonts");
  106.         /* NOTREACHED */
  107.     }
  108.     didinit++;
  109.     ADDFONT(invisops);
  110.     ADDFONT(tfmops);
  111.     ADDFONT(blankops);
  112.     ADDFONT(boxops);
  113.     ADDFONT(pxlops);
  114.     ADDFONT(gfops);
  115.     ADDFONT(pkops);
  116.     nextfc = &fonts;
  117.     if (file == NULL)
  118.         if ((file = getenv(CONFENV)) == NULL)
  119.             file = FONTDESC;
  120.     readconf(file);
  121. }
  122.  
  123. /*
  124.  * Find a font's operations, given its name.
  125.  */
  126. static struct fontops *
  127. findops(name)
  128.     register char *name;
  129. {
  130.     register struct fontops *fo;
  131.  
  132.     for (fo = fontops; fo != NULL; fo = fo->fo_next)
  133.         if (EQ(fo->fo_name, name))
  134.             return (fo);
  135.     return (NULL);
  136. }
  137.  
  138. /*
  139.  * Read the named configuration file.  The file is split into
  140.  * lines, and lines are split into words; if the first word is
  141.  * "font", this is a fontconf, and we read the remainder of the
  142.  * words and make a fontconf entry.
  143.  */
  144. static void
  145. readconf(name)
  146.     char *name;
  147. {
  148.     register FILE *f;    /* config file */
  149.     register int c;        /* char and word counter */
  150.     int isenv;        /* true => doing `fontenv', not `font' */
  151.     char *env;        /* value from getenv() */
  152.     struct fontconf proto;    /* prototype fontconf */
  153.     char *v[20];        /* word vector */
  154.     char line[BUFSIZ];    /* input line */
  155.  
  156.     if ((f = fopen(name, "r")) == NULL)
  157.         error(1, -1, "cannot read font configuration file \"%s\"",
  158.             name);
  159.     cfname = name;
  160.     cfline = 0;
  161.     while (fgets(line, sizeof (line), f) != NULL) {
  162.         cfline++;
  163.         if ((c = strlen(line)) > 0) {
  164.             if (line[--c] != '\n')
  165.                 badcf("line too long");
  166.             line[c] = 0;
  167.         }
  168.         if ((c = split(line, v, sizeof v / sizeof *v)) < 0)
  169.             badcf("too many words");
  170.         /* skip things that are not fonts */
  171.         if (c == 0)
  172.             continue;
  173.         if (EQ(v[0], "font"))
  174.             isenv = 0;
  175.         else if (EQ(v[0], "fontenv"))
  176.             isenv = 1;
  177.         else
  178.             continue;
  179.         switch (c) {
  180.         case 1:
  181.             badcf("missing font typename");
  182.             /* NOTREACHED */
  183.         case 2:
  184.             badcf("missing font spec (engine)");
  185.             /* NOTREACHED */
  186.         case 3:
  187.             badcf("missing slop value");
  188.             /* NOTREACHED */
  189.         case 4:
  190.             badcf(isenv ? "need environment variable" :
  191.                 "need pathname");
  192.             /* NOTREACHED */
  193.         case 5:
  194.             if (isenv)
  195.                 badcf("need suffix");
  196.             break;
  197.         case 6:
  198.             if (isenv)
  199.                 break;
  200.         default:
  201.             error(0, 0,
  202.                 "%s, line %d: warning: %d extra word(s) ignored",
  203.                 cfname, cfline, c - 5);
  204.             break;
  205.         }
  206.         if ((proto.fc_ops = findops(v[1])) == NULL) {
  207.             error(0, 0,
  208.                 "\"%s\", line %d: unknown font type \"%s\" ignored",
  209.                 cfname, cfline, v[1]);
  210.             continue;
  211.         }
  212.  
  213.         /*
  214.          * For fontenv, if the environment variable is not actually
  215.          * set in the environment, just skip over this line.
  216.          */
  217.         if (isenv && (env = getenv(v[4])) == NULL)
  218.             continue;
  219.         proto.fc_next = NULL;
  220.         proto.fc_spec = EQ(v[2], spec_any) ? NULL : strsave(v[2]);
  221.         proto.fc_slop = atoi(v[3]);
  222.         if (proto.fc_slop < 0)    /* quietly enforce proper slops */
  223.             proto.fc_slop = 0;
  224.         if (isenv)
  225.             setfenv(&proto, env, v[5]);
  226.         else
  227.             setfont(&proto, strsave(v[4]));
  228.     }
  229. }
  230.  
  231. /*
  232.  * Handle fontenv lines by appending as many configuration entries
  233.  * as there are components in the given environment variable.
  234.  */
  235. static void
  236. setfenv(pfc, env, suf)
  237.     struct fontconf *pfc;
  238.     char *env, *suf;
  239. {
  240.     register char *s, *t;
  241.     register int len, suflen = strlen(suf);
  242.     register char *mem, *slash;
  243.     char *munch = strsave(env);    /* a copy we can write on */
  244.     struct fontops *fo;
  245.  
  246.     /*
  247.      * Loop over the path.  Turn `foo' into `foo/<suf1><suf2>';
  248.      * turn an empty string into just <suf1><suf2>.  Put these
  249.      * names in fresh memory and set them up as places to search.
  250.      */
  251.     for (s = env; (t = s) != NULL; s = t) {
  252.         for (;;) {
  253.             if (*t == ':') {
  254.                 *t++ = 0;
  255.                 len = t - s;    /* includes trailing NUL */
  256.                 break;
  257.             }
  258.             if (*t++ == 0) {
  259.                 len = t - s;    /* includes trailing NUL */
  260.                 t = NULL;
  261.                 break;
  262.             }
  263.         }
  264.         if (len != 0) {
  265.             slash = "/";
  266.             len++;
  267.         } else
  268.             slash = "";
  269.         if ((mem = malloc(len + suflen)) == NULL)
  270.             error(1, -1, "out of memory while saving $%s", env);
  271.         (void) sprintf(mem, "%s%s%s", s, slash, suf);
  272.         setfont(pfc, mem);
  273.     }
  274.     free(munch);
  275. }
  276.  
  277. /*
  278.  * Turn a prototype fontconf into a real one.
  279.  */
  280. static void
  281. setfont(pfc, path)
  282.     struct fontconf *pfc;
  283.     char *path;
  284. {
  285.     register struct fontconf *fc;
  286.  
  287.     if ((fc = (struct fontconf *)malloc(sizeof(*fc))) == NULL)
  288.         error(1, -1, "out of memory for font configuration (sorry)");
  289.     *fc = *pfc;
  290.     fc->fc_path = path;
  291.     *nextfc = fc;
  292.     nextfc = &fc->fc_next;
  293. }
  294.  
  295. /*
  296.  * Complain about a problem in the configuration file.
  297.  */
  298. static void
  299. badcf(why)
  300.     char *why;
  301. {
  302.  
  303.     error(1, 0, "\"%s\", line %d: %s", cfname, cfline, why);
  304.     /* NOTREACHED */
  305. }
  306.  
  307. /*
  308.  * Copy string s into buffer buf, dropping off any numerical suffix.
  309.  * E.g., cmr7 and cmr10 become cmr.  (This is the `%b' operator.)
  310.  */
  311. static void
  312. basify(s, buf, size)
  313.     char *s, *buf;
  314.     int size;
  315. {
  316.     register char *p, *endp;
  317.     register int n;
  318.  
  319.     for (p = s; *p; p++)
  320.         if (!isdigit(*p))
  321.             endp = p;
  322.     if ((n = endp + 1 - s) >= size)
  323.         error(1, 0, "font name `%s' too long for %%b (sorry)", s);
  324.     (void) strncpy(buf, s, n);
  325.     buf[n] = 0;
  326. }
  327.  
  328. /*
  329.  * Turn a prototype path, name, and magnification into a full
  330.  * path (expand %f, %m, %b).
  331.  */
  332. static void
  333. pave(result, proto, name, mag)
  334.     char *result, *proto, *name;
  335.     int mag;
  336. {
  337.     register int c;
  338.     register char *s, *d, *p;
  339.     char num[30], fontbase[256];
  340.  
  341.     d = result;
  342.     p = proto;
  343.     s = NULL;
  344.     num[0] = 0;        /* will need changing for other bases */
  345.     fontbase[0] = 0;
  346.  
  347.     while (p != NULL) {
  348.         /*
  349.          * If sourcing from s, take its next character, and
  350.          * insert it directly.  Otherwise take the next path
  351.          * character and interpret it.
  352.          */
  353.         if (s != NULL) {
  354.             if ((c = *s++) == 0) {
  355.                 s = NULL;
  356.                 continue;
  357.             }
  358.             goto put;
  359.         }
  360.         if ((c = *p++) == 0)
  361.             p = NULL;
  362.         if (c != '%')
  363.             goto put;
  364.  
  365.         switch (c = *p++) {
  366.  
  367.         case 'b':
  368.             if (fontbase[0] == 0)
  369.                 basify(name, fontbase, sizeof(fontbase));
  370.             s = fontbase;
  371.             continue;
  372.  
  373.         case 'f':
  374.         case 'n':
  375.         case 's':
  376.             s = name;
  377.             continue;
  378.  
  379.         case 'd':
  380.         case 'm':
  381.             if (num[0] == 0)
  382.                 (void) sprintf(num, "%d", mag);
  383.             s = num;
  384.             continue;
  385.  
  386.         case 0:
  387.             c = '%';
  388.             p--;
  389.             /* FALLTHROUGH */
  390.         }
  391. put:
  392.         if (d - result >= PATHLEN)
  393.             error(1, 0, "font path `%s' too long (sorry)", proto);
  394.         *d++ = c;
  395.     }
  396. }
  397.  
  398. /*
  399.  * Given a font name and size, return the first font that fits, along
  400.  * with its name (via fname).  If we cannot find such a font, we set
  401.  * *fname to point to a `canonical' example font name, unless there are
  402.  * are no fonts for the device, in which case we set *fname to NULL.
  403.  */
  404. struct font *
  405. GetFont(nm, dvimag, dvidsz, dev, fname)
  406.     char *nm;
  407.     i32 dvimag, dvidsz;
  408.     char *dev, **fname;
  409. {
  410.  
  411.     return (getafont(nm, dvimag, dvidsz, dev, fname, 1));
  412. }
  413.  
  414. /*
  415.  * Same as GetFont, but caller promises never to ask for rasters.
  416.  */
  417. struct font *
  418. GetRasterlessFont(nm, dvimag, dvidsz, dev, fname)
  419.     char *nm;
  420.     i32 dvimag, dvidsz;
  421.     char *dev, **fname;
  422. {
  423.  
  424.     return (getafont(nm, dvimag, dvidsz, dev, fname, 0));
  425. }
  426.  
  427. /*
  428.  * NEED TO THINK ABOUT gf NAMING CONVENTIONS HERE: ARE THEY LIKE pxl?
  429.  * WHAT ABOUT OTHERS?
  430.  */
  431. static struct font *
  432. getafont(nm, dvimag, dvidsz, dev, fname, wantrast)
  433.     char *nm;
  434.     i32 dvimag, dvidsz;
  435.     char *dev, **fname;
  436.     int wantrast;
  437. {
  438.     register int slop, fmag;
  439.     register struct font *f;
  440.     register struct fontconf *fc;
  441.     register struct fontops *fo;
  442.     register char *path;
  443.     int fd, scaled;
  444.     double mag;
  445.     static char firstpath[PATHLEN], laterpath[PATHLEN];
  446.  
  447.     if (!didinit)
  448.         fontinit((char *)NULL);
  449.  
  450.     /*
  451.      * The equation below means, approximately, `the font is
  452.      * magnified by the ratio of the actual size dvimag to the
  453.      * design size dvidsz, and then further scaled by the
  454.      * global magnification.'  We multiply this by the printer's
  455.      * resolution in dots per inch, then use the per-font
  456.      * conversion factor to convert a dots-per-inch value to
  457.      * a font name `%m' magnification (extension).
  458.      */
  459.     mag = (double) dvimag / (double) dvidsz;
  460.     scaled = mag * 1000.0 + 0.5;
  461.     mag *= Conversion.c_mag * Conversion.c_dpi;
  462.  
  463.     path = firstpath;    /* no canonical font name yet */
  464.     for (fc = fonts; fc != NULL; fc = fc->fc_next) {
  465.         if (dev != NULL && fc->fc_spec != NULL &&
  466.             !EQ(dev, fc->fc_spec))
  467.             continue;
  468.         /*
  469.          * Fake fonts are ignored unless there is already
  470.          * `canonical' real font.  The first non-fake font
  471.          * is the `canonical' one.
  472.          */
  473.         fo = fc->fc_ops;
  474.         if (path == firstpath && fo->fo_fakefont)
  475.             continue;
  476.         fmag = mag * fo->fo_dpitomag + 0.5;
  477.         for (slop = 0; slop <= fc->fc_slop; slop++) {
  478.             pave(path, fc->fc_path, nm, fmag + slop);
  479.             if ((fd = open(path, 0)) >= 0)
  480.                 goto found;
  481.             path = laterpath;    /* tried at least one now */
  482.             if (slop) {
  483.                 pave(path, fc->fc_path, nm, fmag - slop);
  484.                 if ((fd = open(path, 0)) >= 0)
  485.                     goto found;
  486.             }
  487.         }
  488.     }
  489.  
  490.     /* not found */
  491.     if (path == firstpath) {
  492.         *fname = NULL;
  493.         errno = ENXIO;
  494.     } else {
  495.         *fname = firstpath;
  496.         errno = ENOENT;
  497.     }
  498.     return (NULL);
  499.  
  500. found:
  501.     *fname = path;
  502.  
  503.     /* allocate space for the per-font info, and read it in */
  504.     f = (struct font *)malloc(sizeof *f);
  505.     if (f == NULL) {
  506.         errno = ENOMEM;
  507.         return (NULL);
  508.     }
  509.     f->f_flags = wantrast ? FF_RASTERS : 0;
  510.     f->f_ops = fc->fc_ops;
  511.     f->f_path = strsave(path);
  512.     f->f_font = strsave(nm);
  513.     f->f_dvimag = dvimag;
  514.     f->f_dvidsz = dvidsz;
  515.     f->f_scaled = scaled;
  516.     f->f_pspace = f->f_dvimag / 6;    /* a three-unit "thin space" */
  517.     f->f_nspace = -4 * f->f_pspace;
  518.     f->f_vspace = 5 * f->f_pspace;
  519.     errno = 0;
  520.     if ((*f->f_ops->fo_read)(f, fd)) {
  521.         int e = errno;    /* paranoid */
  522.  
  523.         free(f->f_path);
  524.         free(f->f_font);
  525.         free((char *)f);
  526.         errno = e;
  527.         return (NULL);
  528.     }
  529.     if (f->f_ops->fo_fakefont) {
  530.         error(0, 0, "Warning: no font for %s", Font_TeXName(f));
  531.         if (firstpath[0])
  532.             error(0, 0, "(wanted, e.g., \"%s\")", firstpath);
  533.         error(0, 0, "I will substitute %s for the missing glyphs",
  534.             f->f_ops->fo_fakefont == 1 ? "boxes" : "white space");
  535.     }
  536.     return (f);
  537. }
  538.