diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2021-08-20 05:47:57 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2021-08-20 05:47:57 -0700 |
commit | 4aaf96f5aaab5c249c3c8ea6d24ee6683bca6f10 (patch) | |
tree | a55a4672b67612a05726e820ce9c99f5b8e6a503 | |
parent | f374abcd23a63f628a9ec7b84e2d797d3fc28342 (diff) | |
download | txr-4aaf96f5aaab5c249c3c8ea6d24ee6683bca6f10.tar.gz txr-4aaf96f5aaab5c249c3c8ea6d24ee6683bca6f10.tar.bz2 txr-4aaf96f5aaab5c249c3c8ea6d24ee6683bca6f10.zip |
listener: unbundle from termios.
This commit fixes the conceptual issue that when there is no termios
support (HAVE_TERMIOS is absent/false), then there is no
listener at all, even though the listener supports plain mode
that doesn't require termios.
* Makefile (linenoise/linenoise.o): Link in unconditionally,
not subject to have_termios.
* linenoise.c: Include termios-related header only if
HAVE_TERMIOS.
(struct lino_state): Define the completion_callback and
orig_termios members only if HAVE_TERMIOS.
(wcnsprintf, atexit_handler, enable_raw_mode,
disable_raw_mode, get_cursor_position, get_columns,
lino_clear_screen, refresh_line, handle_resize, generate_beep,
delete_undo, free_undo_stack, record_undo, record_triv_undo,
remove_noop_undo, restore_undo, undo_subst_hist_idx,
undo_renumber_hist_idx, free_completions, sync_data_to_buf,
compare_completions, complete_line, lino_set_completion_cb,
lino_add_completion, next_hist_match, copy_display_params,
history_search, ab_init, ab_append, ab_free, sync_data_to_buf,
copy_display_params, refresh_singleline, col_offset_in_str,
refresh_multiline, refresh_line, move_cursor_multiline,
move_cursor, scan_match_rev, scan_rev, scan_match_fwd,
scan_fwd, find_nearest_paren, usec_delay, paren_jump, flash,
yank, yank_by_ptr, update_sel, clear_sel, yank_sel,
delete_sel, edit_insert, edit_insert_str, edit_move_left,
edit_move_right, edit_move_home, edit_move_sol, edit_move_end,
edit_move_eol, edit_move_matching_paren, edit_history_next,
edit_delete, edit_backspace, edit_delete_prev_all,
edit_delete_to_eol, edit_delete_prev_word, edit_delete_line,
tr, char, edit_in_editor, edit, sigwinch_handler): Functions
defined only if HAVE_TERMIOS.
(struct abuf, struct row_values): Struct types defined only if
HAVE_TERMIOS.
(screen_rows): Defined only if HAVE_TERMIOS.
(linenoise): Support only noninteractive read loop unless
HAVE_TERMIOS.
(lino_make): If HAVE_TERMIOS is false, then set the
noninteractive flag, so the linenoise function enters
the plain-mode loop.
(lino_cleanup, lino_hist_add): Add #ifdefs to avoid calling
nonexistent functions when HAVE_TERMIOS is false.
* linenoise/linenoise.h (struct lino_completions,
lino_compl_cb_t): Define these types only if HAVE_TERMIOS.
(lino_set_completion_cb, lino_add_completion): Declare only if
HAVE_TERMIOS.
* parser.c: Include linenoise/linenoise.h unconditionally.
(report_security_problem, load_rcfile, repl_intr,
read_eval_ret_last, get_home_path, repl_warning,
is_balanced_line, hist_save): Now define regardless of
HAVE_TERMIOS.
(repl): Define regardless of HAVE_TERMIOS, but don't set
completion or atom callback if HAVE_TERMIOS is false.
* parser.h (repl): Declare unconditionally, not subject to
HAVE_TERMIOS.
* txr.c (if_termios): New macro.
(opt_noninteractive): Initialize to 1 if HAVE_TERMIOS is false.
(help): Text about entering into listener mode is always
present now, even in a build withou HAVE_TERMIOS.
(banner): Function is always defined. If we don't
HAVE_TERMIOS, then the unused string literal that will
never be printed is replaced by nil.
(hint): Function removed.
(txr_main): Blocks conditional on HAVE_TERMIOS that either
call banner and go to the repl, or else call hint and exit,
are reduced to unconditionally calling banner and going to the
repl. All #if HAVE_TERMIOS blocks are similarly replaced with
just the HAVE_TERMIOS case.
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | linenoise/linenoise.c | 41 | ||||
-rw-r--r-- | linenoise/linenoise.h | 4 | ||||
-rw-r--r-- | parser.c | 13 | ||||
-rw-r--r-- | parser.h | 2 | ||||
-rw-r--r-- | txr.c | 44 |
6 files changed, 59 insertions, 47 deletions
@@ -56,6 +56,7 @@ OBJS += arith.o hash.o utf8.o filter.o eval.o parser.o rand.o combi.o sysif.o OBJS += args.o lisplib.o cadr.o struct.o itypes.o buf.o jmp.o protsym.o ffi.o OBJS += strudel.o vm.o chksum.o chksums/sha256.o chksums/crc32.o chksums/md5.o OBJS += tree.o time.o +OBJS += linenoise/linenoise.o OBJS-$(debug_support) += debug.o OBJS-$(have_syslog) += syslog.o OBJS-$(have_glob) += glob.o @@ -63,7 +64,6 @@ OBJS-$(have_ftw) += ftw.o OBJS-$(have_posix_sigs) += signal.o OBJS-$(have_sockets) += socket.o OBJS-$(have_termios) += termios.o -OBJS-$(have_termios) += linenoise/linenoise.o EXTRA_OBJS-$(add_win_res) += win/txr.res STDLIB_SRCS := $(wildcard stdlib/*.tl) diff --git a/linenoise/linenoise.c b/linenoise/linenoise.c index 256553d4..7c945964 100644 --- a/linenoise/linenoise.c +++ b/linenoise/linenoise.c @@ -42,8 +42,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <termios.h> -#include <unistd.h> #include <stddef.h> #include <wchar.h> #include <stdlib.h> @@ -52,13 +50,16 @@ #include <string.h> #include <ctype.h> #include <wctype.h> -#include <sys/types.h> -#include <sys/ioctl.h> #include <signal.h> #include <limits.h> #include <assert.h> #include <stdarg.h> +#include <unistd.h> #include "config.h" +#if HAVE_TERMIOS +#include <termios.h> +#include <sys/types.h> +#include <sys/ioctl.h> #if HAVE_POLL #include <poll.h> #endif @@ -67,6 +68,7 @@ #include <sys/fcntl.h> #include <io.h> #endif +#endif #include "linenoise.h" #ifdef __cplusplus @@ -92,13 +94,17 @@ struct lino_state { lino_t *next, *prev; /* Links for global list: must be first */ /* Lifetime enduring state */ +#if HAVE_TERMIOS lino_compl_cb_t *completion_callback; +#endif void *cb_ctx; /* User context for completion callback */ lino_atom_cb_t *atom_callback; void *ca_ctx; /* User context for atom callback */ lino_enter_cb_t *enter_callback; void *ce_ctx; /* User context for enter callback */ +#if HAVE_TERMIOS struct termios orig_termios; /* In order to restore at exit.*/ +#endif #ifdef __CYGWIN__ int orig_imode, orig_omode; #endif @@ -162,10 +168,14 @@ enum key_action { static lino_os_t lino_os; static lino_t lino_list; volatile sig_atomic_t lino_list_busy; +#if HAVE_TERMIOS static int atexit_registered = 0; /* Register atexit just 1 time. */ +#endif #define nelem(array) (sizeof (array) / sizeof (array)[0]) +#if HAVE_TERMIOS + static int wcsnprintf(wchar_t *s, size_t nchar, const wchar_t *fmt, ...) { int ret; @@ -178,6 +188,8 @@ static int wcsnprintf(wchar_t *s, size_t nchar, const wchar_t *fmt, ...) return wcslen(s); } +#endif + /* ======================= Low level terminal handling ====================== */ /* Set if to use or not the multi line mode. */ @@ -225,6 +237,8 @@ void lino_set_enter_cb(lino_t *l, lino_enter_cb_t *cb, void *ctx) l->ce_ctx = ctx; } +#if HAVE_TERMIOS + static void atexit_handler(void); /* Raw mode: 1960 magic shit. */ @@ -2523,6 +2537,8 @@ static void sigwinch_handler(int sig) } #endif +#endif + /* The main function of the linenoise library * handles a non-TTY input file descriptor by opening * a standard I/O stream on it and reading lines @@ -2530,7 +2546,6 @@ static void sigwinch_handler(int sig) * the edit function. */ wchar_t *linenoise(lino_t *ls, const wchar_t *prompt) { - int count; int ifd = lino_os.fileno_fn(ls->tty_ifs); if (ls->noninteractive || !isatty(ifd)) { @@ -2589,6 +2604,8 @@ wchar_t *linenoise(lino_t *ls, const wchar_t *prompt) return ret; } else { wchar_t *ret = 0; +#if HAVE_TERMIOS + int count; #ifdef SIGWINCH static struct sigaction blank; struct sigaction sa = blank, oa; @@ -2614,6 +2631,7 @@ wchar_t *linenoise(lino_t *ls, const wchar_t *prompt) #ifdef SIGWINCH sigaction(SIGWINCH, &oa, 0); #endif +#endif return ret; } } @@ -2648,6 +2666,9 @@ lino_t *lino_make(mem_t *ifs, mem_t *ofs) ls->tty_ofs = ofs; link_into_list(&lino_list, ls); +#if !HAVE_TERMIOS + ls->noninteractive = 1; +#endif } return ls; @@ -2677,9 +2698,13 @@ static void free_hist(lino_t *ls); static void lino_cleanup(lino_t *ls) { +#if HAVE_TERMIOS disable_raw_mode(ls); +#endif free_hist(ls); +#if HAVE_TERMIOS free_undo_stack(ls); +#endif lino_os.free_fn(ls->clip); ls->clip = 0; lino_os.free_fn(ls->result); @@ -2729,6 +2754,8 @@ static void free_hist(lino_t *ls) { } } +#if HAVE_TERMIOS + /* At exit we'll try to fix the terminal to the initial conditions. */ static void atexit_handler(void) { lino_t *ls; @@ -2737,6 +2764,8 @@ static void atexit_handler(void) { lino_cleanup(ls); } +#endif + /* This is the API call to add a new entry in the linenoise history. * It uses a fixed array of char pointers that are shifted (memmoved) * when the history max length is reached in order to remove the older @@ -2776,7 +2805,9 @@ int lino_hist_add(lino_t *ls, const wchar_t *line) { } ls->history[ls->history_len] = linecopy; ls->history_len++; +#if HAVE_TERMIOS undo_renumber_hist_idx(ls, 1); +#endif return 1; } diff --git a/linenoise/linenoise.h b/linenoise/linenoise.h index 7fef68d9..bc72eaa7 100644 --- a/linenoise/linenoise.h +++ b/linenoise/linenoise.h @@ -92,6 +92,8 @@ typedef struct lino_os { wide_disp \ } +#if HAVE_TERMIOS + typedef struct lino_completions { size_t len; wchar_t **cvec; @@ -102,6 +104,8 @@ typedef void lino_compl_cb_t(const wchar_t *, lino_completions_t *, void *ctx); void lino_set_completion_cb(lino_t *, lino_compl_cb_t *, void *ctx); void lino_add_completion(lino_completions_t *, const wchar_t *); +#endif + void lino_init(lino_os_t *); lino_t *lino_make(mem_t *istream, mem_t *ostream); lino_t *lino_copy(lino_t *); @@ -66,9 +66,7 @@ #include "vm.h" #include "ffi.h" #include "txr.h" -#if HAVE_TERMIOS #include "linenoise/linenoise.h" -#endif val parser_s, unique_s, circref_s; val listener_hist_len_s, listener_multi_line_p_s, listener_sel_inclusive_p_s; @@ -863,8 +861,6 @@ val txr_parse(val source_in, val error_stream, return pi->syntax_tree; } -#if HAVE_TERMIOS - static void report_security_problem(val name) { val self = lit("listener"); @@ -928,6 +924,8 @@ static void load_rcfile(val name) uw_catch_end; } +#if HAVE_TERMIOS + static val get_visible_syms(val package, int include_fallback) { val fblist; @@ -1159,6 +1157,8 @@ static wchar_t *provide_atom(lino_t *l, const wchar_t *str, int n, void *ctx) return out; } +#endif + static val repl_intr(val signo, val async_p) { (void) signo; @@ -1520,8 +1520,11 @@ val repl(val bindings, val in_stream, val out_stream, val env) reg_varl(result_hash_sym, result_hash); +#if HAVE_TERMIOS lino_set_completion_cb(ls, provide_completions, 0); lino_set_atom_cb(ls, provide_atom, 0); +#endif + lino_set_enter_cb(ls, is_balanced_line, 0); lino_set_tempfile_suffix(ls, ".tl"); @@ -1680,8 +1683,6 @@ val repl(val bindings, val in_stream, val out_stream, val env) return nil; } -#endif - val parser_errors(val parser) { val self = lit("parser-errors"); @@ -138,9 +138,7 @@ val read_eval_stream(val self, val stream, val error_stream); val read_compiled_file(val self, val stream, val error_stream); val txr_parse(val source, val error_stream, val error_return_val, val name_in); -#if HAVE_TERMIOS val repl(val bindings, val in_stream, val out_stream, val env); -#endif void parser_common_init(parser_t *); void parser_cleanup(parser_t *); val parser(val stream, val name, val lineno); @@ -63,6 +63,12 @@ #endif #include "txr.h" +#if HAVE_TERMIOS +#define if_termios(THEN, ELSE) (THEN) +#else +#define if_termios(THEN, ELSE) (ELSE) +#endif + const wchli_t *version = wli(TXR_VER); #ifdef TXR_BUILD_ID const wchli_t *build_id = wli(TXR_BUILD_ID); @@ -70,7 +76,7 @@ const wchli_t *build_id = wli(TXR_BUILD_ID); wchar_t *progname; static const char *progname_u8; static val prog_path = nil, sysroot_path = nil; -int opt_noninteractive; +int opt_noninteractive = if_termios(0, 1); int opt_noprofile; int opt_compat; int opt_dbg_expansion; @@ -87,10 +93,8 @@ static void help(void) "\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 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" @@ -182,7 +186,6 @@ static void help(void) format(std_output, text, static_str(version), prog_string, nao); } -#if HAVE_TERMIOS static void banner(val self) { if (!isatty(c_int(stream_fd(std_input), self))) @@ -192,18 +195,12 @@ static void banner(val self) 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"), - 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")), + if_termios(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) { @@ -577,13 +574,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(self); goto repl; -#else - hint(); - return EXIT_FAILURE; -#endif } for (ref_arg_list = arg_list, arg = upop(&arg_list, &arg_undo); @@ -1047,15 +1039,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 @@ -1111,13 +1096,8 @@ int txr_main(int argc, char **argv) goto repl; if (evaled) return EXIT_SUCCESS; -#if HAVE_TERMIOS banner(self); goto repl; -#else - hint(); - return EXIT_FAILURE; -#endif } drop_privilege(); @@ -1199,7 +1179,6 @@ int txr_main(int argc, char **argv) } repl: -#if HAVE_TERMIOS if (compat_val) format(std_output, lit("Note: operating in TXR ~a compatibility mode " @@ -1211,6 +1190,5 @@ repl: 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; } |