Compare commits

..

No commits in common. "master" and "1.16.1" have entirely different histories.

22 changed files with 408 additions and 750 deletions

View File

@ -23,7 +23,7 @@ addons:
description: "A small line editing library" description: "A small line editing library"
notification_email: troglobit@gmail.com notification_email: troglobit@gmail.com
build_command_prepend: "./autogen.sh && ./configure --enable-sigstop --enable-terminal-bell" build_command_prepend: "./autogen.sh && ./configure --enable-sigstop --enable-terminal-bell"
build_command: "make clean all" build_command: "make -j5"
branch_pattern: dev branch_pattern: dev
# We don't store generated files (configure and Makefile) in GIT, # We don't store generated files (configure and Makefile) in GIT,
@ -31,4 +31,4 @@ addons:
script: script:
- ./autogen.sh - ./autogen.sh
- ./configure --enable-sigstop --enable-terminal-bell - ./configure --enable-sigstop --enable-terminal-bell
- make clean all - make -j5

View File

@ -4,35 +4,8 @@ Change Log
All notable changes to the project are documented in this file. All notable changes to the project are documented in this file.
[1.17.1][] - 2020-02-23 [1.16.1] - 2019-06-07
----------------------- ---------------------
### Fixes
- Fix #38: Fix for multiline representing as one line
- Fix packaging, missing files in libeditline1, regression from 1.16.0
- Fix packaging, update to latest std version
- Fix formatting of function names in man page
- Restore tar.gz distribution, for usability on systems that do not
have xz in their default install
[1.17.0][] - 2020-01-05
-----------------------
### Changes
- Simple multi-line support by Dima Volynets, @dvolynets
### Fixes
- Fix return value from `read_history()` and `write_history()`, could
return `errno` instead of `EOF` to indicate error. Now both functions
have uniform return values on error
- Handle internal `realloc()` errors better. Now memory is not leaked
if `realloc()` fails
- Fix possible NULL pointer dereference in key binding lookup function
[1.16.1][] - 2019-06-07
-----------------------
### Changes ### Changes
- Major updates to the `editline.3` man page - Major updates to the `editline.3` man page
@ -249,9 +222,7 @@ Adaptations to Debian editline package.
- First version, forked from Minix current 2008-06-06 - First version, forked from Minix current 2008-06-06
[UNRELEASED]: https://github.com/troglobit/finit/compare/1.17.1...HEAD [UNRELEASED]: https://github.com/troglobit/finit/compare/1.16.0...HEAD
[1.17.1]: https://github.com/troglobit/finit/compare/1.17.0...1.17.1
[1.17.0]: https://github.com/troglobit/finit/compare/1.16.1...1.17.0
[1.16.1]: https://github.com/troglobit/finit/compare/1.16.0...1.16.1 [1.16.1]: https://github.com/troglobit/finit/compare/1.16.0...1.16.1
[1.16.0]: https://github.com/troglobit/finit/compare/1.15.3...1.16.0 [1.16.0]: https://github.com/troglobit/finit/compare/1.15.3...1.16.0
[1.15.3]: https://github.com/troglobit/finit/compare/1.15.2...1.15.3 [1.15.3]: https://github.com/troglobit/finit/compare/1.15.2...1.15.3
@ -269,3 +240,9 @@ Adaptations to Debian editline package.
[Travis-CI]: https://travis-ci.org/troglobit/uftpd [Travis-CI]: https://travis-ci.org/troglobit/uftpd
[Coverity Scan]: https://scan.coverity.com/projects/2947 [Coverity Scan]: https://scan.coverity.com/projects/2947
[README.md]: https://github.com/troglobit/editline/blob/master/README.md [README.md]: https://github.com/troglobit/editline/blob/master/README.md
<!--
-- Local Variables:
-- mode: markdown
-- End:
-->

View File

@ -2,11 +2,11 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libeditline.pc pkgconfig_DATA = libeditline.pc
doc_DATA = README.md LICENSE doc_DATA = README.md LICENSE
EXTRA_DIST = README.md LICENSE ChangeLog.md INSTALL.md EXTRA_DIST = README.md LICENSE ChangeLog.md INSTALL.md
SUBDIRS = src include man SUBDIRS = src include man examples
if ENABLE_EXAMPLES ## Generate .deb package
SUBDIRS += examples package build-deb:
endif @dpkg-buildpackage -uc -us
## Generate MD5 checksum file ## Generate MD5 checksum file
MD5 = md5sum MD5 = md5sum
@ -39,7 +39,7 @@ package:
dpkg-buildpackage -uc -us -B dpkg-buildpackage -uc -us -B
## Target to run when building a release ## Target to run when building a release
release: release-hook distcheck md5-dist package release: distcheck release-hook md5-dist package
@echo @echo
@echo "Resulting release files:" @echo "Resulting release files:"
@echo "=========================================================================" @echo "========================================================================="

View File

@ -33,8 +33,6 @@ to use the library is available in the `examples/` directory.
Editline is maintained collaboratively at [GitHub][]. Editline is maintained collaboratively at [GitHub][].
> **Note:** Windows is not a supported target for editline.
Example Example
------- -------
@ -58,7 +56,6 @@ sub-directory.
e.g. `~/src/example.c` e.g. `~/src/example.c`
```C ```C
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <editline.h> #include <editline.h>
@ -198,7 +195,6 @@ current maintainer works exclusively on GNU/Linux systems, so it may use
GCC and GNU Make specific extensions here and there. This is not on GCC and GNU Make specific extensions here and there. This is not on
purpose and patches or pull requests to correct this are most welcome! purpose and patches or pull requests to correct this are most welcome!
0. Call <kbd>./autogen.sh</kbd> if you build from git
1. Configure editline with default features: <kbd>./configure</kbd> 1. Configure editline with default features: <kbd>./configure</kbd>
2. Build the library and examples: <kbd>make all</kbd> 2. Build the library and examples: <kbd>make all</kbd>
3. Install using <kbd>make install</kbd> 3. Install using <kbd>make install</kbd>

View File

