Compare commits

..

121 Commits

Author SHA1 Message Date
Joachim Wiberg
9df73e8670
Merge pull request #74 from tgree/macos_prototypes_fix
Fix function prototypes
2025-04-06 13:34:10 +02:00
Terry Greeniaus
f53bebdbe9 Fix function prototypes.
This allows it to compile on macOS 15.3.2 using the default command-line
tools (clang-1600.0.26.6).
2025-04-05 23:17:20 -06:00
Joachim Wiberg
50bde4b5c3 Constify
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-12-08 21:41:48 +01:00
Joachim Wiberg
651c0bf38b examples: update prompt in fileman to show cwd
This shows off the rl_set_prompt() API to provide a more dynamic prompt.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-12-08 21:36:12 +01:00
Joachim Wiberg
d1ea173949 Fix and make sure to use rl_set_prompt() API
Fixes #51

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-12-08 21:34:56 +01:00
Joachim Wiberg
2c0313a3b5 Move forward wordwise should move to end of current word
For a similar feel like GNU Readline we should not skip to the next word
but stop at the end of the current.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-12-08 08:22:27 +01:00
Joachim Wiberg
41d80b5b14 Calling Ctrl-U should delete from cursor to beginning
Fixes #71

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-12-08 08:12:19 +01:00
Joachim Wiberg
c7437c8ce3 Fix doube free in completion
When falling back to rl_filename_completion_fuction as compentry
generator, the complete() function caused double free because the
generator did not return a strdup'ed entry but one of its own that
it freed when done.

