65 Commits

Author SHA1 Message Date
Joachim Nilsson
02cccd1e87 Update ChangeLog and bump version for v1.17.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-01-05 09:53:19 +01:00
Joachim Nilsson
01dd4045b4 Bump ABI revision, v1.0.1 --> v1.0.2
Most notably, changes in behavior in history functions.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-01-05 09:49:47 +01:00
Joachim Nilsson
99ae6b86cb Revert "Travis-CI: Disable clang temporarily for Coverity Scan run"
This reverts commit d9f725f20a.
2020-01-05 08:29:58 +01:00
Joachim Nilsson
1305d05b75 examples: Refactor CLI unlock gimmick to fix possible Coverity issue
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-01-05 08:21:36 +01:00
Joachim Nilsson
d9f725f20a Travis-CI: Disable clang temporarily for Coverity Scan run
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-01-05 07:58:33 +01:00
Joachim Nilsson
7278fd8581 Travis-CI: Clean build between different phases
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-01-05 07:58:13 +01:00
Joachim Nilsson
f619d9d788 Follow-up to d310910, use EOF instead of -1 in calls to reposition()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-01-05 07:52:31 +01:00
Joachim Nilsson
6c74203cbd Update ChangeLog with latest fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-01-05 07:52:31 +01:00
Joachim Nilsson
b44335f413 Defensive programming, check within boundaries before deref
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-01-05 07:52:31 +01:00
Joachim Nilsson
e36aae07f8 Refactor move_cursor_forward() into tty_forwardn()
- Use same namespace like other tty movement functions
- Replace globally exposed itoa() and dangerous strcpy() with snprintf()

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-01-05 07:52:31 +01:00
Joachim Nilsson
cf8f962e4f Handle realloc() failures better
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-01-05 07:52:31 +01:00
Joachim Nilsson
deb2884310 Fix error return value from read_history() and write_history()
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-01-05 07:52:31 +01:00
Joachim Nilsson
81840c0f84 Update ChangeLog to reflect latest changes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-11-28 07:03:44 +01:00
Joachim Nilsson
0b295197f6 Merge branch 'echoprotocol-simple_multiline' 2019-11-28 07:01:48 +01:00
Joachim Nilsson
1802e086e0 Bump version for v1.17.0 release cycle
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-11-28 07:01:13 +01:00
Joachim Nilsson
12d5584721 Fix for() loop; "statement with no effect" warning from GCC
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-11-28 06:59:53 +01:00
Joachim Nilsson
35506cd22e Minor, coding style fixups
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-11-28 06:58:37 +01:00
Joachim Nilsson
f35af9f20d Merge branch 'simple_multiline' of https://github.com/echoprotocol/editline into echoprotocol-simple_multiline 2019-11-28 06:41:43 +01:00
dvolynets
498b041a35 fixed indentations 2019-11-20 15:14:21 +03:00
dvolynets
d3109109c4 added simple multiline support 2019-11-20 15:14:02 +03:00
Joachim Nilsson
7355f56d25 Update ChangeLog(s) and bump version for v1.16.1 release
New ABI version 1.0.1

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-06-07 12:04:01 +02:00
Joachim Nilsson
5496152d51 Rephrase section introducing Jush, the stupid UNIX shell
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-06-01 17:24:59 +02:00
Joachim Nilsson
13f8d5f69c Merge pull request #32 from abitmore/search-end-cleanup
Cleanup el_intr_pending in h_search_end()
2019-05-08 17:11:02 +02:00
Joachim Nilsson
c2b65646ea Revert "Fi #31: Aborting i-search with Ctrl-C should not generate signal"
This reverts commit e2c3b41d9a.
2019-05-08 17:10:21 +02:00
Joachim Nilsson
e2c3b41d9a Fi #31: Aborting i-search with Ctrl-C should not generate signal
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-05-08 17:04:15 +02:00
Joachim Nilsson
4a17180d37 Add SIGINT notification to cli example, for debugging
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-05-08 17:03:49 +02:00
Joachim Nilsson
3e046cafd2 Clear line on failed Ctrl-R operation
The Ctrl-R search prompt and failed search text may be longer than
the regular CLI prompt.  This patch clears the line to remove any
lingering artefacts.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-05-08 16:57:40 +02:00
Joachim Nilsson
0e493addab Fix #30: Ctrl-R with empty search string clears screen
The screen should only be cleared on Ctrl-L *and* empty regular line,
not when searching with an empty string.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-05-08 16:55:33 +02:00
abitmore
842bd67dd4 Cleanup el_intr_pending in h_search_end()
Fixes an issue when user pressed Ctrl+C when searching.
2019-05-08 07:51:13 -04:00
Joachim Nilsson
0eb8f228f7 Merge pull request #29 from abitmore/rl_set_getc_func
Add rl_set_getc_func()
2019-05-08 10:48:39 +02:00
abitmore
8f6d724e30 Add rl_set_getc_func()
So it's possible to install another implementation of rl_getc() function.
2019-05-07 17:58:06 -04:00
Joachim Nilsson
ee176c80d7 Only display return from readline() when there's something to show.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-05-06 01:20:46 +02:00
Joachim Nilsson
979f05a5eb Follow-up to a4b67d2: Ctrl-L redisplay line when not on empty line
Like Ctrl-D, when on an empty line we clear the screen, when editing a
garbled line we refresh the line.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-05-06 00:54:57 +02:00
Joachim Nilsson
c95d25731d Always use enums for el_status_t return values
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-05-06 00:54:17 +02:00
Joachim Nilsson
61d40f406f examples: Catch SIGINT instead of mapping Ctrl-C, use default Ctrl-D
We want Ctrl-C to work as in Bash, so let's just catch SIGINT (and do
nothing).  Also, the default Ctrl-D handler does what we want, i.e.
exit the CLI when we're on an empty line.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-05-06 00:52:13 +02:00
Joachim Nilsson
385cd77e9b Merge branch 'abitmore-patch-1' 2019-05-03 17:13:39 +02:00
Abit
448a3dac08 Avoid continuously duplicate commands in history
When adding a command to history, if CONFIG_UNIQUE_HISTORY is defined, always compare current command with the last entry in history.
2019-05-03 16:54:25 +02:00
Joachim Nilsson
7506826ac7 debian: libeditline1 does not have any shlib deps.
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-27 15:44:30 +02:00
Joachim Nilsson
ec7f752095 debian: Add missing pkg-cconfig .pc file to -dev package
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-27 15:43:56 +02:00
Joachim Nilsson
959a9e7199 Prepare for debian v1.16.1 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-27 15:01:28 +02:00
Joachim Nilsson
397ac9dd56 Update ChangeLog with latest fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-27 12:47:20 +02:00
Joachim Nilsson
e58868bec1 Mention jush as another example of Editline
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-27 12:46:59 +02:00
Joachim Nilsson
650d0f15c6 Correction, this version of the library stems from Minix 2
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-27 12:46:31 +02:00
Joachim Nilsson
2aee394b44 Major update of man page, exand on APIs and history of library
- Convert from obtruse troff syntax to simpler mdoc format
- Add history APIs, most relevant extra APIs available
- Expand on the history of the library
- Rewrite some sections for accessiblilty

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-27 12:32:58 +02:00
Joachim Nilsson
dd1af360c3 Merge branch 'dtzWill-fix/narrow-terms' 2019-04-27 09:11:19 +02:00
Will Dietz
8660aef4b7 editline: fix behavior when tty is narrower than column width
Fixes crash when dividing by the number of columns,
which was computed as zero in this situation.

