Back to index

tetex-bin  3.0
db.c
Go to the documentation of this file.
00001 /* db.c: an external database to avoid filesystem lookups.
00002 
00003 Copyright (C) 1994, 95, 96, 97 Karl Berry.
00004 
00005 This library is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU Library General Public
00007 License as published by the Free Software Foundation; either
00008 version 2 of the License, or (at your option) any later version.
00009 
00010 This library is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 Library General Public License for more details.
00014 
00015 You should have received a copy of the GNU Library General Public
00016 License along with this library; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00018 
00019 #include <kpathsea/config.h>
00020 #include <kpathsea/absolute.h>
00021 #include <kpathsea/c-stat.h>
00022 #include <kpathsea/c-fopen.h>
00023 #include <kpathsea/c-pathch.h>
00024 #include <kpathsea/db.h>
00025 #include <kpathsea/hash.h>
00026 #include <kpathsea/line.h>
00027 #include <kpathsea/pathsearch.h>
00028 #include <kpathsea/readable.h>
00029 #include <kpathsea/str-list.h>
00030 #include <kpathsea/tex-file.h>
00031 #include <kpathsea/variable.h>
00032 
00033 static hash_table_type db; /* The hash table for all the ls-R's.  */
00034 /* SMALL: The old size of the hash table was 7603, with the assumption
00035    that a minimal ls-R bas about 3500 entries.  But a typical ls-R will
00036    be more like double that size.  */
00037 #ifndef DB_HASH_SIZE
00038 #define DB_HASH_SIZE 15991
00039 #endif
00040 #ifndef DB_NAME
00041 #define DB_NAME "ls-R"
00042 #endif
00043 #ifndef DB_NAME_LC
00044 #define DB_NAME_LC "ls-r"
00045 #endif
00046 
00047 static const_string db_names[] = {
00048     DB_NAME,
00049     DB_NAME_LC,
00050     NULL
00051 };
00052 
00053 static hash_table_type alias_db;
00054 #ifndef ALIAS_NAME
00055 #define ALIAS_NAME "aliases"
00056 #endif
00057 #ifndef ALIAS_HASH_SIZE
00058 #define ALIAS_HASH_SIZE 1009
00059 #endif
00060 
00061 static str_list_type db_dir_list;
00062 
00063 /* If DIRNAME contains any element beginning with a `.' (that is more
00064    than just `./'), return true.  This is to allow ``hidden''
00065    directories -- ones that don't get searched.  */
00066 
00067 static boolean
00068 ignore_dir_p P1C(const_string, dirname)
00069 {
00070   const_string dot_pos = dirname;
00071   
00072   while ((dot_pos = strchr (dot_pos + 1, '.'))) {
00073     /* If / before and no / after, skip it. */
00074     if (IS_DIR_SEP (dot_pos[-1]) && dot_pos[1] && !IS_DIR_SEP (dot_pos[1]))
00075       return true;
00076   }
00077   
00078   return false;
00079 }
00080 
00081 /* If no DB_FILENAME, return false (maybe they aren't using this feature).
00082    Otherwise, add entries from DB_FILENAME to TABLE, and return true.  */
00083 
00084 static boolean
00085 db_build P2C(hash_table_type *, table,  const_string, db_filename)
00086 {
00087   string line;
00088   unsigned dir_count = 0, file_count = 0, ignore_dir_count = 0;
00089   unsigned len = strlen (db_filename) - sizeof (DB_NAME) + 1; /* Keep the /. */
00090   string top_dir = (string)xmalloc (len + 1);
00091   string cur_dir = NULL; /* First thing in ls-R might be a filename.  */
00092   FILE *db_file = fopen (db_filename, FOPEN_R_MODE);
00093   
00094   strncpy (top_dir, db_filename, len);
00095   top_dir[len] = 0;
00096   
00097   if (db_file) {
00098     while ((line = read_line (db_file)) != NULL) {
00099       len = strlen (line);
00100 
00101       /* A line like `/foo:' = new dir foo.  Allow both absolute (/...)
00102          and explicitly relative (./...) names here.  It's a kludge to
00103          pass in the directory name with the trailing : still attached,
00104          but it doesn't actually hurt.  */
00105       if (len > 0 && line[len - 1] == ':' && kpse_absolute_p (line, true)) {
00106         /* New directory line.  */
00107         if (!ignore_dir_p (line)) {
00108           /* If they gave a relative name, prepend full directory name now.  */
00109           line[len - 1] = DIR_SEP;
00110           /* Skip over leading `./', it confuses `match' and is just a
00111              waste of space, anyway.  This will lose on `../', but `match'
00112              won't work there, either, so it doesn't matter.  */
00113           cur_dir = *line == '.' ? concat (top_dir, line + 2) : xstrdup (line);
00114           dir_count++;
00115         } else {
00116           cur_dir = NULL;
00117           ignore_dir_count++;
00118         }
00119 
00120       /* Ignore blank, `.' and `..' lines.  */
00121       } else if (*line != 0 && cur_dir   /* a file line? */
00122                  && !(*line == '.'
00123                       && (line[1] == 0 || (line[1] == '.' && line[2] == 0))))
00124       {
00125         /* Make a new hash table entry with a key of `line' and a data
00126            of `cur_dir'.  An already-existing identical key is ok, since
00127            a file named `foo' can be in more than one directory.  Share
00128            `cur_dir' among all its files (and hence never free it).
00129 
00130            Note that we assume that all names in the ls-R file have already
00131            been case-smashed to lowercase where appropriate.
00132         */
00133         hash_insert_normalized (table, xstrdup (line), cur_dir);
00134         file_count++;
00135 
00136       } /* else ignore blank lines or top-level files
00137            or files in ignored directories*/
00138 
00139       free (line);
00140     }
00141 
00142     xfclose (db_file, db_filename);
00143 
00144     if (file_count == 0) {
00145       WARNING1 ("kpathsea: No usable entries in %s", db_filename);
00146       WARNING ("kpathsea: See the manual for how to generate ls-R");
00147       db_file = NULL;
00148     } else {
00149       str_list_add (&db_dir_list, xstrdup (top_dir));
00150     }
00151 
00152 #ifdef KPSE_DEBUG
00153     if (KPSE_DEBUG_P (KPSE_DEBUG_HASH)) {
00154       /* Don't make this a debugging bit, since the output is so
00155          voluminous, and being able to specify -1 is too useful.
00156          Instead, let people who want it run the program under
00157          a debugger and change the variable that way.  */
00158       boolean hash_summary_only = true;
00159 
00160       DEBUGF4 ("%s: %u entries in %d directories (%d hidden).\n",
00161                db_filename, file_count, dir_count, ignore_dir_count);
00162       DEBUGF ("ls-R hash table:");
00163       hash_print (*table, hash_summary_only);
00164       fflush (stderr);
00165     }
00166 #endif /* KPSE_DEBUG */
00167   }
00168 
00169   free (top_dir);
00170 
00171   return db_file != NULL;
00172 }
00173 
00174 
00175 /* Insert FNAME into the hash table.  This is for files that get built
00176    during a run.  We wouldn't want to reread all of ls-R, even if it got
00177    rebuilt.  */
00178 
00179 void
00180 kpse_db_insert P1C(const_string, passed_fname)
00181 {
00182   /* We might not have found ls-R, or even had occasion to look for it
00183      yet, so do nothing if we have no hash table.  */
00184   if (db.buckets) {
00185     const_string dir_part;
00186     string fname = xstrdup (passed_fname);
00187     string baseptr = (string)xbasename (fname);
00188     const_string file_part = xstrdup (baseptr);
00189 
00190     *baseptr = '\0';  /* Chop off the filename.  */
00191     dir_part = fname; /* That leaves the dir, with the trailing /.  */
00192 
00193     /* Note that we do not assuse that these names have been normalized. */
00194     hash_insert (&db, file_part, dir_part);
00195   }
00196 }
00197 
00198 /* Return true if FILENAME could be in PATH_ELT, i.e., if the directory
00199    part of FILENAME matches PATH_ELT.  Have to consider // wildcards, but
00200    $ and ~ expansion have already been done.  */
00201      
00202 static boolean
00203 match P2C(const_string, filename,  const_string, path_elt)
00204 {
00205   const_string original_filename = filename;
00206   boolean matched = false;
00207   
00208   for (; *filename && *path_elt; filename++, path_elt++) {
00209     if (FILECHARCASEEQ (*filename, *path_elt)) /* normal character match */
00210       ;
00211 
00212     else if (IS_DIR_SEP (*path_elt)  /* at // */
00213              && original_filename < filename && IS_DIR_SEP (path_elt[-1])) {
00214       while (IS_DIR_SEP (*path_elt))
00215         path_elt++; /* get past second and any subsequent /'s */
00216       if (*path_elt == 0) {
00217         /* Trailing //, matches anything. We could make this part of the
00218            other case, but it seems pointless to do the extra work.  */
00219         matched = true;
00220         break;
00221       } else {
00222         /* Intermediate //, have to match rest of PATH_ELT.  */
00223         for (; !matched && *filename; filename++) {
00224           /* Try matching at each possible character.  */
00225           if (IS_DIR_SEP (filename[-1])
00226               && FILECHARCASEEQ (*filename, *path_elt))
00227             matched = match (filename, path_elt);
00228         }
00229         /* Prevent filename++ when *filename='\0'. */
00230         break;
00231       }
00232     }
00233 
00234     else /* normal character nonmatch, quit */
00235       break;
00236   }
00237   
00238   /* If we've reached the end of PATH_ELT, check that we're at the last
00239      component of FILENAME, we've matched.  */
00240   if (!matched && *path_elt == 0) {
00241     /* Probably PATH_ELT ended with `vf' or some such, and FILENAME ends
00242        with `vf/ptmr.vf'.  In that case, we'll be at a directory
00243        separator.  On the other hand, if PATH_ELT ended with a / (as in
00244        `vf/'), FILENAME being the same `vf/ptmr.vf', we'll be at the
00245        `p'.  Upshot: if we're at a dir separator in FILENAME, skip it.
00246        But if not, that's ok, as long as there are no more dir separators.  */
00247     if (IS_DIR_SEP (*filename))
00248       filename++;
00249       
00250     while (*filename && !IS_DIR_SEP (*filename))
00251       filename++;
00252     matched = *filename == 0;
00253   }
00254   
00255   return matched;
00256 }
00257 
00258 
00259 /* If DB_DIR is a prefix of PATH_ELT, return true; otherwise false.
00260    That is, the question is whether to try the db for a file looked up
00261    in PATH_ELT.  If PATH_ELT == ".", for example, the answer is no. If
00262    PATH_ELT == "/usr/local/lib/texmf/fonts//tfm", the answer is yes.
00263    
00264    In practice, ls-R is only needed for lengthy subdirectory
00265    comparisons, but there's no gain to checking PATH_ELT to see if it is
00266    a subdir match, since the only way to do that is to do a string
00267    search in it, which is all we do anyway.  */
00268    
00269 static boolean
00270 elt_in_db P2C(const_string, db_dir,  const_string, path_elt)
00271 {
00272   boolean found = false;
00273 
00274   while (!found && FILECHARCASEEQ (*db_dir++, *path_elt++)) {
00275     /* If we've matched the entire db directory, it's good.  */
00276     if (*db_dir == 0)
00277       found = true;
00278  
00279     /* If we've reached the end of PATH_ELT, but not the end of the db
00280        directory, it's no good.  */
00281     else if (*path_elt == 0)
00282       break;
00283   }
00284 
00285   return found;
00286 }
00287 
00288 /* If ALIAS_FILENAME exists, read it into TABLE.  */
00289 
00290 static boolean
00291 alias_build P2C(hash_table_type *, table,  const_string, alias_filename)
00292 {
00293   string line, real, alias;
00294   unsigned count = 0;
00295   FILE *alias_file = fopen (alias_filename, FOPEN_R_MODE);
00296 
00297   if (alias_file) {
00298     while ((line = read_line (alias_file)) != NULL) {
00299       /* comments or empty */
00300       if (*line == 0 || *line == '%' || *line == '#') {
00301         ;
00302       } else {
00303         /* Each line should have two fields: realname aliasname.  */
00304         real = line;
00305         while (*real && ISSPACE (*real))
00306           real++;
00307         alias = real;
00308         while (*alias && !ISSPACE (*alias))
00309           alias++;
00310         *alias++ = 0;
00311         while (*alias && ISSPACE (*alias)) 
00312           alias++;
00313         /* Is the check for errors strong enough?  Should we warn the user
00314            for potential errors?  */
00315         if (strlen (real) != 0 && strlen (alias) != 0) {
00316           /* Stuff in the alias file should be normalized. */
00317           hash_insert_normalized (table, xstrdup (alias), xstrdup (real));
00318           count++;
00319         }
00320       }
00321       free (line);
00322     }
00323 
00324 #ifdef KPSE_DEBUG
00325     if (KPSE_DEBUG_P (KPSE_DEBUG_HASH)) {
00326       /* As with ls-R above ... */
00327       boolean hash_summary_only = true;
00328       DEBUGF2 ("%s: %u aliases.\n", alias_filename, count);
00329       DEBUGF ("alias hash table:");
00330       hash_print (*table, hash_summary_only);
00331       fflush (stderr);
00332     }
00333 #endif /* KPSE_DEBUG */
00334 
00335     xfclose (alias_file, alias_filename);
00336   }
00337 
00338   return alias_file != NULL;
00339 }
00340 
00341 /* Initialize the path for ls-R files, and read them all into the hash
00342    table `db'.  If no usable ls-R's are found, set db.buckets to NULL.  */
00343 
00344 void
00345 kpse_init_db P1H(void)
00346 {
00347   boolean ok = false;
00348   const_string db_path;
00349   string *db_files;
00350   string *orig_db_files;
00351 
00352   assert(sizeof(DB_NAME) == sizeof(DB_NAME_LC));
00353 
00354   db_path = kpse_init_format (kpse_db_format);
00355   db_files = kpse_all_path_search_list (db_path, db_names);
00356   orig_db_files = db_files;
00357   
00358   /* Must do this after the path searching (which ends up calling
00359     kpse_db_search recursively), so db.buckets stays NULL.  */
00360   db = hash_create (DB_HASH_SIZE);
00361 
00362   while (db_files && *db_files) {
00363     if (db_build (&db, *db_files))
00364       ok = true;
00365     free (*db_files);
00366     db_files++;
00367   }
00368   
00369   if (!ok) {
00370     /* If db can't be built, leave `size' nonzero (so we don't
00371        rebuild it), but clear `buckets' (so we don't look in it).  */
00372     free (db.buckets);
00373     db.buckets = NULL;
00374   }
00375 
00376   free (orig_db_files);
00377 
00378   /* Add the content of any alias databases.  There may exist more than
00379      one alias file along DB_NAME files.  This duplicates the above code
00380      -- should be a function.  */
00381   ok = false;
00382   db_files = kpse_all_path_search (db_path, ALIAS_NAME);
00383   orig_db_files = db_files;
00384 
00385   alias_db = hash_create (ALIAS_HASH_SIZE);
00386 
00387   while (db_files && *db_files) {
00388     if (alias_build (&alias_db, *db_files))
00389       ok = true;
00390     free (*db_files);
00391     db_files++;
00392   }
00393 
00394   if (!ok) {
00395     free (alias_db.buckets);
00396     alias_db.buckets = NULL;
00397   }
00398 
00399   free (orig_db_files);
00400 }
00401 
00402 /* Avoid doing anything if this PATH_ELT is irrelevant to the databases. */
00403 
00404 str_list_type *
00405 kpse_db_search P3C(const_string, name,  const_string, orig_path_elt,
00406                    boolean, all)
00407 {
00408   string *db_dirs, *orig_dirs, *r;
00409   const_string last_slash;
00410   string path_elt;
00411   boolean done;
00412   str_list_type *ret;
00413   unsigned e;
00414   string *aliases = NULL;
00415   boolean relevant = false;
00416   
00417   /* If we failed to build the database (or if this is the recursive
00418      call to build the db path), quit.  */
00419   if (db.buckets == NULL)
00420     return NULL;
00421   
00422   /* When tex-glyph.c calls us looking for, e.g., dpi600/cmr10.pk, we
00423      won't find it unless we change NAME to just `cmr10.pk' and append
00424      `/dpi600' to PATH_ELT.  We are justified in using a literal `/'
00425      here, since that's what tex-glyph.c unconditionally uses in
00426      DPI_BITMAP_SPEC.  But don't do anything if the / begins NAME; that
00427      should never happen.  */
00428   last_slash = strrchr (name, '/');
00429   if (last_slash && last_slash != name) {
00430     unsigned len = last_slash - name + 1;
00431     string dir_part = (string)xmalloc (len);
00432     strncpy (dir_part, name, len - 1);
00433     dir_part[len - 1] = 0;
00434     path_elt = concat3 (orig_path_elt, "/", dir_part);
00435     name = last_slash + 1;
00436   } else
00437     path_elt = (string) orig_path_elt;
00438 
00439   /* Don't bother doing any lookups if this `path_elt' isn't covered by
00440      any of database directories.  We do this not so much because the
00441      extra couple of hash lookups matter -- they don't -- but rather
00442      because we want to return NULL in this case, so path_search can
00443      know to do a disk search.  */
00444   for (e = 0; !relevant && e < STR_LIST_LENGTH (db_dir_list); e++) {
00445     relevant = elt_in_db (STR_LIST_ELT (db_dir_list, e), path_elt);
00446   }
00447   if (!relevant)
00448     return NULL;
00449 
00450   /* If we have aliases for this name, use them.  */
00451   if (alias_db.buckets)
00452     aliases = hash_lookup (alias_db, name);
00453 
00454   if (!aliases) {
00455     aliases = XTALLOC1 (string);
00456     aliases[0] = NULL;
00457   }
00458   {  /* Push aliases up by one and insert the original name at the front.  */
00459     unsigned i;
00460     unsigned len = 1; /* Have NULL element already allocated.  */
00461     for (r = aliases; *r; r++)
00462       len++;
00463     XRETALLOC (aliases, len + 1, string);
00464     for (i = len; i > 0; i--) {
00465       aliases[i] = aliases[i - 1];
00466     }
00467     aliases[0] = (string) name;
00468   }
00469 
00470   done = false;
00471   for (r = aliases; !done && *r; r++) {
00472     string ctry = *r;
00473 
00474     /* We have an ls-R db.  Look up `try'.  */
00475     orig_dirs = db_dirs = hash_lookup (db, ctry);
00476 
00477     ret = XTALLOC1 (str_list_type);
00478     *ret = str_list_init ();
00479 
00480     /* For each filename found, see if it matches the path element.  For
00481        example, if we have .../cx/cmr10.300pk and .../ricoh/cmr10.300pk,
00482        and the path looks like .../cx, we don't want the ricoh file.  */
00483     while (!done && db_dirs && *db_dirs) {
00484       string db_file = concat (*db_dirs, ctry);
00485       boolean matched = match (db_file, path_elt);
00486 
00487 #ifdef KPSE_DEBUG
00488       if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
00489         DEBUGF3 ("db:match(%s,%s) = %d\n", db_file, path_elt, matched);
00490 #endif
00491 
00492       /* We got a hit in the database.  Now see if the file actually
00493          exists, possibly under an alias.  */
00494       if (matched) {
00495         string found = NULL;
00496         if (kpse_readable_file (db_file)) {
00497           found = db_file;
00498           
00499         } else {
00500           string *a;
00501           
00502           free (db_file); /* `db_file' wasn't on disk.  */
00503           
00504           /* The hit in the DB doesn't exist in disk.  Now try all its
00505              aliases.  For example, suppose we have a hierarchy on CD,
00506              thus `mf.bas', but ls-R contains `mf.base'.  Find it anyway.
00507              Could probably work around this with aliases, but
00508              this is pretty easy and shouldn't hurt.  The upshot is that
00509              if one of the aliases actually exists, we use that.  */
00510           for (a = aliases + 1; *a && !found; a++) {
00511             string atry = concat (*db_dirs, *a);
00512             if (kpse_readable_file (atry))
00513               found = atry;
00514             else
00515               free (atry);
00516           }
00517         }
00518           
00519         /* If we have a real file, add it to the list, maybe done.  */
00520         if (found) {
00521           str_list_add (ret, found);
00522           if (!all && found)
00523             done = true;
00524         }
00525       } else { /* no match in the db */
00526         free (db_file);
00527       }
00528       
00529 
00530       /* On to the next directory, if any.  */
00531       db_dirs++;
00532     }
00533 
00534     /* This is just the space for the pointers, not the strings.  */
00535     if (orig_dirs && *orig_dirs)
00536       free (orig_dirs);
00537   }
00538   
00539   free (aliases);
00540   
00541   /* If we had to break up NAME, free the temporary PATH_ELT.  */
00542   if (path_elt != orig_path_elt)
00543     free (path_elt);
00544 
00545   return ret;
00546 }
00547 
00548 str_list_type *
00549 kpse_db_search_list P3C(const_string*, names,  const_string, path_elt,
00550                         boolean, all)
00551 {
00552   string *db_dirs, *orig_dirs, *r;
00553   const_string last_slash, name, path;
00554   boolean done;
00555   str_list_type *ret;
00556   unsigned e;
00557   string *aliases;
00558   boolean relevant = false;
00559   int n;
00560   
00561   /* If we failed to build the database (or if this is the recursive
00562      call to build the db path), quit.  */
00563   if (db.buckets == NULL)
00564     return NULL;
00565 
00566   /* Don't bother doing any lookups if this `path_elt' isn't covered by
00567      any of database directories.  We do this not so much because the
00568      extra couple of hash lookups matter -- they don't -- but rather
00569      because we want to return NULL in this case, so path_search can
00570      know to do a disk search.  */
00571   for (e = 0; !relevant && e < STR_LIST_LENGTH (db_dir_list); e++) {
00572     relevant = elt_in_db (STR_LIST_ELT (db_dir_list, e), path_elt);
00573   }
00574   if (!relevant)
00575     return NULL;
00576 
00577   done = false;
00578   /* Handle each name. */
00579   for (n = 0; !done && names[n]; n++) {
00580       name = names[n];
00581 
00582       /* Absolute names should have been caught in our caller. */
00583       if (kpse_absolute_p(name, true))
00584           continue;
00585 
00586       /* When tex-glyph.c calls us looking for, e.g., dpi600/cmr10.pk, we
00587          won't find it unless we change NAME to just `cmr10.pk' and append
00588          `/dpi600' to PATH_ELT.  We are justified in using a literal `/'
00589          here, since that's what tex-glyph.c unconditionally uses in
00590          DPI_BITMAP_SPEC.  But don't do anything if the / begins NAME; that
00591          should never happen.  */
00592       last_slash = strrchr (name, '/');
00593       if (last_slash && last_slash != name) {
00594           unsigned len = last_slash - name + 1;
00595           string dir_part = (string)xmalloc (len);
00596           strncpy (dir_part, name, len - 1);
00597           dir_part[len - 1] = 0;
00598           path = concat3 (path_elt, "/", dir_part);
00599           name = last_slash + 1;
00600           free(dir_part);
00601       } else {
00602           path = path_elt;
00603       }
00604       
00605       /* If we have aliases for this name, use them.  */
00606       if (alias_db.buckets)
00607           aliases = hash_lookup (alias_db, name);
00608       else
00609           aliases = NULL;
00610 
00611       if (!aliases) {
00612           aliases = XTALLOC1 (string);
00613           aliases[0] = NULL;
00614       } 
00615       {  /* Push aliases up by one and insert the original name at the front.  */
00616           unsigned i;
00617           unsigned len = 1; /* Have NULL element already allocated.  */
00618           for (r = aliases; *r; r++)
00619               len++;
00620           XRETALLOC (aliases, len + 1, string);
00621           for (i = len; i > 0; i--) {
00622               aliases[i] = aliases[i - 1];
00623           }
00624           aliases[0] = (string) name;
00625       }
00626 
00627       for (r = aliases; !done && *r; r++) {
00628           string ctry = *r;
00629 
00630           /* We have an ls-R db.  Look up `try'.  */
00631           orig_dirs = db_dirs = hash_lookup (db, ctry);
00632           
00633           ret = XTALLOC1 (str_list_type);
00634           *ret = str_list_init ();
00635 
00636           /* For each filename found, see if it matches the path element.  For
00637              example, if we have .../cx/cmr10.300pk and .../ricoh/cmr10.300pk,
00638              and the path looks like .../cx, we don't want the ricoh file.  */
00639           while (!done && db_dirs && *db_dirs) {
00640               string db_file = concat (*db_dirs, ctry);
00641               boolean matched = match (db_file, path);
00642               
00643 #ifdef KPSE_DEBUG
00644               if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH))
00645                 DEBUGF3 ("db:match(%s,%s) = %d\n", db_file, path, matched);
00646 #endif
00647 
00648               /* We got a hit in the database.  Now see if the file actually
00649                  exists, possibly under an alias.  */
00650               if (matched) {
00651                   string found = NULL;
00652                   if (kpse_readable_file (db_file)) {
00653                       found = db_file;
00654                       
00655                   } else {
00656                       string *a;
00657                       
00658                       free (db_file); /* `db_file' wasn't on disk.  */
00659                       
00660                       /* The hit in the DB doesn't exist in disk.  Now try all its
00661                          aliases.  For example, suppose we have a hierarchy on CD,
00662                          thus `mf.bas', but ls-R contains `mf.base'.  Find it anyway.
00663                          Could probably work around this with aliases, but
00664                          this is pretty easy and shouldn't hurt.  The upshot is that
00665                          if one of the aliases actually exists, we use that.  */
00666                       for (a = aliases + 1; *a && !found; a++) {
00667                           string atry = concat (*db_dirs, *a);
00668                           if (kpse_readable_file (atry))
00669                               found = atry;
00670                           else
00671                               free (atry);
00672                       }
00673                   }
00674                   
00675                   /* If we have a real file, add it to the list, maybe done.  */
00676                   if (found) {
00677                       str_list_add (ret, found);
00678                       if (!all && found)
00679                           done = true;
00680                   }
00681               } else { /* no match in the db */
00682                   free (db_file);
00683               }
00684               
00685               /* On to the next directory, if any.  */
00686               db_dirs++;
00687           }
00688           
00689           /* This is just the space for the pointers, not the strings.  */
00690           if (orig_dirs && *orig_dirs)
00691               free (orig_dirs);
00692       }
00693       
00694       free (aliases);
00695       if (path != path_elt)
00696           free((string)path);
00697   }
00698   return ret;
00699   
00700 }
00701