home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / tex / texsrc1 / Src / lib / c / pathsrch < prev    next >
C/C++ Source or Header  |  1993-05-21  |  13KB  |  437 lines

  1. /* pathsrch.c: look for files based on paths, i.e., colon-separated
  2.    lists of directories.  
  3.    
  4.    Perhaps we should allow % specifiers in the paths for the resolution, etc.
  5.  
  6.    This is a RISC OS ONLY version!
  7.    Things not needed in RISC OS are cut out
  8.  
  9. Copyright (C) 1992 Free Software Foundation, Inc.
  10.  
  11. This program is free software; you can redistribute it and/or modify
  12. it under the terms of the GNU General Public License as published by
  13. the Free Software Foundation; either version 2, or (at your option)
  14. any later version.
  15.  
  16. This program is distributed in the hope that it will be useful,
  17. but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19. GNU General Public License for more details.
  20.  
  21. You should have received a copy of the GNU General Public License
  22. along with this program; if not, write to the Free Software
  23. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  24.  
  25. #include "config.h"
  26.  
  27. #include "c-pathch.h"
  28. #include "c-namemx.h"
  29. #include "c-pathmx.h"
  30. #include "paths.h"
  31. #include "c-ctype.h"
  32. #include "riscos_ex.h"
  33. #include "pathsrch.h"
  34.  
  35. #define dir_p(name) riscos_isdir(name)
  36.  
  37. static void add_directory P3H(string **, unsigned *, string);
  38. static void expand_subdir P3H(string **, unsigned *, string);
  39. static string readable P1H(string);
  40. #if 0
  41. static string *find_dir_list P1H(string);
  42. static void save_dir_list P2H(string, string *);
  43. #endif
  44. boolean riscos_readaccess P1H(string);
  45.  
  46. /* If FILENAME is absolute or explicitly relative (i.e., starts with
  47.    `@.', or `^.' or there's a ':', '&', '\' or '$' in it), or if DIR_LIST is
  48.    null, we return whether
  49.    FILENAME is readable as-is.  Otherwise, we test if FILENAME is in any of
  50.    the directories listed in DIR_LIST.  (The last entry of DIR_LIST must
  51.    be null.)  We return the complete path if found, NULL else.
  52.    
  53.    In the interests of doing minimal work here, we assume that each
  54.    element of DIR_LIST already ends with a `.'.
  55.    
  56.    DIR_LIST is most conveniently made by calling `initialize_path_list'.
  57.    This is a separate routine because we allow recursive searching, and
  58.    it may take some time to discover the list of directories.  
  59.    We do not want to incur that overhead every time we want to look for
  60.    a file.
  61.    
  62.    (Actually, `.' is not hardwired into this routine; we use PATH_SEP,
  63.    defined above.)  */
  64.  
  65. string
  66. find_path_filename P2C(string, filename,  string *, dir_list)
  67. {
  68.   string found_name = NULL;
  69.   
  70.   /* If FILENAME is absolute or explicitly relative, or if DIR_LIST is
  71.      null, only check if FILENAME is readable.  */
  72.   if (riscos_absolute (filename) || dir_list == NULL)
  73.   {
  74.     found_name = readable (filename);
  75.   }
  76.   else
  77.     { /* Test if FILENAME is in any of the directories in DIR_LIST.  */
  78.       string save_filename = filename;
  79.       boolean substituting; /* if true, we substituted @ */
  80.       
  81.       while (*dir_list != NULL)
  82.         {
  83.           if (**dir_list == '@') {
  84.             substituting = true;
  85.             filename = concat3(current_path, *dir_list + 1, save_filename);
  86.           }
  87.           else {
  88.             filename = concat (*dir_list, save_filename);
  89.             substituting = false;
  90.           }
  91.  
  92.           found_name = readable (filename);
  93.           if (found_name == NULL)
  94.             {
  95.               free (filename);
  96.               dir_list++;
  97.             }
  98.           else
  99.             {
  100.               if (found_name != filename)
  101.                 free (filename);
  102.               if (substituting) found_name = concat(*dir_list, save_filename);
  103.               break;
  104.             }
  105.         }
  106.     }
  107.   
  108.   return found_name;
  109. }
  110.  
  111.  
  112. /* If NAME is readable, return it.  If the error is ENAMETOOLONG,
  113.    truncate any too-long path components and return the result (unless
  114.    there were no too-long components, i.e., a overall too-long name
  115.    caused the error, in which case return NULL).  On any other error,
  116.    return NULL.
  117.    
  118.    POSIX invented this brain-damage of not necessarily truncating
  119.    pathname components; the system's behavior is defined by the value of
  120.    the symbol _POSIX_NO_TRUNC, but you can't change it dynamically! 
  121.  
  122.    RISC OS does things a bit differently. We need some kernel routines
  123.    for testing read access, and we don't truncate filenames, as different
  124.    filing systems might allow different filename lengths. */
  125.  
  126. #include <kernel.h>
  127.  
  128. static string
  129. readable (name)
  130.     string name;
  131. {
  132.   string ret = NULL;
  133.   
  134.   if (riscos_readaccess(name))
  135.     ret = name;
  136.   else
  137.   {
  138.     char *pos;
  139. #ifdef RISCOS_DEBUG
  140.     fprintf(stderr, "readable(\"%s\") tries ", name);
  141. #endif
  142.     /* Try .sty file without extension */
  143.     pos = strrchr(name, '.');
  144.     if (pos && strcmp(pos + 1, "sty") == 0) {
  145.       *pos = '\0';
  146. #ifdef RISCOS_DEBUG
  147.       fprintf(stderr, "\"%s\"\n", name);
  148. #endif
  149.       if (riscos_readaccess(name)) ret = name;
  150.       else *pos = '.';
  151.     }
  152. #ifdef RISCOS_DEBUG
  153.     fprintf(stderr, "\n");
  154. #endif
  155.   }
  156.   
  157.   return ret;
  158. }
  159.  
  160. /* OS_File 17: prm p.836 or c.riscos_ex */
  161.  
  162. boolean
  163. riscos_readaccess(string name)
  164. {
  165.   _kernel_osfile_block block;
  166.  
  167.   return (_kernel_osfile(17, name, &block) == 1 && (block.end & 1));
  168. }
  169.  
  170. /* Return a NULL-terminated array of directory names, each name ending
  171.    with PATH_SEP, created by parsing the PATH_DELIMITER-separated list
  172.    in the value of the environment variable ENV_NAME, or DEFAULT_PATH if
  173.    the envvar is not set.
  174.    
  175.    A leading or trailing colon in the value of ENV_NAME is replaced by
  176.    DEFAULT_PATH.
  177.    
  178.    Any element of the path that ends with double PATH_SEP characters
  179.    (e.g., `foo..') is replaced by all its subdirectories.
  180.  
  181.    If ENV_NAME is null, only parse DEFAULT_PATH.  If both are null, do
  182.    nothing and return NULL.
  183.  
  184.    Under RISC OS all paths have "$Path" appended. */
  185.  
  186. string *
  187. initialize_path_list P2C(string, env_name,  string, default_path)
  188. {
  189.   string dir, path;
  190.   string *dir_list = NULL;
  191.   unsigned dir_count = 0;
  192.   string env_value = NULL;
  193.   string orig_path;
  194.  
  195.   if (env_name) {
  196.     string path_name;
  197.     path_name = concat (env_name, "$Path");
  198.     env_value = getenv (path_name);
  199.   }
  200.   orig_path = expand_default (env_value, default_path);
  201.  
  202.   if (orig_path == NULL || *orig_path == 0)
  203.     return NULL;
  204.  
  205.   /* If we've already seen this colon-separated list, then just get it
  206.      back instead of going back to the filesystem.  */
  207. #if 0
  208.   dir_list = find_dir_list (orig_path);
  209.   if (dir_list != NULL)
  210.     return dir_list;
  211. #endif
  212.   
  213.   if (*orig_path == PATH_DELIMITER)
  214.     add_directory(&dir_list, &dir_count, "@.");
  215.  
  216.   path = concat (PATH_DELIMITER_STRING, orig_path);
  217. #ifdef RISCOS_DEBUG
  218.   fprintf(stderr, "Parsing \"%s\"\n", path);
  219. #endif
  220.  
  221.   /* Find each element in the path in turn.  */
  222.   for (dir = strtok (path, PATH_DELIMITER_STRING); dir != NULL;
  223.        dir = strtok (NULL, PATH_DELIMITER_STRING))
  224.     {
  225.       int len;
  226.  
  227.       len = strlen (dir);
  228.  
  229.       /* If `dir' is the empty string, skip it.  */
  230.       if (len == 0)
  231.         continue;
  232.  
  233.       /* If `dir' ends in double dots, do subdirectories (and remove
  234.          the second dot, so the final pathnames we return don't look
  235.          like foo..bar.).  Because we obviously want to do subdirectories
  236.          of `dir', we don't check if it is a leaf.  This means that if
  237.          `dir' is `foo..', and `foo' contains only symlinks (so our leaf
  238.          test below would be true), the symlinks are chased.  */
  239.       if (len > 2 && dir[len - 1] == PATH_SEP && dir[len - 2] == PATH_SEP)
  240.         {
  241.           dir[len - 1] = 0;
  242.           if (riscos_isdir (dir))
  243.             {
  244.               add_directory (&dir_list, &dir_count, dir);
  245.               expand_subdir (&dir_list, &dir_count, dir);
  246.             }
  247.         }
  248.       else
  249.         { /* Don't bother to add the directory if it doesn't exist.  */
  250.           if (riscos_isdir (dir))
  251.             add_directory (&dir_list, &dir_count, dir);
  252.         }
  253.     }
  254.   
  255.   /* Add the terminating null entry to `dir_list'.  */
  256.   dir_count++;
  257.   XRETALLOC (dir_list, dir_count, string);
  258.   dir_list[dir_count - 1] = NULL;
  259.   
  260. #if 0
  261.   /* Save the directory list we just found.  */
  262.   save_dir_list (orig_path, dir_list);
  263. #endif
  264.  
  265. #ifdef RISCOS_DEBUG
  266.   {
  267.     int i = 0;
  268.     while (dir_list[i]) fprintf(stderr, "  \"%s\"\