* doc/m4.texinfo (Invoking m4): Update according to POSIX 200x
[m4.git] / src / path.c
blob634b1ec641e9d22a212eb38591096f6452bc8a60
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;
54 char *env_path;
56 if (no_gnu_extensions)
57 return;
59 env_path = getenv ("M4PATH");
60 if (env_path == NULL)
61 return;
63 env_path = xstrdup (env_path);
64 path = env_path;
68 path_end = strchr (path, ':');
69 if (path_end)
70 *path_end = '\0';
71 add_include_directory (path);
72 path = path_end + 1;
74 while (path_end);
75 free (env_path);
78 void
79 add_include_directory (const char *dir)
81 includes *incl;
83 if (no_gnu_extensions)
84 return;
86 if (*dir == '\0')
87 dir = ".";
89 incl = (includes *) xmalloc (sizeof (struct includes));
90 incl->next = NULL;
91 incl->len = strlen (dir);
92 incl->dir = xstrdup (dir);
94 if (incl->len > dir_max_length) /* remember len of longest directory */
95 dir_max_length = incl->len;
97 if (dir_list_end == NULL)
98 dir_list = incl;
99 else
100 dir_list_end->next = incl;
101 dir_list_end = incl;
103 #ifdef DEBUG_INCL
104 fprintf (stderr, "add_include_directory (%s);\n", dir);
105 #endif
108 /* Search for FILE, first in `.', then according to -I options. If
109 successful, return the open file, and if RESULT is not NULL, set
110 *RESULT to a malloc'd string that represents the file found with
111 respect to the current working directory. */
113 FILE *
114 m4_path_search (const char *file, char **result)
116 FILE *fp;
117 includes *incl;
118 char *name; /* buffer for constructed name */
119 int e;
121 if (result)
122 *result = NULL;
124 /* Reject empty file. */
125 if (!*file)
127 errno = ENOENT;
128 return NULL;
131 /* Look in current working directory first. */
132 fp = fopen (file, "r");
133 if (fp != NULL)
135 if (set_cloexec_flag (fileno (fp), true) != 0)
136 M4ERROR ((warning_status, errno,
137 "Warning: cannot protect input file across forks"));
138 if (result)
139 *result = xstrdup (file);
140 return fp;
143 /* If file not found, and filename absolute, fail. */
144 if (*file == '/' || no_gnu_extensions)
145 return NULL;
146 e = errno;
148 name = (char *) xmalloc (dir_max_length + 1 + strlen (file) + 1);
150 for (incl = dir_list; incl != NULL; incl = incl->next)
152 strncpy (name, incl->dir, incl->len);
153 name[incl->len] = '/';
154 strcpy (name + incl->len + 1, file);
156 #ifdef DEBUG_INCL
157 fprintf (stderr, "m4_path_search (%s) -- trying %s\n", file, name);
158 #endif
160 fp = fopen (name, "r");
161 if (fp != NULL)
163 if (debug_level & DEBUG_TRACE_PATH)
164 DEBUG_MESSAGE2 ("path search for `%s' found `%s'", file, name);
165 if (set_cloexec_flag (fileno (fp), true) != 0)
166 M4ERROR ((warning_status, errno,
167 "Warning: cannot protect input file across forks"));
168 if (result)
169 *result = name;
170 else
171 free (name);
172 errno = e;
173 return fp;
176 free (name);
177 errno = e;
178 return fp;
181 #ifdef DEBUG_INCL
183 static void M4_GNUC_UNUSED
184 include_dump (void)
186 includes *incl;
188 fprintf (stderr, "include_dump:\n");
189 for (incl = dir_list; incl != NULL; incl = incl->next)
190 fprintf (stderr, "\t%s\n", incl->dir);
193 #endif /* DEBUG_INCL */