home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / octave-1.1.1p1-base.tgz / octave-1.1.1p1-base.tar / fsf / octave / kpathsea / tex-glyph.c < prev    next >
C/C++ Source or Header  |  1994-03-24  |  12KB  |  397 lines

  1. /* tex-glyph.c: Search for GF/PK files.
  2.  
  3. Copyright (C) 1993, 94 Karl Berry.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include <kpathsea/config.h>
  20.  
  21. #include <kpathsea/expand.h>
  22. #include <kpathsea/fontmap.h>
  23. #include <kpathsea/pathsearch.h>
  24. #include <kpathsea/tex-file.h>
  25. #include <kpathsea/tex-glyph.h>
  26. #include <kpathsea/tex-make.h>
  27. #include <kpathsea/variable.h>
  28.  
  29. /* Routines are in bottom-up order.  */
  30.  
  31. /* Return malloced filename for bitmap font NAME at resolution DPI with
  32.    extension SUFFIX.  We depend on callers setting the environment
  33.    variables; we only find the right variable spec to use.  */
  34.  
  35. #ifndef KPATHSEA_BITMAP_NAME
  36. #ifdef DOS
  37. /* dpi300\cmr10.pk */
  38. #define KPATHSEA_BITMAP_NAME \
  39.   "dpi$KPATHSEA_DPI\\$KPATHSEA_NAME.$KPATHSEA_FORMAT"
  40. #else
  41. /* cmr10.300pk */
  42. #define KPATHSEA_BITMAP_NAME "$KPATHSEA_NAME.$KPATHSEA_DPI$KPATHSEA_FORMAT"
  43. #endif /* not DOS */
  44. #endif /* not KPATHSEA_BITMAP_NAME */
  45.  
  46. static string
  47. bitmap_name P3C(const_string, name,  unsigned, dpi,  const_string, suffix)
  48. {
  49.   string ret;
  50.   const_string spec = getenv ("KPATHSEA_BITMAP_NAME");
  51.   
  52.   /* We could save a speck of time by setting the environment variable
  53.      to our compile-time default at the beginning of the program, but it
  54.      it doesn't seem worth the code separation.  */
  55.   if (!spec)
  56.     spec = KPATHSEA_BITMAP_NAME;
  57.   
  58.   ret = kpse_var_expand (spec);
  59.  
  60.   return ret;
  61. }
  62.  
  63.  
  64. /* Look up FONT_NAME at resolution DPI in PATH, with filename suffix
  65.    EXTENSION.  Return file found or NULL.  */
  66.  
  67. static string
  68. try_format P4C(const_string, font_name,  unsigned, dpi,
  69.                const_string, path,  const_string, extension)
  70. {
  71.   string name, ret;
  72.   
  73.   /* Set the suffix on the name we'll be searching for.  */
  74.   xputenv ("KPATHSEA_FORMAT", extension);
  75.  
  76.   name = bitmap_name (font_name, dpi, extension);
  77.   ret = kpse_path_search (path, name, true);
  78.   
  79.   if (name != ret)
  80.     free (name);
  81.     
  82.   return ret;
  83. }
  84.  
  85. /* Look for FONT_NAME at resolution DPI, using GLYPH_PATHS.  If
  86.    GLYPH_PATHS[format] is NULL, don't search for that format; otherwise,
  87.    it is the raw search path to use for that format.  Search the
  88.    (entire) PK path first, then the GF path, if we're looking for both.
  89.    Return the filename found, and (if it's non-NULL) fill in FONT_FILE.  */
  90.  
  91. static string
  92. try_size P4C(const_string, font_name,
  93.              unsigned, dpi,
  94.              string *, glyph_paths,
  95.              kpse_font_file_type *, font_file)
  96. {
  97.   kpse_file_format_type format_found;
  98.   string ret;
  99.   string gf_path = glyph_paths[kpse_gf_format];
  100.   string pk_path = glyph_paths[kpse_pk_format];
  101.  
  102.   xputenv_int ("KPATHSEA_DPI", dpi);
  103.   
  104.   /* Look for PK first (since it's more likely to be found), then GF.  */
  105.   ret = pk_path ? try_format (font_name, dpi, pk_path, "pk") : NULL;
  106.  
  107.   if (ret != NULL)
  108.     format_found = kpse_pk_format;
  109.   else
  110.     {
  111.       if (gf_path)
  112.         {
  113.           ret = try_format (font_name, dpi, gf_path, "gf");
  114.           format_found = kpse_gf_format;
  115.         }
  116.     }
  117.   
  118.   if (ret != NULL && font_file)
  119.     { /* Success.  Fill in the return info.  Discard const.  */
  120.       font_file->name = (string) font_name;
  121.       font_file->dpi = dpi;
  122.       font_file->format = format_found;
  123.     }
  124.     
  125.   return ret;
  126. }
  127.  
  128. /* Look for FONT_NAME at resolution DPI, then at the resolutions within
  129.    KPSE_BITMAP_TOLERANCE of DPI.  See `try_name' for information on
  130.    other args and return value.  */
  131.  
  132. static string
  133. try_resolution P4C(const_string, font_name,
  134.                    unsigned, dpi,
  135.                    string *, glyph_paths,
  136.                    kpse_font_file_type *, font_file)
  137. {
  138.   string ret = try_size (font_name, dpi, glyph_paths, font_file);
  139.   
  140.   if (!ret)
  141.     {
  142.       unsigned r;
  143.       unsigned tolerance = KPSE_BITMAP_TOLERANCE (dpi);
  144.       unsigned lower_bound = (int) (dpi - tolerance) < 0 ? 0 : dpi - tolerance;
  145.       unsigned upper_bound = dpi + tolerance;
  146.       
  147.       /* Prefer scaling up to scaling down, since scaling down can omit
  148.          character features (Tom did this in dvips).  */
  149.       for (r = lower_bound; !ret && r <= upper_bound; r++)
  150.         if (r != dpi)
  151.           ret = try_size (font_name, r, glyph_paths, font_file);
  152.     }
  153.   
  154.   return ret;
  155. }
  156.  
  157. /* Look up FONT_NAME in format FORMAT at DPI in the texfonts.map files
  158.    that we can find, returning the filename found and FONT_FILE.  */
  159.  
  160. static string
  161. try_fontmap P4C(const_string, font_name,
  162.                 unsigned, dpi,
  163.         string *, glyph_paths,
  164.                 kpse_font_file_type *, font_file)
  165. {
  166.   static hash_table_type fontmap;
  167.   string *mapped_names;
  168.   string ret = NULL;
  169.  
  170.   if (fontmap.size == 0)
  171.     { /* If we wanted to complicate our lives, we could handle separate
  172.          maps for GF and PK ones.  I don't see that this has any
  173.          practical utility, though, because if someone wants an alias,
  174.          most likely the alias should apply to non-glyphs as well as
  175.          glyphs (let alone to only GF format or PK format).  */
  176.       const_string map_path = KPSE_GLYPH_PATH ();
  177.       fontmap = map_create (map_path);
  178.     }
  179.  
  180.   mapped_names = map_lookup (fontmap, font_name);
  181.   if (mapped_names)
  182.     {
  183.       string mapped_name;
  184.       while ((mapped_name = *mapped_names++) && !ret)
  185.         {
  186.           xputenv ("KPATHSEA_NAME", mapped_name);
  187.           ret = try_resolution (mapped_name, dpi, glyph_paths, font_file);
  188.         }
  189.     }
  190.  
  191.   return ret;
  192. }
  193.  
  194. /* Look for FONT_NAME in `kpse_fallback_resolutions', omitting DPI if we
  195.    happen across it.  Pass GLYPH_PATHS and FONT_FILE along as usual.
  196.    Assume `kpse_fallback_resolutions' is sorted.  */
  197.  
  198. static string
  199. try_fallback_resolutions P4C(const_string, font_name,
  200.                              unsigned, dpi,
  201.                              string *, glyph_paths,
  202.                              kpse_font_file_type *, font_file)
  203. {
  204.   unsigned s;
  205.   int loc, max_loc;
  206.   int lower_loc, upper_loc;
  207.   unsigned lower_diff, upper_diff;
  208.   unsigned closest_diff = UINT_MAX;
  209.   string ret = NULL; /* Initialize in case the first fallback resolution
  210.                         is DPI.  */
  211.  
  212.   /* First find the fallback size closest to DPI.  */
  213.   for (s = 0; kpse_fallback_resolutions[s] != 0; s++)
  214.     {
  215.       unsigned this_diff = abs (kpse_fallback_resolutions[s] - dpi);
  216.       if (this_diff < closest_diff)
  217.         {
  218.           closest_diff = this_diff;
  219.           loc = s;
  220.         }
  221.     }
  222.   max_loc = s;
  223.   lower_loc = loc - 1;
  224.   upper_loc = loc + 1;
  225.   
  226.   for (;;)
  227.     {
  228.       /* Don't bother to try DPI itself again.  */
  229.       if (kpse_fallback_resolutions[loc] != dpi)
  230.         ret = try_resolution (font_name, kpse_fallback_resolutions[loc],
  231.                               glyph_paths, font_file);
  232.       if (ret)
  233.         break;
  234.       
  235.       /* That didn't work. How far away are the locs above or below?  */
  236.       lower_diff = lower_loc > -1
  237.                    ? dpi - kpse_fallback_resolutions[lower_loc] : INT_MAX;
  238.       upper_diff = upper_loc < max_loc
  239.                    ? kpse_fallback_resolutions[upper_loc] - dpi : INT_MAX;
  240.       
  241.       /* But if we're at the end in both directions, quit.  */
  242.       if (lower_diff == INT_MAX && upper_diff == INT_MAX)
  243.         break;
  244.       
  245.       /* Go in whichever direction is closest.  */
  246.       if (lower_diff < upper_diff)
  247.         {
  248.           loc = lower_loc;
  249.           lower_loc--;
  250.         }
  251.       else
  252.         {
  253.           loc = upper_loc;
  254.           upper_loc++;
  255.         }
  256.     }
  257.  
  258.   return ret;
  259. }
  260.  
  261. /* See the .h file for description.  This is the entry point.  */
  262.  
  263. string
  264. kpse_find_glyph_format P4C(const_string, font_name,
  265.                            unsigned, dpi,
  266.                            kpse_file_format_type, format,
  267.                            kpse_font_file_type *, font_file)
  268. {
  269.   string glyph_paths[kpse_any_glyph_format];
  270.   string ret;
  271.   kpse_source_type source;
  272.   
  273.   /* Initialize the path strings for the glyph formats we will try.  */
  274.   glyph_paths[kpse_gf_format]
  275.     = format == kpse_any_glyph_format || format == kpse_gf_format
  276.       ? KPSE_GF_PATH () : NULL;
  277.   
  278.   glyph_paths[kpse_pk_format]
  279.    =  format == kpse_any_glyph_format || format == kpse_pk_format
  280.       ? KPSE_PK_PATH () : NULL;
  281.  
  282.  
  283.   /* Start the search: try the name we're given.  */
  284.   source = kpse_source_normal;
  285.   xputenv ("KPATHSEA_NAME", font_name);
  286.   ret = try_resolution (font_name, dpi, glyph_paths, font_file);
  287.   
  288.   /* Sorry for the spaghetti logic.  How to improve?  */
  289.   if (!ret)
  290.     {
  291.       /* Maybe FONT_NAME was an alias.  */
  292.       source = kpse_source_alias;
  293.       ret = try_fontmap (font_name, dpi, glyph_paths, font_file);
  294.  
  295.       /* OK, maybe we can create it on the fly with MakeTeXPK.  */
  296.       if (!ret)
  297.         {
  298.           source = kpse_source_maketex;
  299.           /* `try_resolution' leaves the envvar set randomly.  */
  300.           xputenv_int ("KPATHSEA_DPI", dpi);
  301.           ret = kpse_make_tex (format, font_name);
  302.         }
  303.        
  304.       /* If MakeTeX... succeeded, set return struct.  (Doesn't make sense for
  305.          `kpse_make_tex' to set it, since it can only succeed or fail,
  306.          unlike the other routines.)  */
  307.       if (ret)
  308.         {
  309.           KPSE_FONT_FILE_DPI (*font_file) = dpi;
  310.           /* Discarding const here.  */
  311.           KPSE_FONT_FILE_NAME (*font_file) = (string) font_name;
  312.         }
  313.  
  314.       /* If MakeTeX... failed, try any fallback resolutions.  */
  315.       else
  316.         {
  317.           if (kpse_fallback_resolutions)
  318.             ret = try_fallback_resolutions (font_name, dpi, glyph_paths,
  319.                                             font_file);
  320.  
  321.           /* We're down to the font of last resort.  */
  322.           if (!ret && kpse_fallback_font)
  323.             {
  324.               /* As before, first try it at the given size.  */
  325.               source = kpse_source_fallback;
  326.               xputenv ("KPATHSEA_NAME", kpse_fallback_font);
  327.               ret = try_resolution (kpse_fallback_font, dpi,
  328.                                     glyph_paths, font_file);
  329.               
  330.               /* The fallback font at the fallback resolutions.  */
  331.               if (!ret && kpse_fallback_resolutions)
  332.                 ret = try_fallback_resolutions (kpse_fallback_font, dpi,
  333.                                                glyph_paths, font_file);
  334.             }
  335.         }
  336.     }
  337.   
  338.   /* If RET is null, then the caller must not look at FONT_FILE, so it
  339.      doesn't matter if we assign something incorrect to it.  */
  340.   KPSE_FONT_FILE_SOURCE (*font_file) = source;
  341.   
  342.   return ret;
  343. }
  344.  
  345. #ifdef TEST
  346.  
  347. void
  348. test_find_glyph (const_string font_name, unsigned dpi)
  349. {
  350.   string answer;
  351.   kpse_font_file_type ret;
  352.   
  353.   printf ("\nSearch for %s@%u:\n\t", font_name, dpi);
  354.  
  355.   answer = kpse_find_glyph_format (font_name, dpi,
  356.                                    kpse_any_glyph_format, &ret);
  357.   if (answer)
  358.     {
  359.       string format = ret.format == kpse_pk_format ? "pk" : "gf";
  360.       if (!ret.name)
  361.         ret.name = "(null)";
  362.       printf ("%s\n\t(%s@%u, %s)\n", answer, ret.name, ret.dpi, format);
  363.     }
  364.   else
  365.     puts ("(null)");
  366. }
  367.  
  368.  
  369. int
  370. main ()
  371. {
  372.   test_find_glyph ("/usr/local/lib/tex/fonts/cm/cmr10", 300); /* absolute */
  373.   test_find_glyph ("cmr10", 300);     /* normal */
  374.   test_find_glyph ("logo10", 300);    /* find gf */
  375.   test_find_glyph ("cmr10", 299);     /* find 300 */
  376.   test_find_glyph ("circle10", 300);  /* in fontmap */
  377.   test_find_glyph ("none", 300);      /* do not find */
  378.   kpse_fallback_font = "cmr10";
  379.   test_find_glyph ("fallback", 300);  /* find fallback font cmr10 */
  380.   kpse_init_fallback_resolutions ("KPATHSEA_TEST_SIZES");
  381.   test_find_glyph ("fallbackdpi", 759); /* find fallback font cmr10@300 */
  382.   
  383.   xputenv ("GFFONTS", ".");
  384.   test_find_glyph ("cmr10", 300);     /* different GFFONTS/TEXFONTS */
  385.   
  386.   return 0;
  387. }
  388.  
  389. #endif /* TEST */
  390.  
  391.  
  392. /*
  393. Local variables:
  394. test-compile-command: "gcc -posix -g -I. -I.. -DTEST tex-glyph.c kpathsea.a"
  395. End:
  396. */
  397.