From: Nick Bowler Date: Wed, 5 Jul 2023 01:15:39 +0000 (-0400) Subject: cdecl99: Fall back to getline, instead of Gnulib's readline. X-Git-Tag: v1.3~134 X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/commitdiff_plain/247d234f2e263700e0a7ce7f6c9219d010c182ca cdecl99: Fall back to getline, instead of Gnulib's readline. When building without readline, instead of using Gnulib's readline replacement, use getline directly. We can combine most of the batch and interactive mode processing loops which saves a bunch of pointless extra code in the readline-disabled case. To actually do this, we prepare a Gnulib "local dir" to implement a cut-down readline module that includes the configure tests only. --- diff --git a/.gitignore b/.gitignore index 2a3a25d..b99d82d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,6 @@ /exported.sh /gitlog-to-changelog /install-sh -/lib /libtool /ltmain.sh /missing diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000..baacf4f --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1,3 @@ +/* +!/.gitignore +!/local diff --git a/lib/local/modules/gnulib-local b/lib/local/modules/gnulib-local new file mode 100644 index 0000000..20e3120 --- /dev/null +++ b/lib/local/modules/gnulib-local @@ -0,0 +1,35 @@ +Description: +Helper to export gnulib-tool local-dir settings to Automake and distribute +files automatically. + +configure.ac: +AC_REQUIRE([AC_PROG_AWK])dnl +m4_pushdef([gl_LOCAL_DIR], + [m4_define([_GNULIB_LOCAL_DIR_], $][@)])m4_divert_push([KILL]) +m4_include([m4/gnulib-cache.m4]) +m4_popdef([gl_LOCAL_DIR])m4_divert_pop([KILL])dnl +AC_SUBST([GNULIB_LOCAL_DIR], m4_defn([_GNULIB_LOCAL_DIR_])) + +Makefile.am: +GNULIB_LOCAL_DIST = modules/gnulib-local +GNULIB_LOCAL_DIRS_AWK = \ + { for (i=1; i<=NF; i++) { sub(/\/[^\/]*$$/, "", $$i); dirs[$$i]=1; } } \ + END { for (i in dirs) print outdir "/" i; } + +dist-hook: dist-gnulib-local +dist-gnulib-local: + save_IFS=$$IFS; \ + IFS=:; set x $(GNULIB_LOCAL_DIR); shift; \ + IFS=$$save_IFS; \ + outdir="$(top_distdir)/$$1"; \ + dirs=`echo $(GNULIB_LOCAL_DIST) \ + | $(AWK) '$(GNULIB_LOCAL_DIRS_AWK)' outdir="$$outdir"`; \ + ( set -x; $(MKDIR_P) $$dirs && chmod u+w $$dirs ) || exit; \ + for f in $(GNULIB_LOCAL_DIST); do \ + for indir; do \ + test -f "$(top_srcdir)/$$indir/$$f" || continue; \ + ( set -x; cp -p "$(top_srcdir)/$$indir/$$f" "$$outdir/$$f" ) || exit; \ + break; \ + done; \ + done +.PHONY: dist-gnulib-local diff --git a/lib/local/modules/readline b/lib/local/modules/readline new file mode 100644 index 0000000..3a9c7f4 --- /dev/null +++ b/lib/local/modules/readline @@ -0,0 +1,30 @@ +Description: +Simple implementation of readline, modified to include only the +Autoconf library tests (2023-07). + +Files: +m4/readline.m4 + +Depends-on: +gnulib-local +havelib + +configure.ac: +gl_FUNC_READLINE + +Makefile.am: +GNULIB_LOCAL_DIST += modules/readline + +Include: +#if HAVE_READLINE_READLINE_H +# include +#endif + +Link: +$(LTLIBREADLINE) when linking with libtool, $(LIBREADLINE) otherwise + +License: +GPL + +Maintainer: +Simon Josefsson diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4 index 2b29495..c970305 100644 --- a/m4/gnulib-cache.m4 +++ b/m4/gnulib-cache.m4 @@ -27,7 +27,7 @@ # Specification in the form of a command-line invocation: -# gnulib-tool --import \ +# gnulib-tool --import --local-dir=lib/local \ # --lib=libgnu \ # --source-base=lib \ # --m4-base=m4 \ @@ -53,7 +53,7 @@ # tls # Specification in the form of a few gnulib-tool.m4 macro invocations: -gl_LOCAL_DIR([]) +gl_LOCAL_DIR([lib/local]) gl_MODULES([ getline getopt-gnu diff --git a/src/cdecl99.c b/src/cdecl99.c index 5ddc889..d7ddd77 100644 --- a/src/cdecl99.c +++ b/src/cdecl99.c @@ -29,7 +29,6 @@ #include #include -#include #include #include @@ -40,6 +39,10 @@ #include "copysym.h" #include "options.h" +#if HAVE_READLINE_READLINE_H +# include +#endif + static const char *progname = "cdecl99"; static bool interactive = true; @@ -112,22 +115,6 @@ static int is_blank_line(const char *line) return !line[strspn(line, " \t")]; } -static int repl(void) -{ - char *line; - - for (; (line = readline("> ")); free(line)) { - if (!is_blank_line(line)) - add_history(line); - - if (run_command(line, true) > 0) - break; - } - - free(line); - return 0; -} - static int repl_cmdline(unsigned count, char **commands) { int ret = 0; @@ -144,32 +131,59 @@ static int repl_cmdline(unsigned count, char **commands) return ret; } -static int repl_noninteractive(void) +static int do_getline(char **linebuf, size_t *n) { - int rc, ret = 0, saved_errno; - char *line = NULL; - size_t n; + ssize_t rc; - while (getline(&line, &n, stdin) >= 0) { - char *c = strchr(line, '\n'); - if (c) - *c = '\0'; + if ((rc = getline(linebuf, n, stdin)) < 0) { + if (ferror(stdin)) + print_error("%s", strerror(errno)); + return 0; + } - rc = run_command(line, false); - if (rc < 0) - ret = -1; - else if (rc > 0) - break; + if (rc-- && (*linebuf)[rc] == '\n') + (*linebuf)[rc] = '\0'; + return 1; +} + +static int do_readline(char **linebuf, size_t *n, int interactive) +{ +#if !HAVE_READLINE + if (interactive) { + fputs("> ", stdout); + fflush(stdout); } - saved_errno = errno; - free(line); + return do_getline(linebuf, n); +#else + if (!interactive) + return do_getline(linebuf, n); + + free(*linebuf); + if (!(*linebuf = readline("> "))) + return 0; + + if (!is_blank_line(*linebuf)) + add_history(*linebuf); + return 1; +#endif +} + +static int repl(int interactive) +{ + char *line = NULL; + int ret = 0; + size_t n; - if (ferror(stdin)) { - print_error("%s", strerror(saved_errno)); - return -1; + while (do_readline(&line, &n, interactive)) { + int rc = run_command(line, interactive); + if (rc > 0) + break; + else if (rc < 0) + ret = -!interactive; } + free(line); return ret; } @@ -270,12 +284,10 @@ int main(int argc, char **argv) case INIT_EXIT_FAILURE: return EXIT_FAILURE; } - if (interactive) - rc = repl(); - else if (execute) + if (execute) rc = repl_cmdline(execute, argv); else - rc = repl_noninteractive(); + rc = repl(interactive); if (rc != 0) return EXIT_FAILURE;