summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libguile/load.c145
1 files changed, 84 insertions, 61 deletions
diff --git a/libguile/load.c b/libguile/load.c
index bfe9fa410..6650837c9 100644
--- a/libguile/load.c
+++ b/libguile/load.c
@@ -213,7 +213,9 @@ SCM scm_listofnullstr;
/* Search PATH for a directory containing a file named FILENAME.
The file must be readable, and not a directory.
If we find one, return its full filename; otherwise, return #f.
- If FILENAME is absolute, return it unchanged. */
+ If FILENAME is absolute, return it unchanged.
+ If given, EXTENSIONS is a list of strings; for each directory
+ in PATH, we search for FILENAME concatenated with each EXTENSION. */
SCM_PROC(s_search_path, "search-path", 2, 1, 0, scm_search_path);
SCM
scm_search_path (path, filename, extensions)
@@ -221,25 +223,25 @@ scm_search_path (path, filename, extensions)
SCM filename;
SCM extensions;
{
- char *buf, *endp;
+ char *filename_chars;
int filename_len;
- size_t max_path_len;
- size_t max_ext_len;
- SCM result = SCM_BOOL_F;
+ size_t max_path_len; /* maximum length of any PATH element */
+ size_t max_ext_len; /* maximum length of any EXTENSIONS element */
SCM_ASSERT (scm_ilength (path) >= 0, path, SCM_ARG1, s_search_path);
SCM_ASSERT (SCM_NIMP (filename) && SCM_ROSTRINGP (filename), filename,
SCM_ARG2, s_search_path);
if (SCM_UNBNDP (extensions))
- extensions = scm_listofnullstr;
+ extensions = SCM_EOL;
else
SCM_ASSERT (scm_ilength (extensions) >= 0, extensions,
SCM_ARG3, s_search_path);
+
+ filename_chars = SCM_ROCHARS (filename);
filename_len = SCM_ROLENGTH (filename);
/* If FILENAME is absolute, return it unchanged. */
- if (filename_len >= 1
- && SCM_ROCHARS (filename)[0] == '/')
+ if (filename_len >= 1 && filename_chars[0] == '/')
return filename;
/* Find the length of the longest element of path. */
@@ -258,6 +260,28 @@ scm_search_path (path, filename, extensions)
}
}
+ /* If FILENAME has an extension, don't try to add EXTENSIONS to it. */
+ {
+ char *endp;
+
+ for (endp = filename_chars + filename_len - 1;
+ endp >= filename_chars;
+ endp--)
+ {
+ if (*endp == '.')
+ {
+ /* This filename already has an extension, so cancel the
+ list of extensions. */
+ extensions = SCM_EOL;
+ break;
+ }
+ else if (*endp == '/')
+ /* This filename has no extension, so keep the current list
+ of extensions. */
+ break;
+ }
+ }
+
/* Find the length of the longest element of the load extensions
list. */
{
@@ -275,63 +299,62 @@ scm_search_path (path, filename, extensions)
}
}
- /* Remove the same extension that FILENAME already has. */
- for (endp = SCM_ROCHARS (filename) + filename_len - 1;
- endp > SCM_ROCHARS (filename) && *endp != '/'; endp--)
- if (*endp == '.')
- {
- extensions = scm_delete (scm_makfromstr (endp, SCM_ROCHARS (filename)
- + filename_len - endp, 0),
- extensions);
- break;
- }
-
SCM_DEFER_INTS;
- buf = scm_must_malloc (max_path_len + 1 + filename_len + max_ext_len + 1,
- s_search_path);
+ {
+ SCM result = SCM_BOOL_F;
+ int buf_size = max_path_len + 1 + filename_len + max_ext_len + 1;
+ char *buf = scm_must_malloc (buf_size, s_search_path);
- /* Try every path element. At this point, we know it's a proper
- list of strings. */
- for (; SCM_NIMP (path); path = SCM_CDR (path))
- {
- int len;
- SCM dir = SCM_CAR (path), exts;
-
- /* Concatenate the path name and the filename. */
- len = SCM_ROLENGTH (dir);
- memcpy (buf, SCM_ROCHARS (dir), len);
- if (len >= 1 && buf[len - 1] != '/')
- buf[len++] = '/';
- memcpy (buf + len, SCM_ROCHARS (filename), filename_len);
- endp = buf + len + filename_len;
-
- /* Try every extension. At this point, we know it's a proper
- list of strings. */
- for (exts = extensions; SCM_NIMP (exts); exts = SCM_CDR (exts))
- {
- SCM ext = SCM_CAR (exts);
- struct stat mode;
-
- /* Concatenate the extension. */
- len = SCM_ROLENGTH (ext);
- memcpy (endp, SCM_ROCHARS (ext), len);
- *(endp + len) = '\0';
-
- if (stat (buf, &mode) == 0
- && ! (mode.st_mode & S_IFDIR)
- && access (buf, R_OK) == 0)
- {
- result = scm_makfromstr (buf, endp + len - buf, 0);
- goto end;
- }
- }
- }
+ /* This simplifies the loop below a bit. */
+ if (SCM_NULLP (extensions))
+ extensions = scm_listofnullstr;
- end:
- scm_must_free (buf);
- SCM_ALLOW_INTS;
- return result;
+ /* Try every path element. At this point, we know the path is a
+ proper list of strings. */
+ for (; SCM_NIMP (path); path = SCM_CDR (path))
+ {
+ int len;
+ SCM dir = SCM_CAR (path);
+ SCM exts;
+
+ /* Concatenate the path name and the filename. */
+ len = SCM_ROLENGTH (dir);
+ memcpy (buf, SCM_ROCHARS (dir), len);
+ if (len >= 1 && buf[len - 1] != '/')
+ buf[len++] = '/';
+ memcpy (buf + len, filename_chars, filename_len);
+ len += filename_len;
+
+ /* Try every extension. At this point, we know the extension
+ list is a proper, nonempty list of strings. */
+ for (exts = extensions; SCM_NIMP (exts); exts = SCM_CDR (exts))
+ {
+ SCM ext = SCM_CAR (exts);
+ int ext_len = SCM_ROLENGTH (ext);
+ struct stat mode;
+
+ /* Concatenate the extension. */
+ memcpy (buf + len, SCM_ROCHARS (ext), ext_len);
+ buf[len + ext_len] = '\0';
+
+ /* If the file exists at all, we should return it. If the
+ file is inaccessible, then that's an error. */
+ if (stat (buf, &mode) == 0
+ && ! (mode.st_mode & S_IFDIR))
+ {
+ result = scm_makfromstr (buf, len + ext_len, 0);
+ goto end;
+ }
+ }
+ }
+
+ end:
+ scm_must_free (buf);
+ scm_done_malloc (- buf_size);
+ SCM_ALLOW_INTS;
+ return result;
+ }
}