Instead, always have at least one "column" even if it wraps.
2019-04-26 13:30:15 -05:00
Joachim Nilsson
6a4d77ca69 Update ChangeLog with latest fixes
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-07 12:46:23 +02:00
Joachim Nilsson
0b554cf8c8 Bump version for v1.16.1 release cycle
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2019-04-07 12:46:01 +02:00
Joachim Nilsson
8f5a5da754 examples/fileman.c: Further code cleanup and simplification
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-12-31 22:51:39 +01:00
Joachim Nilsson
a237e39181 examples/fileman.c: Refactor and cleanup
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-12-31 22:49:28 +01:00
Joachim Nilsson
3cb74b6d87 examples/fileman.c: Remove unnecessary code
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-12-31 22:41:15 +01:00
Joachim Nilsson
5c8429dcee examples/fileman.c: Deregister
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-12-31 22:39:20 +01:00
Joachim Nilsson
8566eb8384 examples/fileman.c: Reindent to project coding style
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-12-31 22:30:45 +01:00
Joachim Nilsson
8e34e4e417 Merge pull request #23 from LnL7/redisplay-clear
make Ctrl-L clear the screen instead of just starting a new line
2018-12-24 08:27:50 +01:00
Daiderd Jordan
a4b67d2268 make Ctrl-L clear the screen instead of just starting a new line 2018-12-23 20:49:25 +01:00
Joachim Nilsson
0b7142eb8e examples: cli: Add password prompt (hidden input) example
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-11-17 11:50:26 +01:00
Joachim Nilsson
2137b9df9f Revert "Merge pull request #21 from cogutvalera/issue_1171"
This reverts commit cddd8d8de0, reversing
changes made to 4ec7d26a9d.
2018-11-15 10:27:22 +01:00
Joachim Nilsson
66d8ae84e2 Revert "Coding style and const fixes to last PR"
This reverts commit fbb1f8800a.
2018-11-15 10:26:03 +01:00
Joachim Nilsson
fbb1f8800a Coding style and const fixes to last PR
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-10-24 08:28:34 +02:00
Joachim Nilsson
cddd8d8de0 Merge pull request #21 from cogutvalera/issue_1171
Hide secret information
2018-10-24 08:00:54 +02:00
Valera Cogut
1db83fe6c6 Fixed inconsistent indentation 2018-10-18 16:54:16 +03:00
Valera Cogut
3cd9894747 Added example for hiding secret information 2018-10-18 12:58:14 +03:00
Valera Cogut
4784fe2491 Hide secret information 2018-10-18 11:15:35 +03:00
Joachim Nilsson
4ec7d26a9d Fix #20: configure --disable-eof does not bite
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-21 07:17:19 +02:00
Joachim Nilsson
ebefa8b890 Refactor, simplify helper macro
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2018-09-21 07:12:24 +02:00
14 changed files with 1003 additions and 787 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 -j5" build_command: "make clean all"
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 -j5 - make clean all

View File

