summaryrefslogtreecommitdiffstats
path: root/txr.c
diff options
context:
space:
mode:
Diffstat (limited to 'txr.c')
-rw-r--r--txr.c483
1 files changed, 322 insertions, 161 deletions
diff --git a/txr.c b/txr.c
index ae639782..d1c02db0 100644
--- a/txr.c
+++ b/txr.c
@@ -1,4 +1,4 @@
-/* Copyright 2009-2020
+/* Copyright 2009-2024
* Kaz Kylheku <kaz@kylheku.com>
* Vancouver, Canada
* All rights reserved.
@@ -6,23 +6,24 @@
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
@@ -56,36 +57,53 @@
#include "regex.h"
#include "arith.h"
#include "sysif.h"
+#include "itypes.h"
#if HAVE_GLOB
#include "glob.h"
#endif
#include "txr.h"
+#if CONFIG_FULL_REPL
+#define if_full_repl(THEN, ELSE) (THEN)
+#else
+#define if_full_repl(THEN, ELSE) (ELSE)
+#endif
+
const wchli_t *version = wli(TXR_VER);
+#ifdef TXR_BUILD_ID
+const wchli_t *build_id = wli(TXR_BUILD_ID);
+#endif
wchar_t *progname;
static const char *progname_u8;
static val prog_path = nil, sysroot_path = nil;
-int opt_noninteractive;
+int opt_noninteractive = if_full_repl(0, 1);
+int opt_noprofile;
int opt_compat;
int opt_dbg_expansion;
+int opt_free_all;
val stdlib_path;
+val self_path_s;
+
+#if HAVE_FORK_STUFF
+#define IF_HAVE_FORK_STUFF(THEN, ELSE) THEN
+#else
+#define IF_HAVE_FORK_STUFF(THEN, ELSE) ELSE
+#endif
static void help(void)
{
val text = lit(
"\n"
"TXR Version ~a\n"
-"Copyright 2009-2020 Kaz Kylheku <kaz@kylheku.com>\n"
+"Copyright 2009-2024 Kaz Kylheku <kaz@kylheku.com>\n"
"\n"
"Usage:\n"
"\n"
-" ~a [ options ] query-file { data-file }*\n"
+" ~a [ options ] script-file { argument }*\n"
"\n"
-#if HAVE_TERMIOS
"If no arguments are present, TXR will enter into interactive listener mode.\n"
"\n"
-#endif
-"The query-file or data-file arguments may be specified as -, in which case\n"
+"The script-file or data-file arguments may be specified as -, in which case\n"
"standard input is used. All data-file arguments which begin with a !\n"
"character are treated as command pipes. Those which begin with a $\n"
"are interpreted as directories to read. Leading arguments which begin\n"
@@ -104,8 +122,6 @@ static void help(void)
"-Dvar Predefine variable var, with empty string value.\n"
"-q Quiet: don't report errors during query matching.\n"
"-v Verbose: extra logging from matcher.\n"
-"-b Don't dump list of bindings, or 'false'\n"
-" on unsuccessful termination.\n"
"-B Force list of bindings to be dumped, or false\n"
" if termination is unsuccessful.\n"
"-l If dumping bindings, use TXR Lisp format.\n"
@@ -121,44 +137,53 @@ static void help(void)
" Additional dimensions beyond N are fudged\n"
" by generating numeric suffixes. Implies -B.\n"
"-c query-text The query is read from the query-text argument\n"
-" itself. The query-file argument is omitted in\n"
+" itself. The script-file argument is omitted in\n"
" this case; the first argument is a data file.\n"
-"-f query-file Specify the query-file as an option argument.\n"
-" option, instead of the query-file argument.\n"
+"-f script-file Specify the script-file as an option argument\n"
+" instead of as the script-file argument.\n"
" This allows #! scripts to pass options through\n"
-" to the utility.\n"
-"-e expression Evaluate TXR Lisp expression. Can be specified\n"
-" multiple times. The query-file arg becomes optional.\n"
-"-p expression Like -e, but prints the result of the expression\n"
+" to the txr utility.\n"
+"-e expressions Evaluate zero or more TXR Lisp expressions.\n"
+" Can be specified multiple times. The script-file\n"
+" arg becomes optional.\n"
+"-p expression Evaluate a single expression, and print the value\n"
" using the prinl function.\n"
"-P expression Like -p, but prints using pprinl.\n"
"-t expression Like -p, but prints using tprint.\n"
+"-b var=value Bind a Lisp global variable as if by defparml.\n"
+" var and value are parsed as Lisp syntax.\n"
+" value is not evaluated.\n"
"-C N Request backward-compatible behavior to the\n"
" specified version of TXR.\n"
"--help Reproduce this help text.\n"
-"--version Display program version\n"
-"--license Display software license\n"
+"--version Display program version.\n"
+"--build-id Print build ID string if compiled in.\n"
+"--license Display software license.\n"
" Use of txr implies agreement with the disclaimer\n"
" section at the bottom of the license.\n"
"--lisp Treat unsuffixed query files as TXR Lisp.\n"
"--compiled Treat unsuffixed query files as compiled TXR Lisp.\n"
-"--lisp-bindings Synonym for -l\n"
-"--debugger Synonym for -d\n"
+"--lisp-bindings Synonym for -l.\n"
+"--debugger Synonym for -d.\n"
"--backtrace Enable backtraces.\n"
-"--noninteractive Synonym for -n\n"
-"--compat=N Synonym for -C N\n"
+"--noninteractive Synonym for -n.\n"
+"--compat=N Synonym for -C N.\n"
+"--in-package=name Switch to specified package\n"
+"--compile=src[:target] Compile a file.\n"
"--gc-delta=N Invoke garbage collection when malloc activity\n"
" increments by N megabytes since last collection.\n"
"--args... Allows multiple arguments to be encoded as a single\n"
-" argument. This is useful in hash-bang scripting.\n"
-" Peculiar syntax. See manual.\n"
+" argument. This is useful in hash-bang scripts.\n"
+" Peculiar syntax. See the manual.\n"
"--eargs... arg Extended version of --args: additionally consumes\n"
-" the following argument arg, and allows one or more\n"
+" the following argument arg and allows one or more\n"
" copies of it to be to be embedded in the\n"
-" encoded arguments. See manual.\n"
-#if HAVE_FORK_STUFF
-"--reexec Re-execute TXR with remaining arguments.\n"
-#endif
+" encoded arguments. See the manual.\n"
+"--noprofile Do not read .txr_profile when entering listener.\n"
+IF_HAVE_FORK_STUFF(
+"--reexec Re-execute TXR with remaining arguments.\n",
+""
+)
"--debug-autoload Allow debugger to step through library auto-loading.\n"
"--debug-expansion Allow debugger to step through macro-expansion of query.\n"
"--yydebug Debug Yacc parser, if compiled with YYDEBUG support.\n"
@@ -173,21 +198,21 @@ static void help(void)
format(std_output, text, static_str(version), prog_string, nao);
}
-#if HAVE_TERMIOS
-static void banner(void)
+static void banner(val self)
{
+ if (!isatty(c_int(stream_fd(std_input), self)))
+ return;
+
format(std_output,
- lit("This is the TXR Lisp interactive listener of TXR ~a.\n"
- "Quit with :quit or Ctrl-D on empty line. Ctrl-X ? for cheatsheet.\n"),
+ if3(opt_noninteractive,
+ lit("This is the TXR Lisp plain mode listener of TXR ~a.\n"
+ "Quit with :quit or Ctrl-D on an empty line.\n"),
+ if_full_repl(lit("This is the TXR Lisp interactive "
+ "listener of TXR ~a.\n"
+ "Quit with :quit or Ctrl-D on an empty line. "
+ "Ctrl-X ? for cheatsheet.\n"), nil)),
static_str(version), nao);
}
-#else
-static void hint(void)
-{
- format(std_error, lit("~a: incorrect arguments: try --help\n"),
- prog_string, nao);
-}
-#endif
static val check_hash_bang(val stream, val args, int *occurs)
{
@@ -254,11 +279,16 @@ static val get_self_path(void)
val execname = string_utf8(getexecname());
if (car(execname) == chr('/'))
return execname;
- return format(nil, lit("~a/~a"), getcwd_wrap(), execname, nao);
+ return scat3(getcwd_wrap(), chr('/'), execname);
}
#else
static val get_self_path(void)
{
+ char self[PATH_MAX];
+
+ if (progname_u8 && realpath(progname_u8, self))
+ return string_utf8(self);
+
return lit(TXR_INST_PATH);
}
#endif
@@ -278,45 +308,50 @@ static val substitute_basename(val edited_path, val source_path)
source_path);
return if3(lslash,
- format(nil, lit("~a~a"),
- sub_str(edited_path, 0, succ(lslash)),
- basename, nao),
+ scat2(sub_str(edited_path, 0, succ(lslash)), basename),
basename);
}
static val sysroot(val target)
{
- return format(nil, lit("~a~a"), sysroot_path, target, nao);
+ return scat2(sysroot_path, target);
}
static void sysroot_init(void)
{
val prog_dir;
- const wchar_t *psc = wref(coerce(const wchar_t *, path_sep_chars));
+ const wchar_t *psc = coerce(const wchar_t *, path_sep_chars);
+ int share_txr_stdlib = 1;
-#if HAVE_WINDOWS_H
- val slash = regex_compile(lit("\\\\"), nil);
-#endif
protect(&prog_path, &sysroot_path, &stdlib_path, convert(val *, 0));
prog_path = get_self_path();
#if HAVE_WINDOWS_H
- prog_path = regsub(slash, lit("/"), prog_path);
+ prog_path = regsub(lit("\\"), lit("/"), prog_path);
#endif
prog_dir = dir_name(prog_path);
if (ref(prog_dir, negone) != chr(psc[0]))
- prog_dir = format(nil, lit("~a~a"), prog_dir, chr(psc[0]), nao);
+ prog_dir = scat3(prog_dir, chr(psc[0]), null_string);
if (!(maybe_sysroot(lit(TXR_REL_PATH)) ||
- maybe_sysroot(lit(TXR_REL_PATH EXE_SUFF)) ||
- maybe_sysroot(lit(PROG_NAME)) ||
- maybe_sysroot(lit(PROG_NAME EXE_SUFF)) ||
- maybe_sysroot(substitute_basename(lit(TXR_REL_PATH), prog_path))))
+ maybe_sysroot(substitute_basename(lit(TXR_REL_PATH), prog_path)) ||
+ (share_txr_stdlib = 0) ||
+ maybe_sysroot(lit(PROG_NAME EXE_SUFF))))
{
sysroot_path = prog_dir;
}
- stdlib_path = sysroot(lit("share/txr/stdlib/"));
+ stdlib_path = sysroot(if3(share_txr_stdlib,
+ 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),
@@ -359,7 +394,7 @@ static int license(void)
for (iter = path_list; iter; iter = cdr(iter)) {
val lic = open_file(car(iter), lit("r"));
- put_lines(lazy_stream_cons(lic), std_output);
+ put_lines(lazy_stream_cons(lic, nil), std_output);
put_char(chr('\n'), std_output);
}
}
@@ -378,6 +413,16 @@ static int license(void)
return retval;
}
+static void free_all(void)
+{
+ if (opt_free_all) {
+ regex_free_all();
+ gc_free_all();
+ arith_free_all();
+ free(progname);
+ }
+}
+
int txr_main(int argc, char **argv);
int main(int argc, char **argv)
@@ -386,6 +431,7 @@ int main(int argc, char **argv)
repress_privilege();
progname = utf8_dup_from(argv[0] ? argv[0]: "txr");
progname_u8 = argv[0];
+ atexit(free_all);
init(&stack_bottom);
match_init();
debug_init();
@@ -399,6 +445,38 @@ static void requires_arg(val opt)
prog_string, opt, nao);
}
+static void do_compile_opt(val arg)
+{
+ val compile_update_file = intern(lit("compile-update-file"), user_package);
+ val col_pos = search_str(arg, lit(":"), nil, nil);
+ val source = arg;
+ val target = nil;
+
+ if (col_pos) {
+ target = sub_str(source, succ(col_pos), t);
+ source = sub_str(source, zero, col_pos);
+ }
+
+ reg_varl(self_path_s, source);
+
+ funcall2(compile_update_file, source, target);
+}
+
+static int do_in_package_opt(val opt, val arg)
+{
+ val pkg_binding = lookup_var(nil, package_s);
+ val package = find_package(arg);
+
+ if (!package) {
+ format(std_error, lit("~a: option --~a: ~a package not found\n"),
+ prog_string, opt, arg, nao);
+ return 0;
+ }
+
+ rplacd(pkg_binding, package);
+ return 1;
+}
+
static int do_fixnum_opt(int (*opt_func)(val), val opt, val arg)
{
if (arg) {
@@ -420,7 +498,7 @@ static int do_fixnum_opt(int (*opt_func)(val), val opt, val arg)
static int compat(val optval)
{
- int compat = c_num(optval);
+ int compat = c_num(optval, lit("txr"));
int min = compat_fixup(compat);
if (min) {
@@ -431,6 +509,8 @@ static int compat(val optval)
}
sysroot_compat_fixup(compat);
+ match_compat_fixup(compat);
+
opt_compat = compat;
reg_varl(intern(lit("compat"), system_package), num(compat));
return 1;
@@ -438,33 +518,21 @@ static int compat(val optval)
static int array_dim(val optval)
{
- opt_arraydims = c_num(optval);
+ opt_arraydims = c_num(optval, lit("txr"));
opt_print_bindings = 1;
return 1;
}
static int gc_delta(val optval)
{
- opt_gc_delta = c_num(mul(optval, num_fast(1048576)));
+ opt_gc_delta = c_num(mul(optval, num_fast(1048576)), lit("gc"));
return 1;
}
-static void free_all(void)
-{
- static int called;
-
- if (!called) {
- called = 1;
- regex_free_all();
- gc_free_all();
- arith_free_all();
- free(progname);
- }
-}
-
#ifndef CONFIG_DEBUG_SUPPORT
static void no_dbg_support(val arg)
{
+ drop_privilege();
format(std_error,
lit("~a: option ~a requires debug support compiled in\n"),
prog_string, arg, nao);
@@ -473,21 +541,21 @@ static void no_dbg_support(val arg)
static int parse_once_noerr(val stream, val name)
{
- val pfx = format(nil, lit("~a:"), name, nao);
+ val pfx = scat2(name, lit(":"));
ignerr_func_body(int, 0, parse_once(prog_string, stream, name),
std_error, pfx);
}
static val read_compiled_file_noerr(val self, val stream, val name, val error_stream)
{
- val pfx = format(nil, lit("~a:"), name, nao);
+ val pfx = scat2(name, lit(":"));
ignerr_func_body(val, nil, read_compiled_file(self, stream, error_stream),
std_error, pfx);
}
static val read_eval_stream_noerr(val self, val stream, val name, val error_stream)
{
- val pfx = format(nil, lit("~a:"), name, nao);
+ val pfx = scat2(name, lit(":"));
ignerr_func_body(val, nil, read_eval_stream(self, stream, error_stream),
std_error, pfx);
}
@@ -508,7 +576,6 @@ int txr_main(int argc, char **argv)
val txr_lisp_p = nil;
val enter_repl = nil;
val args_s = intern(lit("*args*"), user_package);
- val self_path_s = intern(lit("self-path"), user_package);
val compat_var = lit("TXR_COMPAT");
val compat_val = getenv_wrap(compat_var);
val orig_args = nil, ref_arg_list = nil;
@@ -518,6 +585,13 @@ int txr_main(int argc, char **argv)
static char alt_args_buf[128 + 7] = "@(txr):", *alt_args = alt_args_buf + 7;
+ self_path_s = intern(lit("self-path"), user_package);
+
+ if (ends_with(lit("lisp" EXE_SUFF), prog_path, nil, nil))
+ txr_lisp_p = t;
+ else if (ends_with(lit("vm" EXE_SUFF), prog_path, nil, nil))
+ txr_lisp_p = chr('o');
+
setvbuf(stderr, 0, _IOLBF, 0);
if (compat_val && length(compat_val) != zero) {
@@ -553,13 +627,8 @@ int txr_main(int argc, char **argv)
arg_list = list(string_utf8(alt_args), nao);
} else if (argc <= 1) {
drop_privilege();
-#if HAVE_TERMIOS
- banner();
+ banner(self);
goto repl;
-#else
- hint();
- return EXIT_FAILURE;
-#endif
}
for (ref_arg_list = arg_list, arg = upop(&arg_list, &arg_undo);
@@ -574,7 +643,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);
+ 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);
@@ -634,18 +703,31 @@ int txr_main(int argc, char **argv)
/* Odd case 3: -Dfoo=bar syntax. */
if (equal(sub(arg, zero, two), lit("-D"))) {
val dopt_arg = sub(arg, two, t);
- cons_bind(var, def, split_str(dopt_arg, lit("=")));
- val deflist = if2(def, split_str(car(def), lit(",")));
- val sym = intern(var, cur_package);
+ val eq_pos = search_str(dopt_arg, lit("="), nil, nil);
- if (rest(deflist))
- bindings = cons(cons(sym, deflist), bindings);
- else if (deflist)
- bindings = cons(cons(sym, car(deflist)), bindings);
- else
- bindings = cons(cons(sym, t), bindings);
+ if (eq_pos) {
+ val var = sub_str(dopt_arg, zero, eq_pos);
+ val def = sub_str(dopt_arg, succ(eq_pos), t);
+ val deflist = split_str(def, lit(","));
+ val sym = intern(var, cur_package);
- match_reg_var(sym);
+ if (rest(deflist))
+ bindings = cons(cons(sym, deflist), bindings);
+ else
+ bindings = cons(cons(sym, car(deflist)), bindings);
+
+ match_reg_var(sym);
+ } else {
+ if (search_str(dopt_arg, lit(","), nil, nil)) {
+ format(std_error,
+ lit("~a: bad -D syntax: ~a\n"), prog_string, arg, nao);
+ return EXIT_FAILURE;
+ } else {
+ val sym = intern(dopt_arg, cur_package);
+ bindings = cons(cons(sym, null_string), bindings);
+ match_reg_var(sym);
+ }
+ }
continue;
}
@@ -670,8 +752,29 @@ int txr_main(int argc, char **argv)
continue;
}
+ if (equal(opt, lit("compile"))) {
+ if (!org) {
+ requires_arg(opt);
+ return EXIT_FAILURE;
+ }
+ reg_var(args_s, or2(orig_args, arg_list));
+ do_compile_opt(org);
+ evaled = t;
+ continue;
+ }
+
+ if (equal(opt, lit("in-package"))) {
+ if (!org) {
+ requires_arg(opt);
+ return EXIT_FAILURE;
+ }
+ if (!do_in_package_opt(opt, org))
+ return EXIT_FAILURE;
+ continue;
+ }
+
/* Long opts with no arguments */
- if (org) {
+ if (0) noarg: {
drop_privilege();
format(std_error,
lit("~a: option --~a takes no argument, ~a given\n"),
@@ -680,12 +783,24 @@ int txr_main(int argc, char **argv)
}
if (equal(opt, lit("version"))) {
+ if (org)
+ goto noarg;
drop_privilege();
format(std_output, lit("~a: version ~a\n"),
prog_string, static_str(version), nao);
return 0;
}
+ if (equal(opt, lit("build-id"))) {
+ if (org)
+ goto noarg;
+ drop_privilege();
+#ifdef TXR_BUILD_ID
+ format(std_output, lit("~a\n"), static_str(build_id), nao);
+#endif
+ return 0;
+ }
+
if (equal(opt, lit("help"))) {
drop_privilege();
help();
@@ -693,46 +808,65 @@ int txr_main(int argc, char **argv)
}
if (equal(opt, lit("license"))) {
+ if (org)
+ goto noarg;
drop_privilege();
return license();
}
if (equal(opt, lit("gc-debug"))) {
+ if (org)
+ goto noarg;
drop_privilege();
opt_gc_debug = 1;
continue;
} else if (equal(opt, lit("vg-debug"))) {
- drop_privilege();
#if HAVE_VALGRIND
+ if (org)
+ goto noarg;
+ drop_privilege();
opt_vg_debug = 1;
continue;
#else
+ drop_privilege();
format(std_error,
lit("~a: option ~a requires Valgrind support compiled in\n"),
prog_string, arg, nao);
return EXIT_FAILURE;
#endif
} else if (equal(opt, lit("dv-regex"))) {
+ if (org)
+ goto noarg;
opt_derivative_regex = 1;
continue;
} else if (equal(opt, lit("lisp-bindings"))) {
+ if (org)
+ goto noarg;
opt_lisp_bindings = 1;
opt_print_bindings = 1;
continue;
} else if (equal(opt, lit("lisp"))) {
+ if (org)
+ goto noarg;
txr_lisp_p = t;
continue;
} else if (equal(opt, lit("compiled"))) {
+ if (org)
+ goto noarg;
txr_lisp_p = chr('o');
continue;
#if HAVE_FORK_STUFF
} else if (equal(opt, lit("reexec"))) {
+ if (org)
+ goto noarg;
exec_wrap(prog_path, arg_list);
return EXIT_FAILURE;
#endif
} else if (equal(opt, lit("debugger"))) {
- drop_privilege();
#if CONFIG_DEBUG_SUPPORT
+ if (org)
+ goto noarg;
+ drop_privilege();
opt_debugger = 1;
debug_set(DBG_ENABLE | DBG_BACKTRACE);
continue;
@@ -741,8 +875,10 @@ int txr_main(int argc, char **argv)
return EXIT_FAILURE;
#endif
} else if (equal(opt, lit("debug-autoload"))) {
- drop_privilege();
#if CONFIG_DEBUG_SUPPORT
+ if (org)
+ goto noarg;
+ drop_privilege();
opt_debugger = 1;
opt_dbg_autoload = 1;
debug_set(DBG_ENABLE | DBG_BACKTRACE);
@@ -752,8 +888,10 @@ int txr_main(int argc, char **argv)
return EXIT_FAILURE;
#endif
} else if (equal(opt, lit("debug-expansion"))) {
- drop_privilege();
#if CONFIG_DEBUG_SUPPORT
+ if (org)
+ goto noarg;
+ drop_privilege();
opt_debugger = 1;
opt_dbg_expansion = 1;
debug_set(DBG_ENABLE | DBG_BACKTRACE);
@@ -763,6 +901,8 @@ int txr_main(int argc, char **argv)
return EXIT_FAILURE;
#endif
} else if (equal(opt, lit("yydebug"))) {
+ if (org)
+ goto noarg;
drop_privilege();
if (have_yydebug) {
yydebug_onoff(1);
@@ -778,6 +918,8 @@ int txr_main(int argc, char **argv)
return EXIT_FAILURE;
}
} else if (equal(opt, lit("backtrace"))) {
+ if (org)
+ goto noarg;
#if CONFIG_DEBUG_SUPPORT
debug_set(DBG_BACKTRACE);
continue;
@@ -786,11 +928,20 @@ int txr_main(int argc, char **argv)
return EXIT_FAILURE;
#endif
} else if (equal(opt, lit("noninteractive"))) {
+ if (org)
+ goto noarg;
opt_noninteractive = 1;
stream_set_prop(std_input, real_time_k, nil);
continue;
} else if (equal(opt, lit("free-all"))) {
- atexit(free_all);
+ if (org)
+ goto noarg;
+ opt_free_all = 1;
+ continue;
+ } else if (equal(opt, lit("noprofile"))) {
+ if (org)
+ goto noarg;
+ opt_noprofile = 1;
continue;
} else {
drop_privilege();
@@ -827,20 +978,27 @@ int txr_main(int argc, char **argv)
case 'b':
drop_privilege();
{
- val pair = partition_star(arg, pos(chr('='), arg, nil, nil));
- val sym = lisp_parse(pop(&pair), std_error,
- colon_k, lit("cmdline-expr"), colon_k);
- val obj = lisp_parse(pop(&pair), std_error,
- colon_k, lit("cmdline-expr"), colon_k);
-
- if (!bindable(sym)) {
+ val pair = split_str(arg, chr('='));
+ if (cdr(pair)) {
+ val sym = lisp_parse(pop(&pair), std_error,
+ colon_k, lit("cmdline-expr"), colon_k);
+ val obj = lisp_parse(pop(&pair), std_error,
+ colon_k, lit("cmdline-expr"), colon_k);
+
+ if (!bindable(sym)) {
+ format(std_error,
+ lit("~a: ~s isn't a bindable symbol\n"),
+ prog_string, sym, nao);
+ return EXIT_FAILURE;
+ }
+
+ reg_var(sym, obj);
+ } else {
format(std_error,
- lit("~a: ~s isn't a bindable symbol\n"),
- prog_string, sym, nao);
+ lit("~a: -b argument must be var=val syntax\n"),
+ prog_string, nao);
return EXIT_FAILURE;
}
-
- reg_var(sym, obj);
}
break;
case 'c':
@@ -874,8 +1032,10 @@ int txr_main(int argc, char **argv)
prog_string, arg, spec_file_str, nao);
return EXIT_FAILURE;
}
- if (wcscmp(c_str(spec_file), L"-") != 0) {
- open_txr_file(spec_file, &txr_lisp_p, &spec_file_str, &parse_stream);
+ 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, 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);
@@ -895,10 +1055,17 @@ int txr_main(int argc, char **argv)
reg_varl(self_path_s, lit("cmdline-expr"));
reg_var(args_s, or2(orig_args, arg_list));
- eval_intrinsic(lisp_parse(arg, std_error, colon_k,
- lit("cmdline-expr"), colon_k),
- make_env(bindings, nil, nil));
+ {
+ val forms = read_objects_from_string(arg, std_error, colon_k,
+ lit("cmdline-expr"));
+
+ if (forms != colon_k)
+ eval_intrinsic(cons(progn_s, forms),
+ make_env(bindings, nil, nil), nil);
+ }
+
evaled = t;
+
args_new = cdr(lookup_global_var(args_s));
if (args_new != args_saved) {
@@ -926,7 +1093,7 @@ int txr_main(int argc, char **argv)
obj = eval_intrinsic(lisp_parse(arg, std_error, colon_k,
lit("cmdline-expr"), colon_k),
- make_env(bindings, nil, nil));
+ make_env(bindings, nil, nil), nil);
gc_hint(obj);
pf(z(obj), std_output);
@@ -967,15 +1134,8 @@ int txr_main(int argc, char **argv)
break;
case 'i':
drop_privilege();
-#if HAVE_TERMIOS
enter_repl = t;
break;
-#else
- format(std_error,
- lit("~a: option ~a requires a platform with termios\n"),
- prog_string, arg, nao);
- return EXIT_FAILURE;
-#endif
case 'd':
drop_privilege();
#if CONFIG_DEBUG_SUPPORT
@@ -1031,13 +1191,8 @@ int txr_main(int argc, char **argv)
goto repl;
if (evaled)
return EXIT_SUCCESS;
-#if HAVE_TERMIOS
- banner();
+ banner(self);
goto repl;
-#else
- hint();
- return EXIT_FAILURE;
-#endif
}
drop_privilege();
@@ -1061,10 +1216,11 @@ int txr_main(int argc, char **argv)
val parser_obj = ensure_parser(parse_stream, spec_file_str);
parser_t *parser = parser_get_impl(prog_string, parser_obj);
parse_once_noerr(parse_stream, spec_file_str);
+ mut(parser_obj);
gc_state(gc);
close_stream(parse_stream, nil);
-
+ run_load_hooks(dyn_env);
uw_release_deferred_warnings();
spec = parser->syntax_tree;
@@ -1103,36 +1259,41 @@ int txr_main(int argc, char **argv)
reg_varl(car(binding), cdr(binding));
}
- if (txr_lisp_p == chr('o')) {
- val result = read_compiled_file_noerr(self, parse_stream, spec_file_str,
- std_error);
- if (!enter_repl)
- return result ? 0 : EXIT_FAILURE;
- } else {
- val result = read_eval_stream_noerr(self, parse_stream, spec_file_str,
- std_error);
-
- close_stream(parse_stream, nil);
-
- uw_release_deferred_warnings();
-
- if (!enter_repl)
- return result ? 0 : EXIT_FAILURE;
+ {
+ if (txr_lisp_p == chr('o')) {
+ uw_block_begin (load_s, ret);
+ ret = read_compiled_file_noerr(self, parse_stream,
+ spec_file_str, std_error);
+ uw_block_end;
+ if (!enter_repl)
+ exit_wrap(ret);
+ } else if (enter_repl) {
+ uw_block_begin (load_s, ret);
+ ret = read_eval_stream_noerr(self, parse_stream,
+ spec_file_str, std_error);
+ uw_block_end;
+ close_stream(parse_stream, nil);
+ run_load_hooks(dyn_env);
+ uw_release_deferred_warnings();
+ } else {
+ uw_block_begin (load_s, ret);
+ ret = read_eval_stream(self, parse_stream, std_error);
+ uw_block_end;
+ exit_wrap(ret);
+ }
}
repl:
-#if HAVE_TERMIOS
if (compat_val)
format(std_output,
lit("Note: operating in TXR ~a compatibility mode "
"due to environment variable.\n"),
num(opt_compat), nao);
reg_var(args_s, or2(orig_args, arg_list));
- reg_varl(intern(lit("self-path"), user_package), lit("listener"));
+ reg_varl(self_path_s, lit("listener"));
env_vbind(dyn_env, package_s,
opt_compat && opt_compat <= 190 ? user_package : public_package);
env_vbind(dyn_env, load_recursive_s, nil);
repl(bindings, std_input, std_output, nil);
-#endif
return 0;
}