Initial commit.

master
Mid Favila 3 months ago
commit 9a97e08178
  1. 276
      ChangeLog.md
  2. 18
      LICENSE
  3. 29
      Makefile
  4. 272
      README.md
  5. 442
      complete.c
  6. 169
      config.h
  7. 286
      editline.3
  8. 2064
      editline.c
  9. 232
      editline.h
  10. 12
      libeditline.pc
  11. 251
      sysunix.c
  12. 36
      unix.h

@ -0,0 +1,276 @@
Change Log
==========
All notable changes to the project are documented in this file.
[1.17.1][] - 2022-08-25
-----------------------
### Changes
- Revert to Make.
[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
-----------------------
Event loop callback support.
### Changes
- `rl_unintialize()`, new function to free all memory, by Claus Fischer
- `rl_insert_text()`, new GNU Readline compat function
- `rl_refresh_line()`, new GNU Readline compat function
- `rl_callback_*()`, alternate interface to plain `readline()` for event
loops. Modeled after the GNU Readline API
- `rl_completion_entry_function`, and `rl_attempted_completion_function`
are two new GNU Readline compat user hooks for the completion framework
- `rl_completion_matches()` and `rl_filename_completion_function()`
are two new GNU Readline compat functions
- Add new example: `fileman.c` from GNU Readline to demonstrate the
level of compatibility of the revamped completion framework
- Add support for Ctrl-Right and Ctrl-Left, forward/backward word
- Add .deb package to official release target
### Fixes
- Fixed header guards, avoid using leading `__`
- Spell check fixes
- Remove duplicate code in history check
- Use `NULL` instead of `0`, and `-1` instead of `NULL`, where applicable
- Misc. minor Coverity Scan fixes
- Misc. minor fixes to `testit.c` example code
- Add `-Wextra` to std `CFLAGS`
- Check `fclose()` return value in in `write_history()` and `read_history()`
- Initialize global variables and reset to `NULL` on `free()`
- Fix off-by-one in forward kill word, avoid deleting too much
- Skip (or kill) leading whitespace when skipping (or killing) forwards
[1.15.3][] - 2017-09-07
-----------------------
Bug fix release.
### Changes
- Refactor all enable/disable configure options, same problem as in #7
### Fixes
- Fix #7: `--enable-termcap` configure option does not work. The script
enabled termcap by default rather than the other way around.
Also, check for terminfo as well, when `--enable-termcap` is selected.
[1.15.2][] - 2016-06-06
-----------------------
Bug fixes and minor feature creep in `pkg-config` support.
### Changes
- Prevent mangling of symbols when linking with C++. Patch courtesy of
Jakub Pawlowski
- Add `libeditline.pc` for `pkg-config`
### Fixes
- Do not assume a termcap library exists, check for `tgetent()` in
curses, ncurses, tinfo and termcap libraries
- Call `tty_flush()` when user calls `rl_forced_update_display()`
to prevent screen becoming garbled. Patch by Jakub Pawlowski
[1.15.1][] - 2015-11-16
-----------------------
Bug fixes only.
### Changes
- Update README with origin of this version of editline
### Fixes
- Fix build system, don't force automake v1.11, require at least v1.11
- Fix build problem with examples using `--enable-termcap`
[1.15.0][] - 2015-09-10
-----------------------
### Changes
- Add support for `--disable-eof` and `--disable-sigint` to disable
default Ctrl-D and Ctrl-C behavior
- Add support for `el_no_hist` to disable access to and auto-save of history
- GNU readline compat functions for prompt handling and redisplay
- Refactor: replace variables named 'new' with non-reserved word
- Add support for [Travis-CI][], continuous integration with GitHub
- Add support for [Coverity Scan][], the best static code analyzer,
integrated with [Travis-CI][] -- scan runs for each push to master
- Rename NEWS.md --> ChangeLog.md, with symlinks for <kbd>make install</kbd>
- Attempt to align with http://keepachangelog.com/ for this file
- Cleanup and improve Markdown syntax in [README.md][]
- Add API and example to [README.md][], inspired by [libuEv][]
- Removed generated files from version control. Use `./autogen.sh`
to generate the `configure` script when working from GIT. This
does not affect distributed tarballs
### Fixes
- Fix issue #2, regression in Ctrl-D (EOF) behavior. Regression
introduced in [1.14.1][]. Fixed by @TobyGoodwin
- Fix memory leak in completion handler. Found by [Coverity Scan][].
- Fix suspicious use of `sizeof(char **)`, same as `sizeof(char *)` but
non-portable. Found by [Coverity Scan][]
- Fix out-of-bounds access in user key binding routines
Found by [Coverity Scan][].
- Fix invisible example code in man page
[1.14.2][] - 2014-09-14
-----------------------
Bug fixes only.
### Fixes
- Fix `el_no_echo` bug causing secrets to leak when disabling no-echo
- Handle `EINTR` in syscalls better
[1.14.1][] - 2014-09-14
-----------------------
Minor fixes and additions.
### Changes
- Don't print status message on `stderr` in key binding funcions
- Export `el_del_char()`
- Check for and return pending signals when detected
- Allow custom key bindings ...
### Fixes
- Bug fixes ...
[1.14.0][] - 2010-08-10
-----------------------
Major cleanups and further merges with Debian editline package.
### Changes
- Merge in changes to `debian/` from `editline_1.12-6.debian.tar.gz`
- Migrate to use libtool
- Make `UNIQUE_HISTORY` configurable
- Make scrollback history (`HIST_SIZE`) configurable
- Configure options for toggling terminal bell and `SIGSTOP` (Ctrl-Z)
- Configure option for using termcap to read/control terminal size
- Rename Signal to `el_intr_pending`, from Festival speech-tools
- Merge support for capitalizing words (`M-c`) from Festival
speech-tools by Alan W Black <mailto:awb()cstr!ed!ac!uk>
- Fallback backspace handling, in case `tgetstr("le")` fails
### Fixes
- Cleanups and fixes thanks to the Sparse static code analysis tool
- Merge `el_no_echo` patch from Festival speech-tools
- Merge fixes from Heimdal project
- Completely refactor `rl_complete()` and `rl_list_possib()` with
fixes from the Heimdal project. Use `rl_set_complete_func()` and
`rl_set_list_possib_func()`. Default completion callbacks are now
available as a configure option `--enable-default-complete`
- Memory leak fixes
- Actually fix 8-bit handling by reverting old Debian patch
- Merge patch to improve compatibility with GNU readline, thanks to
Steve Tell from way back in 1997 and 1998
[1.13.0][] - 2010-03-09
-----------------------
Adaptations to Debian editline package.
### Changes
- Major version number bump, adapt to Jim Studt's v1.12
- Import `debian/` directory and adapt it to configure et al.
- Change library name to libeditline to distinguish it from BSD libedit
[0.3.0][] - 2009-02-08
----------------------
### Changes
- Support for ANSI arrow keys using <kbd>configure --enable-arrow-keys</kbd>
[0.2.3][] - 2008-12-02
----------------------
### Changes
- Patches from Debian package merged
- Support for custom command completion
[0.1.0][] - 2008-06-07
----------------------
### Changes
- First version, forked from Minix current 2008-06-06
[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
[1.15.1]: https://github.com/troglobit/finit/compare/1.15.0...1.15.1
[1.15.0]: https://github.com/troglobit/finit/compare/1.14.2...1.15.0
[1.14.2]: https://github.com/troglobit/finit/compare/1.14.1...1.14.2
[1.14.1]: https://github.com/troglobit/finit/compare/1.14.0...1.14.1
[1.14.0]: https://github.com/troglobit/finit/compare/1.13.0...1.14.0
[1.13.0]: https://github.com/troglobit/finit/compare/0.3.0...1.13.0
[0.3.0]: https://github.com/troglobit/finit/compare/0.2.3...0.3.0
[0.2.3]: https://github.com/troglobit/finit/compare/0.1.0...0.2.3
[0.1.0]: https://github.com/troglobit/finit/compare/0.0.0...0.1.0
[libuEv]: http://github.com/troglobit/libuev
[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

@ -0,0 +1,18 @@
Copyright 1992,1993 Simmule Turner and Rich Salz
All rights reserved.
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:
1. The authors are not responsible for the consequences of use of this
software, no matter how awful, even if they arise from flaws in it.
2. The origin of this software must not be misrepresented, either by
explicit claim or by omission. Since few users ever read sources,
credits must appear in the documentation.
3. Altered versions must be plainly marked as such, and must not be
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.

@ -0,0 +1,29 @@
.POSIX:
TARGETS = libeditline.so libeditline.so.1 libeditline.so.1.0.2 libeditline.a
all: dynamic static
install: all
install -Dm644 ${TARGETS} ${DESTDIR}/${PREFIX}/lib/
install -Dm644 editline.3 ${DESTDIR}/${PREFIX}/share/man/man3/
install -Dm644 libeditline.pc ${DESTDIR}/${PREFIX}/lib/pkgconfig/
dynamic: object
cc -o libeditline.so -shared *.o
ln -s libeditline.so libeditline.so.1
ln -s libeditline.so libeditline.so.1.0.2
static: object
ar -r *.o
mv a.out libeditline.a
object: complete.o editline.o sysunix.o
clean:
rm *.so* *.a *.o
.SUFFIX:
.c.o:
cc -c $<

@ -0,0 +1,272 @@
Editline
========
[![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
Table of Contents
-----------------
* [Introduction](#introduction)
* [API](#api)
* [Example](#example)
* [Build & Install](#build--install)
* [Origin & References](#origin--references)
Introduction
------------
This is a small [line editing][] library. It can be linked into almost
any program to provide command line editing and history functions. It
is call compatible with the [FSF readline][] library, but at a fraction
of the size, and as a result fewer features. It is also distributed
under a much more liberal [License][].
The small size (<30k), lack of dependencies (ncurses not needed!), and
the free license should make this library interesting to many embedded
developers.
Editline has several optional build-time features that can be enabled by
supplying different options to the GNU configure script. See the output
from <kbd>configure --help</kbd> for details. Some useful hints on how
to use the library is available in the `examples/` directory.
Editline is maintained collaboratively at [GitHub][].
Example
-------
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.
tar xf editline-1.15.3.tar.xz
cd editline-1.15.3/
./configure --prefix=/usr
make all
sudo make install
2. Place the below source code in a separate project directory,
e.g. `~/src/example.c`
```C
#include <stdlib.h>
#include <editline.h>
int main(void)
{
char *p;
while ((p = readline("CLI> ")) != NULL) {
puts(p);
free(p);
}
return 0;
}
```
3. Compile the example:
cd ~/src/
make LDLIBS=-leditline example
Here I use `make` and rely on its implicit (built-in) rules to handle
all the compiler magic, but you may want to create your own Makefile for
the project. In particular if you don't change the default prefix
(above), because then you need to specify the search path for the
include file(s) and the library manually.
A simple `~/src/Makefile` could look like this:
CFLAGS = -I/usr/local/include
LDFLAGS = -L/usr/local/lib
LDLIBS = -leditline
EXEC = example
OBJS = example.o
all: $(EXEC)
$(EXEC): $(OBJS)
clean:
$(RM) $(OBJS) $(EXEC)
distclean: clean
$(RM) *.o *~ *.bak
Then simply type `make` from your `~/src/` directory. You can also use
`pkg-config` for your `~/src/Makefile`, replace the following lines:
CFLAGS = $(shell pkg-config --cflags libeditline)
LDFLAGS = $(shell pkg-config --libs-only-L libeditline)
LDLIBS = $(shell pkg-config --libs-only-l libeditline)
Then simply type <kbd>make</kbd>, like above.
However, most `.rpm` based distributions `pkg-config` doesn't search in
`/usr/local` anymore, so you need to call make like this:
PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig make
Debian/Ubuntu based systems do not have this problem.
API
---
Here is the libeditline interfaces. It has a small compatibility layer
to [FSF readline][], which may not be entirely up-to-date.
```C
/* Editline specific global variables. */
int el_no_echo; /* Do not echo input characters */
int el_no_hist; /* Disable auto-save of and access to history,
* e.g. for password prompts or wizards */
int el_hist_size; /* Size of history scrollback buffer, default: 15 */
/* Editline specific functions. */
char * el_find_word (void);
void el_print_columns (int ac, char **av);
el_status_t el_ring_bell (void);
el_status_t el_del_char (void);
/* Callback function for key binding */
typedef el_status_t el_keymap_func_t(void);
/* Bind key to a callback, use CTL('f') to change Ctrl-F, for example */
el_status_t el_bind_key (int key, el_keymap_func_t function);
el_status_t el_bind_key_in_metamap (int key, el_keymap_func_t function);
/* For compatibility with FSF readline. */
int rl_point;
int rl_mark;
int rl_end;
int rl_inhibit_complete;
char *rl_line_buffer;
const char *rl_readline_name;
void (*rl_deprep_term_function)(void);
void rl_deprep_terminal (void);
void rl_reset_terminal (const char *terminal_name);
void rl_initialize (void);
void rl_uninitialize (void); /* Free all internal memory */
void rl_save_prompt (void);
void rl_restore_prompt (void);
void rl_set_prompt (const char *prompt);
void rl_clear_message (void);
void rl_forced_update_display (void);
/* Main function to use, saves history by default */
char *readline (const char *prompt);
/* Use to save a read line to history, when el_no_hist is set */
void add_history (const char *line);
/* Load and save editline history from/to a file. */
int read_history (const char *filename);
int write_history (const char *filename);
/* Magic completion API, see examples/cli.c for more info */
rl_complete_func_t *rl_set_complete_func (rl_complete_func_t *func);
rl_list_possib_func_t *rl_set_list_possib_func (rl_list_possib_func_t *func);
/* Alternate interface to plain readline(), for event loops */
void rl_callback_handler_install (const char *prompt, rl_vcpfunc_t *lhandler);
void rl_callback_read_char (void);
void rl_callback_handler_remove (void);
```
Build & Install
---------------
Editline was originally designed for older UNIX systems and Plan 9. The
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!
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>
The `$DESTDIR` environment variable is honored at install. For more
options, see <kbd>./configure --help</kbd>
Remember to run `ldconfig` after install to update the linker cache. If
you've installed to a non-standard location (`--prefix`) you may also
have to update your `/etc/ld.so.conf`, or use `pkg-confg` to build your
application (above).
**NOTE:** RedHat/Fedora/CentOS and other `.rpm`-based distributions do
not consider `/usr/local` as standard path anymore. So make sure to
`./configure --prefix=/usr`, otherwise the build system use the GNU
default, which is `/usr/local`. The Debian based distributions, like
Ubuntu, do not have this problem.
Origin & References
--------------------
This [line editing][] library was created by [Rich Salz][] and Simmule
Turner and in 1992. It is distributed with a “[C News][]-like” license,
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 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
also relies on libtermcap (usually supplied by ncurses), whereas this
library only uses termios from the standard C library.
Patches and bug fixes from the following forks, based on the original
[comp.sources.unix][] posting, have been merged:
* Debian [libeditline][]
* [Heimdal][]
* [Festival][] speech-tools
* [Steve Tell][]'s editline patches
The version numbering scheme today follows that of the Debian version,
details available in the [ChangeLog.md][]. The current [maintainer][]
was unaware of the Debian version for quite some time, so a different
name and versioning scheme was used. In June 2009 this was changed to
line up alongside Debian, with the intent is to eventually merge the
efforts.
Outstanding issues are listed in the [TODO.md][] file.
[GitHub]: https://github.com/troglobit/editline
[line editing]: https://github.com/troglobit/editline/blob/master/docs/README
[release tarball]: https://github.com/troglobit/editline/releases
[maintainer]: http://troglobit.com
[C News]: https://en.wikipedia.org/wiki/C_News
[TODO.md]: https://github.com/troglobit/editline/blob/master/docs/TODO.md
[ChangeLog.md]: https://github.com/troglobit/editline/blob/master/ChangeLog.md
[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 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
[Heimdal]: http://www.h5l.org
[Festival]: http://festvox.org/festival/
[Steve Tell]: http://www.cs.unc.edu/~tell/dist.html
[License]: https://github.com/troglobit/editline/blob/master/LICENSE
[License Badge]: https://img.shields.io/badge/License-C%20News-orange.svg
[Travis]: https://travis-ci.org/troglobit/editline
[Travis Status]: https://travis-ci.org/troglobit/editline.png?branch=master
[Coverity Scan]: https://scan.coverity.com/projects/2982
[Coverity Status]: https://scan.coverity.com/projects/2982/badge.svg

@ -0,0 +1,442 @@
/* History and file completion functions for editline library.
*
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
* All rights reserved.
*
* 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:
* 1. The authors are not responsible for the consequences of use of this
* software, no matter how awful, even if they arise from flaws in it.
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Since few users ever read sources,
* credits must appear in the documentation.
* 3. Altered versions must be plainly marked as such, and must not be
* 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.
*/
#include <ctype.h>
#include "editline.h"
#define MAX_TOTAL_MATCHES (256 << sizeof(char *))
int rl_attempted_completion_over = 0;
rl_completion_func_t *rl_attempted_completion_function = NULL;
rl_compentry_func_t *rl_completion_entry_function = NULL;
/* Wrap strcmp() for qsort() -- weird construct to pass -Wcast-qual */
static int compare(const void *p1, const void *p2)
{
char *const *v1 = (char *const *)p1;
char *const *v2 = (char *const *)p2;
return strcmp(*v1, *v2);
}
/* 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)
{
char **av;
char **word;
char *p;
DIR *dp;
DIRENTRY *ep;
size_t ac;
size_t len;
size_t choices;
size_t total;
if ((dp = opendir(dir)) == NULL)
return 0;
av = NULL;
ac = 0;
len = strlen(file);
choices = 0;
total = 0;
while ((ep = readdir(dp)) != NULL) {
p = ep->d_name;
if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
continue;
if (len && strncmp(p, file, len) != 0)
continue;
choices++;
if ((total += strlen(p)) > MAX_TOTAL_MATCHES) {
/* This is a bit too much. */
while (ac > 0) free(av[--ac]);
continue;
}
if ((ac % MEM_INC) == 0) {
word = malloc(sizeof(char *) * (ac + MEM_INC));
if (!word) {
total = 0;
break;
}
if (ac) {
memcpy(word, av, ac * sizeof(char *));
free(av);
}
*avp = av = word;
}
if ((av[ac] = strdup(p)) == NULL) {
if (ac == 0)
free(av);
total = 0;
break;
}
ac++;
}
/* Clean up and return. */
closedir(dp);
if (total > MAX_TOTAL_MATCHES) {
char many[sizeof(total) * 3];
p = many + sizeof(many);
*--p = '\0';
while (choices > 0) {
*--p = '0' + choices % 10;
choices /= 10;
}
while (p > many + sizeof(many) - 8)
*--p = ' ';
if ((p = strdup(p)) != NULL)
av[ac++] = p;
if ((p = strdup("choices")) != NULL)
av[ac++] = p;
} else {
if (ac)
qsort(av, ac, sizeof(char *), compare);
}
return ac;
}
/* Split a pathname into allocated directory and trailing filename parts. */
static int SplitPath(const char *path, char **dirpart, char **filepart)
{
static char DOT[] = ".";
char *dpart;
char *fpart;
if ((fpart = strrchr(path, '/')) == NULL) {
if ((dpart = strdup(DOT)) == NULL)
return -1;
if ((fpart = strdup(path)) == NULL) {
free(dpart);
return -1;
}
} else {
if ((dpart = strdup(path)) == NULL)
return -1;
dpart[fpart - path + 1] = '\0';
if ((fpart = strdup(fpart + 1)) == NULL) {
free(dpart);
return -1;
}
}
*dirpart = dpart;
*filepart = fpart;
return 0;
}
static rl_complete_func_t *el_complete_func = NULL;
/* For compatibility with the Heimdal project. */
rl_complete_func_t *rl_set_complete_func(rl_complete_func_t *func)
{
rl_complete_func_t *old = el_complete_func;
el_complete_func = func;
return old;
}
/* Attempt to complete the pathname, returning an allocated copy.
* Fill in *match if we completed it, or set it to 0 if ambiguous. */
char *el_filename_complete(char *pathname, int *match)
{
char **av;
char *dir;
char *file;
char *path;
char *p;
size_t ac;
size_t end;
size_t i;
size_t j;
size_t len;
if (SplitPath((const char *)pathname, &dir, &file) < 0)
return NULL;
if ((ac = FindMatches(dir, file, &av)) == 0) {
free(dir);
free(file);
return NULL;
}
p = NULL;
len = strlen(file);
if (ac == 1) {
/* Exactly one match -- finish it off. */
*match = 1;
j = strlen(av[0]) - len + 2;
p = malloc(sizeof(char) * (j + 1));
if (p) {
memcpy(p, av[0] + len, j);
len = strlen(dir) + strlen(av[0]) + 2;
path = malloc(sizeof(char) * len);
if (path) {
snprintf(path, len, "%s/%s", dir, av[0]);
rl_add_slash(path, p);
free(path);
}
}
} else {
*match = 0;
if (len) {
/* Find largest matching substring. */
for (i = len, end = strlen(av[0]); i < end; i++) {
for (j = 1; j < ac; j++) {
if (av[0][i] != av[j][i])
goto breakout;
}
}
breakout:
if (i > len) {
j = i - len + 1;
p = malloc(sizeof(char) * j);
if (p) {
memcpy(p, av[0] + len, j);
p[j - 1] = '\0';
}
}
}
}
/* Clean up and return. */
free(dir);
free(file);
for (i = 0; i < ac; i++)
free(av[i]);
free(av);
return p;
}
char *rl_filename_completion_function(const char *text, int state)
{
char *dir;
char *file;
static char **av;
static size_t i, ac;
if (!state) {
if (SplitPath(text, &dir, &file) < 0)
return NULL;
ac = FindMatches(dir, file, &av);
free(dir);
free(file);
if (!ac)
return NULL;
i = 0;
}
if (i < ac)
return av[i++];
do {
free(av[--i]);
} while (i > 0);
return NULL;
}
/* Similar to el_find_word(), but used by GNU Readline API */
static char *rl_find_token(size_t *len)
{
char *ptr;
int pos;
for (pos = rl_point; pos < rl_end; pos++) {
if (isspace(rl_line_buffer[pos])) {
if (pos > 0)
pos--;
break;
}
}
ptr = &rl_line_buffer[pos];
while (pos >= 0 && !isspace(rl_line_buffer[pos])) {
if (pos == 0)
break;
pos--;
}
if (ptr != &rl_line_buffer[pos]) {
*len = (size_t)(ptr - &rl_line_buffer[pos]);
return &rl_line_buffer[pos];
}
return NULL;
}
/*
* "uses an application-supplied generator function to generate the list
* of possible matches, and then returns the array of these matches. The
* caller should place the address of its generator function in
* rl_completion_entry_function"
*/
char **rl_completion_matches(const char *token, rl_compentry_func_t *generator)
{
int state = 0, num = 0;
char **array, *entry;
if (!generator) {
generator = rl_completion_entry_function;
if (!generator)
generator = rl_filename_completion_function;
}
if (!generator)
return NULL;
array = malloc(512 * sizeof(char *));
if (!array)
return NULL;
while (num < 511 && (entry = generator(token, state))) {
state = 1;
array[num++] = entry;
}
array[num] = NULL;
if (!num) {
free(array);
return NULL;
}
return array;
}
static char *complete(char *token, int *match)
{
size_t len = 0;
char *word, **words = NULL;
int start, end;
word = rl_find_token(&len);
if (!word)
goto fallback;
start = word - rl_line_buffer;
end = start + len;
word = strndup(word, len);
if (!word)
goto fallback;
rl_attempted_completion_over = 0;
words = rl_attempted_completion_function(word, start, end);
if (!rl_attempted_completion_over && !words)
words = rl_completion_matches(word, NULL);
if (words) {
int i = 0;
free(word);
word = NULL;
if (words[0])
word = strdup(words[0] + len);
while (words[i])
free(words[i++]);
free(words);
if (word)
return word;
}
fallback:
return el_filename_complete(token, match);
}
/*
* First check for editline specific custom completion function, then
* for any GNU Readline compat, then fallback to filename completion.
*/
char *rl_complete(char *token, int *match)
{
if (el_complete_func)
return el_complete_func(token, match);
if (rl_attempted_completion_function)
return complete(token, match);
return el_filename_complete(token, match);
}
static rl_list_possib_func_t *el_list_possib_func = NULL;
/* For compatibility with the Heimdal project. */
rl_list_possib_func_t *rl_set_list_possib_func(rl_list_possib_func_t *func)
{
rl_list_possib_func_t *old = el_list_possib_func;
el_list_possib_func = func;
return old;
}
/* Default possible completions. */
int el_filename_list_possib(char *pathname, char ***av)
{
char *dir;
char *file;
int ac;
if (SplitPath(pathname, &dir, &file) < 0)
return 0;
ac = FindMatches(dir, file, av);
free(dir);
free(file);
return ac;
}
/* Return all possible completions. */
int rl_list_possib(char *token, char ***av)
{
if (el_list_possib_func)
return el_list_possib_func(token, av);
return el_filename_list_possib(token, av);
}
/**
* Local Variables:
* c-file-style: "k&r"
* c-basic-offset: 4
* End:
*/

@ -0,0 +1,169 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if the `closedir' function returns void instead of `int'. */
/* #undef CLOSEDIR_VOID */
/* Define to include ANSI arrow keys support. */
#define CONFIG_ANSI_ARROWS 1
/* Define to enable EOF (Ctrl-D) key. */
#define CONFIG_EOF 1
/* Define to enable SIGINT (Ctrl-C) key. */
#define CONFIG_SIGINT 1
/* Define to enable SIGSTOP (Ctrl-Z) key. */
/* #undef CONFIG_SIGSTOP */
/* Define to enable terminal bell on completion. */
/* #undef CONFIG_TERMINAL_BELL */
/* Define to skip duplicate lines in the scrollback history. */
#define CONFIG_UNIQUE_HISTORY 1
/* Define to use the termcap library for terminal size. */
/* #undef CONFIG_USE_TERMCAP */
/* Define to 1 if `TIOCGWINSZ' requires <sys/ioctl.h>. */
#define GWINSZ_IN_SYS_IOCTL 1
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
*/
#define HAVE_DIRENT_H 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `curses' library (-lcurses). */
/* #undef HAVE_LIBCURSES */
/* Define to 1 if you have the `ncurses' library (-lncurses). */
/* #undef HAVE_LIBNCURSES */
/* Define to 1 if you have the `termcap' library (-ltermcap). */
/* #undef HAVE_LIBTERMCAP */
/* Define to 1 if you have the `terminfo' library (-lterminfo). */
/* #undef HAVE_LIBTERMINFO */
/* Define to 1 if you have the `tinfo' library (-ltinfo). */
/* #undef HAVE_LIBTINFO */
/* Define to 1 if you have the <malloc.h> header file. */
#define HAVE_MALLOC_H 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
/* #undef HAVE_NDIR_H */
/* Define to 1 if you have the `perror' function. */
#define HAVE_PERROR 1
/* Define to 1 if you have the <sgtty.h> header file. */
/* #undef HAVE_SGTTY_H */
/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
/* #undef HAVE_STAT_EMPTY_STRING_BUG */
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the `strdup' function. */
#define HAVE_STRDUP 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strrchr' function. */
#define HAVE_STRRCHR 1
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
*/
/* #undef HAVE_SYS_DIR_H */
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
*/
/* #undef HAVE_SYS_NDIR_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the `tcgetattr' function. */
#define HAVE_TCGETATTR 1
/* Define to 1 if you have the <termcap.h> header file. */
#define HAVE_TERMCAP_H 1
/* Define to 1 if you have the <termios.h> header file. */
#define HAVE_TERMIOS_H 1
/* Define to 1 if you have the <termio.h> header file. */
/* #undef HAVE_TERMIO_H */
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#define LT_OBJDIR ".libs/"
/* Name of package */
#define PACKAGE "editline"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "https://github.com/troglobit/editline/issues"
/* Define to the full name of this package. */
#define PACKAGE_NAME "editline"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "editline 1.17.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "editline"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.17.1"
/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
/* #undef STAT_MACROS_BROKEN */
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Default to UNIX backend, should be detected. */
#define SYS_UNIX 1
/* Version number of package */
#define VERSION "1.17.1"
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */

@ -0,0 +1,286 @@
.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
.Fn readline
function displays the given
.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
.Xr free 3
when the calling program is done with it.
.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,
.Ar n ,
where
.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:
.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
.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
.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
.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
.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
.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
.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.
.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 other places. The original manual
page was made by David W. Sanderson.
.Pp
This version was originally based on the Minix 2 sources, but has since
evolved to include patches from all relevant forks. It is currently
maintained by Joachim Nilsson at GitHub,
.Aq http://github.com/troglobit/editline
.Sh BUGS
Does not handle multiple lines or unicode characters well.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,232 @@
/* Internal header file for editline library.
*
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
* All rights reserved.
*
* 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:
* 1. The authors are not responsible for the consequences of use of this
* software, no matter how awful, even if they arise from flaws in it.
* 2. The origin of this software must not be misrepresented, either by
* explicit claim or by omission. Since few users ever read sources,
* credits must appear in the documentation.
* 3. Altered versions must be plainly marked as such, and must not be
* 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.
*/
#ifndef EDITLINE_PRIVATE_H_
#define EDITLINE_PRIVATE_H_
#include "config.h"
#include <stdio.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef SYS_UNIX
#include "unix.h"
#endif
#ifdef SYS_OS9
#include "os9.h"
#endif
/* The following two are for TIOCGWINSZ */
#ifdef HAVE_TERMIOS_H
# include <termios.h>
#endif
#ifdef GWINSZ_IN_SYS_IOCTL
# include <sys/ioctl.h>
#endif
#define MEM_INC 64
#define SCREEN_INC 256
/* 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.
*/
extern int rl_eof;
extern int rl_erase;
extern int rl_intr;
extern int rl_kill;
extern int rl_quit;
#ifdef CONFIG_SIGSTOP