@@ -4,6 +4,40 @@ 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.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
- Major updates to the `editline.3` man page
- Cleanup of examples `cli.c` and `fileman.c`
- Add example of hidden input prompt to `cli.c`
### Fixes
- Fix #20: `configure --disable-eof` does not bite
- Fix #23: Make Ctrl-L clear the screan instead of starting a new line
Like Ctrl-D, which exits, Ctrl-L only clears the screen when the line
is empty and the cursor is at the start of the line, otherwise Ctrl-L
will redraw/refresh the current line.
- Fix #24: Fix behavior when TTY is narrower than column width, by Will Dietz
- Fix #25: Avoid continuously duplicate commands in history
- Fix #31: Aborting i-search with Ctrl-C should not generate signal
[1.16.0][] - 2018-09-16 [1.16.0][] - 2018-09-16
----------------------- -----------------------
@@ -203,7 +237,9 @@ 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.16.0...HEAD [UNRELEASED]: https://github.com/troglobit/finit/compare/1.17.0...HEAD
[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.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
[1.15.2]: https://github.com/troglobit/finit/compare/1.15.1...1.15.2 [1.15.2]: https://github.com/troglobit/finit/compare/1.15.1...1.15.2
@@ -220,9 +256,3 @@ 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

@@ -37,9 +37,11 @@ Editline is maintained collaboratively at [GitHub][].
Example Example
------- -------
Here is a very brief example to illustrate how one can use Editline to Below is a very brief example to illustrate how one can use Editline to
create a simple CLI, use Ctrl-D to exit the program. More examples are create a simple CLI, Ctrl-D exits the program. A slightly more advanced
availble in the source tree. example is Jush, <https://github.com/troglobit/jush/>, a small and very
simplistic UNIX shell. The Editline sources also include an `examples/`
sub-directory.
1. Build and install the library, preferably using a [release tarball][] 1. Build and install the library, preferably using a [release tarball][]
The configure script defaults to a `/usr/local` prefix. The configure script defaults to a `/usr/local` prefix.
@@ -221,7 +223,7 @@ similar to the [BSD license][]. Rich's current version is however under
the Apache license. For details on the licensing terms of this version the Apache license. For details on the licensing terms of this version
of the software, see [License][]. of the software, see [License][].
This version of the editline library was forked from the [Minix 3][] This version of the editline library was forked from the [Minix 2][]
source tree and is *not* related to the similarily named NetBSD version source tree and is *not* related to the similarily named NetBSD version
that [Jess Thrysøe][jess] disitributes to the world outside *BSD. The that [Jess Thrysøe][jess] disitributes to the world outside *BSD. The
libraries have much in common, but the latter is heavily refactored and libraries have much in common, but the latter is heavily refactored and
@@ -255,7 +257,7 @@ Outstanding issues are listed in the [TODO.md][] file.
[FSF readline]: http://www.gnu.org/software/readline/ [FSF readline]: http://www.gnu.org/software/readline/
[Rich Salz]: https://github.com/richsalz/editline/ [Rich Salz]: https://github.com/richsalz/editline/
[comp.sources.unix]: http://ftp.cs.toronto.edu/pub/white/pub/rc/editline.shar [comp.sources.unix]: http://ftp.cs.toronto.edu/pub/white/pub/rc/editline.shar
[Minix 3]: http://www.cise.ufl.edu/~cop4600/cgi-bin/lxr/http/source.cgi/lib/editline/ [Minix 2]: http://www.cise.ufl.edu/~cop4600/cgi-bin/lxr/http/source.cgi/lib/editline/
[jess]: http://thrysoee.dk/editline/ [jess]: http://thrysoee.dk/editline/
[BSD license]: http://en.wikipedia.org/wiki/BSD_licenses [BSD license]: http://en.wikipedia.org/wiki/BSD_licenses
[libeditline]: http://packages.qa.debian.org/e/editline.html [libeditline]: http://packages.qa.debian.org/e/editline.html

View File

@@ -1,4 +1,4 @@
AC_INIT(editline, 1.16.0, https://github.com/troglobit/editline/issues) AC_INIT(editline, 1.17.0, https://github.com/troglobit/editline/issues)
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz]) AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])
@@ -69,8 +69,8 @@ AS_IF([test "x$enable_unique_history" != "xno"],
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_terminal_bell" != "xno"], AS_IF([test "x$enable_eof" != "xno"],
AC_DEFINE(CONFIG_EOF, 1, [Define to enable EOF (Ctrl-C) 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.]))

16
debian/changelog vendored
View File

@@ -1,3 +1,19 @@
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
* Minor bug fix and documentation update release.
* Add missing pkg-config .pc file to -dev package
-- Joachim Nilsson <troglobit@gmail.com> Fri, 07 Jun 2019 11:45:50 +0200
editline (1.16.0) unstable; urgency=medium editline (1.16.0) unstable; urgency=medium
* New upstream release, v1.60.0 * New upstream release, v1.60.0

2
debian/control vendored
View File

@@ -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

View File

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

View File

