* src/Makefile.am (m4_LDADD): Add any gnulib dependent libraries.
[m4/ericb.git] / src / path.c
blobca604142b9baf6cc032a8b3d928c6e5d4baa8963
1 /* GNU m4 -- A simple macro processor
3 Copyright (C) 1989, 1990, 1991, 1992, 1993, 2004, 2006 Free Software
4 Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA
22 /* Handling of path search of included files via the builtins "include"
23 and "sinclude". */
25 #include "m4.h"
27 struct includes
29 struct includes *next; /* next directory to search */
30 const char *dir; /* directory */
31 int len;
34 typedef struct includes includes;
36 static includes *dir_list; /* the list of path directories */
37 static includes *dir_list_end; /* the end of same */
38 static int dir_max_length; /* length of longest directory name */
41 void
42 include_init (void)
44 dir_list = NULL;
45 dir_list_end = NULL;
46 dir_max_length = 0;
49 void
50 include_env_init (void)
52 char *path;
53 char *path_end;
55 if (no_gnu_extensions)
56 return;
58 path = getenv ("M4PATH");
59 if (path == NULL)
60 return;
64 path_end = strchr (path, ':');
65 if (path_end)
66 *path_end = '\0';
67 add_include_directory (path);
68 path = path_end + 1;
70 while (path_end);
73 void
74 add_include_directory (const char *dir)
76 includes *incl;
78 if (no_gnu_extensions)
79 return;
81 if (*dir == '\0')
82 dir = ".";
84 incl = (includes *) xmalloc (sizeof (struct includes));
85 incl->next = NULL;
86 incl->len = strlen (dir);
87 incl->dir = xstrdup (dir);
89 if (incl->len > dir_max_length) /* remember len of longest directory */
90 dir_max_length = incl->len;
92 if (dir_list_end == NULL)
93 dir_list = incl;
94 else
95 dir_list_end->next = incl;
96 dir_list_end = incl;
98 #ifdef DEBUG_INCL
99 fprintf (stderr, "add_include_directory (%s);\n", dir);
100 #endif
103 /* Search for FILE, first in `.', then according to -I options. If
104 successful, return the open file, and if RESULT is not NULL, set
105 *RESULT to a malloc'd string that represents the file found with
106 respect to the current working directory. */
108 FILE *
109 path_search (const char *file, const char **result)
111 FILE *fp;
112 includes *incl;
113 char *name; /* buffer for constructed name */
114 int e;
116 if (result)
117 *result = NULL;
119 /* Reject empty file. */
120 if (!*file)
122 errno = ENOENT;
123 return NULL;
126 /* Look in current working directory first. */
127 fp = fopen (file, "r");
128 if (fp != NULL)
130 if (set_cloexec_flag (fileno (fp), true) != 0)
131 M4ERROR ((warning_status, errno,
132 "Warning: cannot protect input file across forks"));
133 if (result)
134 *result = xstrdup (file);
135 return fp;
138 /* If file not found, and filename absolute, fail. */
139 if (*file == '/' || no_gnu_extensions)
140 return NULL;
141 e = errno;
143 name = (char *) xmalloc (dir_max_length + 1 + strlen (file) + 1);
145 for (incl = dir_list; incl != NULL; incl = incl->next)
147 strncpy (name, incl->dir, incl->len);
148 name[incl->len] = '/';
149 strcpy (name + incl->len + 1, file);
151 #ifdef DEBUG_INCL
152 fprintf (stderr, "path_search (%s) -- trying %s\n", file, name);
153 #endif
155 fp = fopen (name, "r");
156 if (fp != NULL)
158 if (debug_level & DEBUG_TRACE_PATH)
159 DEBUG_MESSAGE2 ("path search for `%s' found `%s'", file, name);
160 if (set_cloexec_flag (fileno (fp), true) != 0)
161 M4ERROR ((warning_status, errno,
162 "Warning: cannot protect input file across forks"));
163 if (result)
164 *result = name;
165 else
166 free (name);
167 errno = e;
168 return fp;
171 free (name);
172 errno = e;
173 return fp;
176 #ifdef DEBUG_INCL
178 static void M4_GNUC_UNUSED
179 include_dump (void)
181 includes *incl;
183 fprintf (stderr, "include_dump:\n");
184 for (incl = dir_list; incl != NULL; incl = incl->next)
185 fprintf (stderr, "\t%s\n", incl->dir);
188 #endif /* DEBUG_INCL */