infopath.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /* infopath.c -- INFOPATH handling.
  2. $Id$
  3. Copyright 1993, 1997, 1998, 2000, 2002, 2003, 2004, 2007, 2008, 2009, 2011,
  4. 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
  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 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "info.h"
  17. #include "info-utils.h"
  18. #include "session.h"
  19. #include "filesys.h"
  20. typedef struct {
  21. char *name; /* Path to directory to be searched. */
  22. dev_t device; /* Storage device this directory is on. */
  23. ino_t inode; /* Inode number, used to detect duplicates. */
  24. } INFO_DIR;
  25. INFO_DIR **infodirs = 0;
  26. size_t infodirs_index = 0;
  27. size_t infodirs_slots = 0;
  28. /* Exclude default file search directories. */
  29. int infopath_no_defaults_p;
  30. static void infopath_add_dir (char *path);
  31. char *extract_colon_unit (char *string, int *idx);
  32. void
  33. infopath_init ()
  34. {
  35. /* Initialize INFOPATH.
  36. Highest priority is the environment variable, if set
  37. Then comes the user's INFODIR from the Makefile.
  38. The hardwired default settings (filesys.h) are the lowest priority. */
  39. char *path_from_env = getenv ("INFOPATH");
  40. if (path_from_env)
  41. {
  42. infopath_add (path_from_env);
  43. }
  44. if (!infopath_no_defaults_p)
  45. {
  46. #ifdef INFODIR /* $infodir, set by configure script in Makefile */
  47. infopath_add (INFODIR);
  48. #ifdef INFODIR2 /* $datadir/info, which could be different. */
  49. if (!STREQ (INFODIR, INFODIR2))
  50. infopath_add (INFODIR2);
  51. #endif /* INFODIR2 */
  52. #endif /* INFODIR */
  53. }
  54. if (!path_from_env)
  55. {
  56. infopath_add (DEFAULT_INFOPATH);
  57. }
  58. else
  59. {
  60. /* Only insert default path if there is a trailing : on INFOPATH. */
  61. unsigned len = strlen (path_from_env);
  62. if (len && path_from_env[len - 1] == PATH_SEP[0])
  63. {
  64. path_from_env[len - 1] = 0;
  65. infopath_add (DEFAULT_INFOPATH);
  66. }
  67. }
  68. }
  69. /* Return value to be freed by caller. */
  70. char *
  71. infopath_string ()
  72. {
  73. struct text_buffer path;
  74. int dir_idx;
  75. char *this_dir;
  76. this_dir = infopath_first (&dir_idx);
  77. if (!this_dir)
  78. return "";
  79. text_buffer_init (&path);
  80. while (1)
  81. {
  82. text_buffer_printf (&path, "%s", this_dir);
  83. this_dir = infopath_next (&dir_idx);
  84. if (!this_dir)
  85. break;
  86. text_buffer_add_char (&path, ':');
  87. }
  88. return text_buffer_base (&path);
  89. }
  90. /* For each path element PREFIX/DIR in PATH substitute either
  91. PREFIX/share/info or PREFIX/info if that directory exists. */
  92. static void
  93. build_infopath_from_path (void)
  94. {
  95. char *path_from_env, *temp_dirname;
  96. int dirname_index = 0;
  97. struct stat finfo;
  98. path_from_env = getenv ("PATH");
  99. while ((temp_dirname = extract_colon_unit (path_from_env, &dirname_index)))
  100. {
  101. unsigned int i, dir = 0;
  102. /* Find end of DIRNAME/ (but ignore "/") */
  103. for (i = 0; temp_dirname[i]; i++)
  104. if (i && IS_SLASH (temp_dirname[i]))
  105. dir = i + 1;
  106. /* Discard path elements ending with "/", "/.", or "/.." */
  107. if (!temp_dirname[dir] || STREQ (temp_dirname + dir, ".") || STREQ (temp_dirname + dir, "."))
  108. dir = 0;
  109. if (dir)
  110. {
  111. temp_dirname = xrealloc (temp_dirname, dir + strlen ("share/info") +1);
  112. /* first try DIRNAME/share/info */
  113. strcpy (temp_dirname + dir, "share/info");
  114. if (stat (temp_dirname, &finfo) != 0 || !S_ISDIR (finfo.st_mode))
  115. {
  116. /* then try DIRNAME/info */
  117. strcpy (temp_dirname + dir, "info");
  118. if (stat (temp_dirname, &finfo) != 0 || !S_ISDIR (finfo.st_mode))
  119. dir = 0;
  120. }
  121. }
  122. if (dir)
  123. infopath_add_dir (temp_dirname);
  124. else
  125. free (temp_dirname);
  126. }
  127. }
  128. /* Add directory at PATH to Info search path. A reference to PATH is retained,
  129. or PATH is freed. */
  130. static void
  131. infopath_add_dir (char *path)
  132. {
  133. struct stat dirinfo;
  134. INFO_DIR *entry;
  135. int i;
  136. if (stat (path, &dirinfo) == -1)
  137. {
  138. debug (2, ("inaccessible directory %s not added to INFOPATH", path));
  139. free (path);
  140. return; /* Doesn't exist, or not accessible. */
  141. }
  142. for (i = 0; i < infodirs_index; i++)
  143. {
  144. if ( dirinfo.st_ino == infodirs[i]->inode
  145. && dirinfo.st_dev == infodirs[i]->device
  146. /* On MS-Windows, `stat' returns zero as the inode, so we
  147. use file-name comparison instead for that OS. */
  148. && (infodirs[i]->inode != 0 || fncmp (path, infodirs[i]->name) == 0))
  149. {
  150. debug (2, ("duplicate directory %s not added to INFOPATH", path));
  151. free (path);
  152. return; /* We have it already. */
  153. }
  154. }
  155. debug (2, ("adding %s to INFOPATH", path));
  156. entry = xmalloc (sizeof (INFO_DIR));
  157. entry->name = path;
  158. entry->inode = dirinfo.st_ino;
  159. entry->device = dirinfo.st_dev;
  160. add_pointer_to_array (entry, infodirs_index, infodirs, infodirs_slots, 8);
  161. }
  162. /* Add PATH to the list of paths found in INFOPATH. PATH should be allocated
  163. on the heap and not referenced by the caller after calling this function.
  164. If PATH is "PATH", add a sequence of path elements derived from the
  165. environment variable PATH. */
  166. void
  167. infopath_add (char *path)
  168. {
  169. int idx = 0;
  170. char *dirname;
  171. while (dirname = extract_colon_unit (path, &idx))
  172. {
  173. if (!strcmp ("PATH", dirname))
  174. {
  175. free (dirname);
  176. build_infopath_from_path ();
  177. }
  178. else
  179. infopath_add_dir (dirname);
  180. }
  181. }
  182. /* Used to iterate over INFOPATH. Return value should not be freed
  183. by caller. */
  184. char *
  185. infopath_next (int *idx)
  186. {
  187. INFO_DIR *entry;
  188. if (!infodirs)
  189. return 0;
  190. entry = infodirs[(*idx)++];
  191. if (!entry)
  192. return 0;
  193. return entry->name;
  194. }
  195. char *
  196. infopath_first (int *idx)
  197. {
  198. *idx = 0;
  199. return infopath_next (idx);
  200. }
  201. /* Given a string containing units of information separated by the
  202. PATH_SEP character, return the next one after IDX, or NULL if there
  203. are no more. Advance IDX to the character after the colon. */
  204. char *
  205. extract_colon_unit (char *string, int *idx)
  206. {
  207. unsigned int i = (unsigned int) *idx;
  208. unsigned int start = i;
  209. if (!string || i >= strlen (string))
  210. return NULL;
  211. if (!string[i]) /* end of string */
  212. return NULL;
  213. /* Advance to next PATH_SEP. */
  214. while (string[i] && string[i] != PATH_SEP[0])
  215. i++;
  216. {
  217. char *value = xmalloc ((i - start) + 1);
  218. strncpy (value, &string[start], (i - start));
  219. value[i - start] = 0;
  220. i++; /* move past PATH_SEP */
  221. *idx = i;
  222. return value;
  223. }
  224. }