@ -1,6 +1,5 @@
AC_INIT(editline, 1.17.1, https://github.com/troglobit/editline/issues) AC_INIT(editline, 1.16.1, https://github.com/troglobit/editline/issues)
AC_CONFIG_AUX_DIR(aux) AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
AM_INIT_AUTOMAKE([1.11 foreign dist-xz])
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
@ -61,35 +60,29 @@ AC_ARG_ENABLE(terminal-bell,
AC_ARG_ENABLE(termcap, AC_ARG_ENABLE(termcap,
AS_HELP_STRING([--enable-termcap], [Use termcap library to query terminal size.])) AS_HELP_STRING([--enable-termcap], [Use termcap library to query terminal size.]))
AC_ARG_ENABLE([examples],
[AC_HELP_STRING([--enable-examples], [Build examples/ directory])],
[], [enable_examples=no])
# #
# Check what features have been enabled # Check what features have been enabled
# #
AS_IF([test "x$enable_unique_history" != "xno"], [ AS_IF([test "x$enable_unique_history" != "xno"],
AC_DEFINE(CONFIG_UNIQUE_HISTORY, 1, [Define to skip duplicate lines in the scrollback history.])]) AC_DEFINE(CONFIG_UNIQUE_HISTORY, 1, [Define to skip duplicate lines in the scrollback history.]))
AS_IF([test "x$enable_terminal_bell" != "xno"], [ AS_IF([test "x$enable_terminal_bell" != "xno"],
AC_DEFINE(CONFIG_ANSI_ARROWS, 1, [Define to include ANSI arrow keys support.])]) AC_DEFINE(CONFIG_ANSI_ARROWS, 1, [Define to include ANSI arrow keys support.]))
AS_IF([test "x$enable_eof" != "xno"], [ AS_IF([test "x$enable_eof" != "xno"],
AC_DEFINE(CONFIG_EOF, 1, [Define to enable EOF (Ctrl-D) key.])]) AC_DEFINE(CONFIG_EOF, 1, [Define to enable EOF (Ctrl-D) key.]))
AS_IF([test "x$enable_sigint" != "xno"], [ AS_IF([test "x$enable_sigint" != "xno"],
AC_DEFINE(CONFIG_SIGINT, 1, [Define to enable SIGINT (Ctrl-C) key.])]) AC_DEFINE(CONFIG_SIGINT, 1, [Define to enable SIGINT (Ctrl-C) key.]))
AS_IF([test "x$enable_sigstop" = "xyes"], [ AS_IF([test "x$enable_sigstop" = "xyes"],
AC_DEFINE(CONFIG_SIGSTOP, 1, [Define to enable SIGSTOP (Ctrl-Z) key.])]) AC_DEFINE(CONFIG_SIGSTOP, 1, [Define to enable SIGSTOP (Ctrl-Z) key.]))
AS_IF([test "x$enable_terminal_bell" = "xyes"], [ AS_IF([test "x$enable_terminal_bell" = "xyes"],
AC_DEFINE(CONFIG_TERMINAL_BELL, 1, [Define to enable terminal bell on completion.])]) AC_DEFINE(CONFIG_TERMINAL_BELL, 1, [Define to enable terminal bell on completion.]))
AM_CONDITIONAL([ENABLE_EXAMPLES], [test "$enable_examples" = yes])
# Check for a termcap compatible library if enabled # Check for a termcap compatible library if enabled
AS_IF([test "x$enable_termcap" = "xyes"], [ AS_IF([test "x$enable_termcap" = "xyes"],
AC_DEFINE(CONFIG_USE_TERMCAP, 1, [Define to use the termcap library for terminal size.]) AC_DEFINE(CONFIG_USE_TERMCAP, 1, [Define to use the termcap library for terminal size.])
AC_CHECK_LIB(terminfo, tgetent, , [ AC_CHECK_LIB(terminfo, tgetent, , [
AC_CHECK_LIB(termcap, tgetent, , [ AC_CHECK_LIB(termcap, tgetent, , [
@ -100,7 +93,7 @@ AS_IF([test "x$enable_termcap" = "xyes"], [
]) ])
]) ])
]) ])
])]) ]))
# Generate all files # Generate all files
AC_OUTPUT AC_OUTPUT

17
debian/changelog vendored
View File

@ -1,20 +1,3 @@
editline (1.17.1) stable; urgency=medium
* Fix multiline representing as one line
* Fix missing content in libedtline1, introduced in 1.16.0
* Update packaging to latest std version
-- Joachim Nilsson <troglobit@gmail.com> Sun, 23 Feb 2020 18:46:41 +0100
editline (1.17.0) unstable; urgency=medium
* Simple multi-line support
* Handle internal realloc() errors better
* Fix return value from read_history() and write_history()
* Fix potential NULL pointer dereference in key binging lookup
-- Joachim Nilsson <troglobit@gmail.com> Sun, 05 Jan 2020 09:47:34 +0100
editline (1.16.1) unstable; urgency=medium editline (1.16.1) unstable; urgency=medium
* Minor bug fix and documentation update release. * Minor bug fix and documentation update release.

2
debian/compat vendored
View File

@ -1 +1 @@
10 9

8
debian/control vendored
View File

@ -1,9 +1,9 @@
Source: editline Source: editline
Section: devel Section: devel
Priority: optional Priority: optional
Build-Depends: debhelper (>= 10), libtool Build-Depends: debhelper (>= 5.0), libtool
Maintainer: Joachim Wiberg <troglobit@gmail.com> Maintainer: Joachim Nilsson <troglobit@gmail.com>
Standards-Version: 4.3.0 Standards-Version: 3.8.3
Package: libeditline-dev Package: libeditline-dev
Architecture: any Architecture: any
@ -21,7 +21,7 @@ Description: development files for libeditline
Package: libeditline1 Package: libeditline1
Architecture: any Architecture: any
Section: libs Section: libs
Depends: ${shlibs:Depends}, ${misc:Depends} Depends: ${misc:Depends}
Description: line editing library similar to readline Description: line editing library similar to readline
This is a line-editing library. It can be linked into almost any program This is a line-editing library. It can be linked into almost any program
to provide command-line editing and recall. It is call-compatible with a to provide command-line editing and recall. It is call-compatible with a

25
debian/copyright vendored
View File

@ -1,23 +1,17 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ This package was debianized by Jim Studt <jim@federated.com> on
Upstream-Name: editline Fri, 5 May 2000 13:25:51 -0500.
Upstream-Contact: Joachim Wiberg <troglobit@gmail.com>
Source: http://github.com/troglobit/editline
Comment: This package was originally debianized by Jim Studt <jim@federated.com>
on Fri, 5 May 2000 13:25:51 -0500. It was received from, then upstream
author, Rich Salz <rsalz@shore.net>
Files: * It was received from Rich Salz rsalz@shore.net
Copyright: 1992,1993 Simmule Turner and Rich Salz.
License: C-News
Files: debian/* Upstream Author: Rich Salz rsalz@shore.net
Copyright: 2010-2020 Joachim Wiberg <troglobit@gmail.com>
License: BSD-2-clause Copyright:
Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved.
License: C-News
This software is not subject to any license of the American Telephone This software is not subject to any license of the American Telephone
and Telegraph Company or of the Regents of the University of California. and Telegraph Company or of the Regents of the University of California.
.
Permission is granted to anyone to use this software for any purpose on Permission is granted to anyone to use this software for any purpose on
any computer system, and to alter it and redistribute it freely, subject any computer system, and to alter it and redistribute it freely, subject
to the following restrictions: to the following restrictions:
@ -30,3 +24,4 @@ License: C-News
misrepresented as being the original software. Since few users misrepresented as being the original software. Since few users
ever read sources, credits must appear in the documentation. ever read sources, credits must appear in the documentation.
4. This notice may not be removed or altered. 4. This notice may not be removed or altered.

View File

@ -1,5 +1,4 @@
usr/include/*.h usr/include/*.h
usr/lib/*/libeditline*.*a usr/lib/*/libeditline*.*a
usr/lib/*/libeditline.so
usr/lib/*/pkgconfig/* usr/lib/*/pkgconfig/*
usr/share/man/man3/* usr/share/man/man3/*

1
debian/libeditline0.install vendored Normal file
View File

@ -0,0 +1 @@
usr/lib/*/libeditline*.so*

