/* fontmap.c: read a file for additional font names.

Copyright (C) 1993 Free Software Foundation, Inc.

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

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "config.h"

#include "c-pathmx.h"
#include "fontmap.h"



/* Fontname mapping.  We use a straightforward hash table.  */

#define MAP_SIZE 199


/* The hash function.  We go for simplicity here.  */

static unsigned
map_hash (key)
    char *key;
{
  unsigned n = 0;
  
  /* There are very few font names which are anagrams of each other (I
     think), so no point in weighting the characters.  */
  while (*key != 0)
    n += *key++;
  
  n %= MAP_SIZE;
  
  return n;
}

/* Look up STR in MAP.  Return the corresponding `value' or NULL.  */

static char *
map_lookup_str (map, key)
    map_type map;
    char *key;
{
  map_element_type *p;
  unsigned n = map_hash (key);
  
  for (p = map[n]; p != NULL; p = p->next)
    if (STREQ (key, p->key))
      return p->value;
  
  return NULL;
}


/* Look up KEY in MAP; if it's not found, remove any suffix from KEY and
   try again.  */

char *
map_lookup (map, key)
    map_type map;
    char *key;
{
  extern string extend_filename ();
  string suffix = find_suffix (key);
  string ret = map_lookup_str (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 = map_lookup_str (map, base_key);

          free (base_key);
        }
    }

  /* Append the same suffix we took off, if necessary.  */
  if (ret)
    ret = extend_filename (ret, suffix);

  return ret;
}

/* If KEY is not already in MAP, insert it and VALUE.  */

static void
map_insert (map, key, value)
    map_type map;
    char *key;
    char *value;
{
  unsigned n = map_hash (key);
  map_element_type **p = &map[n];
  map_element_type ***trailer = &p;

  while (*p != NULL && !STREQ (key, (*p)->key))
    {
       *p = (*p)->next;
       trailer = &p;
    }

  if (*p == NULL)
    {
      **trailer = XTALLOC (MAP_SIZE, map_element_type);
      (**trailer)->key = xstrdup (key);
      (**trailer)->value = xstrdup (value);
      (**trailer)->next = NULL;
    }
}

/* Open and read the mapping file 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 (map, map_filename)
    map_type map;
    char *map_filename;
{
  extern FILE *xfopen ();	/* In xfopen.c.  */
  extern char *read_line ();	/* In line.c.  */
  char *l;
  unsigned map_lineno = 0;
  FILE *f = xfopen (map_filename, FOPEN_R_MODE);
  
  while ((l = read_line (f)) != NULL)
    {
      string filename;
      string comment_loc = strrchr (l, '%');
      
      map_lineno++;
      
      /* Ignore anything after a %.  */
      if (comment_loc)
        *comment_loc = 0;
      
      /* If we don't have any filename, that's ok, the line is blank.  */
      filename = strtok (l, " \t");
      if (filename)
        {
          string alias = strtok (NULL, " \t");
          
          /* But if we have a filename and no alias, something's wrong.  */
          if (alias == NULL || *alias == 0)
            fprintf (stderr, "%s:%u: Alias missing for filename `%s'.\n",
                     map_filename, map_lineno, filename);
          else
            {
              /* We've got everything.  Insert the new entry.  */
              map_insert (map, alias, filename);
            }
        }
      
      free (l);
    }
  
  xfclose (f, map_filename);
}


/* Look for the file `texfonts.map' in each of the directories in
   DIR_LIST.  Entries in earlier files override later files.  */

map_type
map_create (dir_list)
    string *dir_list;
{
  map_type map = (map_type) xcalloc (MAP_SIZE, sizeof (map_element_type *));
  
  while (*dir_list)
    {
      char filename[PATH_MAX];
      
      /* We don't bother with the filename truncation that `readable' in
         `pathsrch.c' does, since we ourselves are giving the filename,
         and I don't think it's worth worrying about too-long
         intermediate directory names in the path.  */
      strcpy (filename, *dir_list);
      strcat (filename, "texfonts.map");
      
      if (access (filename, R_OK) == 0)
        map_file_parse (map, filename);
      
      dir_list++;
    }
  return map;
}
