/* fontmap.c: read files for additional font names.

Copyright (C) 1993, 94, 95, 96 Free Software Foundation, Inc.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#include <kpathsea/config.h>

#include <kpathsea/c-ctype.h>
#include <kpathsea/c-fopen.h>
#include <kpathsea/fontmap.h>
#include <kpathsea/hash.h>
#include <kpathsea/line.h>
#include <kpathsea/pathsearch.h>
#include <kpathsea/str-list.h>
#include <kpathsea/tex-file.h>

/* We have one and only one fontmap, so may as well make it static
   instead of passing it around.  */
static hash_table_type map;
#ifndef MAP_NAME
#define MAP_NAME "texfonts.map"
#endif
#ifndef MAP_HASH_SIZE
#define MAP_HASH_SIZE 4001
#endif

static const_string map_path; /* Only want to create this once. */

/* Return next whitespace-delimited token in STR or NULL if none.  */

static string
token P1C(const_string, str)
{
  unsigned len;
  const_string start;
  string ret;
  
  while (*str && ISSPACE (*str))
    str++;
  
  start = str;
  while (*str && !ISSPACE (*str))
    str++;
  
  len = str - start;
  ret = xmalloc (len + 1);
  strncpy (ret, start, len);
  ret[len] = 0;
  
  return ret;
}

/* Open and read the mapping file MAP_FILENAME, putting its entries into
   MAP. Comments begin with % and continue to the end of the line.  Each
   line of the file defines an entry: the first word is the real
   filename (e.g., `ptmr'), the second word is the alias (e.g.,
   `Times-Roman'), and any subsequent words are ignored.  .tfm is added
   if either the filename or the alias have no extension.  This is the
   same order as in Dvips' psfonts.map; unfortunately, we can't have TeX
   read that same file, since most of the real filenames start with an
   `r', because of the virtual fonts Dvips uses.  */

static void
map_file_parse P1C(const_string, map_filename)
{
  char *orig_l;
  unsigned map_lineno = 0;
  FILE *f = xfopen (map_filename, FOPEN_R_MODE);
  
  while ((orig_l = read_line (f)) != NULL) {
    string filename;
    string l = orig_l;
    string comment_loc = strrchr (l, '%');
    if (!comment_loc) {
      comment_loc = strstr (l, "@c");
    }
    
    /* Ignore anything after a % or @c.  */
    if (comment_loc)
      *comment_loc = 0;

    map_lineno++;

    /* Skip leading whitespace so we can use strlen below.  Can't use
       strtok since this routine is recursive.  */
    while (*l && ISSPACE (*l))
      l++;
      
    /* If we don't have any filename, that's ok, the line is blank.  */
    filename = token (l);
    if (filename) {
      string alias = token (l + strlen (filename));

      if (STREQ (filename, "include")) {
        if (alias == NULL) {
          WARNING2 ("%s:%u: Filename argument for include directive missing",
                    map_filename, map_lineno);
        } else {
          string include_fname = kpse_path_search (map_path, alias, false);
          if (include_fname) {
            map_file_parse (include_fname);
            if (include_fname != alias)
              free (include_fname);
          } else {
            WARNING3 ("%s:%u: Can't find fontname include file `%s'",
                      map_filename, map_lineno, alias);
          }
          free (alias);
          free (filename);
        }

      /* But if we have a filename and no alias, something's wrong.  */
      } else if (alias == NULL) {
        WARNING3 ("%s:%u: Fontname alias missing for filename `%s'",
                  map_filename, map_lineno, filename);
        free (filename);

      } else {
        /* We've got everything.  Insert the new entry.  They were
           already dynamically allocated, so don't bother with xstrdup.  */
        hash_insert (&map, alias, filename);
      }
    }

    free (l);
  }
  
  xfclose (f, map_filename);
}

/* Parse the file MAP_NAME in each of the directories in PATH and
   return the resulting structure.  Entries in earlier files override
   later files.  */

static void
read_all_maps P1H(void)
{
  string *filenames;
  
  map_path = kpse_init_format (kpse_fontmap_format);
  filenames = kpse_all_path_search (map_path, MAP_NAME);
  
  map = hash_create (MAP_HASH_SIZE);

  while (*filenames) {
    map_file_parse (*filenames);
    filenames++;
  }
}

/* Look up KEY in texfonts.map's; if it's not found, remove any suffix
   from KEY and try again.  Create the map if necessary.  */

string *
kpse_fontmap_lookup P1C(const_string, key)
{
  string *ret;
  string suffix = find_suffix (key);
  
  if (map.size == 0) {
    read_all_maps ();
  }

  ret = hash_lookup (map, key);
  if (!ret) {
    /* OK, the original KEY didn't work.  Let's check for the KEY without
       an extension -- perhaps they gave foobar.tfm, but the mapping only
       defines `foobar'.  */
    if (suffix) {
      string base_key = remove_suffix (key);
      ret = hash_lookup (map, base_key);
      free (base_key);
    }
  }

  /* Append any original suffix.  */
  if (ret && suffix) {
    string *elt;
    for (elt = ret; *elt; elt++) {
      *elt = extend_filename (*elt, suffix);
    }
  }

  return ret;
}
