summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-04-25 00:14:23 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-04-25 00:14:23 -0700
commite3a06759eebdc2b4e2d0b8d08cb64eb99a40d3e3 (patch)
treef9a7c20e14a49a92a156a1f9a652cc18fd1e1e45
parentec69fdce7fae00a34d0ae88dae388705fedc1f8f (diff)
downloadtxr-e3a06759eebdc2b4e2d0b8d08cb64eb99a40d3e3.tar.gz
txr-e3a06759eebdc2b4e2d0b8d08cb64eb99a40d3e3.tar.bz2
txr-e3a06759eebdc2b4e2d0b8d08cb64eb99a40d3e3.zip
New: load can search multiple directories.
* eval.c (load_search_dirs_s): New symbol variable. (load): Initialize the name variable whose address is passed as the third argument of open_txr_file, which is now an in-out parameter. Pass t for the new search_dirs parameter, so that load benefits from the searching. (eval_init): Initialize load_search_dirs_s and register the *load-search-dirs* special variable. * eval.h (load_search_dirs_s): Declared. (load_search_dirs): New macro. * match.c (v_load): Initialize the variable passed as third argument of open_txr_file. * parser.c (open_txr_file): Take a new argument, search_dirs. If this is t, it tells the function "if the path is not found, then recurse on the *load-search-dirs* variable. Otherwise, if the value is not t, it is a list of the remaining directories to try. The existing parameter orig_in_resolved_out must now point to a location which is initialized. It is assumed to hold the original target that was passed to the load function. The first_try_path is a the path to actually try, derived from that one. Thus, the caller of open_txr_file gets to determine the initial try path using its own algorithm. Then any recursive calls that go through *load-search-dirs* will pass a first argument which is made of the original name, combined with a search dir. (load_rcfile): Pass pointer to initialized location as third argument of open-txr_file, and pass a nil value for search_dirs: no search takes place when looking for that file, which is at a single, fixed location. * parser.h (open_txr_file): Declaration updated. * txr.c (sysroot_init): Initialize *load-search-dirs*. (txr_main): Ensure third argument in all calls to open_txr_file points to initialized variable, with the correct value, and pass t for the search_dirs argument. * txr.1: Documented. * stdlib/doc-syms.tl: Updated. New: load can search multiple directories. * eval.c (load_search_dirs_s): New symbol variable. (load): Initialize the name variable whose address is passed as the third argument of open_txr_file, which is now an in-out parameter. Pass t for the new search_dirs parameter, so that load benefits from the searching. (eval_init): Initialize load_search_dirs_s and register the *load-search-dirs* special variable. * eval.h (load_search_dirs_s): Declared. (load_search_dirs): New macro. * match.c (v_load): Initialize the variable passed as third * argument of open_txr_file. * parser.c (open_txr_file): Take a new argument, search_dirs. If this is t, it tells the function "if the path is not found, then recurse on the *load-search-dirs* variable. Otherwise, if the value is not t, it is a list of the remaining directories to try. The existing parameter orig_in_resolved_out must now point to a location which is initialized. It is assumed to hold the original target that was passed to the load function. The first_try_path is a the path to actually try, derived from that one. Thus, the caller of open_txr_file gets to determine the initial try path using its own algorithm. Then any recursive calls that go through *load-search-dirs* will pass a first argument which is made of the original name, combined with a search dir. (load_rcfile): Pass pointer to initialized location as third argument of open-txr_file, and pass a nil value for search_dirs: no search takes place when looking for that file, which is at a single, fixed location. * parser.h (open_txr_file): Declaration updated. * txr.c (sysroot_init): Initialize *load-search-dirs*. (txr_main): Ensure third argument in all calls to open_txr_file points to initialized variable, with the correct value, and pass t for the search_dirs argument. * txr.1: Documented. * stdlib/doc-syms.tl: Updated.
-rw-r--r--eval.c8
-rw-r--r--eval.h3
-rw-r--r--match.c4
-rw-r--r--parser.c26
-rw-r--r--parser.h3
-rw-r--r--stdlib/doc-syms.tl1
-rw-r--r--txr.192
-rw-r--r--txr.c13
8 files changed, 131 insertions, 19 deletions
diff --git a/eval.c b/eval.c
index ed3c88f7..0915b0b8 100644
--- a/eval.c
+++ b/eval.c
@@ -102,7 +102,7 @@ val vector_lit_s, vec_list_s, tree_lit_s, tree_construct_s;
val macro_time_s, macrolet_s;
val defsymacro_s, symacrolet_s, prof_s, switch_s, struct_s;
val fbind_s, lbind_s, flet_s, labels_s;
-val load_path_s, load_hooks_s, load_recursive_s;
+val load_path_s, load_hooks_s, load_recursive_s, load_search_dirs_s;
val load_time_s, load_time_lit_s;
val eval_only_s, compile_only_s;
val const_foldable_s;
@@ -4669,13 +4669,13 @@ val load(val target)
cat_str(nappend2(sub_list(split_str(parent, lit("/")),
zero, negone),
cons(target, nil)), lit("/")));
- val name, stream;
+ val name = target, stream;
val txr_lisp_p = t;
val saved_dyn_env = dyn_env;
val load_dyn_env = make_env(nil, nil, dyn_env);
val rec = cdr(lookup_var(nil, load_recursive_s));
- open_txr_file(path, &txr_lisp_p, &name, &stream, self);
+ open_txr_file(path, &txr_lisp_p, &name, &stream, t, self);
if (match_str(or2(get_line(stream), null_string), lit("#!"), nil))
parser_set_lineno(self, stream, two);
@@ -6751,6 +6751,7 @@ void eval_init(void)
load_path_s = intern(lit("*load-path*"), user_package);
load_hooks_s = intern(lit("*load-hooks*"), user_package);
load_recursive_s = intern(lit("*load-recursive*"), system_package);
+ load_search_dirs_s = intern(lit("*load-search-dirs*"), user_package);
load_time_s = intern(lit("load-time"), user_package);
load_time_lit_s = intern(lit("load-time-lit"), system_package);
eval_only_s = intern(lit("eval-only"), user_package);
@@ -7081,6 +7082,7 @@ void eval_init(void)
reg_var(load_path_s, nil);
reg_symacro(intern(lit("self-load-path"), user_package), load_path_s);
reg_var(load_recursive_s, nil);
+ reg_var(load_search_dirs_s, nil);
reg_var(load_hooks_s, nil);
reg_fun(intern(lit("expand"), user_package), func_n2o(no_warn_expand, 1));
reg_fun(intern(lit("expand*"), user_package), func_n2o(expand, 1));
diff --git a/eval.h b/eval.h
index 173368ee..02e36002 100644
--- a/eval.h
+++ b/eval.h
@@ -34,12 +34,13 @@ extern val eval_error_s, if_s, call_s, identity_s;
extern val eq_s, eql_s, equal_s, less_s;
extern val car_s, cdr_s;
extern val last_form_evaled;
-extern val load_path_s, load_hooks_s, load_recursive_s;
+extern val load_path_s, load_hooks_s, load_recursive_s, load_search_dirs_s;
extern val special_s, struct_s;
extern val dyn_env;
#define load_path (deref(lookup_var_l(nil, load_path_s)))
+#define load_search_dirs (deref(lookup_var_l(nil, load_search_dirs_s)))
NORETURN val eval_error(val ctx, val fmt, ...);
val ctx_form(val obj);
diff --git a/match.c b/match.c
index 81cf7c8d..9d5a0a6b 100644
--- a/match.c
+++ b/match.c
@@ -4609,14 +4609,14 @@ static val v_load(match_files_ctx *c)
cat_str(nappend2(sub_list(split_str(parent, lit("/")),
zero, negone),
cons(target, nil)), lit("/")));
- val stream, name;
+ val stream, name = target;
val txr_lisp_p = nil;
val ret = nil;
val saved_dyn_env = dyn_env;
val load_dyn_env = make_env(nil, nil, dyn_env);
val rec = cdr(lookup_var(nil, load_recursive_s));
- open_txr_file(path, &txr_lisp_p, &name, &stream, self);
+ open_txr_file(path, &txr_lisp_p, &name, &stream, t, self);
uw_simple_catch_begin;
diff --git a/parser.c b/parser.c
index 9564d276..cdfceff1 100644
--- a/parser.c
+++ b/parser.c
@@ -513,7 +513,8 @@ val parser_circ_ref(parser_t *p, val num)
}
void open_txr_file(val first_try_path, val *txr_lisp_p,
- val *orig_in_resolved_out, val *stream, val self)
+ val *orig_in_resolved_out, val *stream,
+ val search_dirs, val self)
{
enum { none, tl, tlo, txr } suffix;
@@ -599,11 +600,26 @@ void open_txr_file(val first_try_path, val *txr_lisp_p,
}
if (in == 0) {
+ val try_next;
#ifdef ENOENT
except:
#endif
- uw_ethrowf(errno_to_file_error(errno),
- lit("unable to open ~a"), try_path, nao);
+ if (abs_path_p(*orig_in_resolved_out))
+ search_dirs = nil;
+ else if (search_dirs == t)
+ search_dirs = load_search_dirs;
+
+#ifdef ENOENT
+ if (errno != ENOENT || search_dirs == nil)
+#else
+ if (search_dirs == nil)
+#endif
+ uw_ethrowf(errno_to_file_error(errno),
+ lit("~a: ~a not found"), self, *orig_in_resolved_out, nao);
+ try_next = path_cat(pop(&search_dirs), *orig_in_resolved_out);
+ open_txr_file(try_next, txr_lisp_p, orig_in_resolved_out, stream,
+ search_dirs, self);
+ return;
}
found:
@@ -899,14 +915,14 @@ static void report_security_problem(val name)
static void load_rcfile(val name)
{
val self = lit("listener");
- val resolved_name;
+ val resolved_name = name;
val lisp_p = t;
val stream = nil;
val path_private_to_me_p = intern(lit("path-private-to-me-p"), user_package);
uw_catch_begin (catch_error, sy, va);
- open_txr_file(name, &lisp_p, &resolved_name, &stream, self);
+ open_txr_file(name, &lisp_p, &resolved_name, &stream, nil, self);
if (stream) {
if (!funcall1(path_private_to_me_p, stream)) {
diff --git a/parser.h b/parser.h
index 5c709ce3..eb669418 100644
--- a/parser.h
+++ b/parser.h
@@ -102,7 +102,8 @@ void yyset_extra(parser_t *, yyscan_t);
void yyset_hold_char(yyscan_t, int);
void parser_l_init(void);
void open_txr_file(val first_try_path, val *txr_lisp_p,
- val *orig_in_resolved_out, val *stream, val self);
+ val *orig_in_resolved_out, val *stream,
+ val search_dirs, val self);
void prime_parser(parser_t *, val name, enum prime_parser);
void prime_parser_post(parser_t *, enum prime_parser);
#ifdef SPACE
diff --git a/stdlib/doc-syms.tl b/stdlib/doc-syms.tl
index 53d01739..037675db 100644
--- a/stdlib/doc-syms.tl
+++ b/stdlib/doc-syms.tl
@@ -19,6 +19,7 @@
("*listener-sel-inclusive-p*" "N-02E4924F")
("*load-hooks*" "N-02D09712")
("*load-path*" "N-01D1DB58")
+ ("*load-search-dirs*" "N-004CCBF6")
("*match-macro*" "N-012A473F")
("*opt-level*" "N-03FDEBBC")
("*package*" "N-000CBBA0")
diff --git a/txr.1 b/txr.1
index 7b6b92c1..2e084cb1 100644
--- a/txr.1
+++ b/txr.1
@@ -9098,6 +9098,19 @@ is tried, and so forth, as described for the
.code load
function.
+If these initial attempts to find the file fail, and the failure
+is due to the file not being found rather than some other problem such as a
+permission error, and
+.meta expr
+isn't an absolute path according to
+.codn abs-path-p ,
+then additional attempts are made by searching for the file in the
+list of directories given in the
+.code *load-search-dirs*
+variable. Details are given in the description of the \*(TL
+.code load
+function.
+
Both the
.code load
and
@@ -77572,8 +77585,33 @@ with the resulting path. If that file is not found, then the suffix
.code .tl
is similarly tried.
-If an unsuffixed file is opened, its contents are treated as interpreted Lisp.
-Files ending in
+If the above
+.I "initial attempts"
+to find the file fail, and the failure
+is due to the file not being found rather than some other problem such as a
+permission error, and
+.meta target
+isn't an absolute path according to
+.codn abs-path-p ,
+then additional attempts are made by searching for the file in the
+list of directories given in the
+.code *load-search-dirs*
+variable. For each directory taken from this variable, the directory
+is combined with the relative
+.meta target
+as if using the
+.code path-cat
+function, and the resulting path is tried, with all the same suffix probing
+that is performed by the initial attempts. If any such a path is pure relative,
+it is interpreted relative to the current working directory, and not relative
+.codn *load-path* :
+only the initial attempts have that special behavior.
+
+An exception is thrown if a file is not found, or if any attempt to open
+a file results in an error other than non-existence.
+
+If an unsuffixed file is successfully opened, its contents are treated as
+interpreted Lisp. Files ending in
.code .txr_profile
are also treated as interpreted Lisp. Files ending in
.code .tlo
@@ -77729,6 +77767,40 @@ parsing and processing of a loaded \*(TX source file.
Also, during the processing of the profile file (see Interactive Profile File),
the variable is bound to the name of that file.
+.coNP Special variable @ *load-search-dirs*
+.desc
+The
+.code *load-search-dirs*
+variable holds a list of directories which are searched for a file to be
+loaded by the
+.code load
+function, the
+.code @(load)
+and
+.code @(include)
+directives, as well as by \*(TX's command line processing.
+
+Each of these situations first searches for a file in its characteristic
+way. If that fails due to the file not being found, and the name is
+a relative path, then the directories in
+.code *load-search-dirs*
+are probed, in order.
+
+The variable is initialized to a list which contains exactly one directory: a
+.code lib/
+directory dynamically calculated relative to \*(TX the executable location.
+Then intent is that third-party library modules may be installed there,
+and easily found by
+.codn load .
+For more information, see the section Deployment Directory Structure.
+
+The
+.code *load-search-dirs*
+isn't influenced by any environment variables, which is deliberate.
+If a system has multiple installations of different versions of \*(TX
+in different locations, an environment variable intended for one installation
+could be mistakenly used by the others, resulting in chaos.
+
.coNP Special variable @ *load-hooks*
.desc
The
@@ -87610,6 +87682,8 @@ The executable may be renamed, it need not be called
.../stdlib/cadr.tlo
.../stdlib/except.tl
...
+ .../share/txr/lib/...
+
.brev
The above structure is assumed if the executable finds itself
@@ -87626,11 +87700,19 @@ the following structure is expected:
.../stdlib/cadr.tl
.../stdlib/cadr.tlo
.../stdlib/except.tl
- ...
+ ...
+ .../lib/...
.brev
-Note that this has changed starting in \*(TX 264. Older versions
-of \*(TX, when the executable is not in a directory named
+The
+.strn lib/
+directory shown above is for third-party libraries.
+This is the directory indicated in the default value of the
+.code *load-search-dirs*
+special variable. The directory is not required to exist.
+
+Note that this structure had changed starting in \*(TX 264. Older versions of
+\*(TX, when the executable is not in a directory named
.strn bin ,
expect the following structure:
diff --git a/txr.c b/txr.c
index df3f9b14..0af94623 100644
--- a/txr.c
+++ b/txr.c
@@ -345,6 +345,14 @@ static void sysroot_init(void)
lit("share/txr/stdlib/"),
lit("stdlib/")));
+ {
+ loc lsd = lookup_var_l(nil, load_search_dirs_s);
+ set(lsd, cons(sysroot(if3(share_txr_stdlib,
+ lit("share/txr/lib/"),
+ lit("lib/"))),
+ nil));
+ }
+
reg_varl(intern(lit("stdlib"), user_package), stdlib_path);
reg_varl(intern(lit("*txr-version*"), user_package),
toint(lit(TXR_VER), nil));
@@ -599,7 +607,7 @@ int txr_main(int argc, char **argv)
if (car(arg) != chr('-')) {
if (!parse_stream) {
spec_file_str = arg;
- open_txr_file(arg, &txr_lisp_p, &spec_file_str, &parse_stream, self);
+ open_txr_file(arg, &txr_lisp_p, &spec_file_str, &parse_stream, t, self);
simulate_setuid_setgid(parse_stream);
dyn_env = make_env(nil, nil, dyn_env);
env_vbind(dyn_env, load_path_s, spec_file_str);
@@ -968,8 +976,9 @@ int txr_main(int argc, char **argv)
return EXIT_FAILURE;
}
if (wcscmp(c_str(spec_file, self), L"-") != 0) {
+ spec_file_str = spec_file;
open_txr_file(spec_file, &txr_lisp_p, &spec_file_str,
- &parse_stream, self);
+ &parse_stream, t, self);
simulate_setuid_setgid(parse_stream);
dyn_env = make_env(nil, nil, dyn_env);
env_vbind(dyn_env, load_path_s, spec_file_str);