Fixes #56

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-12-07 10:38:57 +01:00
Joachim Wiberg
22bdb0478c Minor, update maintainer last name
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-12-07 08:33:54 +01:00
Joachim Wiberg
fb4d7268de
Merge pull request #70 from 9999years/recognize-meta-arrows
Recognize `Meta+Left` and `Meta+Right` for word navigation
2024-12-07 08:32:55 +01:00
Rebecca Turner
4c4455353a
Add support for \e[1;3C and \e[1;3D 2024-09-09 09:44:44 -07:00
Rebecca Turner
d0f2a5bc23
Recognize Meta+Left and Meta+Right
I'm not sure exactly where to find canonical documentation for these
codes, but this seems to match what my terminal produces (macOS + iTerm2
+ Fish + Tmux).

It might also be nice to have some more support for editing the bindings
for these characters; sequences of more than one character are not
supported by `el_bind_key` and similar.
2024-09-08 19:32:28 -07:00
Joachim Wiberg
ac81ca6d4b
Merge pull request #69 from vikrrrr/missing-global
Add rl_attempted_completion_over global to header

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2024-09-07 11:02:46 +02:00
Arthur Michas
93d952291f
Add rl_attempted_completion_over global to header
Signed-off-by: Arthur Michas <vikr@protonmail.com>
2024-09-07 02:53:08 +02:00
Joachim Wiberg
caf4b3c0ce
Merge pull request #67 from Feoramund/respect-hist-size 2024-05-27 17:44:43 +02:00
Joachim Wiberg
6207edfe95
Merge pull request #68 from Feoramund/respect-default-prompt 2024-05-27 17:44:05 +02:00
Feoramund
e0f686506a
Respect default prompt
A prompt `"? "` is set in `rl_initialize`, but it is never seen, because
this line was replacing it with `NILSTR`.
2024-05-26 04:13:29 -04:00
Feoramund
aefda06a0c
Respect el_hist_size
It was previously subject to a sort of off-by-one error, because of the
addition of `NILSTR` in `el_prep`. This should allow a history size of 1
to function correctly now.
2024-05-26 03:38:04 -04:00
Joachim Wiberg
425584840c
Merge pull request #64 from trofi/autoconf-2.72-fix 2023-12-24 03:45:37 +01:00
Sergei Trofimovich
2b788be1c8 configure.ac: add second parameter quoting around the rest of AS_IF for consistency 2023-12-23 19:17:19 +00:00
Sergei Trofimovich
f444a316f5 configure.ac: fix autoconf-2.72 compatibility
`autoconf-2.72` slightly changed `AS_IF`/`AC_CHECL_LIB` definitions and
exposed the bug of missng quoting around the arguments:

    editline> ./configure: line 13944: syntax error near unexpected token `;;'
    editline> ./configure: line 13944: ` ;;'

The change adds quoting as suggested by https://savannah.gnu.org/support/index.php?110990
2023-12-23 19:13:52 +00:00
Joachim Wiberg
7633fbceee
Merge pull request #63 from nobody5050/patch-1
fix filename inaccuracy

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2023-01-29 06:47:11 +01:00
nobody5050
d903a940a5
fix filename inaccuracy 2023-01-28 12:44:44 -06:00
Joachim Wiberg
3ccc3a5120
Merge pull request #62 from al20878/master
Fix #61: gcc sign extension warnings

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-10-23 15:14:18 +02:00
Tony Lawrence
c50d4c34d8 Avoid using (char) in <ctype.h> macros (#61) 2022-10-22 20:02:23 -04:00
Tony Lawrence
70c80ac22e Mention autoconf.sh in build instructions (#61) 2022-10-22 20:02:16 -04:00
Joachim Wiberg
9fa05ba384 Add early notice on Windows not being supported
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-02-19 22:41:32 +01:00
Joachim Wiberg
9d4c6f7042 Drop orig. effort to support WIN32
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2022-02-19 22:38:55 +01:00
Joachim Wiberg
fc866f60d6
Merge pull request #57 from rcombs/patch-1
Include stdio.h from editline.h
2022-02-19 22:09:15 +01:00
rcombs
f7b58d3c0d
Include stdio.h from editline.h
Fixes `#include <editline.h>` without first including `<stdio.h>`, which previously errored at the missing typedef for `FILE`.
2022-02-17 17:59:40 -06:00
Joachim Wiberg
36e0921c71
Merge pull request #54 from tejing1/master
handle home and end keys in urxvt
2021-07-06 08:23:08 +02:00
Jeff Huffman
ec62e11a72
handle home and end keys in urxvt 2021-06-27 22:44:30 -04:00
Joachim Wiberg
0f4f5b0228
Merge pull request #53 from oxalica/fix/tmux-home-end
Fix Home (\e[1~) and End (\e[4~) in tmux
2021-05-29 15:22:18 +02:00
oxalica
265c1fb6a0
Fix Home (\e[1~) and End (\e[4~) in tmux 2021-05-29 14:30:05 +08:00
Joachim Wiberg
69c7e86967 Merge branch 'mlundh-bufferOverrunFix'
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2021-02-25 10:51:58 +01:00
Martin Lundh
3acd6a8b60 Fixed buffer overrun issue detected by address sanitizer. 2021-02-25 10:22:50 +01:00
Joachim Nilsson
62bba78258 Fix #41: add missing include in example
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-08-02 02:15:37 +02:00
Joachim Nilsson
63b94d2089 configure: Add --enable-examples option to build examples/
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-06-08 18:47:17 +02:00
Joachim Nilsson
2ebe9058a1
Merge pull request #40 from gh-fork-dump/master
POSIX recommends <sys/select.h> for select()
2020-06-08 18:43:27 +02:00
Stephen Gregoratto
d4b25ca85e include <sys/select.h> in excallback
Fixes an build issue when cross-compiling for SerenityOS[1]

[1] https://github.com/SerenityOS/serenity
2020-06-09 00:21:11 +10:00
Joachim Nilsson
ecabef273e debian: Upload to stable
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 19:07:45 +01:00
Joachim Nilsson
751c8ac7d1 Check for release tag before calling distcheck
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:46:59 +01:00
Joachim Nilsson
70d190340a Update changelogs and bump version for v1.17.1 release
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:46:48 +01:00
Joachim Nilsson
db318fd765 Drop duplicate package: rule
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:43:52 +01:00
Joachim Nilsson
d2fa0e4c6e Put auxillary files generated by autotools in aux/
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:43:52 +01:00
Joachim Nilsson
3e40e24e11 Reintroduce .tar.gz for distribution archives
For systems that don't have xz in the base install.

Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:43:52 +01:00
Joachim Nilsson
322055b89a debian: Ship upstream ChangeLog in .deb
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:43:52 +01:00
Joachim Nilsson
e1981428e7 debian: Add hardening, recommended by lintian
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:43:52 +01:00
Joachim Nilsson
d65245abbd debian: .so symlinks should be in -dev package, found by lintian
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:43:52 +01:00
Joachim Nilsson
45c9b94e11 debian: Update to Standards-Version 4.3.0 and fix shlib deps
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:43:52 +01:00
Joachim Nilsson
bfcf222bdc debian: Add symbols file, found by lintian
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:43:52 +01:00
Joachim Nilsson
49c466a23d man: Update mdoc markup of functions
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:43:52 +01:00
Joachim Nilsson
6702d3262d debian: Update to copyright format 1.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:43:52 +01:00
Joachim Nilsson
d8f3759367 debian: Fix missing content in libedtline1, introduced in 1.16.0
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
2020-02-23 18:43:52 +01:00
Joachim Nilsson
8d5d04f667
Merge pull request #38 from echoprotocol/ECHO-732
added fix for multiline representing as one line
2020-01-13 19:04:28 +01:00
dvolynets
ceee039cfc added fix for multiline representing as one line 2020-01-13 12:15:27 +03:00
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
23 changed files with 1325 additions and 891 deletions

View File

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

View File

@ -4,6 +4,52 @@ Change Log
All notable changes to the project are documented in this file.
[1.17.1][] - 2020-02-23
-----------------------
### 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
- 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
-----------------------
@ -203,7 +249,10 @@ Adaptations to Debian editline package.
- 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.1...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.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.2]: https://github.com/troglobit/finit/compare/1.15.1...1.15.2
@ -220,9 +269,3 @@ Adaptations to Debian editline package.
[Travis-CI]: https://travis-ci.org/troglobit/uftpd
[Coverity Scan]: https://scan.coverity.com/projects/2947
[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
doc_DATA = README.md LICENSE
EXTRA_DIST = README.md LICENSE ChangeLog.md INSTALL.md
SUBDIRS = src include man examples
SUBDIRS = src include man
## Generate .deb package
package build-deb:
@dpkg-buildpackage -uc -us
if ENABLE_EXAMPLES
SUBDIRS += examples
endif
## Generate MD5 checksum file
MD5 = md5sum
@ -39,7 +39,7 @@ package:
dpkg-buildpackage -uc -us -B
## Target to run when building a release
release: distcheck release-hook md5-dist package
release: release-hook distcheck md5-dist package
@echo
@echo "Resulting release files:"
@echo "========================================================================="

View File

@ -33,13 +33,17 @@ to use the library is available in the `examples/` directory.
Editline is maintained collaboratively at [GitHub][].
> **Note:** Windows is not a supported target for editline.
Example
-------
Here 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
availble in the source tree.
Below is a very brief example to illustrate how one can use Editline to
create a simple CLI, Ctrl-D exits the program. A slightly more advanced
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][]
The configure script defaults to a `/usr/local` prefix.
@ -54,6 +58,7 @@ availble in the source tree.
e.g. `~/src/example.c`
```C
#include <stdio.h>
#include <stdlib.h>
#include <editline.h>
@ -193,6 +198,7 @@ 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
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>
2. Build the library and examples: <kbd>make all</kbd>
3. Install using <kbd>make install</kbd>
@ -221,7 +227,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
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
that [Jess Thrysøe][jess] disitributes to the world outside *BSD. The
libraries have much in common, but the latter is heavily refactored and
@ -255,7 +261,7 @@ Outstanding issues are listed in the [TODO.md][] file.
[FSF readline]: http://www.gnu.org/software/readline/
[Rich Salz]: https://github.com/richsalz/editline/
[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/
[BSD license]: http://en.wikipedia.org/wiki/BSD_licenses
[libeditline]: http://packages.qa.debian.org/e/editline.html

View File

@ -1,5 +1,6 @@
AC_INIT(editline, 1.16.0, https://github.com/troglobit/editline/issues)
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
AC_INIT(editline, 1.17.1, https://github.com/troglobit/editline/issues)
AC_CONFIG_AUX_DIR(aux)
AM_INIT_AUTOMAKE([1.11 foreign dist-xz])
AM_SILENT_RULES([yes])
AC_CONFIG_MACRO_DIR([m4])
@ -60,29 +61,35 @@ AC_ARG_ENABLE(terminal-bell,
AC_ARG_ENABLE(termcap,
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
#
AS_IF([test "x$enable_unique_history" != "xno"],
AC_DEFINE(CONFIG_UNIQUE_HISTORY, 1, [Define to skip duplicate lines in the scrollback history.]))
AS_IF([test "x$enable_unique_history" != "xno"], [
AC_DEFINE(CONFIG_UNIQUE_HISTORY, 1, [Define to skip duplicate lines in the scrollback history.])])
AS_IF([test "x$enable_terminal_bell" != "xno"],
AC_DEFINE(CONFIG_ANSI_ARROWS, 1, [Define to include ANSI arrow keys support.]))
AS_IF([test "x$enable_terminal_bell" != "xno"], [
AC_DEFINE(CONFIG_ANSI_ARROWS, 1, [Define to include ANSI arrow keys support.])])
AS_IF([test "x$enable_terminal_bell" != "xno"],
AC_DEFINE(CONFIG_EOF, 1, [Define to enable EOF (Ctrl-C) key.]))
AS_IF([test "x$enable_eof" != "xno"], [
AC_DEFINE(CONFIG_EOF, 1, [Define to enable EOF (Ctrl-D) key.])])
AS_IF([test "x$enable_sigint" != "xno"],
AC_DEFINE(CONFIG_SIGINT, 1, [Define to enable SIGINT (Ctrl-C) key.]))
AS_IF([test "x$enable_sigint" != "xno"], [
AC_DEFINE(CONFIG_SIGINT, 1, [Define to enable SIGINT (Ctrl-C) key.])])
AS_IF([test "x$enable_sigstop" = "xyes"],
AC_DEFINE(CONFIG_SIGSTOP, 1, [Define to enable SIGSTOP (Ctrl-Z) key.]))
AS_IF([test "x$enable_sigstop" = "xyes"], [
AC_DEFINE(CONFIG_SIGSTOP, 1, [Define to enable SIGSTOP (Ctrl-Z) key.])])
AS_IF([test "x$enable_terminal_bell" = "xyes"],
AC_DEFINE(CONFIG_TERMINAL_BELL, 1, [Define to enable terminal bell on completion.]))
AS_IF([test "x$enable_terminal_bell" = "xyes"], [
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
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_CHECK_LIB(terminfo, tgetent, , [
AC_CHECK_LIB(termcap, tgetent, , [
@ -93,7 +100,7 @@ AS_IF([test "x$enable_termcap" = "xyes"],
])
])
])
]))
])])
# Generate all files
AC_OUTPUT

24
debian/changelog vendored
View File

@ -1,3 +1,27 @@
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
* 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
* New upstream release, v1.60.0

2
debian/compat vendored
View File

@ -1 +1 @@
9
10

6
debian/control vendored
View File

@ -1,9 +1,9 @@
Source: editline
Section: devel
Priority: optional
Build-Depends: debhelper (>= 5.0), libtool
Maintainer: Joachim Nilsson <troglobit@gmail.com>
Standards-Version: 3.8.3
Build-Depends: debhelper (>= 10), libtool
Maintainer: Joachim Wiberg <troglobit@gmail.com>
Standards-Version: 4.3.0
Package: libeditline-dev
Architecture: any

25
debian/copyright vendored
View File

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

View File

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

View File

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

1
debian/libeditline1.install vendored Normal file
View File

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

67
debian/libeditline1.symbols vendored Normal file
View File

@ -0,0 +1,67 @@
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,8 +1,16 @@
#!/usr/bin/make -f
# Uncomment this to turn on verbose mode.
# 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
override_dh_installchangelogs:
dh_installchangelogs ChangeLog.md

View File

@ -64,7 +64,10 @@ static int my_rl_list_possib(char *token, char ***av)
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++) {
if (!strncmp(list[i], token, strlen (token))) {
copy[total] = strdup(list[i]);
@ -98,39 +101,68 @@ el_status_t list_possible(void)
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)
{
puts("Abort!");
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)
{
char *line;
char *prompt = "cli> ";
signal(SIGINT, breakit);
/* Setup callbacks */
rl_set_complete_func(&my_rl_complete);
rl_set_list_possib_func(&my_rl_list_possib);
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);
read_history(HISTORY);
while ((line = readline(prompt)) != NULL) {
while ((line = readline(prompt))) {
if (!strncmp(line, "unlock", 6) && unlock("secret")) {
free(line);
fprintf(stderr, "\nSecurity breach, user logged out!\n");
break;
}
if (*line != '\0')
printf("\t\t\t|%s|\n", line);
free(line);
}

View File

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

View File

@ -7,6 +7,7 @@
*/
#include <assert.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
@ -21,14 +22,11 @@
#include "editline.h"
void * xmalloc (size_t size);
void too_dangerous(char *caller);
void initialize_readline ();
void initialize_readline(const char *prompt);
int execute_line(char *line);
int valid_argument(char *caller, char *arg);
typedef int rl_icpfunc_t (char *);
/* The names of functions that actually do the manipulation. */
int com_list(char *);
int com_view(char *);
@ -41,16 +39,13 @@ int com_help(char *);
int com_cd(char *);
int com_quit(char *);
/* A structure which contains information on the commands this program
can understand. */
typedef struct {
struct cmd {
char *name; /* User printable name of the function. */
rl_icpfunc_t *func; /* Function to call to do the job. */
int (*func)(char *); /* Function to call to do the job. */
char *doc; /* Documentation for this function. */
} COMMAND;
};
COMMAND commands[] = {
struct cmd commands[] = {
{ "cd", com_cd, "Change to directory DIR"},
{ "delete", com_delete, "Delete FILE"},
{ "help", com_help, "Display this text"},
@ -63,44 +58,33 @@ COMMAND commands[] = {
{ "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 }
{ NULL, NULL, NULL },
};
/* Forward declarations. */
char *stripwhite ();
COMMAND *find_command ();
char *stripwhite(char *string);
struct cmd *find_command(char *name);
/* The name of this program, as taken from argv[0]. */
char *progname;
/* ~/.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. */
int done;
char *
dupstr (char* s)
{
char *r;
r = xmalloc (strlen (s) + 1);
strcpy (r, s);
return (r);
}
int
main (int argc __attribute__((__unused__)), char **argv)
int main(int argc, char **argv)
{
char *line, *s;
progname = argv[0];
setlocale(LC_CTYPE, "");
initialize_readline(); /* Bind our completer. */
initialize_readline("(FileMan)");
/* Loop reading and executing lines until the user quits. */
for ( ; done == 0; )
{
line = readline ("FileMan: ");
for (; done == 0;) {
line = readline(NULL);
if (!line)
break;
@ -129,17 +113,19 @@ main (int argc __attribute__((__unused__)), char **argv)
#endif
free(line);
}
exit (0);
puts("");
write_history(fileman_history);
free(fileman_history);
return 0;
}
/* Execute a command line. */
int
execute_line (char *line)
int execute_line(char *line)
{
register int i;
COMMAND *command;
int i;
struct cmd *command;
char *word;
/* Isolate the command word. */
@ -156,10 +142,9 @@ execute_line (char *line)
command = find_command(word);
if (!command)
{
if (!command) {
fprintf(stderr, "%s: No such command for FileMan.\n", word);
return (-1);
return -1;
}
/* Get argument to command, if any. */
@ -169,35 +154,34 @@ execute_line (char *line)
word = line + i;
/* 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
command. Return a NULL pointer if NAME isn't a command name. */
COMMAND *
find_command (char *name)
struct cmd *find_command(char *name)
{
register int i;
int i;
for (i = 0; commands[i].name; i++)
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. */
char *
stripwhite (char *string)
/*
* Strip whitespace from the start and end of STRING. Return a pointer
* into 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)
return (s);
return s;
t = s + strlen(s) - 1;
while (t > s && isspace(*t))
@ -215,31 +199,70 @@ stripwhite (char *string)
char *command_generator(const char *, 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
complete on command names if this is the first word in the line, or
on filenames if not. */
void
initialize_readline ()
/*
* 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
* on filenames if not.
*/
void initialize_readline(const char *prompt)
{
const char *home;
size_t len;
/* Allow conditional parsing of the ~/.inputrc file. */
rl_readline_name = "FileMan";
/* Tell the completer that we want a crack first. */
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();
}
/* Attempt to complete on the contents of TEXT. START and END
bound the region of rl_line_buffer that contains the word to
complete. TEXT is the word to complete. We can use the entire
contents of rl_line_buffer in case we want to do some simple
parsing. Returnthe array of matches, or NULL if there aren't any. */
char **
fileman_completion (const char* text, int start, int end __attribute__((__unused__)))
/*
* 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 **matches;
char cwd[1024];
size_t len;
matches = (char **)NULL;
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);
}
/*
* Attempt to complete on the contents of TEXT. START and END
* bound the region of rl_line_buffer that contains the word to
* complete. TEXT is the word to complete. We can use the entire
* contents of rl_line_buffer in case we want to do some simple
* parsing. Returnthe array of matches, or NULL if there aren't any.
*/
char **fileman_completion(const char *text, int start, int end)
{
char **matches = 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
@ -247,16 +270,13 @@ fileman_completion (const char* text, int start, int end __attribute__((__unused
if (start == 0)
matches = rl_completion_matches(text, command_generator);
return (matches);
return matches;
}
/* Generator function for command completion. STATE lets us
know whether to start from scratch; without any state
(i.e. STATE == 0), then we start at the top of the list. */
char *
command_generator (text, state)
const char *text;
int state;
char *command_generator(const char *text, int state)
{
static int list_index, len;
char *name;
@ -264,24 +284,22 @@ command_generator (text, state)
/* If this is a new word to complete, initialize now. This
includes saving the length of TEXT for efficiency, and
initializing the index variable to 0. */
if (!state)
{
if (!state) {
list_index = 0;
len = strlen(text);
}
/* Return the next name which partially matches from the
command list. */
while ((name = commands[list_index].name))
{
while ((name = commands[list_index].name)) {
list_index++;
if (strncmp(name, text, len) == 0)
return (dupstr(name));
return strdup(name);
}
/* If no names matched, then return NULL. */
return ((char *)NULL);
return NULL;
}
/* **************************************************************** */
@ -295,34 +313,32 @@ command_generator (text, state)
static char syscom[1024];
/* List the file(s) named in arg. */
int
com_list (char *arg)
int com_list(char *arg)
{
if (!arg)
arg = "";
sprintf(syscom, "ls -FClg %s", arg);
return (system (syscom));
return system(syscom);
}
int
com_view (char *arg)
int com_view(char *arg)
{
if (!valid_argument("view", arg))
return 1;
sprintf(syscom, "more %s", arg);
return (system (syscom));
return system(syscom);
}
int
com_history(char* arg __attribute__((__unused__)))
int com_history(char *arg)
{
const char *he;
/* rewind history */
while (el_prev_hist())
;
while (el_prev_hist()) ;
for (he = el_next_hist(); he != NULL; he = el_next_hist())
printf("%s\n", he);
@ -330,25 +346,22 @@ com_history(char* arg __attribute__((__unused__)))
return 0;
}
int
com_rename (char *arg __attribute__((__unused__)))
int com_rename(char *arg)
{
too_dangerous("rename");
return (1);
return 1;
}
int
com_stat (char *arg)
int com_stat(char *arg)
{
struct stat finfo;
if (!valid_argument("stat", arg))
return (1);
return 1;
if (stat (arg, &finfo) == -1)
{
if (stat(arg, &finfo) == -1) {
perror(arg);
return (1);
return 1;
}
printf("Statistics for `%s':\n", arg);
@ -356,47 +369,41 @@ com_stat (char *arg)
printf("%s has %ld link%s, and is %lld byte%s in length.\n", arg,
(long)finfo.st_nlink,
(finfo.st_nlink == 1) ? "" : "s",
(long long) finfo.st_size,
(finfo.st_size == 1) ? "" : "s");
(long long)finfo.st_size, (finfo.st_size == 1) ? "" : "s");
printf("Inode Last Change at: %s", ctime(&finfo.st_ctime));
printf(" Last access at: %s", ctime(&finfo.st_atime));
printf(" Last modified at: %s", ctime(&finfo.st_mtime));
return (0);
return 0;
}
int
com_delete (char *arg __attribute__((__unused__)))
int com_delete(char *arg)
{
too_dangerous("delete");
return (1);
return 1;
}
/* Print out help for ARG, or for all of the commands if ARG is
not present. */
int
com_help (char *arg)
int com_help(char *arg)
{
register int i;
int i;
int printed = 0;
for (i = 0; commands[i].name; i++)
{
if (!*arg || (strcmp (arg, commands[i].name) == 0))
{
printf ("%s\t\t%s.\n", commands[i].name, commands[i].doc);
for (i = 0; commands[i].name; i++) {
if (!*arg || (strcmp(arg, commands[i].name) == 0)) {
printf("%s\t\t%s.\n", commands[i].name,
commands[i].doc);
printed++;
}
}
if (!printed)
{
if (!printed) {
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. */
if (printed == 6)
{
if (printed == 6) {
printed = 0;
printf("\n");
}
@ -408,32 +415,30 @@ com_help (char *arg)
if (printed)
printf("\n");
}
return (0);
return 0;
}
/* Change to the directory ARG. */
int
com_cd (char *arg)
{
if (chdir (arg) == -1)
int com_cd(char *arg)
{
if (chdir(arg) == -1) {
perror(arg);
return 1;
}
com_pwd ("");
return (0);
//com_pwd("");
fileman_prompt();
return 0;
}
/* Print out the current working directory. */
int
com_pwd (char* ignore __attribute__((__unused__)))
int com_pwd(char *ignore)
{
char dir[1024], *s;
s = (char*)getcwd(dir, sizeof(dir) - 1);
if (s == 0)
{
s = getcwd(dir, sizeof(dir) - 1);
if (!s) {
printf("Error getting pwd: %s\n", dir);
return 1;
}
@ -444,44 +449,34 @@ com_pwd (char* ignore __attribute__((__unused__)))
/* The user wishes to quit using this program. Just set DONE
non-zero. */
int
com_quit (char *arg __attribute__((__unused__)))
int com_quit(char *arg)
{
done = 1;
return (0);
return 0;
}
/* Function which tells you that you can't do this. */
void
too_dangerous (char *caller)
void too_dangerous(char *caller)
{
fprintf (stderr,
"%s: Too dangerous for me to distribute.\n",
caller);
fprintf(stderr, "%s: Too dangerous for me to distribute.\n", caller);
fprintf(stderr, "Write it yourself.\n");
}
/* Return non-zero if ARG is a valid argument for CALLER,
else print an error message and return zero. */
int
valid_argument (char *caller, char *arg)
{
if (!arg || !*arg)
int valid_argument(char *caller, char *arg)
{
if (!arg || !*arg) {
fprintf(stderr, "%s: Argument required.\n", caller);
return (0);
return 0;
}
return (1);
return 1;
}
void *
xmalloc (size_t size)
{
register void *value = (void*)malloc(size);
if (value == 0)
fprintf(stderr, "virtual memory exhausted");
return value;
}
/**
* Local Variables:
* c-file-style: "k&r"
* c-basic-offset: 4
* End:
*/

View File

@ -21,6 +21,8 @@
#ifndef EDITLINE_H_
#define EDITLINE_H_
#include <stdio.h>
/* Handy macros when binding keys. */
#define CTL(x) ((x) & 0x1F)
#define ISCTL(x) ((x) && (x) < ' ')
@ -82,6 +84,7 @@ extern int rl_point;
extern int rl_mark;
extern int rl_end;
extern int rl_inhibit_complete;
extern int rl_attempted_completion_over;
extern char *rl_line_buffer;
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! */
@ -114,6 +117,8 @@ extern void add_history (const char *line);
extern int read_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_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);

View File

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

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

View File

@ -91,6 +91,7 @@ static const char *el_input = NILSTR;
static char *Yanked;
static char *Screen;
static char NEWLINE[]= CRLF;
static char CLEAR[]= "\ec";
static const char *el_term = "dumb";
static int Repeat;
static int old_point;
@ -112,6 +113,9 @@ static int Searching = 0;
static const char *(*search_move)(void);
static const char *old_prompt = 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_hist = 0;
@ -121,6 +125,7 @@ int rl_end;
int rl_meta_chars = 0; /* Display 8-bit chars as the actual char(0) or as `M-x'(1)? */
int rl_inhibit_complete = 0;
char *rl_line_buffer = NULL;
static const char *rl_saved_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! */
FILE *rl_instream = NULL; /* The stdio stream from which input is read. Defaults to stdin if NULL */
@ -133,7 +138,6 @@ extern char *tgetstr(const char *, char **);
extern int tgetent(char *, const char *);
extern int tgetnum(const char *);
#endif
/*
** Misc. local helper functions.
@ -175,8 +179,12 @@ static void tty_put(const char c)
Screen[ScreenCount] = c;
if (++ScreenCount >= ScreenSize) {
char *ptr;
ScreenSize += SCREEN_INC;
Screen = realloc(Screen, sizeof(char) * ScreenSize);
ptr = realloc(Screen, sizeof(char) * ScreenSize);
if (ptr)
Screen = ptr;
}
}
@ -203,10 +211,17 @@ static void tty_show(unsigned char c)
}
}
static void tty_string(char *p)
static void tty_string(const char *p)
{
while (*p)
int i = rl_point + prompt_len + 1;
while (*p) {
tty_show(*p++);
if ((i++) % tty_cols == 0) {
tty_put(' ');
tty_put('\b');
}
}
}
static void tty_push(int c)
@ -250,11 +265,18 @@ static void tty_backn(int n)
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)
{
rl_reset_terminal(NULL);
}
/*
** Glue routines to rl_ttyset()
@ -283,13 +305,18 @@ void el_print_columns(int ac, char **av)
int skip;
int longest;
int cols;
int colwidth;
/* Find longest name, determine column count from that. */
for (longest = 0, i = 0; i < ac; i++) {
if ((j = strlen((char *)av[i])) > longest)
longest = j;
}
cols = tty_cols / (longest + 3);
colwidth = longest + 3;
if (colwidth > tty_cols)
colwidth = tty_cols;
cols = tty_cols / colwidth;
tty_puts(NEWLINE);
for (skip = ac / cols + 1, i = 0; i < skip; i++) {
@ -298,7 +325,7 @@ void el_print_columns(int ac, char **av)
tty_put(*p);
if (j + skip < ac) {
while (++len < longest + 3)
while (++len < colwidth)
tty_put(' ');
}
}
@ -307,20 +334,64 @@ void el_print_columns(int ac, char **av)
}
}
static void reposition(void)
static void reposition(int key)
{
int i;
int len_with_prompt = prompt_len + rl_end;
int n = len_with_prompt / tty_cols; /* determine the number of lines */
int i = 0;
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);
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]);
/* move to the next line */
if ((i + prompt_len + 1) % tty_cols == 0)
tty_put('\n');
}
}
static void left(el_status_t Change)
{
if (rl_point) {
if ((rl_point + prompt_len) % tty_cols == 0) {
tty_puts(line_up);
tty_forwardn(tty_cols);
} else {
tty_back();
}
if (ISMETA(rl_line_buffer[rl_point - 1])) {
if (rl_meta_chars) {
tty_back();
@ -337,6 +408,9 @@ static void left(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]);
if (Change == CSmove)
@ -390,12 +464,6 @@ static el_status_t do_forward(el_status_t move)
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)
break;
} while (++i < Repeat);
@ -421,10 +489,10 @@ static el_status_t do_case(el_case_t type)
for (i = rl_point, p = &rl_line_buffer[i]; rl_point < end; p++) {
if ((type == TOupper) || (type == TOcapitalize && rl_point == i)) {
if (islower(*p))
*p = toupper(*p);
} else if (isupper(*p)) {
*p = tolower(*p);
if (islower((unsigned char)(*p)))
*p = toupper((unsigned char)(*p));
} else if (isupper((unsigned char)(*p))) {
*p = tolower((unsigned char)(*p));
}
right(CSmove);
}
@ -457,10 +525,14 @@ static void ceol(void)
while (rl_point < 0) {
tty_put(' ');
rl_point++;
extras++;
}
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(' ');
if (ISMETA(*p)) {
if (rl_meta_chars) {
@ -474,15 +546,32 @@ 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();
}
}
}
static void clear_line(void)
{
int n = (rl_point + prompt_len) / tty_cols;
rl_point = -(int)strlen(rl_prompt);
if (n > 0) {
for(int k = 0; k < n; k++)
tty_puts(line_up);
tty_put('\r');
}
else {
tty_put('\r');
}
ceol();
rl_point = 0;
rl_end = 0;
rl_line_buffer[0] = '\0';
@ -532,28 +621,36 @@ int rl_insert_text(const char *text)
return rl_point - mark;
}
static el_status_t redisplay(void)
static el_status_t redisplay(int cls)
{
/* XXX: Use "\r\e[K" to get really neat effect on ANSI capable terminals. */
tty_puts(NEWLINE);
tty_puts(rl_prompt);
tty_string(rl_line_buffer);
if (cls)
tty_puts(CLEAR);
else
tty_puts("\r\e[K");
tty_puts(rl_prompt);
rl_point = 0;
tty_string(rl_line_buffer);
rl_point = rl_end;
return CSmove;
}
static el_status_t refresh(void)
{
return redisplay(1);
}
int rl_refresh_line(int ignore1 __attribute__((unused)), int ignore2 __attribute__((unused)))
{
redisplay();
redisplay(0);
return 0;
}
static el_status_t toggle_meta_mode(void)
{
rl_meta_chars = ! rl_meta_chars;
return redisplay();
return redisplay(0);
}
const char *el_next_hist(void)
{
@ -573,7 +670,7 @@ static el_status_t do_insert_hist(const char *p)
clear_line();
rl_point = 0;
reposition();
reposition(EOF);
rl_end = 0;
return insert_string(p);
@ -676,19 +773,20 @@ static const char *search_hist(const char *search, const char *(*move)(void))
static el_status_t h_search_end(const char *p)
{
rl_prompt = old_prompt;
rl_set_prompt(old_prompt);
Searching = 0;
if (p == NULL && el_intr_pending > 0) {
if (el_intr_pending > 0) {
el_intr_pending = 0;
clear_line();
return redisplay();
return redisplay(0);
}
p = search_hist(p, search_move);
if (p == NULL) {
el_ring_bell();
return redisplay();
clear_line();
return redisplay(0);
}
return do_insert_hist(p);
@ -702,8 +800,8 @@ static el_status_t h_search(void)
clear_line();
old_prompt = rl_prompt;
rl_prompt = "Search: ";
tty_puts(rl_prompt);
rl_set_prompt("Search: ");
reposition(EOF);
search_move = Repeat == NO_ARG ? el_prev_hist : el_next_hist;
if (line_handler) {
@ -779,6 +877,7 @@ 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++)
p[0] = p[count];
ceol();
rl_end -= count;
tty_string(&rl_line_buffer[rl_point]);
@ -819,7 +918,7 @@ static el_status_t kill_line(void)
if (Repeat < rl_point) {
i = rl_point;
rl_point = Repeat;
reposition();
reposition(EOF);
delete_string(i - rl_point);
} else if (Repeat > rl_point) {
right(CSmove);
@ -888,7 +987,7 @@ static el_status_t end_line(void)
static el_status_t del_char(void)
{
return delete_string(Repeat == NO_ARG ? 1 : Repeat);
return delete_string(Repeat == NO_ARG ? CSeof : Repeat);
}
el_status_t el_del_char(void)
@ -930,6 +1029,30 @@ static el_status_t meta(void)
return CSeof;
#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. */
if (c == '[' || c == 'O') {
switch (tty_get()) {
@ -937,21 +1060,31 @@ static el_status_t meta(void)
case '1':
{
char seq[4] = { 0 };
seq[0] = tty_get();
for (c = 0; c < 3; c++)
/* \e[1~ */
if (seq[0] == '~')
return beg_line(); /* Home */
for (c = 1; c < 3; c++)
seq[c] = tty_get();
if (!strncmp(seq, ";5C", 3))
return fd_word(); /* Ctrl+Right */
if (!strncmp(seq, ";5D", 3))
return bk_word(); /* Ctrl+Left */
if (!strncmp(seq, ";5C", 3)
|| !strncmp(seq, ";3C", 3))
return fd_word(); /* \e[1;5C = Ctrl+Right */
if (!strncmp(seq, ";5D", 3)
|| !strncmp(seq, ";3D", 3))
return bk_word(); /* \e[1;5D = Ctrl+Left */
break;
}
case '2': tty_get(); return CSstay; /* Insert */
case '3': tty_get(); return del_char(); /* Delete */
case '4': tty_get(); return end_line(); /* End */
case '5': tty_get(); return CSstay; /* PgUp */
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 'B': return h_next(); /* Down */
case 'C': return fd_char(); /* Left */
@ -1021,6 +1154,8 @@ static el_status_t emacs(int c)
static el_status_t tty_special(int c)
{
el_status_t rc;
#ifdef CONFIG_SIGINT
if (c == rl_intr) {
el_intr_pending = SIGINT;
@ -1045,13 +1180,10 @@ static el_status_t tty_special(int c)
return bk_del_char();
if (c == rl_kill) {
if (rl_point != 0) {
rl_point = 0;
reposition();
}
Repeat = rl_point;
rc = bk_del_char();
Repeat = NO_ARG;
return kill_line();
return rc;
}
#ifdef CONFIG_EOF
@ -1082,7 +1214,7 @@ static char *editinput(int complete)
return (char *)"";
case CSmove:
reposition();
reposition(c);
break;
case CSdispatch:
@ -1097,7 +1229,7 @@ static char *editinput(int complete)
return (char *)"";
case CSmove:
reposition();
reposition(c);
break;
case CSdispatch:
@ -1117,7 +1249,7 @@ static char *editinput(int complete)
static void hist_alloc(void)
{
if (!H.Lines)
H.Lines = calloc(el_hist_size, sizeof(char *));
H.Lines = calloc(1 + el_hist_size, sizeof(char *));
}
static void hist_add(const char *p)
@ -1126,7 +1258,7 @@ static void hist_add(const char *p)
char *s;
#ifdef CONFIG_UNIQUE_HISTORY
if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0)
if (H.Size && strcmp(p, H.Lines[H.Size - 1]) == 0)
return;
#endif
@ -1134,11 +1266,11 @@ static void hist_add(const char *p)
if (s == NULL)
return;
if (H.Size < el_hist_size) {
if (H.Size <= el_hist_size) {
H.Lines[H.Size++] = s;
} else {
free(H.Lines[0]);
for (i = 0; i < el_hist_size - 1; i++)
for (i = 0; i < el_hist_size; i++)
H.Lines[i] = H.Lines[i + 1];
H.Lines[i] = s;
}
@ -1150,7 +1282,7 @@ static char *read_redirected(void)
int size = MEM_INC;
char *p;
char *line;
char *end;
const char *end;
p = line = malloc(sizeof(char) * size);
if (!p)
@ -1162,9 +1294,12 @@ static char *read_redirected(void)
int oldpos = end - line;
size += MEM_INC;
p = line = realloc(line, sizeof(char) * size);
if (!p)
p = realloc(line, sizeof(char) * size);
if (!p) {
free(line);
return NULL;
}
line = p;
end = p + size;
p += oldpos; /* Continue where we left off... */
@ -1229,10 +1364,28 @@ 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)
{
if (!rl_prompt)
rl_prompt = "? ";
rl_set_prompt("? ");
hist_alloc();
@ -1251,7 +1404,7 @@ void rl_uninitialize(void)
/* Uninitialize the history */
if (H.Lines) {
for (i = 0; i < el_hist_size; i++) {
for (i = 0; i <= el_hist_size; i++) {
if (H.Lines[i])
free(H.Lines[i]);
H.Lines[i] = NULL;
@ -1273,31 +1426,14 @@ void rl_uninitialize(void)
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)
{
/* Nothing to do atm. */
}
void rl_forced_update_display()
void rl_forced_update_display(void)
{
redisplay();
redisplay(0);
tty_flush();
}
@ -1320,7 +1456,8 @@ static int el_prep(const char *prompt)
if (!Screen)
return -1;
rl_prompt = prompt ? prompt : NILSTR;
rl_set_prompt(prompt);
if (el_no_echo) {
int old = el_no_echo;
@ -1482,8 +1619,11 @@ int read_history(const char *filename)
char buf[SCREEN_INC];
hist_alloc();
fp = fopen(filename, "r");
if (fp) {
if (!fp)
return EOF;
H.Size = 0;
while (H.Size < el_hist_size) {
if (!fgets(buf, SCREEN_INC, fp))
@ -1496,17 +1636,16 @@ int read_history(const char *filename)
return fclose(fp);
}
return errno;
}
int write_history(const char *filename)
{
FILE *fp;
int i = 0;
hist_alloc();
fp = fopen(filename, "w");
if (fp) {
int i = 0;
if (!fp)
return EOF;
while (i < H.Size)
fprintf(fp, "%s\n", H.Lines[i++]);
@ -1514,10 +1653,6 @@ int write_history(const char *filename)
return fclose(fp);
}
return errno;
}
/*
** Move back to the beginning of the current word and return an
** allocated copy of it.
@ -1638,14 +1773,6 @@ static el_status_t accept_line(void)
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)
{
char c;
@ -1768,14 +1895,14 @@ static int argify(char *line, char ***avp)
if (!p)
return 0;
for (c = line; isspace(*c); c++)
for (c = line; isspace((unsigned char)(*c)); c++)
continue;
if (*c == '\n' || *c == '\0')
return 0;
for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
if (!isspace(*c)) {
if (!isspace((unsigned char)(*c))) {
c++;
continue;
}
@ -1843,7 +1970,7 @@ static el_keymap_t Map[64] = {
{ CTL('I'), c_complete },
{ CTL('J'), accept_line },
{ CTL('K'), kill_line },
{ CTL('L'), redisplay },
{ CTL('L'), refresh },
{ CTL('M'), accept_line },
{ CTL('N'), h_next },
{ CTL('O'), el_ring_bell },
@ -1857,11 +1984,7 @@ static el_keymap_t Map[64] = {
{ CTL('W'), bk_kill_word },
{ CTL('X'), exchange },
{ CTL('Y'), yank },
#ifdef SYSTEM_IS_WIN32
{ CTL('Z'), end_of_input },
#else
{ CTL('Z'), el_ring_bell },
#endif
{ CTL('['), meta },
{ CTL(']'), move_to_char },
{ CTL('^'), el_ring_bell },
@ -1893,7 +2016,7 @@ static size_t find_key_in_map(int key, el_keymap_t map[], size_t mapsz)
{
size_t i;
for (i = 0; map[i].Function && i < mapsz; i++) {
for (i = 0; i < mapsz && map[i].Function; i++) {
if (map[i].Key == key)
return i;
}
@ -1933,12 +2056,19 @@ static el_status_t el_bind_key_in_map(int key, el_keymap_func_t function, el_key
el_status_t el_bind_key(int key, el_keymap_func_t function)
{
return el_bind_key_in_map(key, function, Map, ARRAY_ELEMENTS(Map));
return el_bind_key_in_map(key, function, Map, NELEMS(Map));
}
el_status_t el_bind_key_in_metamap(int key, el_keymap_func_t function)
{
return el_bind_key_in_map(key, function, MetaMap, ARRAY_ELEMENTS(MetaMap));
return el_bind_key_in_map(key, function, MetaMap, NELEMS(MetaMap));
}
rl_getc_func_t *rl_set_getc_func(rl_getc_func_t *func)
{
rl_getc_func_t *old = rl_getc_function;
rl_getc_function = func;
return old;
}
/**

View File

@ -57,8 +57,10 @@
#define MEM_INC 64
#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 */
#define ARRAY_ELEMENTS(arr) ((sizeof(arr)/sizeof(0[arr])) / ((size_t)(!(sizeof(arr) % sizeof(0[arr])))))
/* From The Practice of Programming, by Kernighan and Pike */
#ifndef NELEMS
#define NELEMS(array) (sizeof(array) / sizeof(array[0]))
#endif
/*
** Variables and routines internal to this package.