* filesys.c, filesys.h (scm_input_waiting_p): Moved from ports.c.
[bpt/guile.git] / libguile / load.c
CommitLineData
0f2d19dd
JB
1/* Copyright (C) 1995,1996 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 * As a special exception, the Free Software Foundation gives permission
18 * for additional uses of the text contained in its release of GUILE.
19 *
20 * The exception is that, if you link the GUILE library with other files
21 * to produce an executable, this does not by itself cause the
22 * resulting executable to be covered by the GNU General Public License.
23 * Your use of that executable is in no way restricted on account of
24 * linking the GUILE library code into it.
25 *
26 * This exception does not however invalidate any other reasons why
27 * the executable file might be covered by the GNU General Public License.
28 *
29 * This exception applies only to the code released by the
30 * Free Software Foundation under the name GUILE. If you copy
31 * code from other Free Software Foundation releases into a copy of
32 * GUILE, as the General Public License permits, the exception does
33 * not apply to the code that you add in this way. To avoid misleading
34 * anyone as to the status of such modified files, you must delete
35 * this exception notice from them.
36 *
37 * If you write modifications of your own for GUILE, it is your choice
38 * whether to permit this exception to apply to your modifications.
39 * If you do not wish that, delete this exception notice.
40 */
41\f
42
43#include <stdio.h>
44#include "_scm.h"
06721500 45#include "libpath.h"
20e6290e
JB
46#include "fports.h"
47#include "read.h"
48#include "eval.h"
49
50#include "load.h"
06721500
JB
51
52#include <sys/types.h>
53#include <sys/stat.h>
54
55#ifdef HAVE_UNISTD_H
56#include <unistd.h>
57#endif /* HAVE_UNISTD_H */
58
59#ifndef R_OK
60#define R_OK 4
61#endif
0f2d19dd
JB
62
63\f
06721500 64/* Loading a file, given an absolute filename. */
0f2d19dd 65
26544b96
JB
66/* Hook to run when we load a file, perhaps to announce the fact somewhere.
67 Applied to the full name of the file. */
68static SCM *scm_loc_load_hook;
69
523f5266 70SCM_PROC(s_primitive_load, "primitive-load", 1, 2, 0, scm_primitive_load);
0f2d19dd 71SCM
b9d5d654 72scm_primitive_load (filename, case_insensitive_p, sharp)
0f2d19dd 73 SCM filename;
06721500 74 SCM case_insensitive_p;
0f2d19dd 75 SCM sharp;
0f2d19dd 76{
26544b96 77 SCM hook = *scm_loc_load_hook;
06721500 78 SCM_ASSERT (SCM_NIMP (filename) && SCM_ROSTRINGP (filename), filename,
523f5266 79 SCM_ARG1, s_primitive_load);
26544b96
JB
80 SCM_ASSERT (hook == SCM_BOOL_F
81 || (scm_procedure_p (hook) == SCM_BOOL_T),
82 hook, "value of %load-hook is neither a procedure nor #f",
83 s_primitive_load);
84
85 if (hook != SCM_BOOL_F)
86 scm_apply (hook, scm_listify (filename, SCM_UNDEFINED), SCM_EOL);
87
0f2d19dd
JB
88 {
89 SCM form, port;
90 port = scm_open_file (filename,
91 scm_makfromstr ("r", (scm_sizet) sizeof (char), 0));
0f2d19dd
JB
92 while (1)
93 {
06721500 94 form = scm_read (port, case_insensitive_p, sharp);
0f2d19dd
JB
95 if (SCM_EOF_VAL == form)
96 break;
97 scm_eval_x (form);
98 }
99 scm_close_port (port);
100 }
b59b97ba 101 return SCM_UNSPECIFIED;
0f2d19dd
JB
102}
103
104\f
06721500 105/* Initializing the load path, and searching it. */
0f2d19dd 106
26544b96 107/* List of names of directories we search for files to load. */
06721500
JB
108static SCM *scm_loc_load_path;
109
26544b96
JB
110/* List of extensions we try adding to the filenames. */
111static SCM *scm_loc_load_extensions;
112
06721500
JB
113/* Initialize the global variable %load-path, given the value of the
114 LIBRARY_PATH preprocessor symbol and the SCHEME_LOAD_PATH
115 environment variable. */
0f2d19dd 116void
06721500
JB
117scm_init_load_path ()
118{
119 SCM path = SCM_EOL;
120
121#ifdef LIBRARY_PATH
122 path = scm_cons (scm_makfrom0str (LIBRARY_PATH), path);
123#endif /* LIBRARY_PATH */
124
125 {
126 char *path_string = getenv ("SCHEME_LOAD_PATH");
127
128 if (path_string && path_string[0] != '\0')
129 {
130 char *scan, *elt_end;
131
132 /* Scan backwards from the end of the string, to help
133 construct the list in the right order. */
134 scan = elt_end = path_string + strlen (path_string);
135 do {
136 /* Scan back to the beginning of the current element. */
137 do scan--;
138 while (scan >= path_string && *scan != ':');
139 path = scm_cons (scm_makfromstr (scan + 1, elt_end - (scan + 1), 0),
140 path);
141 elt_end = scan;
142 } while (scan >= path_string);
143 }
144 }
145
146 *scm_loc_load_path = path;
147}
148
149
150/* Search %load-path for a directory containing a file named FILENAME.
151 The file must be readable, and not a directory.
26544b96
JB
152 If we find one, return its full filename; otherwise, return #f.
153 If FILENAME is absolute, return it unchanged. */
06721500
JB
154SCM_PROC(s_sys_search_load_path, "%search-load-path", 1, 0, 0, scm_sys_search_load_path);
155SCM
156scm_sys_search_load_path (filename)
157 SCM filename;
158{
159 SCM path = *scm_loc_load_path;
26544b96 160 SCM exts = *scm_loc_load_extensions;
06721500 161 char *buf;
06721500 162 int filename_len;
26544b96
JB
163 int max_path_len;
164 int max_ext_len;
06721500
JB
165
166 SCM_ASSERT (SCM_NIMP (filename) && SCM_ROSTRINGP (filename), filename,
167 SCM_ARG1, s_sys_search_load_path);
26544b96
JB
168 SCM_ASSERT (scm_ilength (path) >= 0, path, "load path is not a proper list",
169 s_sys_search_load_path);
170 SCM_ASSERT (scm_ilength (exts) >= 0, exts,
171 "load extension list is not a proper list",
172 s_sys_search_load_path);
06721500
JB
173 filename_len = SCM_ROLENGTH (filename);
174
26544b96
JB
175 /* If FILENAME is absolute, return it unchanged. */
176 if (filename_len >= 1
177 && SCM_ROCHARS (filename)[0] == '/')
178 return filename;
179
180 /* Find the length of the longest element of path. */
181 {
182 SCM walk;
183
184 max_path_len = 0;
185 for (walk = path; SCM_NIMP (walk); walk = SCM_CDR (walk))
186 {
187 SCM elt = SCM_CAR (walk);
188 SCM_ASSERT (SCM_NIMP (elt) && SCM_ROSTRINGP (elt), elt,
189 "load path is not a list of strings",
190 s_sys_search_load_path);
191 if (SCM_LENGTH (elt) > max_path_len)
192 max_path_len = SCM_LENGTH (elt);
193 }
194 }
195
196 /* Find the length of the longest element of the load extensions
197 list. */
198 {
199 SCM walk;
200
201 max_ext_len = 0;
202 for (walk = exts; SCM_NIMP (walk); walk = SCM_CDR (walk))
203 {
204 SCM elt = SCM_CAR (walk);
205 SCM_ASSERT (SCM_NIMP (elt) && SCM_ROSTRINGP (elt), elt,
206 "load extension list is not a list of strings",
207 s_sys_search_load_path);
208 if (SCM_LENGTH (elt) > max_ext_len)
209 max_ext_len = SCM_LENGTH (elt);
210 }
211 }
212
06721500
JB
213 SCM_DEFER_INTS;
214
26544b96
JB
215 buf = scm_must_malloc (max_path_len + 1 + filename_len + max_ext_len + 1,
216 s_sys_search_load_path);
06721500 217
26544b96
JB
218 /* Try every path element. At this point, we know it's a proper
219 list of strings. */
220 for (; SCM_NIMP (path); path = SCM_CDR (path))
06721500 221 {
26544b96
JB
222 SCM path_elt = SCM_CAR (path);
223
224 /* Try every extension. At this point, we know it's a proper
225 list of strings. */
226 for (exts = *scm_loc_load_extensions;
227 SCM_NIMP (exts);
228 exts = SCM_CDR (exts))
06721500 229 {
26544b96
JB
230 SCM ext_elt = SCM_CAR (exts);
231 int i;
232
233 /* Concatenate the path name, the filename, and the extension. */
234 i = SCM_ROLENGTH (path_elt);
235 memcpy (buf, SCM_ROCHARS (path_elt), i);
236 buf[i++] = '/';
237 memcpy (buf + i, SCM_ROCHARS (filename), filename_len);
238 i += filename_len;
239 memcpy (buf + i, SCM_ROCHARS (ext_elt), SCM_LENGTH (ext_elt));
240 i += SCM_LENGTH (ext_elt);
241 buf[i] = '\0';
06721500
JB
242
243 {
244 struct stat mode;
245
246 if (stat (buf, &mode) >= 0
247 && ! (mode.st_mode & S_IFDIR)
248 && access (buf, R_OK) == 0)
249 {
26544b96 250 SCM result = scm_makfromstr (buf, i, 0);
06721500
JB
251 scm_must_free (buf);
252 SCM_ALLOW_INTS;
253 return result;
254 }
255 }
256 }
06721500
JB
257 }
258
259 scm_must_free (buf);
260 SCM_ALLOW_INTS;
261 return SCM_BOOL_F;
262}
263
264
26544b96 265SCM_PROC(s_primitive_load_path, "primitive-load-path", 1, 2, 0, scm_primitive_load_path);
06721500 266SCM
b9d5d654 267scm_primitive_load_path (filename, case_insensitive_p, sharp)
06721500
JB
268 SCM filename;
269 SCM case_insensitive_p;
270 SCM sharp;
271{
26544b96
JB
272 SCM full_filename;
273
274 SCM_ASSERT (SCM_NIMP (filename) && SCM_ROSTRINGP (filename), filename,
275 SCM_ARG1, s_primitive_load_path);
276
277 full_filename = scm_sys_search_load_path (filename);
278
dbece3a2
GH
279 if (SCM_FALSEP (full_filename))
280 {
26544b96
JB
281 int absolute = (SCM_LENGTH (filename) >= 1
282 && SCM_ROCHARS (filename)[0] == '/');
523f5266 283 scm_misc_error (s_primitive_load_path,
26544b96
JB
284 (absolute
285 ? "Unable to load file %S"
286 : "Unable to find file %S in load path"),
287 scm_listify (filename, SCM_UNDEFINED));
dbece3a2 288 }
26544b96 289
b9d5d654 290 return scm_primitive_load (full_filename, case_insensitive_p, sharp);
06721500
JB
291}
292
293\f
294
0f2d19dd
JB
295void
296scm_init_load ()
0f2d19dd 297{
25d8012c 298 scm_loc_load_path = SCM_CDRLOC(scm_sysintern("%load-path", SCM_EOL));
26544b96
JB
299 scm_loc_load_extensions
300 = SCM_CDRLOC(scm_sysintern("%load-extensions",
301 scm_listify (scm_makfrom0str (""),
302 scm_makfrom0str (".scm"),
303 SCM_UNDEFINED)));
304 scm_loc_load_hook = SCM_CDRLOC(scm_sysintern("%load-hook", SCM_BOOL_F));
06721500 305
0f2d19dd
JB
306#include "load.x"
307}