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"
28 #include "m4private.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
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
;
57 path
->next
= info
->list
;
59 if (info
->list_end
== NULL
)
60 info
->list_end
= path
;
66 if (info
->list_end
== NULL
)
69 info
->list_end
->next
= path
;
70 info
->list_end
= path
;
75 search_path_env_init (m4__search_path_info
*info
, char *path
, bool isabs
)
79 if (info
== NULL
|| path
== NULL
)
84 path_end
= strchr (path
, ':');
87 if (!isabs
|| *path
== '/')
88 search_path_add (info
, path
, false);
95 /* Functions for normal input path search */
98 m4_include_env_init (m4
*context
)
102 if (m4_get_posixly_correct_opt (context
))
105 m4path
= getenv ("M4PATH");
107 m4path
= xstrdup (m4path
);
108 search_path_env_init (m4__get_search_path (context
), m4path
, false);
113 m4_add_include_directory (m4
*context
, const char *dir
, bool prepend
)
115 if (m4_get_posixly_correct_opt (context
))
118 search_path_add (m4__get_search_path (context
), dir
, prepend
);
121 xfprintf (stderr
, "add_include_directory (%s) %s;\n", dir
,
122 prepend
? "prepend" : "append");
126 /* Attempt to open FILE; if it opens, verify that it is not a
127 directory, and ensure it does not leak across execs. */
129 m4_fopen (m4
*context
, const char *file
, const char *mode
)
131 FILE *fp
= fopen (file
, "r");
135 int fd
= fileno (fp
);
136 if (fstat (fd
, &st
) == 0 && S_ISDIR (st
.st_mode
))
142 if (set_cloexec_flag (fileno (fp
), true) != 0)
143 m4_error (context
, 0, errno
, NULL
,
144 _("cannot protect input file across forks"));
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). */
157 m4_path_search (m4
*context
, const char *file
, char **expanded_name
)
160 m4__search_path
*incl
;
161 char *name
; /* buffer for constructed name */
164 if (expanded_name
!= NULL
)
165 *expanded_name
= NULL
;
167 /* Reject empty file. */
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");
181 if (expanded_name
!= NULL
)
182 *expanded_name
= xstrdup (file
);
188 for (incl
= m4__get_search_path (context
)->list
;
189 incl
!= NULL
; incl
= incl
->next
)
191 name
= file_name_concat (incl
->dir
, file
, NULL
);
194 xfprintf (stderr
, "path_search (%s) -- trying %s\n", file
, name
);
197 fp
= m4_fopen (context
, name
, "r");
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
;
211 /* Capture errno only when searching `.'. */
221 m4__include_init (m4
*context
)
223 m4__search_path_info
*info
= m4__get_search_path (context
);
226 search_path_add (info
, "", false);
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 */