@@ -38,9 +38,9 @@ static char *my_rl_complete(char *token, int *match)
int count = 0; int count = 0;
for (i = 0; list[i]; i++) { for (i = 0; list[i]; i++) {
int partlen = strlen (token); /* Part of token */ int partlen = strlen(token); /* Part of token */
if (!strncmp (list[i], token, partlen)) { if (!strncmp(list[i], token, partlen)) {
index = i; index = i;
matchlen = partlen; matchlen = partlen;
count ++; count ++;
@@ -49,7 +49,7 @@ static char *my_rl_complete(char *token, int *match)
if (count == 1) { if (count == 1) {
*match = 1; *match = 1;
return strdup (list[index] + matchlen); return strdup(list[index] + matchlen);
} }
return NULL; return NULL;
@@ -60,15 +60,18 @@ static int my_rl_list_possib(char *token, char ***av)
{ {
int i, num, total = 0; int i, num, total = 0;
char **copy; char **copy;
for (num = 0; list[num]; num++) for (num = 0; list[num]; num++)
; ;
copy = (char **) malloc (num * sizeof(char *)); if (!num)
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]);
total ++; total++;
} }
} }
*av = copy; *av = copy;
@@ -98,41 +101,70 @@ el_status_t list_possible(void)
return el_ring_bell(); return el_ring_bell();
} }
el_status_t do_break(void)
{
puts("Breakout!");
return CSeof;
}
el_status_t do_exit(void)
{
puts("Bye bye!");
return CSeof;
}
el_status_t do_suspend(void) el_status_t do_suspend(void)
{ {
puts("Abort!"); puts("Abort!");
return CSstay; return CSstay;
} }
static void breakit(int signo)
{
(void)signo;
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> ";
signal(SIGINT, breakit);
/* Setup callbacks */ /* Setup callbacks */
rl_set_complete_func(&my_rl_complete); rl_set_complete_func(&my_rl_complete);
rl_set_list_possib_func(&my_rl_list_possib); rl_set_list_possib_func(&my_rl_list_possib);
el_bind_key('?', list_possible); el_bind_key('?', list_possible);
el_bind_key(CTL('C'), do_break);
el_bind_key(CTL('D'), do_exit);
el_bind_key(CTL('Z'), do_suspend); el_bind_key(CTL('Z'), do_suspend);
read_history(HISTORY); read_history(HISTORY);
while ((line = readline(prompt)) != NULL) { while ((line = readline(prompt))) {
printf("\t\t\t|%s|\n", line); if (!strncmp(line, "unlock", 6) && unlock("secret")) {
free(line); free(line);
fprintf(stderr, "\nSecurity breach, user logged out!\n");
break;
}
if (*line != '\0')
printf("\t\t\t|%s|\n", line);
free(line);
} }
write_history(HISTORY); write_history(HISTORY);

View File

@@ -5,7 +5,7 @@
NOTE: this was taken from the GNU Readline documentation and ported NOTE: this was taken from the GNU Readline documentation and ported
to libedit. A command to output the history list was added. to libedit. A command to output the history list was added.
*/ */
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
@@ -21,18 +21,15 @@
#include "editline.h" #include "editline.h"
void * xmalloc (size_t size); void too_dangerous(char *caller);
void too_dangerous (char *caller); void initialize_readline();
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);
typedef int rl_icpfunc_t (char *);
/* The names of functions that actually do the manipulation. */ /* The names of functions that actually do the manipulation. */
int com_list (char *); int com_list(char *);
int com_view (char *); int com_view(char *);
int com_history (char *); int com_history(char *);
int com_rename(char *); int com_rename(char *);
int com_stat(char *); int com_stat(char *);
int com_pwd(char *); int com_pwd(char *);
@@ -41,170 +38,146 @@ int com_help(char *);
int com_cd(char *); int com_cd(char *);
int com_quit(char *); int com_quit(char *);
/* A structure which contains information on the commands this program struct cmd {
can understand. */ char *name; /* User printable name of the function. */
int (*func)(char *); /* Function to call to do the job. */
char *doc; /* Documentation for this function. */
};
typedef struct { struct cmd commands[] = {
char *name; /* User printable name of the function. */ { "cd", com_cd, "Change to directory DIR"},
rl_icpfunc_t *func; /* Function to call to do the job. */ { "delete", com_delete, "Delete FILE"},
char *doc; /* Documentation for this function. */ { "help", com_help, "Display this text"},
} COMMAND; { "?", com_help, "Synonym for `help'"},
{ "list", com_list, "List files in DIR"},
COMMAND commands[] = { { "ls", com_list, "Synonym for `list'"},
{ "cd", com_cd, "Change to directory DIR" }, { "pwd", com_pwd, "Print the current working directory"},
{ "delete", com_delete, "Delete FILE" }, { "quit", com_quit, "Quit using Fileman"},
{ "help", com_help, "Display this text" }, { "rename", com_rename, "Rename FILE to NEWNAME"},
{ "?", com_help, "Synonym for `help'" }, { "stat", com_stat, "Print out statistics on FILE"},
{ "list", com_list, "List files in DIR" }, { "view", com_view, "View the contents of FILE"},
{ "ls", com_list, "Synonym for `list'" }, { "history", com_history, "List editline history"},
{ "pwd", com_pwd, "Print the current working directory" }, { NULL, NULL, NULL },
{ "quit", com_quit, "Quit using Fileman" },
{ "rename", com_rename, "Rename FILE to NEWNAME" },
{ "stat", com_stat, "Print out statistics on FILE" },
{ "view", com_view, "View the contents of FILE" },
{ "history", com_history, "List editline history" },
{ (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL }
}; };
/* Forward declarations. */ /* Forward declarations. */
char *stripwhite (); char *stripwhite();
COMMAND *find_command (); struct cmd *find_command();
/* The name of this program, as taken from argv[0]. */
char *progname;
/* 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;
char * int main(int argc, char **argv)
dupstr (char* s)
{ {
char *r; char *line, *s;
r = xmalloc (strlen (s) + 1); setlocale(LC_CTYPE, "");
strcpy (r, s);
return (r);
}
int initialize_readline(); /* Bind our completer. */
main (int argc __attribute__((__unused__)), char **argv)
{
char *line, *s;
progname = argv[0]; /* Loop reading and executing lines until the user quits. */
for (; done == 0;) {
line = readline("FileMan: ");
setlocale(LC_CTYPE, ""); if (!line)
break;
initialize_readline(); /* Bind our completer. */ /* Remove leading and trailing whitespace from the line.
Then, if there is anything left, add it to the history list
/* Loop reading and executing lines until the user quits. */ and execute it. */
for ( ; done == 0; ) s = stripwhite(line);
{
line = readline ("FileMan: ");
if (!line)
break;
/* Remove leading and trailing whitespace from the line.
Then, if there is anything left, add it to the history list
and execute it. */
s = stripwhite(line);
#if 0 #if 0
if (*s) { if (*s) {
char* expansion; char *expansion;
int result; int result;
result = history_expand(s, &expansion); result = history_expand(s, &expansion);
if (result < 0 || result == 2) { if (result < 0 || result == 2) {
fprintf(stderr, "%s\n", expansion); fprintf(stderr, "%s\n", expansion);
} else { } else {
add_history(expansion); add_history(expansion);
execute_line(expansion); execute_line(expansion);
} }
free(expansion); free(expansion);
} }
#else #else
execute_line(s); execute_line(s);
#endif #endif
free(line); free(line);
} }
exit (0);
return 0; return 0;
} }
/* Execute a command line. */ /* Execute a command line. */
int int execute_line(char *line)
execute_line (char *line)
{ {
register int i; int i;
COMMAND *command; struct cmd *command;
char *word; char *word;
/* Isolate the command word. */ /* Isolate the command word. */
i = 0; i = 0;
while (line[i] && isspace (line[i])) while (line[i] && isspace(line[i]))
i++; i++;
word = line + i; word = line + i;
while (line[i] && !isspace (line[i])) while (line[i] && !isspace(line[i]))
i++; i++;
if (line[i]) if (line[i])
line[i++] = '\0'; line[i++] = '\0';
command = find_command (word); command = find_command(word);
if (!command) if (!command) {
{ fprintf(stderr, "%s: No such command for FileMan.\n", word);
fprintf (stderr, "%s: No such command for FileMan.\n", word); return -1;
return (-1); }
}
/* Get argument to command, if any. */ /* Get argument to command, if any. */
while (isspace (line[i])) while (isspace(line[i]))
i++; i++;
word = line + i; word = line + i;
/* Call the function. */ /* Call the function. */
return ((*(command->func)) (word)); return command->func(word);
} }
/* Look up NAME as the name of a command, and return a pointer to that /* Look up NAME as the name of a command, and return a pointer to that
command. Return a NULL pointer if NAME isn't a command name. */ command. Return a NULL pointer if NAME isn't a command name. */
COMMAND * struct cmd *find_command(char *name)
find_command (char *name)
{ {
register int i; int i;
for (i = 0; commands[i].name; i++) for (i = 0; commands[i].name; i++)
if (strcmp (name, commands[i].name) == 0) if (strcmp(name, commands[i].name) == 0)
return (&commands[i]); return &commands[i];
return ((COMMAND *)NULL); return NULL;
} }
/* Strip whitespace from the start and end of STRING. Return a pointer /*
into STRING. */ * Strip whitespace from the start and end of STRING. Return a pointer
char * * into STRING.
stripwhite (char *string) */
char *stripwhite(char *string)
{ {
register char *s, *t; char *s, *t;
for (s = string; isspace (*s); s++) for (s = string; isspace(*s); s++) ;
;
if (*s == 0) if (*s == 0)
return (s); return s;
t = s + strlen (s) - 1; t = s + strlen(s) - 1;
while (t > s && isspace (*t)) while (t > s && isspace(*t))
t--; t--;
*++t = '\0'; *++t = '\0';
return s; return s;
} }
/* **************************************************************** */ /* **************************************************************** */
@@ -216,72 +189,67 @@ 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);
/* 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 * Tell the GNU Readline library how to complete. We want to try to
on filenames if not. */ * complete on command names if this is the first word in the line, or
void * on filenames if not.
initialize_readline () */
void initialize_readline(void)
{ {
/* 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;
} }
/* Attempt to complete on the contents of TEXT. START and END /*
bound the region of rl_line_buffer that contains the word to * Attempt to complete on the contents of TEXT. START and END
complete. TEXT is the word to complete. We can use the entire * bound the region of rl_line_buffer that contains the word to
contents of rl_line_buffer in case we want to do some simple * complete. TEXT is the word to complete. We can use the entire
parsing. Returnthe array of matches, or NULL if there aren't any. */ * contents of rl_line_buffer in case we want to do some simple
char ** * parsing. Returnthe array of matches, or NULL if there aren't any.
fileman_completion (const char* text, int start, int end __attribute__((__unused__))) */
char **fileman_completion(const char *text, int start, int end)
{ {
char **matches; char **matches = NULL;
matches = (char **)NULL; /* If this word is at the start of the line, then it is a command
to complete. Otherwise it is the name of a file in the current
directory. */
if (start == 0)
matches = rl_completion_matches(text, command_generator);
/* If this word is at the start of the line, then it is a command return matches;
to complete. Otherwise it is the name of a file in the current
directory. */
if (start == 0)
matches = rl_completion_matches (text, command_generator);
return (matches);
} }
/* Generator function for command completion. STATE lets us /* Generator function for command completion. STATE lets us
know whether to start from scratch; without any state know whether to start from scratch; without any state
(i.e. STATE == 0), then we start at the top of the list. */ (i.e. STATE == 0), then we start at the top of the list. */
char * char *command_generator(const char *text, int state)
command_generator (text, state)
const char *text;
int state;
{ {
static int list_index, len; static int list_index, len;
char *name; char *name;
/* If this is a new word to complete, initialize now. This /* If this is a new word to complete, initialize now. This
includes saving the length of TEXT for efficiency, and includes saving the length of TEXT for efficiency, and
initializing the index variable to 0. */ initializing the index variable to 0. */
if (!state) if (!state) {
{ list_index = 0;
list_index = 0; len = strlen(text);
len = strlen (text); }
}
/* Return the next name which partially matches from the /* Return the next name which partially matches from the
command list. */ command list. */
while ((name = commands[list_index].name)) while ((name = commands[list_index].name)) {
{ list_index++;
list_index++;
if (strncmp (name, text, len) == 0) if (strncmp(name, text, len) == 0)
return (dupstr(name)); return strdup(name);
} }
/* If no names matched, then return NULL. */ /* If no names matched, then return NULL. */
return ((char *)NULL); return NULL;
} }
/* **************************************************************** */ /* **************************************************************** */
@@ -295,193 +263,169 @@ command_generator (text, state)
static char syscom[1024]; static char syscom[1024];
/* List the file(s) named in arg. */ /* List the file(s) named in arg. */
int int com_list(char *arg)
com_list (char *arg)
{ {
if (!arg) if (!arg)
arg = ""; arg = "";
sprintf (syscom, "ls -FClg %s", arg); sprintf(syscom, "ls -FClg %s", arg);
return (system (syscom));
return system(syscom);
} }
int int com_view(char *arg)
com_view (char *arg)
{ {
if (!valid_argument ("view", arg)) if (!valid_argument("view", arg))
return 1; return 1;
sprintf (syscom, "more %s", arg); sprintf(syscom, "more %s", arg);
return (system (syscom));
return system(syscom);
} }
int int com_history(char *arg)
com_history(char* arg __attribute__((__unused__)))
{ {
const char *he; const char *he;
/* rewind history */ /* rewind history */
while (el_prev_hist()) while (el_prev_hist()) ;
;
for (he = el_next_hist(); he != NULL; he = el_next_hist()) for (he = el_next_hist(); he != NULL; he = el_next_hist())
printf("%s\n", he); printf("%s\n", he);
return 0; return 0;
} }
int int com_rename(char *arg)
com_rename (char *arg __attribute__((__unused__)))
{ {
too_dangerous ("rename"); too_dangerous("rename");
return (1); return 1;
} }
int int com_stat(char *arg)
com_stat (char *arg)
{ {
struct stat finfo; struct stat finfo;
if (!valid_argument ("stat", arg)) if (!valid_argument("stat", arg))
return (1); return 1;
if (stat (arg, &finfo) == -1) if (stat(arg, &finfo) == -1) {
{ perror(arg);
perror (arg); return 1;
return (1); }
}
printf ("Statistics for `%s':\n", arg); printf("Statistics for `%s':\n", arg);
printf ("%s has %ld link%s, and is %lld byte%s in length.\n", arg, printf("%s has %ld link%s, and is %lld byte%s in length.\n", arg,
(long) finfo.st_nlink, (long)finfo.st_nlink,
(finfo.st_nlink == 1) ? "" : "s", (finfo.st_nlink == 1) ? "" : "s",
(long long) finfo.st_size, (long long)finfo.st_size, (finfo.st_size == 1) ? "" : "s");
(finfo.st_size == 1) ? "" : "s"); printf("Inode Last Change at: %s", ctime(&finfo.st_ctime));
printf ("Inode Last Change at: %s", ctime (&finfo.st_ctime)); printf(" Last access at: %s", ctime(&finfo.st_atime));
printf (" Last access at: %s", ctime (&finfo.st_atime)); printf(" Last modified at: %s", ctime(&finfo.st_mtime));
printf (" Last modified at: %s", ctime (&finfo.st_mtime));
return (0); return 0;
} }
int int com_delete(char *arg)
com_delete (char *arg __attribute__((__unused__)))
{ {
too_dangerous ("delete"); too_dangerous("delete");
return (1); return 1;
} }
/* Print out help for ARG, or for all of the commands if ARG is /* Print out help for ARG, or for all of the commands if ARG is
not present. */ not present. */
int int com_help(char *arg)
com_help (char *arg)
{ {
register int i; int i;
int printed = 0; int printed = 0;
for (i = 0; commands[i].name; i++) for (i = 0; commands[i].name; i++) {
{ if (!*arg || (strcmp(arg, commands[i].name) == 0)) {
if (!*arg || (strcmp (arg, commands[i].name) == 0)) printf("%s\t\t%s.\n", commands[i].name,
{ commands[i].doc);
printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc); printed++;
printed++; }
} }
}
if (!printed) if (!printed) {
{ printf("No commands match `%s'. Possibilties are:\n", arg);
printf ("No commands match `%s'. Possibilties are:\n", arg);
for (i = 0; commands[i].name; i++) for (i = 0; commands[i].name; i++) {
{ /* Print in six columns. */
/* Print in six columns. */ if (printed == 6) {
if (printed == 6) printed = 0;
{ printf("\n");
printed = 0; }
printf ("\n");
}
printf ("%s\t", commands[i].name); printf("%s\t", commands[i].name);
printed++; printed++;
} }
if (printed) if (printed)
printf ("\n"); printf("\n");
} }
return (0);
return 0;
} }
/* Change to the directory ARG. */ /* Change to the directory ARG. */
int int com_cd(char *arg)
com_cd (char *arg)
{ {
if (chdir (arg) == -1) if (chdir(arg) == -1) {
{ perror(arg);
perror (arg); return 1;
return 1; }
}
com_pwd (""); com_pwd("");
return (0); return 0;
} }
/* Print out the current working directory. */ /* Print out the current working directory. */
int int com_pwd(char *ignore)
com_pwd (char* ignore __attribute__((__unused__)))
{ {
char dir[1024], *s; char dir[1024], *s;
s = (char*)getcwd(dir, sizeof(dir) - 1); s = getcwd(dir, sizeof(dir) - 1);
if (s == 0) if (!s) {
{ printf("Error getting pwd: %s\n", dir);
printf ("Error getting pwd: %s\n", dir); return 1;
return 1; }
}
printf ("Current directory is %s\n", dir); printf("Current directory is %s\n", dir);
return 0; return 0;
} }
/* The user wishes to quit using this program. Just set DONE /* The user wishes to quit using this program. Just set DONE
non-zero. */ non-zero. */
int int com_quit(char *arg)
com_quit (char *arg __attribute__((__unused__)))
{ {
done = 1; done = 1;
return (0); return 0;
} }
/* Function which tells you that you can't do this. */ /* Function which tells you that you can't do this. */
void void too_dangerous(char *caller)
too_dangerous (char *caller)
{ {
fprintf (stderr, fprintf(stderr, "%s: Too dangerous for me to distribute.\n", caller);
"%s: Too dangerous for me to distribute.\n", fprintf(stderr, "Write it yourself.\n");
caller);
fprintf (stderr, "Write it yourself.\n");
} }
/* Return non-zero if ARG is a valid argument for CALLER, /* Return non-zero if ARG is a valid argument for CALLER,
else print an error message and return zero. */ else print an error message and return zero. */
int int valid_argument(char *caller, char *arg)
valid_argument (char *caller, char *arg)
{ {
if (!arg || !*arg) if (!arg || !*arg) {
{ fprintf(stderr, "%s: Argument required.\n", caller);
fprintf (stderr, "%s: Argument required.\n", caller); return 0;
return (0); }
}
return (1); return 1;
} }
void * /**
xmalloc (size_t size) * Local Variables:
{ * c-file-style: "k&r"
register void *value = (void*)malloc(size); * c-basic-offset: 4
if (value == 0) * End:
fprintf(stderr, "virtual memory exhausted"); */
return value;
}