View File

@ -1 +0,0 @@
usr/lib/*/libeditline.so.*

View File

@ -1,67 +0,0 @@
libeditline.so.1 libeditline1 #MINVER#
* Build-Depends-Package: libeditline-dev
add_history@Base 1.17.1
el_bind_key@Base 1.17.1
el_bind_key_in_metamap@Base 1.17.1
el_del_char@Base 1.17.1
el_filename_complete@Base 1.17.1
el_filename_list_possib@Base 1.17.1
el_find_word@Base 1.17.1
el_hist_size@Base 1.17.1
el_next_hist@Base 1.17.1
el_no_echo@Base 1.17.1
el_no_hist@Base 1.17.1
el_prev_hist@Base 1.17.1
el_print_columns@Base 1.17.1
el_ring_bell@Base 1.17.1
prompt_len@Base 1.17.1
read_history@Base 1.17.1
readline@Base 1.17.1
rl_add_slash@Base 1.17.1
rl_attempted_completion_function@Base 1.17.1
rl_attempted_completion_over@Base 1.17.1
rl_callback_handler_install@Base 1.17.1
rl_callback_handler_remove@Base 1.17.1
rl_callback_read_char@Base 1.17.1
rl_clear_message@Base 1.17.1
rl_complete@Base 1.17.1
rl_completion_entry_function@Base 1.17.1
rl_completion_matches@Base 1.17.1
rl_deprep_term_function@Base 1.17.1
rl_deprep_terminal@Base 1.17.1
rl_end@Base 1.17.1
rl_eof@Base 1.17.1
rl_erase@Base 1.17.1
rl_event_hook@Base 1.17.1
rl_filename_completion_function@Base 1.17.1
rl_forced_update_display@Base 1.17.1
rl_getc@Base 1.17.1
rl_getc_function@Base 1.17.1
rl_inhibit_complete@Base 1.17.1
rl_initialize@Base 1.17.1
rl_insert_text@Base 1.17.1
rl_instream@Base 1.17.1
rl_intr@Base 1.17.1
rl_kill@Base 1.17.1
rl_line_buffer@Base 1.17.1
rl_list_possib@Base 1.17.1
rl_mark@Base 1.17.1
rl_meta_chars@Base 1.17.1
rl_outstream@Base 1.17.1
rl_point@Base 1.17.1
rl_prep_term_function@Base 1.17.1
rl_prep_terminal@Base 1.17.1
rl_prompt@Base 1.17.1
rl_quit@Base 1.17.1
rl_readline_name@Base 1.17.1
rl_refresh_line@Base 1.17.1
rl_reset_terminal@Base 1.17.1
rl_restore_prompt@Base 1.17.1
rl_save_prompt@Base 1.17.1
rl_set_complete_func@Base 1.17.1
rl_set_getc_func@Base 1.17.1
rl_set_list_possib_func@Base 1.17.1
rl_set_prompt@Base 1.17.1
rl_ttyset@Base 1.17.1
rl_uninitialize@Base 1.17.1
write_history@Base 1.17.1

12
debian/rules vendored
View File

@ -1,16 +1,8 @@
#!/usr/bin/make -f #!/usr/bin/make -f
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1 #export DH_VERBOSE=1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
export DEB_CFLAGS_MAINT_APPEND = -W -Wall -Wextra -O3
export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
include /usr/share/dpkg/default.mk # provides DEB_VERSION
%: %:
dh $@ --with autoreconf dh $@ --with autoreconf
override_dh_installchangelogs:
dh_installchangelogs ChangeLog.md

View File

@ -64,10 +64,7 @@ static int my_rl_list_possib(char *token, char ***av)
for (num = 0; list[num]; num++) for (num = 0; list[num]; num++)
; ;
if (!num) copy = (char **) malloc (num * sizeof(char *));
return 0;
copy = malloc(num * sizeof(char *));
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
if (!strncmp (list[i], token, strlen (token))) { if (!strncmp (list[i], token, strlen (token))) {
copy[total] = strdup (list[i]); copy[total] = strdup (list[i]);
@ -109,41 +106,14 @@ el_status_t do_suspend(void)
static void breakit(int signo) static void breakit(int signo)
{ {
(void)signo;
puts("Got SIGINT"); puts("Got SIGINT");
} }
/* Use el_no_echo when reading passwords and similar */
static int unlock(const char *passwd)
{
char *prompt = "Enter password: ";
char *line;
int rc = 1;
el_no_echo = 1;
while ((line = readline(prompt))) {
rc = strncmp(line, passwd, strlen(passwd));
free(line);
if (rc) {
printf("\nWrong password, please try again, it's secret.\n");
continue;
}
printf("\nAchievement unlocked!\n");
break;
}
el_no_echo = 0;
return rc;
}
int main(void) int main(void)
{ {
char *line; char *line;
char *prompt = "cli> "; char *prompt = "cli> ";
char *passwd = "Enter password: ";
signal(SIGINT, breakit); signal(SIGINT, breakit);
@ -156,11 +126,29 @@ int main(void)
read_history(HISTORY); read_history(HISTORY);
while ((line = readline(prompt))) { while ((line = readline(prompt))) {
if (!strncmp(line, "unlock", 6) && unlock("secret")) { int next = 0;
/* Use el_no_echo when reading passwords and similar */
if (!strncmp(line, "unlock", 6)) {
el_no_echo = 1;
while ((line = readline(passwd))) {
if (strncmp(line, "secret", 6)) {
printf("\nWrong password, please try again, it's secret.\n");
free(line); free(line);
fprintf(stderr, "\nSecurity breach, user logged out!\n"); continue;
}
el_no_echo = 0;
printf("\nAchievement unlocked!\n");
free(line);
next = 1;
break; break;
} }
}
if (next)
continue;
if (*line != '\0') if (*line != '\0')
printf("\t\t\t|%s|\n", line); printf("\t\t\t|%s|\n", line);

View File

@ -39,7 +39,6 @@ Jeff
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/select.h>
#ifdef HAVE_STDLIB_H #ifdef HAVE_STDLIB_H
#include <stdlib.h> #include <stdlib.h>

View File

@ -7,7 +7,6 @@
*/ */
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/file.h> #include <sys/file.h>
@ -23,7 +22,7 @@
#include "editline.h" #include "editline.h"
void too_dangerous(char *caller); void too_dangerous(char *caller);
void initialize_readline(const char *prompt); void initialize_readline();
int execute_line(char *line); int execute_line(char *line);
int valid_argument(char *caller, char *arg); int valid_argument(char *caller, char *arg);
@ -62,15 +61,8 @@ struct cmd commands[] = {
}; };
/* Forward declarations. */ /* Forward declarations. */
char *stripwhite(char *string); char *stripwhite();
struct cmd *find_command(char *name); struct cmd *find_command();
/* ~/.fileman_history */
char *fileman_history;
/* Prompt base and current */
const char *prompt_init;
char *prompt_curr;
/* When non-zero, this means the user is done using this program. */ /* When non-zero, this means the user is done using this program. */
int done; int done;
@ -80,11 +72,12 @@ int main(int argc, char **argv)
char *line, *s; char *line, *s;
setlocale(LC_CTYPE, ""); setlocale(LC_CTYPE, "");
initialize_readline("(FileMan)");
initialize_readline(); /* Bind our completer. */
/* Loop reading and executing lines until the user quits. */ /* Loop reading and executing lines until the user quits. */
for (; done == 0;) { for (; done == 0;) {
line = readline(NULL); line = readline("FileMan: ");
if (!line) if (!line)
break; break;
@ -114,10 +107,6 @@ int main(int argc, char **argv)
free(line); free(line);
} }
puts("");
write_history(fileman_history);
free(fileman_history);
return 0; return 0;
} }
@ -199,58 +188,19 @@ char *stripwhite(char *string)
char *command_generator(const char *, int); char *command_generator(const char *, int);
char **fileman_completion(const char *, int, int); char **fileman_completion(const char *, int, int);
void fileman_prompt(void);
/* /*
* Tell the GNU Readline library how to complete. We want to try to * Tell the GNU Readline library how to complete. We want to try to
* complete on command names if this is the first word in the line, or * complete on command names if this is the first word in the line, or
* on filenames if not. * on filenames if not.
*/ */
void initialize_readline(const char *prompt) void initialize_readline(void)
{ {
const char *home;
size_t len;
/* Allow conditional parsing of the ~/.inputrc file. */ /* Allow conditional parsing of the ~/.inputrc file. */
rl_readline_name = "FileMan"; rl_readline_name = "FileMan";
/* Tell the completer that we want a crack first. */ /* Tell the completer that we want a crack first. */
rl_attempted_completion_function = fileman_completion; rl_attempted_completion_function = fileman_completion;
/* Restore command history */
home = getenv("HOME");
len = (home ? strlen(home) : 0) + 14;
fileman_history = malloc(len);
assert(fileman_history);
snprintf(fileman_history, len, "%s/.fileman_history", home ? home : ".");
read_history(fileman_history);
/* Prompt is updated when moving around in the tree */
prompt_init = prompt;
fileman_prompt();
}
/*
* Update prompt when changing directory. Use an allocated string to
* show off the rl_set_prompt() API for issue #51.
*/
void fileman_prompt(void)
{
char cwd[1024];
size_t len;
if (prompt_curr)
free(prompt_curr);
assert(getcwd(cwd, sizeof(cwd)));
len = strlen(prompt_init) + strlen(cwd) + 10;
prompt_curr = malloc(len);
assert(prompt_curr);
snprintf(prompt_curr, len, "%s %s/> ", prompt_init, cwd);
rl_set_prompt(prompt_curr);
} }
/* /*
@ -427,8 +377,7 @@ int com_cd(char *arg)
return 1; return 1;
} }
//com_pwd(""); com_pwd("");
fileman_prompt();
return 0; return 0;
} }

View File

@ -21,8 +21,6 @@
#ifndef EDITLINE_H_ #ifndef EDITLINE_H_
#define EDITLINE_H_ #define EDITLINE_H_
#include <stdio.h>
/* Handy macros when binding keys. */ /* Handy macros when binding keys. */
#define CTL(x) ((x) & 0x1F) #define CTL(x) ((x) & 0x1F)
#define ISCTL(x) ((x) && (x) < ' ') #define ISCTL(x) ((x) && (x) < ' ')
@ -84,7 +82,6 @@ extern int rl_point;
extern int rl_mark; extern int rl_mark;
extern int rl_end; extern int rl_end;
extern int rl_inhibit_complete; extern int rl_inhibit_complete;
extern int rl_attempted_completion_over;
extern char *rl_line_buffer; extern char *rl_line_buffer;
extern const char *rl_readline_name; extern const char *rl_readline_name;
extern FILE *rl_instream; /* The stdio stream from which input is read. Defaults to stdin if NULL - Not supported yet! */ extern FILE *rl_instream; /* The stdio stream from which input is read. Defaults to stdin if NULL - Not supported yet! */

View File

@ -1,4 +1,4 @@
.Dd February 23, 2020 .Dd April 27, 2019
.Dt EDITLINE 3 .Dt EDITLINE 3
.Os .Os
.Sh NAME .Sh NAME
@ -8,22 +8,10 @@
.Lb libeditline .Lb libeditline
.Sh SYNOPSIS .Sh SYNOPSIS
.In editline.h .In editline.h
.Ft char * .Fn "char *readline" "const char *prompt"
.Fo readline .Fn "void add_history" "const char *line"
.Fa const char *prompt .Fn "int read_history" "const char *filename"
.Fc .Fn "int write_history" "const char *filename"
.Ft void
.Fo add_history
.Fa const char *line
.Fc
.Ft int
.Fo read_history
.Fa const char *filename
.Fc
.Ft int
.Fo write_history
.Fa const char *filename
.Fc
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
is a library that provides n line-editing interface with history. It is a library that provides n line-editing interface with history. It
@ -275,13 +263,12 @@ int main(void)
The original editline library was posted to comp.sources.unix newsgroup The original editline library was posted to comp.sources.unix newsgroup
by created by Simmule R. Turner and Rich Salz in 1992. It now exists in by created by Simmule R. Turner and Rich Salz in 1992. It now exists in
several forks: Debian, Minix, Heimdal, Festival speech tools, Mozilla, several forks: Debian, Minix, Heimdal, Festival speech tools, Mozilla,
Google Gadgets for Linux, and many others. The original manual page was Google Gadgets for Linux, and many other places. The original manual
made by David W. Sanderson. page was made by David W. Sanderson.
.Pp .Pp
This version stems from the Minix 2 sources, but has since evolved to This version was originally based on the Minix 2 sources, but has since
include patches from all relevant forks. It is currently maintained by evolved to include patches from all relevant forks. It is currently
.An Joachim Wiberg maintained by Joachim Nilsson at GitHub,
at .Aq http://github.com/troglobit/editline
.Lk https://github.com/troglobit/editline "GitHub" .
.Sh BUGS .Sh BUGS
Does not handle multiple lines or unicode characters well. Does not handle multiple lines or unicode characters well.

View File

@ -3,4 +3,4 @@ libeditline_la_SOURCES = editline.c editline.h complete.c sysunix.c unix.h
libeditline_la_CFLAGS = -std=gnu99 libeditline_la_CFLAGS = -std=gnu99
libeditline_la_CFLAGS += -W -Wall -Wextra -Wundef -Wunused -Wstrict-prototypes libeditline_la_CFLAGS += -W -Wall -Wextra -Wundef -Wunused -Wstrict-prototypes
libeditline_la_CFLAGS += -Werror-implicit-function-declaration -Wshadow -Wcast-qual libeditline_la_CFLAGS += -Werror-implicit-function-declaration -Wshadow -Wcast-qual
libeditline_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:2:0 libeditline_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:1:0

View File

@ -40,7 +40,7 @@ static int compare(const void *p1, const void *p2)
/* Fill in *avp with an array of names that match file, up to its length. /* Fill in *avp with an array of names that match file, up to its length.
* Ignore . and .. . */ * Ignore . and .. . */
static int FindMatches(const char *dir, const char *file, char ***avp) static int FindMatches(char *dir, char *file, char ***avp)
{ {
char **av; char **av;
char **word; char **word;
@ -128,7 +128,7 @@ static int FindMatches(const char *dir, const char *file, char ***avp)
/* Split a pathname into allocated directory and trailing filename parts. */ /* Split a pathname into allocated directory and trailing filename parts. */
static int SplitPath(const char *path, char **dirpart, char **filepart) static int SplitPath(const char *path, char **dirpart, char **filepart)
{ {
static const char DOT[] = "."; static char DOT[] = ".";
char *dpart; char *dpart;
char *fpart; char *fpart;
@ -197,7 +197,7 @@ char *el_filename_complete(char *pathname, int *match)
if (ac == 1) { if (ac == 1) {
/* Exactly one match -- finish it off. */ /* Exactly one match -- finish it off. */
*match = 1; *match = 1;
j = strlen(av[0]) - len + 1; j = strlen(av[0]) - len + 2;
p = malloc(sizeof(char) * (j + 1)); p = malloc(sizeof(char) * (j + 1));
if (p) { if (p) {
memcpy(p, av[0] + len, j); memcpy(p, av[0] + len, j);
@ -243,7 +243,9 @@ char *el_filename_complete(char *pathname, int *match)
char *rl_filename_completion_function(const char *text, int state) char *rl_filename_completion_function(const char *text, int state)
{ {
static char **av, *dir, *file; char *dir;
char *file;
static char **av;
static size_t i, ac; static size_t i, ac;
if (!state) { if (!state) {
@ -251,47 +253,32 @@ char *rl_filename_completion_function(const char *text, int state)
return NULL; return NULL;
ac = FindMatches(dir, file, &av); ac = FindMatches(dir, file, &av);
if (!ac) {
free(dir); free(dir);
free(file); free(file);
if (!ac)
return NULL; return NULL;
}
i = 0; i = 0;
} }
if (i < ac) { if (i < ac)
size_t len = (dir ? strlen(dir) : 0) + strlen(av[i]) + 3; return av[i++];
char *ptr = malloc(len);
if (ptr) {
snprintf(ptr, len, "%s%s", dir, av[i++]);
if (ac == 1)
rl_add_slash(ptr, ptr);
return ptr;
}
}
do { do {
free(av[--i]); free(av[--i]);
} while (i > 0); } while (i > 0);
free(av);
free(dir);
free(file);
return NULL; return NULL;
} }
/* Similar to el_find_word(), but used by GNU Readline API */ /* Similar to el_find_word(), but used by GNU Readline API */
static char *rl_find_token(size_t *len) static char *rl_find_token(size_t *len)
{ {
const char *ptr; char *ptr;
int pos; int pos;
for (pos = rl_point; pos < rl_end; pos++) { for (pos = rl_point; pos < rl_end; pos++) {
if (isspace((unsigned char) rl_line_buffer[pos])) { if (isspace(rl_line_buffer[pos])) {
if (pos > 0) if (pos > 0)
pos--; pos--;
break; break;
@ -299,7 +286,7 @@ static char *rl_find_token(size_t *len)
} }
ptr = &rl_line_buffer[pos]; ptr = &rl_line_buffer[pos];
while (pos >= 0 && !isspace((unsigned char) rl_line_buffer[pos])) { while (pos >= 0 && !isspace(rl_line_buffer[pos])) {
if (pos == 0) if (pos == 0)
break; break;
@ -380,12 +367,8 @@ static char *complete(char *token, int *match)
free(word); free(word);
word = NULL; word = NULL;
if (words[0])
/* Exactly one match -- finish it off. */
if (words[0] && !words[1]) {
*match = 1;
word = strdup(words[0] + len); word = strdup(words[0] + len);
}
while (words[i]) while (words[i])
free(words[i++]); free(words[i++]);
@ -395,9 +378,6 @@ static char *complete(char *token, int *match)
return word; return word;
} }
if (word)
free(word);
fallback: fallback:
return el_filename_complete(token, match); return el_filename_complete(token, match);
} }

View File

@ -113,9 +113,6 @@ static int Searching = 0;
static const char *(*search_move)(void); static const char *(*search_move)(void);
static const char *old_prompt = NULL; static const char *old_prompt = NULL;
static rl_vcpfunc_t *line_handler = NULL; static rl_vcpfunc_t *line_handler = NULL;
static char *line_up = "\x1b[A";
static char *line_down = "\x1b[B";
static int prompt_len = 0;
int el_no_echo = 0; /* e.g., under Emacs */ int el_no_echo = 0; /* e.g., under Emacs */
int el_no_hist = 0; int el_no_hist = 0;
@ -125,7 +122,6 @@ int rl_end;
int rl_meta_chars = 0; /* Display 8-bit chars as the actual char(0) or as `M-x'(1)? */ int rl_meta_chars = 0; /* Display 8-bit chars as the actual char(0) or as `M-x'(1)? */
int rl_inhibit_complete = 0; int rl_inhibit_complete = 0;
char *rl_line_buffer = NULL; char *rl_line_buffer = NULL;
static const char *rl_saved_prompt = NULL;
const char *rl_prompt = NULL; const char *rl_prompt = NULL;
const char *rl_readline_name = NULL; /* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */ const char *rl_readline_name = NULL; /* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */
FILE *rl_instream = NULL; /* The stdio stream from which input is read. Defaults to stdin if NULL */ FILE *rl_instream = NULL; /* The stdio stream from which input is read. Defaults to stdin if NULL */
@ -138,6 +134,7 @@ extern char *tgetstr(const char *, char **);
extern int tgetent(char *, const char *); extern int tgetent(char *, const char *);
extern int tgetnum(const char *); extern int tgetnum(const char *);
#endif #endif
/* /*
** Misc. local helper functions. ** Misc. local helper functions.
@ -179,12 +176,8 @@ static void tty_put(const char c)
Screen[ScreenCount] = c; Screen[ScreenCount] = c;
if (++ScreenCount >= ScreenSize) { if (++ScreenCount >= ScreenSize) {
char *ptr;
ScreenSize += SCREEN_INC; ScreenSize += SCREEN_INC;
ptr = realloc(Screen, sizeof(char) * ScreenSize); Screen = realloc(Screen, sizeof(char) * ScreenSize);
if (ptr)
Screen = ptr;
} }
} }
@ -211,17 +204,10 @@ static void tty_show(unsigned char c)
} }
} }
static void tty_string(const char *p) static void tty_string(char *p)
{ {
int i = rl_point + prompt_len + 1; while (*p)
while (*p) {
tty_show(*p++); tty_show(*p++);
if ((i++) % tty_cols == 0) {
tty_put(' ');
tty_put('\b');
}
}
} }
static void tty_push(int c) static void tty_push(int c)
@ -265,18 +251,11 @@ static void tty_backn(int n)
tty_back(); tty_back();
} }
static void tty_forwardn(int n)
{
char buf[12];
snprintf(buf, sizeof(buf), "\x1b[%dC", n);
tty_puts(buf);
}
static void tty_info(void) static void tty_info(void)
{ {
rl_reset_terminal(NULL); rl_reset_terminal(NULL);
} }
/* /*
** Glue routines to rl_ttyset() ** Glue routines to rl_ttyset()
@ -312,10 +291,8 @@ void el_print_columns(int ac, char **av)
if ((j = strlen((char *)av[i])) > longest) if ((j = strlen((char *)av[i])) > longest)
longest = j; longest = j;
} }
colwidth = longest + 3; colwidth = longest + 3;
if (colwidth > tty_cols) if (colwidth > tty_cols) colwidth = tty_cols;
colwidth = tty_cols;
cols = tty_cols / colwidth; cols = tty_cols / colwidth;
tty_puts(NEWLINE); tty_puts(NEWLINE);
@ -334,64 +311,20 @@ void el_print_columns(int ac, char **av)
} }
} }
static void reposition(int key) static void reposition(void)
{ {
int len_with_prompt = prompt_len + rl_end; int i;
int n = len_with_prompt / tty_cols; /* determine the number of lines */
int i = 0;
tty_put('\r'); tty_put('\r');
if (n > 0) {
int line;
/* determine num of current line */
if (key == CTL('A') || key == CTL('E') || key == rl_kill)
line = (prompt_len + old_point) / tty_cols;
else
line = len_with_prompt / tty_cols;
/* move to end of line(s) */
if (key == CTL('E')) {
int k;
for (k = line; k < n; k++)
tty_puts(line_down);
/* determine reminder of last line and redraw only it */
i = rl_point - (len_with_prompt % tty_cols);
} else {
int k;
/* CTRL-A, CTRL-U, insert (end, middle), remove (end, middle) */
for (k = line; k > 0; k--)
tty_puts(line_up); /* redraw characters until changed data */
tty_puts(rl_prompt); tty_puts(rl_prompt);
} for (i = 0; i < rl_point; i++)
} else if (n == 0) {
tty_puts(rl_prompt);
}
for (; i < rl_point; i++) {
tty_show(rl_line_buffer[i]); tty_show(rl_line_buffer[i]);
/* move to the next line */
if ((i + prompt_len + 1) % tty_cols == 0)
tty_put('\n');
}
} }
static void left(el_status_t Change) static void left(el_status_t Change)
{ {
if (rl_point) { if (rl_point) {
if ((rl_point + prompt_len) % tty_cols == 0) {
tty_puts(line_up);
tty_forwardn(tty_cols);
} else {
tty_back(); tty_back();
}
if (ISMETA(rl_line_buffer[rl_point - 1])) { if (ISMETA(rl_line_buffer[rl_point - 1])) {
if (rl_meta_chars) { if (rl_meta_chars) {
tty_back(); tty_back();
@ -408,9 +341,6 @@ static void left(el_status_t Change)
static void right(el_status_t Change) static void right(el_status_t Change)
{ {
if ((rl_point + prompt_len + 1) % tty_cols == 0)
tty_put('\n');
else
tty_show(rl_line_buffer[rl_point]); tty_show(rl_line_buffer[rl_point]);
if (Change == CSmove) if (Change == CSmove)
@ -464,6 +394,12 @@ static el_status_t do_forward(el_status_t move)
right(CSstay); right(CSstay);
} }
/* Skip to next word, or skip leading white space if outside a word. */
for ( ; rl_point < rl_end && (p[0] == ' ' || !is_alpha_num(p[0])); rl_point++, p++) {
if (move == CSmove)
right(CSstay);
}
if (rl_point == rl_end) if (rl_point == rl_end)
break; break;
} while (++i < Repeat); } while (++i < Repeat);
@ -489,10 +425,10 @@ static el_status_t do_case(el_case_t type)
for (i = rl_point, p = &rl_line_buffer[i]; rl_point < end; p++) { for (i = rl_point, p = &rl_line_buffer[i]; rl_point < end; p++) {
if ((type == TOupper) || (type == TOcapitalize && rl_point == i)) { if ((type == TOupper) || (type == TOcapitalize && rl_point == i)) {
if (islower((unsigned char)(*p))) if (islower(*p))
*p = toupper((unsigned char)(*p)); *p = toupper(*p);
} else if (isupper((unsigned char)(*p))) { } else if (isupper(*p)) {
*p = tolower((unsigned char)(*p)); *p = tolower(*p);
} }
right(CSmove); right(CSmove);
} }
@ -525,14 +461,10 @@ static void ceol(void)
while (rl_point < 0) { while (rl_point < 0) {
tty_put(' '); tty_put(' ');
rl_point++; rl_point++;
extras++;
} }
for (i = rl_point, p = &rl_line_buffer[i]; i <= rl_end; i++, p++) { for (i = rl_point, p = &rl_line_buffer[i]; i <= rl_end; i++, p++) {
if ((i + prompt_len + 1) % tty_cols == 0){
tty_put(' ');
tty_put('\n');
}
else
tty_put(' '); tty_put(' ');
if (ISMETA(*p)) { if (ISMETA(*p)) {
if (rl_meta_chars) { if (rl_meta_chars) {
@ -546,32 +478,15 @@ static void ceol(void)
} }
} }
for (i += extras; i > rl_point; i--) { for (i += extras; i > rl_point; i--)
if ((i + prompt_len) % tty_cols == 0) {
tty_puts(line_up);
tty_forwardn(tty_cols);
} else {
tty_back(); tty_back();
} }
}
}
static void clear_line(void) static void clear_line(void)
{ {
int n = (rl_point + prompt_len) / tty_cols;
rl_point = -(int)strlen(rl_prompt); rl_point = -(int)strlen(rl_prompt);
if (n > 0) {
for(int k = 0; k < n; k++)
tty_puts(line_up);
tty_put('\r'); tty_put('\r');
}
else {
tty_put('\r');
}
ceol(); ceol();
rl_point = 0; rl_point = 0;
rl_end = 0; rl_end = 0;
rl_line_buffer[0] = '\0'; rl_line_buffer[0] = '\0';
@ -623,15 +538,14 @@ int rl_insert_text(const char *text)
static el_status_t redisplay(int cls) static el_status_t redisplay(int cls)
{ {
if (cls) if (cls && rl_point == 0 && rl_end == 0)
tty_puts(CLEAR); tty_puts(CLEAR);
else else
tty_puts("\r\e[K"); tty_puts("\r\e[K");
tty_puts(rl_prompt); tty_puts(rl_prompt);
rl_point = 0;
tty_string(rl_line_buffer); tty_string(rl_line_buffer);
rl_point = rl_end;
return CSmove; return CSmove;
} }
@ -651,6 +565,7 @@ static el_status_t toggle_meta_mode(void)
rl_meta_chars = ! rl_meta_chars; rl_meta_chars = ! rl_meta_chars;
return redisplay(0); return redisplay(0);
} }
const char *el_next_hist(void) const char *el_next_hist(void)
{ {
@ -670,7 +585,7 @@ static el_status_t do_insert_hist(const char *p)
clear_line(); clear_line();
rl_point = 0; rl_point = 0;
reposition(EOF); reposition();
rl_end = 0; rl_end = 0;
return insert_string(p); return insert_string(p);
@ -773,7 +688,7 @@ static const char *search_hist(const char *search, const char *(*move)(void))
static el_status_t h_search_end(const char *p) static el_status_t h_search_end(const char *p)
{ {
rl_set_prompt(old_prompt); rl_prompt = old_prompt;
Searching = 0; Searching = 0;
if (el_intr_pending > 0) { if (el_intr_pending > 0) {
@ -800,8 +715,8 @@ static el_status_t h_search(void)
clear_line(); clear_line();
old_prompt = rl_prompt; old_prompt = rl_prompt;
rl_set_prompt("Search: "); rl_prompt = "Search: ";
reposition(EOF); tty_puts(rl_prompt);
search_move = Repeat == NO_ARG ? el_prev_hist : el_next_hist; search_move = Repeat == NO_ARG ? el_prev_hist : el_next_hist;
if (line_handler) { if (line_handler) {
@ -877,7 +792,6 @@ static el_status_t delete_string(int count)
for (p = &rl_line_buffer[rl_point], i = rl_end - (rl_point + count) + 1; --i >= 0; p++) for (p = &rl_line_buffer[rl_point], i = rl_end - (rl_point + count) + 1; --i >= 0; p++)
p[0] = p[count]; p[0] = p[count];
ceol(); ceol();
rl_end -= count; rl_end -= count;
tty_string(&rl_line_buffer[rl_point]); tty_string(&rl_line_buffer[rl_point]);
@ -918,7 +832,7 @@ static el_status_t kill_line(void)
if (Repeat < rl_point) { if (Repeat < rl_point) {
i = rl_point; i = rl_point;
rl_point = Repeat; rl_point = Repeat;
reposition(EOF); reposition();
delete_string(i - rl_point); delete_string(i - rl_point);
} else if (Repeat > rl_point) { } else if (Repeat > rl_point) {
right(CSmove); right(CSmove);
@ -1029,30 +943,6 @@ static el_status_t meta(void)
return CSeof; return CSeof;
#ifdef CONFIG_ANSI_ARROWS #ifdef CONFIG_ANSI_ARROWS
/* See: https://en.wikipedia.org/wiki/ANSI_escape_code */
/* Recognize ANSI escapes for `Meta+Left` and `Meta+Right`. */
if (c == '\e') {
switch (tty_get()) {
case '[':
{
switch (tty_get()) {
/* \e\e[C = Meta+Left */
case 'C': return fd_word();
/* \e\e[D = Meta+Right */
case 'D': return bk_word();
default:
break;
}
return el_ring_bell();
}
default:
break;
}
return el_ring_bell();
}
/* Also include VT-100 arrows. */ /* Also include VT-100 arrows. */
if (c == '[' || c == 'O') { if (c == '[' || c == 'O') {
switch (tty_get()) { switch (tty_get()) {
@ -1060,31 +950,21 @@ static el_status_t meta(void)
case '1': case '1':
{ {
char seq[4] = { 0 }; char seq[4] = { 0 };
seq[0] = tty_get();
/* \e[1~ */ for (c = 0; c < 3; c++)
if (seq[0] == '~')
return beg_line(); /* Home */
for (c = 1; c < 3; c++)
seq[c] = tty_get(); seq[c] = tty_get();
if (!strncmp(seq, ";5C", 3) if (!strncmp(seq, ";5C", 3))
|| !strncmp(seq, ";3C", 3)) return fd_word(); /* Ctrl+Right */
return fd_word(); /* \e[1;5C = Ctrl+Right */ if (!strncmp(seq, ";5D", 3))
if (!strncmp(seq, ";5D", 3) return bk_word(); /* Ctrl+Left */
|| !strncmp(seq, ";3D", 3))
return bk_word(); /* \e[1;5D = Ctrl+Left */
break; break;
} }
case '2': tty_get(); return CSstay; /* Insert */ case '2': tty_get(); return CSstay; /* Insert */
case '3': tty_get(); return del_char(); /* Delete */ case '3': tty_get(); return del_char(); /* Delete */
case '4': tty_get(); return end_line(); /* End */
case '5': tty_get(); return CSstay; /* PgUp */ case '5': tty_get(); return CSstay; /* PgUp */
case '6': tty_get(); return CSstay; /* PgDn */ case '6': tty_get(); return CSstay; /* PgDn */
case '7': tty_get(); return beg_line(); /* Home (urxvt) */
case '8': tty_get(); return end_line(); /* End (urxvt) */
case 'A': return h_prev(); /* Up */ case 'A': return h_prev(); /* Up */
case 'B': return h_next(); /* Down */ case 'B': return h_next(); /* Down */
case 'C': return fd_char(); /* Left */ case 'C': return fd_char(); /* Left */
@ -1154,8 +1034,6 @@ static el_status_t emacs(int c)
static el_status_t tty_special(int c) static el_status_t tty_special(int c)
{ {
el_status_t rc;
#ifdef CONFIG_SIGINT #ifdef CONFIG_SIGINT
if (c == rl_intr) { if (c == rl_intr) {
el_intr_pending = SIGINT; el_intr_pending = SIGINT;
@ -1180,10 +1058,13 @@ static el_status_t tty_special(int c)
return bk_del_char(); return bk_del_char();
if (c == rl_kill) { if (c == rl_kill) {
Repeat = rl_point; if (rl_point != 0) {
rc = bk_del_char(); rl_point = 0;
reposition();
}
Repeat = NO_ARG; Repeat = NO_ARG;
return rc;
return kill_line();
} }
#ifdef CONFIG_EOF #ifdef CONFIG_EOF
@ -1214,7 +1095,7 @@ static char *editinput(int complete)
return (char *)""; return (char *)"";
case CSmove: case CSmove:
reposition(c); reposition();
break; break;
case CSdispatch: case CSdispatch:
@ -1229,7 +1110,7 @@ static char *editinput(int complete)
return (char *)""; return (char *)"";
case CSmove: case CSmove:
reposition(c); reposition();
break; break;
case CSdispatch: case CSdispatch:
@ -1249,7 +1130,7 @@ static char *editinput(int complete)
static void hist_alloc(void) static void hist_alloc(void)
{ {
if (!H.Lines) if (!H.Lines)
H.Lines = calloc(1 + el_hist_size, sizeof(char *)); H.Lines = calloc(el_hist_size, sizeof(char *));
} }
static void hist_add(const char *p) static void hist_add(const char *p)
@ -1266,11 +1147,11 @@ static void hist_add(const char *p)
if (s == NULL) if (s == NULL)
return; return;
if (H.Size <= el_hist_size) { if (H.Size < el_hist_size) {
H.Lines[H.Size++] = s; H.Lines[H.Size++] = s;
} else { } else {
free(H.Lines[0]); free(H.Lines[0]);
for (i = 0; i < el_hist_size; i++) for (i = 0; i < el_hist_size - 1; i++)
H.Lines[i] = H.Lines[i + 1]; H.Lines[i] = H.Lines[i + 1];
H.Lines[i] = s; H.Lines[i] = s;
} }
@ -1282,7 +1163,7 @@ static char *read_redirected(void)
int size = MEM_INC; int size = MEM_INC;
char *p; char *p;
char *line; char *line;
const char *end; char *end;
p = line = malloc(sizeof(char) * size); p = line = malloc(sizeof(char) * size);
if (!p) if (!p)
@ -1294,12 +1175,9 @@ static char *read_redirected(void)
int oldpos = end - line; int oldpos = end - line;
size += MEM_INC; size += MEM_INC;
p = realloc(line, sizeof(char) * size); p = line = realloc(line, sizeof(char) * size);
if (!p) { if (!p)
free(line);
return NULL; return NULL;
}
line = p;
end = p + size; end = p + size;
p += oldpos; /* Continue where we left off... */ p += oldpos; /* Continue where we left off... */
@ -1364,28 +1242,10 @@ void rl_reset_terminal(const char *terminal_name)
} }
} }
void rl_set_prompt(const char *prompt)
{
if (prompt)
rl_prompt = prompt;
prompt_len = strlen(rl_prompt);
}
void rl_save_prompt(void)
{
rl_saved_prompt = rl_prompt;
}
void rl_restore_prompt(void)
{
if (rl_saved_prompt)
rl_set_prompt(rl_saved_prompt);
}
void rl_initialize(void) void rl_initialize(void)
{ {
if (!rl_prompt) if (!rl_prompt)
rl_set_prompt("? "); rl_prompt = "? ";
hist_alloc(); hist_alloc();
@ -1404,7 +1264,7 @@ void rl_uninitialize(void)
/* Uninitialize the history */ /* Uninitialize the history */
if (H.Lines) { if (H.Lines) {
for (i = 0; i <= el_hist_size; i++) { for (i = 0; i < el_hist_size; i++) {
if (H.Lines[i]) if (H.Lines[i])
free(H.Lines[i]); free(H.Lines[i]);
H.Lines[i] = NULL; H.Lines[i] = NULL;
@ -1426,12 +1286,29 @@ void rl_uninitialize(void)
Length = 0; Length = 0;
} }
static const char *rl_saved_prompt = NULL;
void rl_save_prompt(void)
{
rl_saved_prompt = rl_prompt;
}
void rl_restore_prompt(void)
{
if (rl_saved_prompt)
rl_prompt = rl_saved_prompt;
}
void rl_set_prompt(const char *prompt)
{
rl_prompt = prompt;
}
void rl_clear_message(void) void rl_clear_message(void)
{ {
/* Nothing to do atm. */ /* Nothing to do atm. */
} }
void rl_forced_update_display(void) void rl_forced_update_display()
{ {
redisplay(0); redisplay(0);
tty_flush(); tty_flush();
@ -1456,8 +1333,7 @@ static int el_prep(const char *prompt)
if (!Screen) if (!Screen)
return -1; return -1;
rl_set_prompt(prompt); rl_prompt = prompt ? prompt : NILSTR;
if (el_no_echo) { if (el_no_echo) {
int old = el_no_echo; int old = el_no_echo;
@ -1619,11 +1495,8 @@ int read_history(const char *filename)
char buf[SCREEN_INC]; char buf[SCREEN_INC];
hist_alloc(); hist_alloc();
fp = fopen(filename, "r"); fp = fopen(filename, "r");
if (!fp) if (fp) {
return EOF;
H.Size = 0; H.Size = 0;
while (H.Size < el_hist_size) { while (H.Size < el_hist_size) {
if (!fgets(buf, SCREEN_INC, fp)) if (!fgets(buf, SCREEN_INC, fp))
@ -1636,16 +1509,17 @@ int read_history(const char *filename)
return fclose(fp); return fclose(fp);
} }
return errno;
}
int write_history(const char *filename) int write_history(const char *filename)
{ {
FILE *fp; FILE *fp;
int i = 0;
hist_alloc(); hist_alloc();
fp = fopen(filename, "w"); fp = fopen(filename, "w");
if (!fp) if (fp) {
return EOF; int i = 0;
while (i < H.Size) while (i < H.Size)
fprintf(fp, "%s\n", H.Lines[i++]); fprintf(fp, "%s\n", H.Lines[i++]);
@ -1653,6 +1527,10 @@ int write_history(const char *filename)
return fclose(fp); return fclose(fp);
} }
return errno;
}
/* /*
** Move back to the beginning of the current word and return an ** Move back to the beginning of the current word and return an
** allocated copy of it. ** allocated copy of it.
@ -1773,6 +1651,14 @@ static el_status_t accept_line(void)
return CSdone; return CSdone;
} }
#ifdef SYSTEM_IS_WIN32
static el_status_t end_of_input(void)
{
rl_line_buffer[rl_end] = '\0';
return CSeof;
}
#endif
static el_status_t transpose(void) static el_status_t transpose(void)
{ {
char c; char c;
@ -1895,14 +1781,14 @@ static int argify(char *line, char ***avp)
if (!p) if (!p)
return 0; return 0;
for (c = line; isspace((unsigned char)(*c)); c++) for (c = line; isspace(*c); c++)
continue; continue;
if (*c == '\n' || *c == '\0') if (*c == '\n' || *c == '\0')
return 0; return 0;
for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) { for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
if (!isspace((unsigned char)(*c))) { if (!isspace(*c)) {
c++; c++;
continue; continue;
} }
@ -1984,7 +1870,11 @@ static el_keymap_t Map[64] = {
{ CTL('W'), bk_kill_word }, { CTL('W'), bk_kill_word },
{ CTL('X'), exchange }, { CTL('X'), exchange },
{ CTL('Y'), yank }, { CTL('Y'), yank },
#ifdef SYSTEM_IS_WIN32
{ CTL('Z'), end_of_input },
#else
{ CTL('Z'), el_ring_bell }, { CTL('Z'), el_ring_bell },
#endif
{ CTL('['), meta }, { CTL('['), meta },
{ CTL(']'), move_to_char }, { CTL(']'), move_to_char },
{ CTL('^'), el_ring_bell }, { CTL('^'), el_ring_bell },
@ -2016,7 +1906,7 @@ static size_t find_key_in_map(int key, el_keymap_t map[], size_t mapsz)
{ {
size_t i; size_t i;
for (i = 0; i < mapsz && map[i].Function; i++) { for (i = 0; map[i].Function && i < mapsz; i++) {
if (map[i].Key == key) if (map[i].Key == key)
return i; return i;
} }