Silence verbose testsuite runs.
[m4.git] / m4 / path.c
blobc83aa2149bb61ad95581826327a8f666eeba7ce3
1 /* GNU m4 -- A simple macro processor
2 Copyright (C) 1989, 1990, 1991, 1992, 1993, 1998, 2004, 2006, 2007,
3 2008, 2009 Free Software Foundation, Inc.
5 This file is part of GNU M4.
7 GNU M4 is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU M4 is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 /* Handling of path search of included files via the builtins "include"
22 and "sinclude". */
24 #include <config.h>
26 #include <string.h>
28 #include "m4private.h"
30 #include "dirname.h"
31 #include "filenamecat.h"
33 /* Define this to see runtime debug info. Implied by DEBUG. */
34 /*#define DEBUG_INCL */
36 static void search_path_add (m4__search_path_info *, const char *, bool);
37 static void search_path_env_init (m4__search_path_info *, char *, bool);
41 * General functions for search paths
44 static void
45 search_path_add (m4__search_path_info *info, const char *dir, bool prepend)
47 m4__search_path *path = (m4__search_path *) xmalloc (sizeof *path);
49 path->len = strlen (dir);
50 path->dir = xstrdup (dir);
52 if (path->len > info->max_length) /* remember len of longest directory */
53 info->max_length = path->len;
55 if (prepend)
57 path->next = info->list;
58 info->list = path;
59 if (info->list_end == NULL)
60 info->list_end = path;
62 else
64 path->next = NULL;
66 if (info->list_end == NULL)
67 info->list = path;
68 else
69 info->list_end->next = path;
70 info->list_end = path;
74 static void
75 search_path_env_init (m4__search_path_info *info, char *path, bool isabs)
77 char *path_end;
79 if (info == NULL || path == NULL)
80 return;
84 path_end = strchr (path, ':');
85 if (path_end)
86 *path_end = '\0';
87 if (!isabs || *path == '/')
88 search_path_add (info, path, false);
89 path = path_end + 1;
91 while (path_end);
95 /* Functions for normal input path search */
97 void
98 m4_include_env_init (m4 *context)
100 char *m4path;
102 if (m4_get_posixly_correct_opt (context))
103 return;
105 m4path = getenv ("M4PATH");
106 if (m4path)
107 m4path = xstrdup (m4path);
108 search_path_env_init (m4__get_search_path (context), m4path, false);
109 free (m4path);
112 void
113 m4_add_include_directory (m4 *context, const char *dir, bool prepend)
115 if (m4_get_posixly_correct_opt (context))
116 return;
118 search_path_add (m4__get_search_path (context), dir, prepend);
120 #ifdef DEBUG_INCL
121 xfprintf (stderr, "add_include_directory (%s) %s;\n", dir,
122 prepend ? "prepend" : "append");
123 #endif
126 /* Attempt to open FILE; if it opens, verify that it is not a
127 directory, and ensure it does not leak across execs. */
128 static FILE *
129 m4_fopen (m4 *context, const char *file, const char *mode)
131 FILE *fp = fopen (file, "r");
132 if (fp)
134 struct stat st;
135 int fd = fileno (fp);
136 if (fstat (fd, &st) == 0 && S_ISDIR (st.st_mode))
138 fclose (fp);
139 errno = EISDIR;
140 return NULL;
142 if (set_cloexec_flag (fileno (fp), true) != 0)
143 m4_error (context, 0, errno, NULL,
144 _("cannot protect input file across forks"));
146 return fp;
149 /* Search for FILE according to -B options, `.', -I options, then
150 M4PATH environment. If successful, return the open file, and if
151 RESULT is not NULL, set *RESULT to a malloc'd string that
152 represents the file found with respect to the current working
153 directory. Otherwise, return NULL, and errno reflects the failure
154 from searching `.' (regardless of what else was searched). */
156 FILE *
157 m4_path_search (m4 *context, const char *file, char **expanded_name)
159 FILE *fp;
160 m4__search_path *incl;
161 char *name; /* buffer for constructed name */
162 int e = 0;
164 if (expanded_name != NULL)
165 *expanded_name = NULL;
167 /* Reject empty file. */
168 if (*file == '\0')
170 errno = ENOENT;
171 return NULL;
174 /* If file is absolute, or if we are not searching a path, a single
175 lookup will do the trick. */
176 if (IS_ABSOLUTE_FILE_NAME (file) || m4_get_posixly_correct_opt (context))
178 fp = m4_fopen (context, file, "r");
179 if (fp != NULL)
181 if (expanded_name != NULL)
182 *expanded_name = xstrdup (file);
183 return fp;
185 return NULL;
188 for (incl = m4__get_search_path (context)->list;
189 incl != NULL; incl = incl->next)
191 name = file_name_concat (incl->dir, file, NULL);
193 #ifdef DEBUG_INCL
194 xfprintf (stderr, "path_search (%s) -- trying %s\n", file, name);
195 #endif
197 fp = m4_fopen (context, name, "r");
198 if (fp != NULL)
200 m4_debug_message (context, M4_DEBUG_TRACE_PATH,
201 _("path search for %s found %s"),
202 quotearg_style (locale_quoting_style, file),
203 quotearg_n_style (1, locale_quoting_style, name));
204 if (expanded_name != NULL)
205 *expanded_name = name;
206 else
207 free (name);
208 return fp;
210 else if (!incl->len)
211 /* Capture errno only when searching `.'. */
212 e = errno;
213 free (name);
216 errno = e;
217 return NULL;
220 void
221 m4__include_init (m4 *context)
223 m4__search_path_info *info = m4__get_search_path (context);
225 assert (info);
226 search_path_add (info, "", false);
230 #ifdef DEBUG_INCL
232 static void M4_GNUC_UNUSED
233 include_dump (m4 *context)
235 m4__search_path *incl;
237 fputs ("include_dump:\n", stderr);
238 for (incl = m4__get_search_path (context)->list;
239 incl != NULL; incl = incl->next)
240 xfprintf (stderr, "\t%s\n", incl->dir);
243 #endif /* DEBUG_INCL */