View File

@@ -114,6 +114,8 @@ extern void add_history (const char *line);
extern int read_history (const char *filename); extern int read_history (const char *filename);
extern int write_history (const char *filename); extern int write_history (const char *filename);
extern rl_getc_func_t *rl_set_getc_func(rl_getc_func_t *func);
extern rl_completion_func_t *rl_attempted_completion_function; extern rl_completion_func_t *rl_attempted_completion_function;
extern rl_complete_func_t *rl_set_complete_func (rl_complete_func_t *func); extern rl_complete_func_t *rl_set_complete_func (rl_complete_func_t *func);
extern rl_list_possib_func_t *rl_set_list_possib_func (rl_list_possib_func_t *func); extern rl_list_possib_func_t *rl_set_list_possib_func (rl_list_possib_func_t *func);

View File

@@ -1,200 +1,274 @@
.TH EDITLINE 3 .Dd April 27, 2019
.SH NAME .Dt EDITLINE 3
editline \- command-line editing library with history .Os
.SH SYNOPSIS .Sh NAME
.nf .Nm editline
.B "char *readline(char *prompt);" .Nd command-line editing library with history
.fi .Sh LIBRARY
.SH DESCRIPTION .Lb libeditline
.I Editline .Sh SYNOPSIS
is a library that provides an line-editing interface with history. .In editline.h
It is intended to be functionally equivalent with the .Fn "char *readline" "const char *prompt"
.I readline .Fn "void add_history" "const char *line"
library provided by the Free Software Foundation, but much smaller. .Fn "int read_history" "const char *filename"
The bulk of this manual page describes the user interface. .Fn "int write_history" "const char *filename"
.PP .Sh DESCRIPTION
.Nm
is a library that provides n line-editing interface with history. It
is intended to be functionally equivalent with the
.Nm readline
library provided by the Free Software Foundation, but much smaller. The
bulk of this manual page describes the basic user interface. More APIs,
both native and for
.Nm readline
compatibility ,
are also available. See the
.Cm editline.h
header file for details.
.Pp
The The
.I readline() .Fn readline
function displays the given function displays the given
.I prompt .Fa prompt
on stdout, waits for user input on stdin and then on stdout, waits for user input on stdin and then returns a line of text
returns a line of text with the trailing newline removed. The data is returned in a with the trailing newline removed. The data is returned in a buffer
buffer allocated with allocated with
.IR malloc (3), .Xr malloc 3 ,
so the space should be released with so the space should be released with
.IR free (3) .Xr free 3
when the calling program is done with it. when the calling program is done with it.
.PP .Pp
Each line returned is copied to the internal history list, unless it happens Each line returned is automatically saved in the internal history list,
to be equal to the previous line. This is configurable if you are building editline unless it happens to be equal to the previous line. This is
from source. configurable if you are building editline from source, i.e. if you would
.SS User Interface rather like to call
A program that uses this library provides a simple emacs-like editing interface to .Fn add_history
its users. A line may be edited before it is sent to the calling program by typing manually.
either control characters or escape sequences. A control character, shown as a caret .Pp
followed by a letter, is typed by holding down the ``control'' key while the letter The
is typed. For example, ``^A'' is a control-A. An escape sequence is entered by .Fn read_history
typing the ``escape'' key followed by one or more characters. The escape key is and
abbreviated as ``ESC''. Note that unlike control keys, case matters in escape .Fn write_history
sequences; ``ESC\ F'' is not the same as ``ESC\ f''. functions can be used to load and store the history of your application.
.PP .Em Note:
An editing command may be typed anywhere on the line, not just at the beginning. In these APIs do not do any tilde or environment variable expansion of the
addition, a return may also be typed anywhere on the line, not just at the end. given filename.
.PP .Ss User Interface
A program that uses this library provides a simple emacs-like editing
interface to its users. A line may be edited before it is sent to the
calling program by typing either control characters or escape sequences.
A control character, shown as a caret followed by a letter, is typed by
holding down the control key while the letter is typed. For example,
.Cm ^A
is a control-A. An escape sequence is entered by typing the escape key
followed by one or more characters. The escape key is abbreviated as
.Cm ESC .
Note that unlike control keys, case matters in escape sequences;
.Cm ESC F
is not the same as
.Cm ESC f .
.Pp
An editing command may be typed anywhere on the line, not just at the
beginning. In addition, a return may also be typed anywhere on the
line, not just at the end.
.Pp
Most editing commands may be given a repeat count, Most editing commands may be given a repeat count,
.IR n , .Ar n ,
where where
.I n .Ar n
is a number. is a number. To enter a repeat count, type the escape key, the number,
To enter a repeat count, type the escape key, the number, and then and then the command to execute. For example,
the command to execute. .Cm ESC 4 ^f
For example, ``ESC\ 4\ ^f'' moves forward four characters. moves forward four characters. If a command may be given a repeat count
If a command may be given a repeat count then the text ``[n]'' is given at the then the text
end of its description. .Cm [n]
.PP is given at the end of its description.
.Pp
The following control characters are accepted: The following control characters are accepted:
.RS .Pp
.nf .Bl -tag -width "ESC DEL " -compact
.ta \w'ESC DEL 'u .It ^A
^A Move to the beginning of the line Move to the beginning of the line
^B Move left (backwards) [n] .It ^B
^D Delete character [n] Move left (backwards) [n]
^E Move to end of line .It ^D
^F Move right (forwards) [n] Delete character [n]
^G Ring the bell .It ^E
^H Delete character before cursor (backspace key) [n] Move to end of line
^I Complete filename (tab key); see below .It ^F
^J Done with line (return key) Move right (forwards) [n]
^K Kill to end of line (or column [n]) .It ^G
^L Redisplay line Ring the bell
^M Done with line (alternate return key) .It ^H
^N Get next line from history [n] Delete character before cursor (backspace key) [n]
^P Get previous line from history [n] .It ^I
^R Search backward (forward if [n]) through history for Complete filename (tab key); see below
\& text; must start line if text begins with an uparrow .It ^J
^T Transpose characters Done with line (return key)
^V Insert next character, even if it is an edit command .It ^K
^W Wipe to the mark Kill to end of line (or column [n])
^X^X Exchange current location and mark .It ^L
^Y Yank back last killed text Redisplay line
^[ Start an escape sequence (escape key) .It ^M
^]c Move forward to next character ``c'' Done with line (alternate return key)
^? Delete character before cursor (delete key) [n] .It ^N
.fi Get next line from history [n]
.RE .It ^P
.PP Get previous line from history [n]
The following escape sequences are provided. .It ^R
.RS Search backward (forward if [n]) through history for text; prefixing the
.nf string with a caret (^) forces it to match only at the beginning of a
.ta \w'ESC DEL 'u history line
ESC\ ^H Delete previous word (backspace key) [n] .It ^T
ESC\ DEL Delete previous word (delete key) [n] Transpose characters
ESC\ SP Set the mark (space key); see ^X^X and ^Y above .It ^V
ESC\ \. Get the last (or [n]'th) word from previous line Insert next character, even if it is an edit command
ESC\ ? Show possible completions; see below .It ^W
ESC\ < Move to start of history Wipe to the mark
ESC\ > Move to end of history .It ^X^X
ESC\ b Move backward a word [n] Exchange current location and mark
ESC\ d Delete word under cursor [n] .It ^Y
ESC\ f Move forward a word [n] Yank back last killed text
ESC\ l Make word lowercase [n] .It ^[
ESC\ m Toggle if 8bit chars display normally or with an Start an escape sequence (escape key)
\& ``M\-'' prefix .It ^]c
ESC\ u Make word uppercase [n] Move forward to next character
ESC\ y Yank back last killed text .Cm c
ESC\ v Show library version .It ^?
ESC\ w Make area up to mark yankable Delete character before cursor (delete key) [n]
ESC\ nn Set repeat count to the number nn .El
ESC\ C Read from environment variable ``_C_'', where C is .Pp
\& an uppercase letter The following escape sequences are provided:
.fi .Pp
.RE .Bl -tag -width "ESC DEL " -compact
.PP .It ESC ^H
Delete previous word (backspace key) [n]
.It ESC DEL
Delete previous word (delete key) [n]
.It ESC SP
Set the mark (space key); see ^X^X and ^Y above
.It ESC\ .
Get the last (or [n]'th) word from previous line
.It ESC\ ?
Show possible completions; see below
.It ESC <
Move to start of history
.It ESC >
Move to end of history
.It ESC b
Move backward a word [n]
.It ESC d
Delete word under cursor [n]
.It ESC f
Move forward a word [n]
.It ESC l
Make word lowercase [n]
.It ESC m
Toggle if 8bit chars display normally or with an
.Ar M-
prefix
.It ESC u
Make word uppercase [n]
.It ESC y
Yank back last killed text
.It ESC v
Show library version
.It ESC w
Make area up to mark yankable
.It ESC nn
Set repeat count to the number nn
.It ESC C
Read from environment variable
.Ar $C ,
where
.Ar C
is an uppercase letter
.El
.Pp
The The
.I editline .Nm
library has a small macro facility. library has a small macro facility. If you type the escape key followed
If you type the escape key followed by an uppercase letter, by an uppercase letter,
.IR C , .Ar C ,
then the contents of the environment variable then the contents of the environment variable
.I _C_ .Ar $C
are read in as if you had typed them at the keyboard. are read in as if you had typed them at the keyboard. For example, if
For example, if the variable the variable
.I _L_ .Ar $L
contains the following: contains the following:
.PP .Pp
.RS .Dl ^A^Kecho '^V^[[H^V^[[2J'^M
^A^Kecho '^V^[[H^V^[[2J'^M .Pp
.RE Then typing
.PP .Cm ESC L
Then typing ``ESC L'' will move to the beginning of the line, kill the will move to the beginning of the line, kill the entire line, enter the
entire line, enter the echo command needed to clear the terminal (if your echo command needed to clear the terminal (if your terminal is like a
terminal is like a VT-100), and send the line back to the shell. VT-100), and send the line back to the shell.
.PP .Pp
The The
.I editline .Nm
library also does filename completion. library also does filename completion. Suppose the root directory has
Suppose the root directory has the following files in it: the following files in it:
.PP .Pp
.RS .Dl bin vmunix
.nf .Dl core vmunix.old
.ta \w'core 'u .Pp
bin vmunix If you type
core vmunix.old .Cm rm /v
.fi and then the tab key,
.RE .Nm
.PP will then finish off as much of the name as possible by adding
If you type ``rm\ /v'' and then the tab key. .Ar munix .
.I Editline Because the name is not unique, it will then beep. If you type the
will then finish off as much of the name as possible by adding ``munix''. escape key and a question mark, it will display the two choices. If you
Because the name is not unique, it will then beep. then type a period and a tab, the library will finish off the filename
If you type the escape key and a question mark, it will display the
two choices.
If you then type a period and a tab, the library will finish off the filename
for you: for you:
.PP .Pp
.RS .Bd -ragged -offset indent
.nf rm /v[TAB]
.RI "rm /v[TAB]" munix ".[TAB]" old .Em munix
.fi \&.[TAB]
.RE .Em old
.PP .Ed
The tab key is shown by ``[TAB]'' and the automatically-entered text .Pp
is shown in italics. The tab key is shown by [TAB] and the automatically-entered text
.SH USAGE is shown in italics, or underline.
.Sh USAGE
To include To include
.I readline() .Nm
in your program, simply call it as you do any other function. Just make sure to link in your program, call it as you do any other function and link your
your program with libeditline. program with
.SS Example .Ar -leditline .
.Ss Example
The following brief example lets you enter a line and edit it, then displays it. The following brief example lets you enter a line and edit it, then displays it.
.nf .Pp
.B "" .Bd -literal -offset indent
.B #include <stdlib.h> #include <stdio.h>
.B "" #include <stdlib.h>
.B extern char *readline(char *prompt); #include <editline.h>
.B ""
.B int main(void) int main(void)
.B { {
.RS char *p;
.B char *p;
.B "" while ((p = readline("CLI> "))) {
.B while ((p = readline("CLI>"))) { puts(p);
.RS free(p);
.B puts(p); }
.B free(p);
.RE return 0;
.B } }
.B "" .El
.B return 0; .Sh AUTHORS
.RE The original editline library was posted to comp.sources.unix newsgroup
.B } by created by Simmule R. Turner and Rich Salz in 1992. It now exists in
.fi several forks: Debian, Minix, Heimdal, Festival speech tools, Mozilla,
.SH AUTHORS Google Gadgets for Linux, and many other places. The original manual
The original editline library was created by Simmule R. Turner and Rich page was made by David W. Sanderson.
Salz. It now exists in several forks: Heimdal, Festival speech tools, .Pp
Mozilla, Google Gadgets for Linux, and many other places. The original This version was originally based on the Minix 2 sources, but has since
manual page was made by David W. Sanderson. This version is maintained evolved to include patches from all relevant forks. It is currently
by Joachim Nilsson at GitHub, maintained by Joachim Nilsson at GitHub,
.Aq http://github.com/troglobit/editline .Aq http://github.com/troglobit/editline
.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:0:0 libeditline_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:2:0

File diff suppressed because it is too large Load Diff

View File

@@ -57,8 +57,10 @@
#define MEM_INC 64 #define MEM_INC 64
#define SCREEN_INC 256 #define SCREEN_INC 256
/* http://stackoverflow.com/questions/1598773/is-there-a-standard-function-in-c-that-would-return-the-length-of-an-array/1598827#1598827 */ /* From The Practice of Programming, by Kernighan and Pike */
#define ARRAY_ELEMENTS(arr) ((sizeof(arr)/sizeof(0[arr])) / ((size_t)(!(sizeof(arr) % sizeof(0[arr]))))) #ifndef NELEMS
#define NELEMS(array) (sizeof(array) / sizeof(array[0]))
#endif
/* /*
** Variables and routines internal to this package. ** Variables and routines internal to this package.