mirror of
https://github.com/troglobit/editline.git
synced 2025-09-18 19:10:09 +08:00
Compare commits
74 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
59fa265d91 | ||
![]() |
5f86c20c87 | ||
![]() |
237014f7d9 | ||
![]() |
bbd0621da8 | ||
![]() |
1a5541256b | ||
![]() |
d4bef671b6 | ||
![]() |
054891f032 | ||
![]() |
6fb3365893 | ||
![]() |
14b6dd37d6 | ||
![]() |
89d2fefbc6 | ||
![]() |
ac522cd749 | ||
![]() |
9a16999f0e | ||
![]() |
e962b9582a | ||
![]() |
29b24dcf83 | ||
![]() |
097fde5267 | ||
![]() |
05ed94047b | ||
![]() |
77d531f5b5 | ||
![]() |
405f091888 | ||
![]() |
d2418161ad | ||
![]() |
b2f1cfbbcc | ||
![]() |
76039b458b | ||
![]() |
a5aaf51530 | ||
![]() |
bd5ae42b4b | ||
![]() |
41bbb304b1 | ||
![]() |
f40a2a6a2c | ||
![]() |
534b3897b8 | ||
![]() |
b4cf343342 | ||
![]() |
4c55280864 | ||
![]() |
78eabbde39 | ||
![]() |
bc510b320e | ||
![]() |
3cf0e89a68 | ||
![]() |
5b43c028c9 | ||
![]() |
1657da4f2e | ||
![]() |
fdda4f5cae | ||
![]() |
f8c6b7f208 | ||
![]() |
9e9f8b03d8 | ||
![]() |
0bfaf351aa | ||
![]() |
2ce0be942e | ||
![]() |
6a7483532c | ||
![]() |
ad3b1c8a07 | ||
![]() |
5be965deec | ||
![]() |
791508a3a1 | ||
![]() |
6de69a406b | ||
![]() |
197f3e1c32 | ||
![]() |
6adf0e98bb | ||
![]() |
bc7fc7e5c0 | ||
![]() |
935895bbf1 | ||
![]() |
2ec55cc9f1 | ||
![]() |
7f7bb5b45c | ||
![]() |
9b7b3121c5 | ||
![]() |
53b160f6a1 | ||
![]() |
779db8817e | ||
![]() |
29a71a53d0 | ||
![]() |
a9824655ee | ||
![]() |
69d9e549a0 | ||
![]() |
94b1a78444 | ||
![]() |
a9d4247c09 | ||
![]() |
a1f0a81a31 | ||
![]() |
ea79fe70f9 | ||
![]() |
621f126128 | ||
![]() |
6137feacdf | ||
![]() |
2075dedc80 | ||
![]() |
54714631e2 | ||
![]() |
a70a933698 | ||
![]() |
b613db2afb | ||
![]() |
6021e54dbc | ||
![]() |
1ace811722 | ||
![]() |
4b8333ad39 | ||
![]() |
ed37cef412 | ||
![]() |
2a3b422137 | ||
![]() |
91937d970d | ||
![]() |
317b43e488 | ||
![]() |
ed87f37409 | ||
![]() |
b30c3479f5 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -4,6 +4,10 @@
|
|||||||
*.o
|
*.o
|
||||||
*.pc
|
*.pc
|
||||||
.deps
|
.deps
|
||||||
|
.testit_history
|
||||||
|
GPATH
|
||||||
|
GRTAGS
|
||||||
|
GTAGS
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
aclocal.m4
|
aclocal.m4
|
||||||
|
@@ -20,7 +20,7 @@ addons:
|
|||||||
coverity_scan:
|
coverity_scan:
|
||||||
project:
|
project:
|
||||||
name: "troglobit/editline"
|
name: "troglobit/editline"
|
||||||
description: "Minix editline"
|
description: "A small line editing library"
|
||||||
notification_email: troglobit@gmail.com
|
notification_email: troglobit@gmail.com
|
||||||
build_command_prepend: "./autogen.sh && ./configure --enable-sigstop --enable-terminal-bell"
|
build_command_prepend: "./autogen.sh && ./configure --enable-sigstop --enable-terminal-bell"
|
||||||
build_command: "make -j5"
|
build_command: "make -j5"
|
||||||
|
44
ChangeLog.md
44
ChangeLog.md
@@ -4,6 +4,40 @@ Change Log
|
|||||||
All notable changes to the project are documented in this file.
|
All notable changes to the project are documented in this file.
|
||||||
|
|
||||||
|
|
||||||
|
[1.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
|
[1.15.3][] - 2017-09-07
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
@@ -13,10 +47,10 @@ Bug fix release.
|
|||||||
- Refactor all enable/disable configure options, same problem as in #7
|
- Refactor all enable/disable configure options, same problem as in #7
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Fix #7: `--enable-termcap` configure option does not work, wrongly
|
- Fix #7: `--enable-termcap` configure option does not work. The script
|
||||||
enables termcap by default.
|
enabled termcap by default rather than the other way around.
|
||||||
|
|
||||||
Also, check for termino as well, when `--enable-termcap` is selected.
|
Also, check for terminfo as well, when `--enable-termcap` is selected.
|
||||||
|
|
||||||
|
|
||||||
[1.15.2][] - 2016-06-06
|
[1.15.2][] - 2016-06-06
|
||||||
@@ -169,7 +203,9 @@ Adaptations to Debian editline package.
|
|||||||
- First version, forked from Minix current 2008-06-06
|
- First version, forked from Minix current 2008-06-06
|
||||||
|
|
||||||
|
|
||||||
[UNRELEASED]: https://github.com/troglobit/finit/compare/1.15.1...HEAD
|
[UNRELEASED]: https://github.com/troglobit/finit/compare/1.16.0...HEAD
|
||||||
|
[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.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.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.15.0]: https://github.com/troglobit/finit/compare/1.14.2...1.15.0
|
||||||
|
3
LICENSE
3
LICENSE
@@ -1,4 +1,5 @@
|
|||||||
Copyright 1992,1993 Simmule Turner and Rich Salz. All rights reserved.
|
Copyright 1992,1993 Simmule Turner and Rich Salz
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
This software is not subject to any license of the American Telephone
|
This software is not subject to any license of the American Telephone
|
||||||
and Telegraph Company or of the Regents of the University of California.
|
and Telegraph Company or of the Regents of the University of California.
|
||||||
|
22
Makefile.am
22
Makefile.am
@@ -6,13 +6,14 @@ SUBDIRS = src include man examples
|
|||||||
|
|
||||||
## Generate .deb package
|
## Generate .deb package
|
||||||
package build-deb:
|
package build-deb:
|
||||||
@dpkg-buildpackage -uc -us -B
|
@dpkg-buildpackage -uc -us
|
||||||
|
|
||||||
## Generate MD5 checksum file
|
## Generate MD5 checksum file
|
||||||
MD5 = md5sum
|
MD5 = md5sum
|
||||||
md5-dist:
|
md5-dist:
|
||||||
@for file in $(DIST_ARCHIVES); do \
|
@for file in $(DIST_ARCHIVES); do \
|
||||||
$(MD5) $$file > $$file.md5; \
|
$(MD5) $$file > ../$$file.md5; \
|
||||||
|
mv $$file ../; \
|
||||||
done
|
done
|
||||||
|
|
||||||
## Check if tagged in git
|
## Check if tagged in git
|
||||||
@@ -33,10 +34,19 @@ release-hook:
|
|||||||
echo; \
|
echo; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# lintian --profile debian -i -I --show-overrides ../$PKG.changes
|
||||||
|
package:
|
||||||
|
dpkg-buildpackage -uc -us -B
|
||||||
|
|
||||||
## Target to run when building a release
|
## Target to run when building a release
|
||||||
release: distcheck release-hook md5-dist
|
release: distcheck release-hook md5-dist package
|
||||||
|
@echo
|
||||||
|
@echo "Resulting release files:"
|
||||||
|
@echo "========================================================================="
|
||||||
@for file in $(DIST_ARCHIVES); do \
|
@for file in $(DIST_ARCHIVES); do \
|
||||||
printf "$$file \tDistribution tarball\n"; \
|
printf "%-40s Distribution tarball\n" $$file; \
|
||||||
printf "$$file.md5\t"; cat $$file.md5 | cut -f1 -d' '; \
|
printf "%-40s " $$file.md5; cat ../$$file.md5 | cut -f1 -d' '; \
|
||||||
mv $$file* ../; \
|
done
|
||||||
|
@for file in `cd ..; ls *$(PACKAGE)*_$(subst _,.,$(VERSION))*`; do \
|
||||||
|
printf "%-40s Debian/Ubuntu package file\n" $$file; \
|
||||||
done
|
done
|
||||||
|
266
README.md
266
README.md
@@ -1,6 +1,6 @@
|
|||||||
Editline
|
Editline
|
||||||
========
|
========
|
||||||
[![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
[![License Badge][]][License] [![Travis Status]][Travis] [![Coverity Status]][Coverity Scan]
|
||||||
|
|
||||||
|
|
||||||
Table of Contents
|
Table of Contents
|
||||||
@@ -20,92 +20,44 @@ This is a small [line editing][] library. It can be linked into almost
|
|||||||
any program to provide command line editing and history functions. It
|
any program to provide command line editing and history functions. It
|
||||||
is call compatible with the [FSF readline][] library, but at a fraction
|
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
|
of the size, and as a result fewer features. It is also distributed
|
||||||
under a much more liberal [LICENSE][].
|
under a much more liberal [License][].
|
||||||
|
|
||||||
The small size (<30k), lack of dependencies (no ncurses needed!), and
|
The small size (<30k), lack of dependencies (ncurses not needed!), and
|
||||||
the free license should make this library interesting to many embedded
|
the free license should make this library interesting to many embedded
|
||||||
developers.
|
developers.
|
||||||
|
|
||||||
Editline has several optional build-time features that can be enabled by
|
Editline has several optional build-time features that can be enabled by
|
||||||
by supplying different options to the GNU configure script. See the
|
supplying different options to the GNU configure script. See the output
|
||||||
output from <kbd>configure --help</kbd> for details. In the `examples/`
|
from <kbd>configure --help</kbd> for details. Some useful hints on how
|
||||||
directory you can find some small code snippets used for testing.
|
to use the library is available in the `examples/` directory.
|
||||||
|
|
||||||
Editline is maintained collaboratively at [GitHub][].
|
Editline is maintained collaboratively at [GitHub][].
|
||||||
|
|
||||||
|
|
||||||
API
|
|
||||||
---
|
|
||||||
|
|
||||||
Here is the interface to editline. 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_initialize(void);
|
|
||||||
void rl_reset_terminal(const char *terminal_name);
|
|
||||||
|
|
||||||
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);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
Example
|
Example
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Here is a very brief example to illustrate how one can use Editline to
|
Here is a very brief example to illustrate how one can use Editline to
|
||||||
create a simple CLI. More examples are availble in the source tree.
|
create a simple CLI, use Ctrl-D to exit the program. More examples are
|
||||||
|
availble in the source tree.
|
||||||
|
|
||||||
|
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
|
```C
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <editline.h>
|
||||||
|
|
||||||
extern char *readline(char *prompt);
|
int main(void)
|
||||||
|
|
||||||
int main (void)
|
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
@@ -118,6 +70,120 @@ create a simple CLI. More examples are availble in the source tree.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
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
|
Build & Install
|
||||||
---------------
|
---------------
|
||||||
@@ -131,27 +197,39 @@ purpose and patches or pull requests to correct this are most welcome!
|
|||||||
2. Build the library and examples: <kbd>make all</kbd>
|
2. Build the library and examples: <kbd>make all</kbd>
|
||||||
3. Install using <kbd>make install</kbd>
|
3. Install using <kbd>make install</kbd>
|
||||||
|
|
||||||
The `$DESTDIR` environment variable is honored at install. See
|
The `$DESTDIR` environment variable is honored at install. For more
|
||||||
<kbd>./configure --help</kbd> for more options.
|
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
|
Origin & References
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
This [line editing][] library was created by Simmule Turner and
|
This [line editing][] library was created by [Rich Salz][] and Simmule
|
||||||
[Rich Salz][upstream] in in 1992. It is distributed under a “C
|
Turner and in 1992. It is distributed with a “[C News][]-like” license,
|
||||||
News-like” license, similar to the [BSD license][]. Rich's latest
|
similar to the [BSD license][]. Rich's current version is however under
|
||||||
version is however under the Apache license. For details on the
|
the Apache license. For details on the licensing terms of this version
|
||||||
licensing terms of this version of the software, see [LICENSE][].
|
of the software, see [License][].
|
||||||
|
|
||||||
This version of the editline library was forked from the [Minix 3][]
|
This version of the editline library was forked from the [Minix 3][]
|
||||||
source tree and is *not* related to the similarily named NetBSD version
|
source tree and is *not* related to the similarily named NetBSD version
|
||||||
that [Jess Thrysøe][jess] disitributes to the world outside BSD. The
|
that [Jess Thrysøe][jess] disitributes to the world outside *BSD. The
|
||||||
libraries have much in common, but the latter is heavily refactored and
|
libraries have much in common, but the latter is heavily refactored and
|
||||||
also relies on libtermcap (usually supplied by ncurses), whereas this
|
also relies on libtermcap (usually supplied by ncurses), whereas this
|
||||||
library only uses termios from the standard C library.
|
library only uses termios from the standard C library.
|
||||||
|
|
||||||
Patches and bug fixes from the following forks, all based on the
|
Patches and bug fixes from the following forks, based on the original
|
||||||
original comp.sources.unix posting, have been merged:
|
[comp.sources.unix][] posting, have been merged:
|
||||||
|
|
||||||
* Debian [libeditline][]
|
* Debian [libeditline][]
|
||||||
* [Heimdal][]
|
* [Heimdal][]
|
||||||
@@ -159,22 +237,24 @@ original comp.sources.unix posting, have been merged:
|
|||||||
* [Steve Tell][]'s editline patches
|
* [Steve Tell][]'s editline patches
|
||||||
|
|
||||||
The version numbering scheme today follows that of the Debian version,
|
The version numbering scheme today follows that of the Debian version,
|
||||||
which can be seen in the [ChangeLog.md][]. The Debian version was
|
details available in the [ChangeLog.md][]. The current [maintainer][]
|
||||||
unknown to the current [maintainer][] for quite some time, so a
|
was unaware of the Debian version for quite some time, so a different
|
||||||
different name and different versioning scheme was used. In June 2009
|
name and versioning scheme was used. In June 2009 this was changed to
|
||||||
this was changed to line up alongside Debian, with the intent is to
|
line up alongside Debian, with the intent is to eventually merge the
|
||||||
eventually merge the efforts.
|
efforts.
|
||||||
|
|
||||||
Outstanding issues are listed in the [TODO.md][] file.
|
Outstanding issues are listed in the [TODO.md][] file.
|
||||||
|
|
||||||
[GitHub]: https://github.com/troglobit/editline
|
[GitHub]: https://github.com/troglobit/editline
|
||||||
[line editing]: https://github.com/troglobit/editline/blob/master/doc/README
|
[line editing]: https://github.com/troglobit/editline/blob/master/docs/README
|
||||||
|
[release tarball]: https://github.com/troglobit/editline/releases
|
||||||
[maintainer]: http://troglobit.com
|
[maintainer]: http://troglobit.com
|
||||||
[LICENSE]: https://github.com/troglobit/editline/blob/master/LICENSE
|
[C News]: https://en.wikipedia.org/wiki/C_News
|
||||||
[TODO.md]: https://github.com/troglobit/editline/blob/master/TODO.md
|
[TODO.md]: https://github.com/troglobit/editline/blob/master/docs/TODO.md
|
||||||
[ChangeLog.md]: https://github.com/troglobit/editline/blob/master/ChangeLog.md
|
[ChangeLog.md]: https://github.com/troglobit/editline/blob/master/ChangeLog.md
|
||||||
[FSF readline]: http://www.gnu.org/software/readline/
|
[FSF readline]: http://www.gnu.org/software/readline/
|
||||||
[upstream]: https://github.com/richsalz/editline/
|
[Rich Salz]: https://github.com/richsalz/editline/
|
||||||
|
[comp.sources.unix]: http://ftp.cs.toronto.edu/pub/white/pub/rc/editline.shar
|
||||||
[Minix 3]: http://www.cise.ufl.edu/~cop4600/cgi-bin/lxr/http/source.cgi/lib/editline/
|
[Minix 3]: http://www.cise.ufl.edu/~cop4600/cgi-bin/lxr/http/source.cgi/lib/editline/
|
||||||
[jess]: http://thrysoee.dk/editline/
|
[jess]: http://thrysoee.dk/editline/
|
||||||
[BSD license]: http://en.wikipedia.org/wiki/BSD_licenses
|
[BSD license]: http://en.wikipedia.org/wiki/BSD_licenses
|
||||||
@@ -182,13 +262,9 @@ Outstanding issues are listed in the [TODO.md][] file.
|
|||||||
[Heimdal]: http://www.h5l.org
|
[Heimdal]: http://www.h5l.org
|
||||||
[Festival]: http://festvox.org/festival/
|
[Festival]: http://festvox.org/festival/
|
||||||
[Steve Tell]: http://www.cs.unc.edu/~tell/dist.html
|
[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]: https://travis-ci.org/troglobit/editline
|
||||||
[Travis Status]: https://travis-ci.org/troglobit/editline.png?branch=master
|
[Travis Status]: https://travis-ci.org/troglobit/editline.png?branch=master
|
||||||
[Coverity Scan]: https://scan.coverity.com/projects/2982
|
[Coverity Scan]: https://scan.coverity.com/projects/2982
|
||||||
[Coverity Status]: https://scan.coverity.com/projects/2982/badge.svg
|
[Coverity Status]: https://scan.coverity.com/projects/2982/badge.svg
|
||||||
|
|
||||||
<!--
|
|
||||||
-- Local Variables:
|
|
||||||
-- mode: markdown
|
|
||||||
-- End:
|
|
||||||
-->
|
|
||||||
|
68
TODO.md
68
TODO.md
@@ -1,68 +0,0 @@
|
|||||||
TODO
|
|
||||||
====
|
|
||||||
|
|
||||||
Issues in need of work. Mostly compatibility with GNU readline, BSD
|
|
||||||
[libedit][], and usability improvements.
|
|
||||||
|
|
||||||
Remember, the general idea is to keep this library editline small with
|
|
||||||
no external dependencies, except a C library.
|
|
||||||
|
|
||||||
|
|
||||||
Add support for running in an event loop
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
To be able to use libeditline from within an event loop like [libuEv][]
|
|
||||||
there are few things to do:
|
|
||||||
|
|
||||||
- Refactor `editinput()` and `readline()`. Break out the active code
|
|
||||||
used for set up and teardown, and the character input logic
|
|
||||||
- Add bare necessities for external callbacks so that an event loop
|
|
||||||
that monitors `el_infd` has something to call on events
|
|
||||||
- GNU Readline has its [alternate interface][gnu] which we should
|
|
||||||
probably implement
|
|
||||||
|
|
||||||
Example usecase of the GNU alternate interface can be found here:
|
|
||||||
http://www.mcld.co.uk/blog/blog.php?274
|
|
||||||
|
|
||||||
|
|
||||||
Verify custom completion handlers
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
Verify for v1.14.0 that custom completion handlers still work After
|
|
||||||
reverting a "fix" in v0.2.2 that made `rl_complete()` a function pointer
|
|
||||||
we need to make sure the same functionality is still available with the
|
|
||||||
new infrastructure. Which is more inspired by BSD libedit and GNU
|
|
||||||
readline.
|
|
||||||
|
|
||||||
|
|
||||||
Check what's needed to run the fileman example
|
|
||||||
----------------------------------------------
|
|
||||||
|
|
||||||
The BSD libedit library has imported the GNU readline "fileman" example
|
|
||||||
into its tree to demonstrate the abilities of that library. This would
|
|
||||||
also be quite useful for this library!
|
|
||||||
|
|
||||||
The first task is to investigate the depependencies and form TODO list
|
|
||||||
items detailing what is missing and, if possible, proposals how to
|
|
||||||
implement including any optional configure flags.
|
|
||||||
|
|
||||||
|
|
||||||
Other minor TODO's
|
|
||||||
------------------
|
|
||||||
|
|
||||||
- Instead of supporting multiline input, try the Emacs approach, line
|
|
||||||
scrolling.
|
|
||||||
- Add support for `rl_bind_key()`, currently only en editline specific
|
|
||||||
`el_bind_key()` exists.
|
|
||||||
- Make `char *rl_prompt;` globally visible.
|
|
||||||
- Add support for `rl_set_prompt()`
|
|
||||||
- Add support for `--enable-utf8` to configure script
|
|
||||||
- Use `strcmp(nl_langinfo(CODESET), "UTF-8")` to look for utf8 capable
|
|
||||||
terminal
|
|
||||||
- Implement simple UTF-8 parser according to
|
|
||||||
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
|
||||||
|
|
||||||
|
|
||||||
[gnu]: http://www.delorie.com/gnu/docs/readline/rlman_41.html#IDX288
|
|
||||||
[libuEv]: https://github.com/troglobit/libuev/
|
|
||||||
[libedit]: http://www.thrysoee.dk/editline/
|
|
10
configure.ac
10
configure.ac
@@ -1,4 +1,4 @@
|
|||||||
AC_INIT(editline, 1.15.3, https://github.com/troglobit/editline/issues)
|
AC_INIT(editline, 1.16.0, https://github.com/troglobit/editline/issues)
|
||||||
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
|
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ AC_HEADER_STAT
|
|||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
# Check for malloc.h instead of AC_FUNC_MALLOC/REALLOC AIX and others
|
# Check for malloc.h instead of AC_FUNC_MALLOC/REALLOC AIX and others
|
||||||
# mess up the traditional malloc check.
|
# mess up the traditional malloc check.
|
||||||
AC_CHECK_HEADERS([malloc.h signal.h stdlib.h string.h termcap.h termio.h termios.h sgtty.h])
|
AC_CHECK_HEADERS([malloc.h signal.h stdlib.h string.h termcap.h termio.h termios.h sgtty.h unistd.h])
|
||||||
|
|
||||||
# In termios.h or in sys/ioctl.g?
|
# In termios.h or in sys/ioctl.g?
|
||||||
AC_HEADER_TIOCGWINSZ
|
AC_HEADER_TIOCGWINSZ
|
||||||
@@ -42,9 +42,6 @@ AC_ARG_ENABLE(unique-history,
|
|||||||
[AS_HELP_STRING([--disable-unique-history],
|
[AS_HELP_STRING([--disable-unique-history],
|
||||||
[Disable uniqify of scrollback. Default: duplicate entries are ignored. Use this to save dupes.])])
|
[Disable uniqify of scrollback. Default: duplicate entries are ignored. Use this to save dupes.])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(default-complete,
|
|
||||||
[AS_HELP_STRING([--disable-default-complete], [Disable default (filename) completion handler.])])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(arrow-keys,
|
AC_ARG_ENABLE(arrow-keys,
|
||||||
[AS_HELP_STRING([--disable-arrow-keys], [Disable ANSI arrow keys.])])
|
[AS_HELP_STRING([--disable-arrow-keys], [Disable ANSI arrow keys.])])
|
||||||
|
|
||||||
@@ -69,9 +66,6 @@ AC_ARG_ENABLE(termcap,
|
|||||||
AS_IF([test "x$enable_unique_history" != "xno"],
|
AS_IF([test "x$enable_unique_history" != "xno"],
|
||||||
AC_DEFINE(CONFIG_UNIQUE_HISTORY, 1, [Define to skip duplicate lines in the scrollback history.]))
|
AC_DEFINE(CONFIG_UNIQUE_HISTORY, 1, [Define to skip duplicate lines in the scrollback history.]))
|
||||||
|
|
||||||
AS_IF([test "x$enable_default_complete" != "xno"],
|
|
||||||
AC_DEFINE(CONFIG_DEFAULT_COMPLETE, 1, [Define to enable the default completion handler.]))
|
|
||||||
|
|
||||||
AS_IF([test "x$enable_terminal_bell" != "xno"],
|
AS_IF([test "x$enable_terminal_bell" != "xno"],
|
||||||
AC_DEFINE(CONFIG_ANSI_ARROWS, 1, [Define to include ANSI arrow keys support.]))
|
AC_DEFINE(CONFIG_ANSI_ARROWS, 1, [Define to include ANSI arrow keys support.]))
|
||||||
|
|
||||||
|
5
debian/.gitignore
vendored
5
debian/.gitignore
vendored
@@ -1,5 +1,10 @@
|
|||||||
*.log
|
*.log
|
||||||
*.debhelper
|
*.debhelper
|
||||||
*.substvars
|
*.substvars
|
||||||
|
autoreconf.*
|
||||||
|
debhelper-build-stamp
|
||||||
files
|
files
|
||||||
tmp/*
|
tmp/*
|
||||||
|
libeditline-dev/*
|
||||||
|
libeditline0/*
|
||||||
|
libeditline1/*
|
||||||
|
11
debian/changelog
vendored
11
debian/changelog
vendored
@@ -1,3 +1,14 @@
|
|||||||
|
editline (1.16.0) unstable; urgency=medium
|
||||||
|
|
||||||
|
* New upstream release, v1.60.0
|
||||||
|
+ Event loop support
|
||||||
|
+ New GNU Readline compat functions and callbacks
|
||||||
|
+ Minor compat fixes for movement and deletion
|
||||||
|
* Bump .so/ABI version => libeditline1
|
||||||
|
* New maintainer, upstream author
|
||||||
|
|
||||||
|
-- Joachim Nilsson <troglobit@gmail.com> Sun, 16 Sep 2018 09:45:53 +0200
|
||||||
|
|
||||||
editline (1.15.3-1) unstable; urgency=medium
|
editline (1.15.3-1) unstable; urgency=medium
|
||||||
|
|
||||||
* New upstream bug fix release, v1.15.3
|
* New upstream bug fix release, v1.15.3
|
||||||
|
6
debian/control
vendored
6
debian/control
vendored
@@ -2,13 +2,13 @@ Source: editline
|
|||||||
Section: devel
|
Section: devel
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Build-Depends: debhelper (>= 5.0), libtool
|
Build-Depends: debhelper (>= 5.0), libtool
|
||||||
Maintainer: Sam Hocevar <sho@debian.org>
|
Maintainer: Joachim Nilsson <troglobit@gmail.com>
|
||||||
Standards-Version: 3.8.3
|
Standards-Version: 3.8.3
|
||||||
|
|
||||||
Package: libeditline-dev
|
Package: libeditline-dev
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Section: libdevel
|
Section: libdevel
|
||||||
Depends: libeditline0 (= ${binary:Version}), ${misc:Depends}
|
Depends: libeditline1 (= ${binary:Version}), ${misc:Depends}
|
||||||
Description: development files for libeditline
|
Description: development files for libeditline
|
||||||
This is a line-editing library. It can be linked into almost any program
|
This is a line-editing library. It can be linked into almost any program
|
||||||
to provide command-line editing and recall. It is call-compatible with a
|
to provide command-line editing and recall. It is call-compatible with a
|
||||||
@@ -18,7 +18,7 @@ Description: development files for libeditline
|
|||||||
This package contains the developer files: static libraries, headers,
|
This package contains the developer files: static libraries, headers,
|
||||||
manpages.
|
manpages.
|
||||||
|
|
||||||
Package: libeditline0
|
Package: libeditline1
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Section: libs
|
Section: libs
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||||
|
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.0 (native)
|
106
docs/HACKING.md
Normal file
106
docs/HACKING.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
Maintenance and Release Checklist
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Maintenance
|
||||||
|
-----------
|
||||||
|
|
||||||
|
* Encourage contributors to write tests, in particular for new features
|
||||||
|
* Run tests regularly, use Travis-CI to do this automatically
|
||||||
|
* Leverage GitHub issues for milestone planning
|
||||||
|
* Reference issues from GitHub pull requests to alert issue subscribers
|
||||||
|
* Bump library ABI version just before release!
|
||||||
|
|
||||||
|
|
||||||
|
Release Checklist
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
* Update ChangeLog, follow http://keepachangelog.com/ loosely
|
||||||
|
- Inform users in a plain language of changes and bug fixes
|
||||||
|
- Do *not* copy-paste GIT commit logs!
|
||||||
|
- Order entries according to importance, most relevant first
|
||||||
|
* Run unit tests: `make check`
|
||||||
|
* Make at least one `-rcN` release and test it in an actual real project
|
||||||
|
* **REMEMBER:** bump ABI version according to below rules
|
||||||
|
* Tag
|
||||||
|
* Push last commit(s) *and* tags to GitHub
|
||||||
|
* Make release
|
||||||
|
|
||||||
|
make distclean
|
||||||
|
./autogen.sh
|
||||||
|
./configure
|
||||||
|
make release
|
||||||
|
|
||||||
|
* Create new release in GitHub releases page
|
||||||
|
* Copy and paste ChangeLog entry, check any stale links!
|
||||||
|
* Upload release tarball and MD5 files
|
||||||
|
|
||||||
|
|
||||||
|
Library Versioning
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Editline relies on GNU Libtool for building the library. For a user of
|
||||||
|
the library it is important to maintain a clear ABI versioning scheme.
|
||||||
|
This is not the same as the Editline version, but rather the library
|
||||||
|
"compatibility level".
|
||||||
|
|
||||||
|
The Editline ABI version is specified in `src/Makefile.am` and looks
|
||||||
|
like this:
|
||||||
|
|
||||||
|
libeditline_la_LDFLAGS = -version-info 0:0:0
|
||||||
|
\ \ `-- age
|
||||||
|
\ `--- revision
|
||||||
|
`---- current
|
||||||
|
|
||||||
|
It must be updated according to the [GNU Libtool recommendations][1]:
|
||||||
|
|
||||||
|
1. Start with version information of `0:0:0` for each libtool library.
|
||||||
|
2. Update the version information only immediately before a public
|
||||||
|
release of your software. More frequent updates are unnecessary, and
|
||||||
|
only guarantee that the current interface number gets larger faster.
|
||||||
|
3. If the library *source code has changed at all* since the last update,
|
||||||
|
then increment revision (`c:r:a` becomes `c:r+1:a`).
|
||||||
|
4. If any *interfaces have been added, removed, or changed* since the
|
||||||
|
last update, increment current, and set revision to 0.
|
||||||
|
5. If any *interfaces have been added* since the last public release,
|
||||||
|
then increment age.
|
||||||
|
6. If any *interfaces have been removed or changed* since the last
|
||||||
|
public release, then set age to 0.
|
||||||
|
|
||||||
|
The libtool ABI versioning logic is very confusing but works if you just
|
||||||
|
disable your brain and follow the rules, one by one.
|
||||||
|
|
||||||
|
**Example #1:** a new function has been added, none of the existing ones
|
||||||
|
have changed. The initial version is 1:0:0, we follow the rules above to
|
||||||
|
the letter: increase revision, increase current and set revision to zero,
|
||||||
|
and finally increase age. This, rather confusingly, gives us 2:0:1 which
|
||||||
|
libtool then translates to `libeditline.so.1.1.0`.
|
||||||
|
|
||||||
|
**Example #2:** some existing functions are changed, they now return an
|
||||||
|
`int` instead of `void`. The initial version is 0:0:0, and we follow the
|
||||||
|
rules again: increment revision, increment current and set revision to
|
||||||
|
zero, set age to zero. This gives us 1:0:0, which is then translated to
|
||||||
|
`libeditline.so.1.0.0`.
|
||||||
|
|
||||||
|
### Note
|
||||||
|
|
||||||
|
Usually, non-developers have no interest in running development versions
|
||||||
|
(releases are frequent enough), and developers are expected to know how
|
||||||
|
to juggle versions. In such an ideal world, it is good enough to bump
|
||||||
|
the library version just prior to a release, point 2.
|
||||||
|
|
||||||
|
However, if releases are few and far between, distributors may start to
|
||||||
|
use snapshots. When a distributor uses a snapshot, the distributor has
|
||||||
|
to handle the library version manually. Things can get ugly when the
|
||||||
|
distributor has released an intermediate version with a bumped library
|
||||||
|
version, and when the official release is bumped to that version, the
|
||||||
|
distributor will then have to bump the library version for the official
|
||||||
|
release, and it can be confusing if someone reports bugs on versions
|
||||||
|
that you didn't even know existed.
|
||||||
|
|
||||||
|
The problem with bumping the version with every change is that if your
|
||||||
|
interface is not finished, the version number might run away, and it
|
||||||
|
looks pretty bad if a library is at version 262. It kind of tells the
|
||||||
|
user that the library interface is volatile, which is not good for
|
||||||
|
business.
|
||||||
|
|
||||||
|
[1]: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
41
docs/TODO.md
Normal file
41
docs/TODO.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
TODO
|
||||||
|
====
|
||||||
|
|
||||||
|
Issues in need of work. Mostly compatibility with GNU readline,
|
||||||
|
BSD [libedit][], and usability improvements.
|
||||||
|
|
||||||
|
Remember, the general idea is to keep this library small with no
|
||||||
|
external dependencies, except for a generic C library.
|
||||||
|
|
||||||
|
|
||||||
|
Check what's needed to run the fileman example
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
The BSD libedit library has imported the GNU readline "fileman" example
|
||||||
|
into its tree to demonstrate the abilities of that library. This would
|
||||||
|
also be quite useful for this library!
|
||||||
|
|
||||||
|
The first task is to investigate the depependencies and form TODO list
|
||||||
|
items detailing what is missing and, if possible, proposals how to
|
||||||
|
implement including any optional configure flags.
|
||||||
|
|
||||||
|
|
||||||
|
Other minor TODO's
|
||||||
|
------------------
|
||||||
|
|
||||||
|
- Instead of supporting multiline input, try the Emacs approach, line
|
||||||
|
scrolling.
|
||||||
|
- Add support for `rl_bind_key()`, currently only en editline specific
|
||||||
|
`el_bind_key()` exists.
|
||||||
|
- Make `char *rl_prompt;` globally visible.
|
||||||
|
- Add support for `rl_set_prompt()`
|
||||||
|
- Add support for `--enable-utf8` to configure script
|
||||||
|
- Use `strcmp(nl_langinfo(CODESET), "UTF-8")` to look for utf8 capable
|
||||||
|
terminal
|
||||||
|
- Implement simple UTF-8 parser according to
|
||||||
|
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||||
|
|
||||||
|
|
||||||
|
[gnu]: http://www.delorie.com/gnu/docs/readline/rlman_41.html#IDX288
|
||||||
|
[libuEv]: https://github.com/troglobit/libuev/
|
||||||
|
[libedit]: http://www.thrysoee.dk/editline/
|
2
examples/.gitignore
vendored
2
examples/.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
*.o
|
*.o
|
||||||
cli
|
cli
|
||||||
testit
|
testit
|
||||||
|
excallback
|
||||||
|
fileman
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
noinst_PROGRAMS = testit cli
|
noinst_PROGRAMS = testit cli excallback fileman
|
||||||
LDADD = $(top_builddir)/src/libeditline.la
|
LDADD = $(top_builddir)/src/libeditline.la
|
||||||
|
AM_CPPFLAGS = -DEDITLINE_LIBRARY
|
||||||
AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include
|
AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include
|
||||||
AM_LDFLAGS = -static
|
AM_LDFLAGS = -static
|
||||||
|
@@ -37,20 +37,17 @@ static char *my_rl_complete(char *token, int *match)
|
|||||||
int matchlen = 0;
|
int matchlen = 0;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
for (i = 0; list[i]; i++)
|
for (i = 0; list[i]; i++) {
|
||||||
{
|
|
||||||
int partlen = strlen (token); /* Part of token */
|
int partlen = strlen (token); /* Part of token */
|
||||||
|
|
||||||
if (!strncmp (list[i], token, partlen))
|
if (!strncmp (list[i], token, partlen)) {
|
||||||
{
|
|
||||||
index = i;
|
index = i;
|
||||||
matchlen = partlen;
|
matchlen = partlen;
|
||||||
count ++;
|
count ++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 1)
|
if (count == 1) {
|
||||||
{
|
|
||||||
*match = 1;
|
*match = 1;
|
||||||
return strdup (list[index] + matchlen);
|
return strdup (list[index] + matchlen);
|
||||||
}
|
}
|
||||||
@@ -66,11 +63,10 @@ static int my_rl_list_possib(char *token, char ***av)
|
|||||||
|
|
||||||
for (num = 0; list[num]; num++)
|
for (num = 0; list[num]; num++)
|
||||||
;
|
;
|
||||||
|
|
||||||
copy = (char **) malloc (num * sizeof(char *));
|
copy = (char **) malloc (num * sizeof(char *));
|
||||||
for (i = 0; i < num; i++)
|
for (i = 0; i < num; i++) {
|
||||||
{
|
if (!strncmp (list[i], token, strlen (token))) {
|
||||||
if (!strncmp (list[i], token, strlen (token)))
|
|
||||||
{
|
|
||||||
copy[total] = strdup (list[i]);
|
copy[total] = strdup (list[i]);
|
||||||
total ++;
|
total ++;
|
||||||
}
|
}
|
||||||
@@ -120,7 +116,7 @@ el_status_t do_suspend(void)
|
|||||||
return CSstay;
|
return CSstay;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int ac __attribute__ ((unused)), char *av[] __attribute__ ((unused)))
|
int main(void)
|
||||||
{
|
{
|
||||||
char *line;
|
char *line;
|
||||||
char *prompt = "cli> ";
|
char *prompt = "cli> ";
|
||||||
@@ -143,3 +139,10 @@ int main(int ac __attribute__ ((unused)), char *av[] __attribute__ ((unused)))
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Variables:
|
||||||
|
* c-file-style: "k&r"
|
||||||
|
* c-basic-offset: 4
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
|
195
examples/excallback.c
Normal file
195
examples/excallback.c
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
From: Jeff Solomon <jsolomon@stanford.edu>
|
||||||
|
Date: Fri, 9 Apr 1999 10:13:27 -0700 (PDT)
|
||||||
|
To: chet@po.cwru.edu
|
||||||
|
Subject: new readline example
|
||||||
|
Message-ID: <14094.12094.527305.199695@mrclean.Stanford.EDU>
|
||||||
|
|
||||||
|
Chet,
|
||||||
|
|
||||||
|
I've been using readline 4.0. Specifically, I've been using the perl
|
||||||
|
version Term::ReadLine::Gnu. It works great.
|
||||||
|
|
||||||
|
Anyway, I've been playing around the alternate interface and I wanted
|
||||||
|
to contribute a little C program, callback.c, to you that you could
|
||||||
|
use as an example of the alternate interface in the /examples
|
||||||
|
directory of the readline distribution.
|
||||||
|
|
||||||
|
My example shows how, using the alternate interface, you can
|
||||||
|
interactively change the prompt (which is very nice imo). Also, I
|
||||||
|
point out that you must roll your own terminal setting when using the
|
||||||
|
alternate interface because readline depreps (using your parlance) the
|
||||||
|
terminal while in the user callback. I try to demostrate what I mean
|
||||||
|
with an example. I've included the program below.
|
||||||
|
|
||||||
|
To compile, I just put the program in the examples directory and made
|
||||||
|
the appropriate changes to the EXECUTABLES and OBJECTS line and added
|
||||||
|
an additional target 'callback'.
|
||||||
|
|
||||||
|
I compiled on my Sun Solaris2.6 box using Sun's cc.
|
||||||
|
|
||||||
|
Let me know what you think.
|
||||||
|
|
||||||
|
Jeff
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined (HAVE_CONFIG_H)
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_STDLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <termios.h> /* xxx - should make this more general */
|
||||||
|
|
||||||
|
#ifdef EDITLINE_LIBRARY
|
||||||
|
# include "editline.h"
|
||||||
|
#else
|
||||||
|
# include <readline/readline.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This little examples demonstrates the alternate interface to using readline.
|
||||||
|
* In the alternate interface, the user maintains control over program flow and
|
||||||
|
* only calls readline when STDIN is readable. Using the alternate interface,
|
||||||
|
* you can do anything else while still using readline (like talking to a
|
||||||
|
* network or another program) without blocking.
|
||||||
|
*
|
||||||
|
* Specifically, this program highlights two importants features of the
|
||||||
|
* alternate interface. The first is the ability to interactively change the
|
||||||
|
* prompt, which can't be done using the regular interface since rl_prompt is
|
||||||
|
* read-only.
|
||||||
|
*
|
||||||
|
* The second feature really highlights a subtle point when using the alternate
|
||||||
|
* interface. That is, readline will not alter the terminal when inside your
|
||||||
|
* callback handler. So let's so, your callback executes a user command that
|
||||||
|
* takes a non-trivial amount of time to complete (seconds). While your
|
||||||
|
* executing the command, the user continues to type keystrokes and expects them
|
||||||
|
* to be re-echoed on the new prompt when it returns. Unfortunately, the default
|
||||||
|
* terminal configuration doesn't do this. After the prompt returns, the user
|
||||||
|
* must hit one additional keystroke and then will see all of his previous
|
||||||
|
* keystrokes. To illustrate this, compile and run this program. Type "sleep" at
|
||||||
|
* the prompt and then type "bar" before the prompt returns (you have 3
|
||||||
|
* seconds). Notice how "bar" is re-echoed on the prompt after the prompt
|
||||||
|
* returns? This is what you expect to happen. Now comment out the 4 lines below
|
||||||
|
* the line that says COMMENT LINE BELOW. Recompile and rerun the program and do
|
||||||
|
* the same thing. When the prompt returns, you should not see "bar". Now type
|
||||||
|
* "f", see how "barf" magically appears? This behavior is un-expected and not
|
||||||
|
* desired.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void process_line(char *line);
|
||||||
|
int change_prompt(void);
|
||||||
|
char *get_prompt(void);
|
||||||
|
|
||||||
|
int prompt = 1;
|
||||||
|
char prompt_buf[40], line_buf[256];
|
||||||
|
tcflag_t old_lflag;
|
||||||
|
cc_t old_vtime;
|
||||||
|
struct termios term;
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
fd_set fds;
|
||||||
|
|
||||||
|
/* Adjust the terminal slightly before the handler is installed. Disable
|
||||||
|
* canonical mode processing and set the input character time flag to be
|
||||||
|
* non-blocking.
|
||||||
|
*/
|
||||||
|
if( tcgetattr(STDIN_FILENO, &term) < 0 ) {
|
||||||
|
perror("tcgetattr");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
old_lflag = term.c_lflag;
|
||||||
|
old_vtime = term.c_cc[VTIME];
|
||||||
|
term.c_lflag &= ~ICANON;
|
||||||
|
term.c_cc[VTIME] = 1;
|
||||||
|
/* COMMENT LINE BELOW - see above */
|
||||||
|
if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) {
|
||||||
|
perror("tcsetattr");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rl_add_defun("change-prompt", change_prompt, CTRL('t'));
|
||||||
|
rl_callback_handler_install(get_prompt(), process_line);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(fileno(stdin), &fds);
|
||||||
|
|
||||||
|
if( select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0) {
|
||||||
|
perror("select");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( FD_ISSET(fileno(stdin), &fds) ) {
|
||||||
|
rl_callback_read_char();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
process_line(char *line)
|
||||||
|
{
|
||||||
|
if( line == NULL ) {
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
/* reset the old terminal setting before exiting */
|
||||||
|
term.c_lflag = old_lflag;
|
||||||
|
term.c_cc[VTIME] = old_vtime;
|
||||||
|
if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) {
|
||||||
|
perror("tcsetattr");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( strcmp(line, "sleep") == 0 ) {
|
||||||
|
sleep(3);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "|%s|\n", line);
|
||||||
|
}
|
||||||
|
|
||||||
|
free (line);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
change_prompt(void)
|
||||||
|
{
|
||||||
|
/* toggle the prompt variable */
|
||||||
|
prompt = !prompt;
|
||||||
|
|
||||||
|
/* save away the current contents of the line */
|
||||||
|
strncpy(line_buf, rl_line_buffer, sizeof(line_buf));
|
||||||
|
line_buf[sizeof(line_buf) - 1] = 0;
|
||||||
|
|
||||||
|
/* install a new handler which will change the prompt and erase the current line */
|
||||||
|
rl_callback_handler_install(get_prompt(), process_line);
|
||||||
|
|
||||||
|
/* insert the old text on the new line */
|
||||||
|
rl_insert_text(line_buf);
|
||||||
|
|
||||||
|
/* redraw the current line - this is an undocumented function. It invokes the
|
||||||
|
* redraw-current-line command.
|
||||||
|
*/
|
||||||
|
return rl_refresh_line(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
get_prompt(void)
|
||||||
|
{
|
||||||
|
/* The prompts can even be different lengths! */
|
||||||
|
sprintf(prompt_buf, "%s",
|
||||||
|
prompt ? "Hit ctrl-t to toggle prompt> " : "Pretty cool huh?> ");
|
||||||
|
return prompt_buf;
|
||||||
|
}
|
487
examples/fileman.c
Normal file
487
examples/fileman.c
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
/* fileman.c -- A tiny application which demonstrates how to use the
|
||||||
|
GNU Readline library. This application interactively allows users
|
||||||
|
to manipulate files and their modes.
|
||||||
|
|
||||||
|
NOTE: this was taken from the GNU Readline documentation and ported
|
||||||
|
to libedit. A command to output the history list was added.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "editline.h"
|
||||||
|
|
||||||
|
void * xmalloc (size_t size);
|
||||||
|
void too_dangerous (char *caller);
|
||||||
|
void initialize_readline ();
|
||||||
|
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 *);
|
||||||
|
int com_history (char *);
|
||||||
|
int com_rename(char *);
|
||||||
|
int com_stat(char *);
|
||||||
|
int com_pwd(char *);
|
||||||
|
int com_delete(char *);
|
||||||
|
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 {
|
||||||
|
char *name; /* User printable name of the function. */
|
||||||
|
rl_icpfunc_t *func; /* Function to call to do the job. */
|
||||||
|
char *doc; /* Documentation for this function. */
|
||||||
|
} COMMAND;
|
||||||
|
|
||||||
|
COMMAND commands[] = {
|
||||||
|
{ "cd", com_cd, "Change to directory DIR" },
|
||||||
|
{ "delete", com_delete, "Delete FILE" },
|
||||||
|
{ "help", com_help, "Display this text" },
|
||||||
|
{ "?", com_help, "Synonym for `help'" },
|
||||||
|
{ "list", com_list, "List files in DIR" },
|
||||||
|
{ "ls", com_list, "Synonym for `list'" },
|
||||||
|
{ "pwd", com_pwd, "Print the current working directory" },
|
||||||
|
{ "quit", com_quit, "Quit using Fileman" },
|
||||||
|
{ "rename", com_rename, "Rename FILE to NEWNAME" },
|
||||||
|
{ "stat", com_stat, "Print out statistics on FILE" },
|
||||||
|
{ "view", com_view, "View the contents of FILE" },
|
||||||
|
{ "history", com_history, "List editline history" },
|
||||||
|
{ (char *)NULL, (rl_icpfunc_t *)NULL, (char *)NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Forward declarations. */
|
||||||
|
char *stripwhite ();
|
||||||
|
COMMAND *find_command ();
|
||||||
|
|
||||||
|
/* The name of this program, as taken from argv[0]. */
|
||||||
|
char *progname;
|
||||||
|
|
||||||
|
/* When non-zero, this means the user is done using this program. */
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
char *line, *s;
|
||||||
|
|
||||||
|
progname = argv[0];
|
||||||
|
|
||||||
|
setlocale(LC_CTYPE, "");
|
||||||
|
|
||||||
|
initialize_readline(); /* Bind our completer. */
|
||||||
|
|
||||||
|
/* Loop reading and executing lines until the user quits. */
|
||||||
|
for ( ; done == 0; )
|
||||||
|
{
|
||||||
|
line = readline ("FileMan: ");
|
||||||
|
|
||||||
|
if (!line)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Remove leading and trailing whitespace from the line.
|
||||||
|
Then, if there is anything left, add it to the history list
|
||||||
|
and execute it. */
|
||||||
|
s = stripwhite(line);
|
||||||
|
#if 0
|
||||||
|
if (*s) {
|
||||||
|
|
||||||
|
char* expansion;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = history_expand(s, &expansion);
|
||||||
|
if (result < 0 || result == 2) {
|
||||||
|
fprintf(stderr, "%s\n", expansion);
|
||||||
|
} else {
|
||||||
|
add_history(expansion);
|
||||||
|
execute_line(expansion);
|
||||||
|
}
|
||||||
|
free(expansion);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
execute_line(s);
|
||||||
|
#endif
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
exit (0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute a command line. */
|
||||||
|
int
|
||||||
|
execute_line (char *line)
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
COMMAND *command;
|
||||||
|
char *word;
|
||||||
|
|
||||||
|
/* Isolate the command word. */
|
||||||
|
i = 0;
|
||||||
|
while (line[i] && isspace (line[i]))
|
||||||
|
i++;
|
||||||
|
word = line + i;
|
||||||
|
|
||||||
|
while (line[i] && !isspace (line[i]))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (line[i])
|
||||||
|
line[i++] = '\0';
|
||||||
|
|
||||||
|
command = find_command (word);
|
||||||
|
|
||||||
|
if (!command)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s: No such command for FileMan.\n", word);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get argument to command, if any. */
|
||||||
|
while (isspace (line[i]))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
word = line + i;
|
||||||
|
|
||||||
|
/* Call the function. */
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
|
||||||
|
for (i = 0; commands[i].name; i++)
|
||||||
|
if (strcmp (name, commands[i].name) == 0)
|
||||||
|
return (&commands[i]);
|
||||||
|
|
||||||
|
return ((COMMAND *)NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strip whitespace from the start and end of STRING. Return a pointer
|
||||||
|
into STRING. */
|
||||||
|
char *
|
||||||
|
stripwhite (char *string)
|
||||||
|
{
|
||||||
|
register char *s, *t;
|
||||||
|
|
||||||
|
for (s = string; isspace (*s); s++)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (*s == 0)
|
||||||
|
return (s);
|
||||||
|
|
||||||
|
t = s + strlen (s) - 1;
|
||||||
|
while (t > s && isspace (*t))
|
||||||
|
t--;
|
||||||
|
*++t = '\0';
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* Interface to Readline Completion */
|
||||||
|
/* */
|
||||||
|
/* **************************************************************** */
|
||||||
|
|
||||||
|
char *command_generator(const char *, int);
|
||||||
|
char **fileman_completion(const char *, int, int);
|
||||||
|
|
||||||
|
/* Tell the GNU Readline library how to complete. We want to try to
|
||||||
|
complete on command names if this is the first word in the line, or
|
||||||
|
on filenames if not. */
|
||||||
|
void
|
||||||
|
initialize_readline ()
|
||||||
|
{
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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__)))
|
||||||
|
{
|
||||||
|
char **matches;
|
||||||
|
|
||||||
|
matches = (char **)NULL;
|
||||||
|
|
||||||
|
/* If this word is at the start of the line, then it is a command
|
||||||
|
to complete. Otherwise it is the name of a file in the current
|
||||||
|
directory. */
|
||||||
|
if (start == 0)
|
||||||
|
matches = rl_completion_matches (text, command_generator);
|
||||||
|
|
||||||
|
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;
|
||||||
|
{
|
||||||
|
static int list_index, len;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
list_index = 0;
|
||||||
|
len = strlen (text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the next name which partially matches from the
|
||||||
|
command list. */
|
||||||
|
while ((name = commands[list_index].name))
|
||||||
|
{
|
||||||
|
list_index++;
|
||||||
|
|
||||||
|
if (strncmp (name, text, len) == 0)
|
||||||
|
return (dupstr(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no names matched, then return NULL. */
|
||||||
|
return ((char *)NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* **************************************************************** */
|
||||||
|
/* */
|
||||||
|
/* FileMan Commands */
|
||||||
|
/* */
|
||||||
|
/* **************************************************************** */
|
||||||
|
|
||||||
|
/* String to pass to system (). This is for the LIST, VIEW and RENAME
|
||||||
|
commands. */
|
||||||
|
static char syscom[1024];
|
||||||
|
|
||||||
|
/* List the file(s) named in arg. */
|
||||||
|
int
|
||||||
|
com_list (char *arg)
|
||||||
|
{
|
||||||
|
if (!arg)
|
||||||
|
arg = "";
|
||||||
|
|
||||||
|
sprintf (syscom, "ls -FClg %s", arg);
|
||||||
|
return (system (syscom));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
com_view (char *arg)
|
||||||
|
{
|
||||||
|
if (!valid_argument ("view", arg))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
sprintf (syscom, "more %s", arg);
|
||||||
|
return (system (syscom));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
com_history(char* arg __attribute__((__unused__)))
|
||||||
|
{
|
||||||
|
const char *he;
|
||||||
|
|
||||||
|
/* rewind history */
|
||||||
|
while (el_prev_hist())
|
||||||
|
;
|
||||||
|
|
||||||
|
for (he = el_next_hist(); he != NULL; he = el_next_hist())
|
||||||
|
printf("%s\n", he);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
com_rename (char *arg __attribute__((__unused__)))
|
||||||
|
{
|
||||||
|
too_dangerous ("rename");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
com_stat (char *arg)
|
||||||
|
{
|
||||||
|
struct stat finfo;
|
||||||
|
|
||||||
|
if (!valid_argument ("stat", arg))
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
if (stat (arg, &finfo) == -1)
|
||||||
|
{
|
||||||
|
perror (arg);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("Statistics for `%s':\n", 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");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
com_delete (char *arg __attribute__((__unused__)))
|
||||||
|
{
|
||||||
|
too_dangerous ("delete");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print out help for ARG, or for all of the commands if ARG is
|
||||||
|
not present. */
|
||||||
|
int
|
||||||
|
com_help (char *arg)
|
||||||
|
{
|
||||||
|
register 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);
|
||||||
|
printed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!printed)
|
||||||
|
{
|
||||||
|
printf ("No commands match `%s'. Possibilties are:\n", arg);
|
||||||
|
|
||||||
|
for (i = 0; commands[i].name; i++)
|
||||||
|
{
|
||||||
|
/* Print in six columns. */
|
||||||
|
if (printed == 6)
|
||||||
|
{
|
||||||
|
printed = 0;
|
||||||
|
printf ("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("%s\t", commands[i].name);
|
||||||
|
printed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printed)
|
||||||
|
printf ("\n");
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change to the directory ARG. */
|
||||||
|
int
|
||||||
|
com_cd (char *arg)
|
||||||
|
{
|
||||||
|
if (chdir (arg) == -1)
|
||||||
|
{
|
||||||
|
perror (arg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
com_pwd ("");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print out the current working directory. */
|
||||||
|
int
|
||||||
|
com_pwd (char* ignore __attribute__((__unused__)))
|
||||||
|
{
|
||||||
|
char dir[1024], *s;
|
||||||
|
|
||||||
|
s = (char*)getcwd(dir, sizeof(dir) - 1);
|
||||||
|
if (s == 0)
|
||||||
|
{
|
||||||
|
printf ("Error getting pwd: %s\n", dir);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("Current directory is %s\n", dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The user wishes to quit using this program. Just set DONE
|
||||||
|
non-zero. */
|
||||||
|
int
|
||||||
|
com_quit (char *arg __attribute__((__unused__)))
|
||||||
|
{
|
||||||
|
done = 1;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function which tells you that you can't do this. */
|
||||||
|
void
|
||||||
|
too_dangerous (char *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)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s: Argument required.\n", caller);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
xmalloc (size_t size)
|
||||||
|
{
|
||||||
|
register void *value = (void*)malloc(size);
|
||||||
|
if (value == 0)
|
||||||
|
fprintf(stderr, "virtual memory exhausted");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@@ -45,6 +45,8 @@ int main(int argc, char *argv[] __attribute__ ((unused)))
|
|||||||
int doit;
|
int doit;
|
||||||
char *prompt, *p;
|
char *prompt, *p;
|
||||||
|
|
||||||
|
read_history(".testit_history");
|
||||||
|
|
||||||
doit = argc == 1;
|
doit = argc == 1;
|
||||||
if ((prompt = getenv("TESTPROMPT")) == NULL)
|
if ((prompt = getenv("TESTPROMPT")) == NULL)
|
||||||
prompt = "testit> ";
|
prompt = "testit> ";
|
||||||
@@ -59,18 +61,18 @@ int main(int argc, char *argv[] __attribute__ ((unused)))
|
|||||||
perror(p);
|
perror(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add_history(p);
|
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write_history(".testit_history");
|
||||||
|
rl_uninitialize();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
* c-file-style: "k&r"
|
||||||
* indent-tabs-mode: t
|
|
||||||
* c-file-style: "ellemtel"
|
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/* Minix editline
|
/*
|
||||||
*
|
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
|
||||||
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is not subject to any license of the American Telephone
|
* This software is not subject to any license of the American Telephone
|
||||||
* and Telegraph Company or of the Regents of the University of California.
|
* and Telegraph Company or of the Regents of the University of California.
|
||||||
@@ -18,8 +18,8 @@
|
|||||||
* ever read sources, credits must appear in the documentation.
|
* ever read sources, credits must appear in the documentation.
|
||||||
* 4. This notice may not be removed or altered.
|
* 4. This notice may not be removed or altered.
|
||||||
*/
|
*/
|
||||||
#ifndef __EDITLINE_H__
|
#ifndef EDITLINE_H_
|
||||||
#define __EDITLINE_H__
|
#define EDITLINE_H_
|
||||||
|
|
||||||
/* Handy macros when binding keys. */
|
/* Handy macros when binding keys. */
|
||||||
#define CTL(x) ((x) & 0x1F)
|
#define CTL(x) ((x) & 0x1F)
|
||||||
@@ -44,13 +44,18 @@ typedef enum {
|
|||||||
} el_status_t;
|
} el_status_t;
|
||||||
|
|
||||||
/* Editline specific types, despite rl_ prefix. From Heimdal project. */
|
/* Editline specific types, despite rl_ prefix. From Heimdal project. */
|
||||||
typedef char* rl_complete_func_t(char*, int*);
|
|
||||||
typedef int rl_list_possib_func_t(char*, char***);
|
typedef int rl_list_possib_func_t(char*, char***);
|
||||||
typedef el_status_t el_keymap_func_t(void);
|
typedef el_status_t el_keymap_func_t(void);
|
||||||
typedef int rl_hook_func_t(void);
|
typedef int rl_hook_func_t(void);
|
||||||
typedef int rl_getc_func_t(void);
|
typedef int rl_getc_func_t(void);
|
||||||
typedef void rl_voidfunc_t(void);
|
typedef void rl_voidfunc_t(void);
|
||||||
typedef void rl_vintfunc_t(int);
|
typedef void rl_vintfunc_t(int);
|
||||||
|
typedef void rl_vcpfunc_t(char *);
|
||||||
|
|
||||||
|
/* FSF Readline compat tupes */
|
||||||
|
typedef char *rl_complete_func_t (char *, int*);
|
||||||
|
typedef char *rl_compentry_func_t (const char *, int);
|
||||||
|
typedef char **rl_completion_func_t (const char *, int, int);
|
||||||
|
|
||||||
/* Display 8-bit chars "as-is" or as `M-x'? Toggle with M-m. (Default:0 - "as-is") */
|
/* Display 8-bit chars "as-is" or as `M-x'? Toggle with M-m. (Default:0 - "as-is") */
|
||||||
extern int rl_meta_chars;
|
extern int rl_meta_chars;
|
||||||
@@ -64,8 +69,13 @@ extern el_status_t el_del_char(void);
|
|||||||
extern el_status_t el_bind_key(int key, el_keymap_func_t function);
|
extern el_status_t el_bind_key(int key, el_keymap_func_t function);
|
||||||
extern el_status_t el_bind_key_in_metamap(int key, el_keymap_func_t function);
|
extern el_status_t el_bind_key_in_metamap(int key, el_keymap_func_t function);
|
||||||
|
|
||||||
|
extern const char *el_next_hist(void);
|
||||||
|
extern const char *el_prev_hist(void);
|
||||||
|
|
||||||
extern char *rl_complete(char *token, int *match);
|
extern char *rl_complete(char *token, int *match);
|
||||||
extern int rl_list_possib(char *token, char ***av);
|
extern int rl_list_possib(char *token, char ***av);
|
||||||
|
extern char **rl_completion_matches(const char *token, rl_compentry_func_t *generator);
|
||||||
|
extern char *rl_filename_completion_function(const char *text, int state);
|
||||||
|
|
||||||
/* For compatibility with FSF readline. */
|
/* For compatibility with FSF readline. */
|
||||||
extern int rl_point;
|
extern int rl_point;
|
||||||
@@ -80,32 +90,41 @@ extern int el_no_echo; /* E.g under emacs, don't echo except prompt */
|
|||||||
extern int el_no_hist; /* Disable auto-save of and access to history -- e.g. for password prompts or wizards */
|
extern int el_no_hist; /* Disable auto-save of and access to history -- e.g. for password prompts or wizards */
|
||||||
extern int el_hist_size; /* size of history scrollback buffer, default: 15 */
|
extern int el_hist_size; /* size of history scrollback buffer, default: 15 */
|
||||||
|
|
||||||
extern void rl_initialize(void);
|
extern void rl_initialize (void);
|
||||||
extern void rl_reset_terminal(const char *terminal_name);
|
extern void rl_reset_terminal (const char *terminal_name);
|
||||||
|
extern void rl_uninitialize (void);
|
||||||
|
|
||||||
void rl_save_prompt(void);
|
extern void rl_save_prompt (void);
|
||||||
void rl_restore_prompt(void);
|
extern void rl_restore_prompt (void);
|
||||||
void rl_set_prompt(const char *prompt);
|
extern void rl_set_prompt (const char *prompt);
|
||||||
|
|
||||||
void rl_clear_message(void);
|
extern void rl_clear_message (void);
|
||||||
void rl_forced_update_display(void);
|
extern void rl_forced_update_display(void);
|
||||||
|
|
||||||
extern char *readline(const char *prompt);
|
extern void rl_prep_terminal (int meta_flag);
|
||||||
extern void add_history(const char *line);
|
extern void rl_deprep_terminal (void);
|
||||||
|
|
||||||
extern int read_history(const char *filename);
|
extern int rl_getc(void);
|
||||||
extern int write_history(const char *filename);
|
extern int rl_insert_text (const char *text);
|
||||||
|
extern int rl_refresh_line (int ignore1, int ignore2);
|
||||||
|
|
||||||
rl_complete_func_t *rl_set_complete_func(rl_complete_func_t *func);
|
extern char *readline (const char *prompt);
|
||||||
rl_list_possib_func_t *rl_set_list_possib_func(rl_list_possib_func_t *func);
|
|
||||||
|
|
||||||
void rl_prep_terminal(int meta_flag);
|
extern void add_history (const char *line);
|
||||||
void rl_deprep_terminal(void);
|
extern int read_history (const char *filename);
|
||||||
|
extern int write_history (const char *filename);
|
||||||
|
|
||||||
int rl_getc(void);
|
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);
|
||||||
|
|
||||||
|
/* Alternate interface to plain readline(), for event loops */
|
||||||
|
extern void rl_callback_handler_install (const char *prompt, rl_vcpfunc_t *lhandler);
|
||||||
|
extern void rl_callback_read_char (void);
|
||||||
|
extern void rl_callback_handler_remove (void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __EDITLINE_H__ */
|
#endif /* EDITLINE_H_ */
|
||||||
|
@@ -173,7 +173,7 @@ The following brief example lets you enter a line and edit it, then displays it.
|
|||||||
.B ""
|
.B ""
|
||||||
.B extern char *readline(char *prompt);
|
.B extern char *readline(char *prompt);
|
||||||
.B ""
|
.B ""
|
||||||
.B int main (void)
|
.B int main(void)
|
||||||
.B {
|
.B {
|
||||||
.RS
|
.RS
|
||||||
.B char *p;
|
.B char *p;
|
||||||
@@ -189,12 +189,12 @@ The following brief example lets you enter a line and edit it, then displays it.
|
|||||||
.RE
|
.RE
|
||||||
.B }
|
.B }
|
||||||
.fi
|
.fi
|
||||||
.SH BUGS AND LIMITATIONS
|
|
||||||
Does not handle multiple lines or unicode characters well. See the TODO
|
|
||||||
file in the distribution if you want to help out.
|
|
||||||
.SH AUTHORS
|
.SH AUTHORS
|
||||||
The original editline library was created by Simmule R. Turner and Rich
|
The original editline library was created by Simmule R. Turner and Rich
|
||||||
$alz. It now exists in several forks: Heimdal, Festival speech tools,
|
Salz. It now exists in several forks: Heimdal, Festival speech tools,
|
||||||
Mozilla, Google Gadgets for Linux, and many other places. The original
|
Mozilla, Google Gadgets for Linux, and many other places. The original
|
||||||
manual page was made by David W. Sanderson. Currently maintained by
|
manual page was made by David W. Sanderson. This version is maintained
|
||||||
Joachim Nilsson at http://github.com/troglobit/editline
|
by Joachim Nilsson at GitHub,
|
||||||
|
.Aq http://github.com/troglobit/editline
|
||||||
|
.SH BUGS
|
||||||
|
Does not handle multiple lines or unicode characters well.
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
lib_LTLIBRARIES = libeditline.la
|
lib_LTLIBRARIES = libeditline.la
|
||||||
libeditline_la_SOURCES = editline.c editline.h complete.c sysunix.c unix.h
|
libeditline_la_SOURCES = editline.c editline.h complete.c sysunix.c unix.h
|
||||||
libeditline_la_CFLAGS = -std=gnu99
|
libeditline_la_CFLAGS = -std=gnu99
|
||||||
libeditline_la_CFLAGS += -W -Wall -Wundef -Wunused -Wstrict-prototypes
|
libeditline_la_CFLAGS += -W -Wall -Wextra -Wundef -Wunused -Wstrict-prototypes
|
||||||
libeditline_la_CFLAGS += -Werror-implicit-function-declaration -Wshadow -Wcast-qual
|
libeditline_la_CFLAGS += -Werror-implicit-function-declaration -Wshadow -Wcast-qual
|
||||||
libeditline_la_LDFLAGS = $(AM_LDFLAGS) -version-info 0:0:0
|
libeditline_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:0:0
|
||||||
|
194
src/complete.c
194
src/complete.c
@@ -1,6 +1,7 @@
|
|||||||
/* History and file completion functions for editline library.
|
/* History and file completion functions for editline library.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved.
|
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is not subject to any license of the American Telephone
|
* This software is not subject to any license of the American Telephone
|
||||||
* and Telegraph Company or of the Regents of the University of California.
|
* and Telegraph Company or of the Regents of the University of California.
|
||||||
@@ -19,10 +20,15 @@
|
|||||||
* 4. This notice may not be removed or altered.
|
* 4. This notice may not be removed or altered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include "editline.h"
|
#include "editline.h"
|
||||||
|
|
||||||
#define MAX_TOTAL_MATCHES (256 << sizeof(char *))
|
#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 */
|
/* Wrap strcmp() for qsort() -- weird construct to pass -Wcast-qual */
|
||||||
static int compare(const void *p1, const void *p2)
|
static int compare(const void *p1, const void *p2)
|
||||||
{
|
{
|
||||||
@@ -74,6 +80,7 @@ static int FindMatches(char *dir, char *file, char ***avp)
|
|||||||
total = 0;
|
total = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ac) {
|
if (ac) {
|
||||||
memcpy(word, av, ac * sizeof(char *));
|
memcpy(word, av, ac * sizeof(char *));
|
||||||
free(av);
|
free(av);
|
||||||
@@ -94,15 +101,22 @@ static int FindMatches(char *dir, char *file, char ***avp)
|
|||||||
closedir(dp);
|
closedir(dp);
|
||||||
if (total > MAX_TOTAL_MATCHES) {
|
if (total > MAX_TOTAL_MATCHES) {
|
||||||
char many[sizeof(total) * 3];
|
char many[sizeof(total) * 3];
|
||||||
|
|
||||||
p = many + sizeof(many);
|
p = many + sizeof(many);
|
||||||
*--p = '\0';
|
*--p = '\0';
|
||||||
while (choices > 0) {
|
while (choices > 0) {
|
||||||
*--p = '0' + choices % 10;
|
*--p = '0' + choices % 10;
|
||||||
choices /= 10;
|
choices /= 10;
|
||||||
}
|
}
|
||||||
while (p > many + sizeof(many) - 8) *--p = ' ';
|
|
||||||
if ((p = strdup(p)) != NULL) av[ac++] = p;
|
while (p > many + sizeof(many) - 8)
|
||||||
if ((p = strdup("choices")) != NULL) av[ac++] = p;
|
*--p = ' ';
|
||||||
|
|
||||||
|
if ((p = strdup(p)) != NULL)
|
||||||
|
av[ac++] = p;
|
||||||
|
|
||||||
|
if ((p = strdup("choices")) != NULL)
|
||||||
|
av[ac++] = p;
|
||||||
} else {
|
} else {
|
||||||
if (ac)
|
if (ac)
|
||||||
qsort(av, ac, sizeof(char *), compare);
|
qsort(av, ac, sizeof(char *), compare);
|
||||||
@@ -112,7 +126,7 @@ static int FindMatches(char *dir, char *file, char ***avp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Split a pathname into allocated directory and trailing filename parts. */
|
/* Split a pathname into allocated directory and trailing filename parts. */
|
||||||
static int SplitPath(char *path, char **dirpart, char **filepart)
|
static int SplitPath(const char *path, char **dirpart, char **filepart)
|
||||||
{
|
{
|
||||||
static char DOT[] = ".";
|
static char DOT[] = ".";
|
||||||
char *dpart;
|
char *dpart;
|
||||||
@@ -121,6 +135,7 @@ static int SplitPath(char *path, char **dirpart, char **filepart)
|
|||||||
if ((fpart = strrchr(path, '/')) == NULL) {
|
if ((fpart = strrchr(path, '/')) == NULL) {
|
||||||
if ((dpart = strdup(DOT)) == NULL)
|
if ((dpart = strdup(DOT)) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((fpart = strdup(path)) == NULL) {
|
if ((fpart = strdup(path)) == NULL) {
|
||||||
free(dpart);
|
free(dpart);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -128,6 +143,7 @@ static int SplitPath(char *path, char **dirpart, char **filepart)
|
|||||||
} else {
|
} else {
|
||||||
if ((dpart = strdup(path)) == NULL)
|
if ((dpart = strdup(path)) == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
dpart[fpart - path + 1] = '\0';
|
dpart[fpart - path + 1] = '\0';
|
||||||
if ((fpart = strdup(fpart + 1)) == NULL) {
|
if ((fpart = strdup(fpart + 1)) == NULL) {
|
||||||
free(dpart);
|
free(dpart);
|
||||||
@@ -147,6 +163,7 @@ rl_complete_func_t *rl_set_complete_func(rl_complete_func_t *func)
|
|||||||
{
|
{
|
||||||
rl_complete_func_t *old = el_complete_func;
|
rl_complete_func_t *old = el_complete_func;
|
||||||
el_complete_func = func;
|
el_complete_func = func;
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +182,7 @@ char *el_filename_complete(char *pathname, int *match)
|
|||||||
size_t j;
|
size_t j;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (SplitPath(pathname, &dir, &file) < 0)
|
if (SplitPath((const char *)pathname, &dir, &file) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if ((ac = FindMatches(dir, file, &av)) == 0) {
|
if ((ac = FindMatches(dir, file, &av)) == 0) {
|
||||||
@@ -196,10 +213,12 @@ char *el_filename_complete(char *pathname, int *match)
|
|||||||
*match = 0;
|
*match = 0;
|
||||||
if (len) {
|
if (len) {
|
||||||
/* Find largest matching substring. */
|
/* Find largest matching substring. */
|
||||||
for (i = len, end = strlen(av[0]); i < end; i++)
|
for (i = len, end = strlen(av[0]); i < end; i++) {
|
||||||
for (j = 1; j < ac; j++)
|
for (j = 1; j < ac; j++) {
|
||||||
if (av[0][i] != av[j][i])
|
if (av[0][i] != av[j][i])
|
||||||
goto breakout;
|
goto breakout;
|
||||||
|
}
|
||||||
|
}
|
||||||
breakout:
|
breakout:
|
||||||
if (i > len) {
|
if (i > len) {
|
||||||
j = i - len + 1;
|
j = i - len + 1;
|
||||||
@@ -222,16 +241,160 @@ char *el_filename_complete(char *pathname, int *match)
|
|||||||
return p;
|
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)
|
char *rl_complete(char *token, int *match)
|
||||||
{
|
{
|
||||||
if (el_complete_func)
|
if (el_complete_func)
|
||||||
return el_complete_func(token, match);
|
return el_complete_func(token, match);
|
||||||
|
|
||||||
#ifdef CONFIG_DEFAULT_COMPLETE
|
if (rl_attempted_completion_function)
|
||||||
|
return complete(token, match);
|
||||||
|
|
||||||
return el_filename_complete(token, match);
|
return el_filename_complete(token, match);
|
||||||
#else
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static rl_list_possib_func_t *el_list_possib_func = NULL;
|
static rl_list_possib_func_t *el_list_possib_func = NULL;
|
||||||
@@ -267,18 +430,13 @@ int rl_list_possib(char *token, char ***av)
|
|||||||
if (el_list_possib_func)
|
if (el_list_possib_func)
|
||||||
return el_list_possib_func(token, av);
|
return el_list_possib_func(token, av);
|
||||||
|
|
||||||
#ifdef CONFIG_DEFAULT_COMPLETE
|
|
||||||
return el_filename_list_possib(token, av);
|
return el_filename_list_possib(token, av);
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* c-file-style: "k&r"
|
||||||
* c-file-style: "ellemtel"
|
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
455
src/editline.c
455
src/editline.c
@@ -1,6 +1,6 @@
|
|||||||
/* Main editing routines for editline library.
|
/*
|
||||||
*
|
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
|
||||||
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is not subject to any license of the American Telephone
|
* This software is not subject to any license of the American Telephone
|
||||||
* and Telegraph Company or of the Regents of the University of California.
|
* and Telegraph Company or of the Regents of the University of California.
|
||||||
@@ -61,6 +61,7 @@ typedef struct {
|
|||||||
char **Lines;
|
char **Lines;
|
||||||
} el_hist_t;
|
} el_hist_t;
|
||||||
|
|
||||||
|
/* User definable callbacks. */
|
||||||
rl_getc_func_t *rl_getc_function = rl_getc;
|
rl_getc_func_t *rl_getc_function = rl_getc;
|
||||||
rl_hook_func_t *rl_event_hook;
|
rl_hook_func_t *rl_event_hook;
|
||||||
rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal;
|
rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal;
|
||||||
@@ -100,12 +101,17 @@ static int el_infd = EL_STDIN;
|
|||||||
static int el_outfd = EL_STDOUT;
|
static int el_outfd = EL_STDOUT;
|
||||||
static el_keymap_t Map[];
|
static el_keymap_t Map[];
|
||||||
static el_keymap_t MetaMap[];
|
static el_keymap_t MetaMap[];
|
||||||
static size_t Length;
|
static size_t Length = 0;
|
||||||
static size_t ScreenCount;
|
static size_t ScreenCount;
|
||||||
static size_t ScreenSize;
|
static size_t ScreenSize;
|
||||||
static char *backspace = "\b";
|
static char *backspace = "\b";
|
||||||
|
static char *old_search = NULL;
|
||||||
static int tty_cols = SCREEN_COLS;
|
static int tty_cols = SCREEN_COLS;
|
||||||
static int tty_rows = SCREEN_ROWS;
|
static int tty_rows = SCREEN_ROWS;
|
||||||
|
static int Searching = 0;
|
||||||
|
static const char *(*search_move)(void);
|
||||||
|
static const char *old_prompt = NULL;
|
||||||
|
static rl_vcpfunc_t *line_handler = NULL;
|
||||||
|
|
||||||
int el_no_echo = 0; /* e.g., under Emacs */
|
int el_no_echo = 0; /* e.g., under Emacs */
|
||||||
int el_no_hist = 0;
|
int el_no_hist = 0;
|
||||||
@@ -114,17 +120,14 @@ int rl_mark;
|
|||||||
int rl_end;
|
int rl_end;
|
||||||
int rl_meta_chars = 0; /* Display 8-bit chars as the actual char(0) or as `M-x'(1)? */
|
int rl_meta_chars = 0; /* Display 8-bit chars as the actual char(0) or as `M-x'(1)? */
|
||||||
int rl_inhibit_complete = 0;
|
int rl_inhibit_complete = 0;
|
||||||
char *rl_line_buffer;
|
char *rl_line_buffer = NULL;
|
||||||
const char *rl_prompt;
|
const char *rl_prompt = NULL;
|
||||||
const char *rl_readline_name; /* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */
|
const char *rl_readline_name = NULL; /* Set by calling program, for conditional parsing of ~/.inputrc - Not supported yet! */
|
||||||
FILE *rl_instream = NULL; /* The stdio stream from which input is read. Defaults to stdin if NULL */
|
FILE *rl_instream = NULL; /* The stdio stream from which input is read. Defaults to stdin if NULL */
|
||||||
FILE *rl_outstream = NULL; /* The stdio stream to which output is flushed. Defaults to stdout if NULL */
|
FILE *rl_outstream = NULL; /* The stdio stream to which output is flushed. Defaults to stdout if NULL */
|
||||||
|
|
||||||
/* User definable callbacks. */
|
|
||||||
char **(*rl_attempted_completion_function)(const char *token, int start, int end);
|
|
||||||
|
|
||||||
/* Declarations. */
|
/* Declarations. */
|
||||||
static char *editinput(void);
|
static char *editinput(int complete);
|
||||||
#ifdef CONFIG_USE_TERMCAP
|
#ifdef CONFIG_USE_TERMCAP
|
||||||
extern char *tgetstr(const char *, char **);
|
extern char *tgetstr(const char *, char **);
|
||||||
extern int tgetent(char *, const char *);
|
extern int tgetent(char *, const char *);
|
||||||
@@ -160,7 +163,6 @@ static void tty_flush(void)
|
|||||||
|
|
||||||
if (!el_no_echo) {
|
if (!el_no_echo) {
|
||||||
res = write(el_outfd, Screen, ScreenCount);
|
res = write(el_outfd, Screen, ScreenCount);
|
||||||
|
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
ScreenCount = 0;
|
ScreenCount = 0;
|
||||||
}
|
}
|
||||||
@@ -172,7 +174,7 @@ static void tty_put(const char c)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Screen[ScreenCount] = c;
|
Screen[ScreenCount] = c;
|
||||||
if (++ScreenCount >= ScreenSize - 1) {
|
if (++ScreenCount >= ScreenSize) {
|
||||||
ScreenSize += SCREEN_INC;
|
ScreenSize += SCREEN_INC;
|
||||||
Screen = realloc(Screen, sizeof(char) * ScreenSize);
|
Screen = realloc(Screen, sizeof(char) * ScreenSize);
|
||||||
}
|
}
|
||||||
@@ -228,10 +230,12 @@ int rl_getc(void)
|
|||||||
static int tty_get(void)
|
static int tty_get(void)
|
||||||
{
|
{
|
||||||
tty_flush();
|
tty_flush();
|
||||||
|
|
||||||
if (el_pushed) {
|
if (el_pushed) {
|
||||||
el_pushed = 0;
|
el_pushed = 0;
|
||||||
return el_push_back;
|
return el_push_back;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*el_input)
|
if (*el_input)
|
||||||
return *el_input++;
|
return *el_input++;
|
||||||
|
|
||||||
@@ -281,9 +285,10 @@ void el_print_columns(int ac, char **av)
|
|||||||
int cols;
|
int cols;
|
||||||
|
|
||||||
/* Find longest name, determine column count from that. */
|
/* Find longest name, determine column count from that. */
|
||||||
for (longest = 0, i = 0; i < ac; i++)
|
for (longest = 0, i = 0; i < ac; i++) {
|
||||||
if ((j = strlen((char *)av[i])) > longest)
|
if ((j = strlen((char *)av[i])) > longest)
|
||||||
longest = j;
|
longest = j;
|
||||||
|
}
|
||||||
cols = tty_cols / (longest + 3);
|
cols = tty_cols / (longest + 3);
|
||||||
|
|
||||||
tty_puts(NEWLINE);
|
tty_puts(NEWLINE);
|
||||||
@@ -291,10 +296,13 @@ void el_print_columns(int ac, char **av)
|
|||||||
for (j = i; j < ac; j += skip) {
|
for (j = i; j < ac; j += skip) {
|
||||||
for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
|
for (p = av[j], len = strlen((char *)p), k = len; --k >= 0; p++)
|
||||||
tty_put(*p);
|
tty_put(*p);
|
||||||
if (j + skip < ac)
|
|
||||||
|
if (j + skip < ac) {
|
||||||
while (++len < longest + 3)
|
while (++len < longest + 3)
|
||||||
tty_put(' ');
|
tty_put(' ');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tty_puts(NEWLINE);
|
tty_puts(NEWLINE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,6 +330,7 @@ static void left(el_status_t Change)
|
|||||||
tty_back();
|
tty_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Change == CSmove)
|
if (Change == CSmove)
|
||||||
rl_point--;
|
rl_point--;
|
||||||
}
|
}
|
||||||
@@ -338,6 +347,7 @@ el_status_t el_ring_bell(void)
|
|||||||
{
|
{
|
||||||
tty_put('\07');
|
tty_put('\07');
|
||||||
tty_flush();
|
tty_flush();
|
||||||
|
|
||||||
return CSstay;
|
return CSstay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,6 +364,7 @@ static el_status_t do_macro(int c)
|
|||||||
el_input = NILSTR;
|
el_input = NILSTR;
|
||||||
return el_ring_bell();
|
return el_ring_bell();
|
||||||
}
|
}
|
||||||
|
|
||||||
return CSstay;
|
return CSstay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,15 +378,23 @@ static el_status_t do_forward(el_status_t move)
|
|||||||
do {
|
do {
|
||||||
p = &rl_line_buffer[rl_point];
|
p = &rl_line_buffer[rl_point];
|
||||||
|
|
||||||
/* Skip to end of word, if inside a word. */
|
/* Skip leading whitespace, like FSF Readline */
|
||||||
for (; rl_point < rl_end && is_alpha_num(p[0]); rl_point++, p++)
|
for ( ; rl_point < rl_end && (p[0] == ' ' || !is_alpha_num(p[0])); rl_point++, p++) {
|
||||||
if (move == CSmove)
|
if (move == CSmove)
|
||||||
right(CSstay);
|
right(CSstay);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip to end of word, if inside a word. */
|
||||||
|
for (; rl_point < rl_end && is_alpha_num(p[0]); rl_point++, p++) {
|
||||||
|
if (move == CSmove)
|
||||||
|
right(CSstay);
|
||||||
|
}
|
||||||
|
|
||||||
/* Skip to next word, or skip leading white space if outside a word. */
|
/* 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++)
|
for ( ; rl_point < rl_end && (p[0] == ' ' || !is_alpha_num(p[0])); rl_point++, p++) {
|
||||||
if (move == CSmove)
|
if (move == CSmove)
|
||||||
right(CSstay);
|
right(CSstay);
|
||||||
|
}
|
||||||
|
|
||||||
if (rl_point == rl_end)
|
if (rl_point == rl_end)
|
||||||
break;
|
break;
|
||||||
@@ -431,11 +450,17 @@ static el_status_t case_cap_word(void)
|
|||||||
|
|
||||||
static void ceol(void)
|
static void ceol(void)
|
||||||
{
|
{
|
||||||
int extras;
|
int extras = 0;
|
||||||
int i;
|
int i;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
for (extras = 0, i = rl_point, p = &rl_line_buffer[i]; i <= rl_end; i++, p++) {
|
while (rl_point < 0) {
|
||||||
|
tty_put(' ');
|
||||||
|
rl_point++;
|
||||||
|
extras++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = rl_point, p = &rl_line_buffer[i]; i <= rl_end; i++, p++) {
|
||||||
tty_put(' ');
|
tty_put(' ');
|
||||||
if (ISMETA(*p)) {
|
if (ISMETA(*p)) {
|
||||||
if (rl_meta_chars) {
|
if (rl_meta_chars) {
|
||||||
@@ -443,7 +468,7 @@ static void ceol(void)
|
|||||||
tty_put(' ');
|
tty_put(' ');
|
||||||
extras += 2;
|
extras += 2;
|
||||||
}
|
}
|
||||||
} if (ISCTL(*p)) {
|
} else if (ISCTL(*p)) {
|
||||||
tty_put(' ');
|
tty_put(' ');
|
||||||
extras++;
|
extras++;
|
||||||
}
|
}
|
||||||
@@ -497,15 +522,32 @@ static el_status_t insert_string(const char *p)
|
|||||||
return rl_point == rl_end ? CSstay : CSmove;
|
return rl_point == rl_end ? CSstay : CSmove;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rl_insert_text(const char *text)
|
||||||
|
{
|
||||||
|
int mark = rl_point;
|
||||||
|
|
||||||
|
insert_string(text);
|
||||||
|
ceol();
|
||||||
|
|
||||||
|
return rl_point - mark;
|
||||||
|
}
|
||||||
|
|
||||||
static el_status_t redisplay(void)
|
static el_status_t redisplay(void)
|
||||||
{
|
{
|
||||||
tty_puts(NEWLINE); /* XXX: Use "\r\e[K" to get really neat effect on ANSI capable terminals. */
|
/* XXX: Use "\r\e[K" to get really neat effect on ANSI capable terminals. */
|
||||||
|
tty_puts(NEWLINE);
|
||||||
tty_puts(rl_prompt);
|
tty_puts(rl_prompt);
|
||||||
tty_string(rl_line_buffer);
|
tty_string(rl_line_buffer);
|
||||||
|
|
||||||
return CSmove;
|
return CSmove;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rl_refresh_line(int ignore1 __attribute__((unused)), int ignore2 __attribute__((unused)))
|
||||||
|
{
|
||||||
|
redisplay();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static el_status_t toggle_meta_mode(void)
|
static el_status_t toggle_meta_mode(void)
|
||||||
{
|
{
|
||||||
rl_meta_chars = ! rl_meta_chars;
|
rl_meta_chars = ! rl_meta_chars;
|
||||||
@@ -513,12 +555,12 @@ static el_status_t toggle_meta_mode(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char *next_hist(void)
|
const char *el_next_hist(void)
|
||||||
{
|
{
|
||||||
return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
|
return H.Pos >= H.Size - 1 ? NULL : H.Lines[++H.Pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *prev_hist(void)
|
const char *el_prev_hist(void)
|
||||||
{
|
{
|
||||||
return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
|
return H.Pos == 0 ? NULL : H.Lines[--H.Pos];
|
||||||
}
|
}
|
||||||
@@ -528,9 +570,10 @@ static el_status_t do_insert_hist(const char *p)
|
|||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return el_ring_bell();
|
return el_ring_bell();
|
||||||
|
|
||||||
|
clear_line();
|
||||||
|
|
||||||
rl_point = 0;
|
rl_point = 0;
|
||||||
reposition();
|
reposition();
|
||||||
ceol();
|
|
||||||
rl_end = 0;
|
rl_end = 0;
|
||||||
|
|
||||||
return insert_string(p);
|
return insert_string(p);
|
||||||
@@ -539,13 +582,13 @@ static el_status_t do_insert_hist(const char *p)
|
|||||||
static el_status_t do_hist(const char *(*move)(void))
|
static el_status_t do_hist(const char *(*move)(void))
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p;
|
||||||
int i;
|
int i = 0;
|
||||||
|
|
||||||
i = 0;
|
|
||||||
do {
|
do {
|
||||||
if ((p = move()) == NULL)
|
if ((p = move()) == NULL)
|
||||||
return el_ring_bell();
|
return el_ring_bell();
|
||||||
} while (++i < Repeat);
|
} while (++i < Repeat);
|
||||||
|
|
||||||
return do_insert_hist(p);
|
return do_insert_hist(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,7 +597,7 @@ static el_status_t h_next(void)
|
|||||||
if (el_no_hist)
|
if (el_no_hist)
|
||||||
return CSstay;
|
return CSstay;
|
||||||
|
|
||||||
return do_hist(next_hist);
|
return do_hist(el_next_hist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static el_status_t h_prev(void)
|
static el_status_t h_prev(void)
|
||||||
@@ -562,7 +605,7 @@ static el_status_t h_prev(void)
|
|||||||
if (el_no_hist)
|
if (el_no_hist)
|
||||||
return CSstay;
|
return CSstay;
|
||||||
|
|
||||||
return do_hist(prev_hist);
|
return do_hist(el_prev_hist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static el_status_t h_first(void)
|
static el_status_t h_first(void)
|
||||||
@@ -584,15 +627,17 @@ static int substrcmp(const char *text, const char *pat, size_t len)
|
|||||||
|
|
||||||
if ((c = *pat) == '\0')
|
if ((c = *pat) == '\0')
|
||||||
return *text == '\0';
|
return *text == '\0';
|
||||||
for ( ; *text; text++)
|
|
||||||
|
for ( ; *text; text++) {
|
||||||
if (*text == c && strncmp(text, pat, len) == 0)
|
if (*text == c && strncmp(text, pat, len) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *search_hist(const char *search, const char *(*move)(void))
|
static const char *search_hist(const char *search, const char *(*move)(void))
|
||||||
{
|
{
|
||||||
static char *old_search;
|
|
||||||
int len;
|
int len;
|
||||||
int pos;
|
int pos;
|
||||||
int (*match)(const char *s1, const char *s2, size_t n);
|
int (*match)(const char *s1, const char *s2, size_t n);
|
||||||
@@ -629,13 +674,28 @@ static const char *search_hist(const char *search, const char *(*move)(void))
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static el_status_t h_search_end(const char *p)
|
||||||
|
{
|
||||||
|
rl_prompt = old_prompt;
|
||||||
|
Searching = 0;
|
||||||
|
|
||||||
|
if (p == NULL && el_intr_pending > 0) {
|
||||||
|
el_intr_pending = 0;
|
||||||
|
clear_line();
|
||||||
|
return redisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
p = search_hist(p, search_move);
|
||||||
|
if (p == NULL) {
|
||||||
|
el_ring_bell();
|
||||||
|
return redisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
return do_insert_hist(p);
|
||||||
|
}
|
||||||
|
|
||||||
static el_status_t h_search(void)
|
static el_status_t h_search(void)
|
||||||
{
|
{
|
||||||
static int Searching;
|
|
||||||
const char *old_prompt;
|
|
||||||
const char *(*move)(void);
|
|
||||||
const char *p;
|
|
||||||
|
|
||||||
if (Searching)
|
if (Searching)
|
||||||
return el_ring_bell();
|
return el_ring_bell();
|
||||||
Searching = 1;
|
Searching = 1;
|
||||||
@@ -644,30 +704,20 @@ static el_status_t h_search(void)
|
|||||||
old_prompt = rl_prompt;
|
old_prompt = rl_prompt;
|
||||||
rl_prompt = "Search: ";
|
rl_prompt = "Search: ";
|
||||||
tty_puts(rl_prompt);
|
tty_puts(rl_prompt);
|
||||||
move = Repeat == NO_ARG ? prev_hist : next_hist;
|
|
||||||
p = editinput();
|
search_move = Repeat == NO_ARG ? el_prev_hist : el_next_hist;
|
||||||
rl_prompt = old_prompt;
|
if (line_handler) {
|
||||||
Searching = 0;
|
editinput(0);
|
||||||
tty_puts(rl_prompt);
|
return CSstay;
|
||||||
if (p == NULL && el_intr_pending > 0) {
|
|
||||||
el_intr_pending = 0;
|
|
||||||
clear_line();
|
|
||||||
return redisplay();
|
|
||||||
}
|
}
|
||||||
p = search_hist(p, move);
|
|
||||||
clear_line();
|
return h_search_end(editinput(1));
|
||||||
if (p == NULL) {
|
|
||||||
el_ring_bell();
|
|
||||||
return redisplay();
|
|
||||||
}
|
|
||||||
return do_insert_hist(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static el_status_t fd_char(void)
|
static el_status_t fd_char(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i = 0;
|
||||||
|
|
||||||
i = 0;
|
|
||||||
do {
|
do {
|
||||||
if (rl_point >= rl_end)
|
if (rl_point >= rl_end)
|
||||||
break;
|
break;
|
||||||
@@ -719,6 +769,7 @@ static el_status_t delete_string(int count)
|
|||||||
*p = '\0';
|
*p = '\0';
|
||||||
return CSmove;
|
return CSmove;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rl_point + count > rl_end && (count = rl_end - rl_point) <= 0)
|
if (rl_point + count > rl_end && (count = rl_end - rl_point) <= 0)
|
||||||
return CSstay;
|
return CSstay;
|
||||||
|
|
||||||
@@ -730,14 +781,14 @@ static el_status_t delete_string(int count)
|
|||||||
ceol();
|
ceol();
|
||||||
rl_end -= count;
|
rl_end -= count;
|
||||||
tty_string(&rl_line_buffer[rl_point]);
|
tty_string(&rl_line_buffer[rl_point]);
|
||||||
|
|
||||||
return CSmove;
|
return CSmove;
|
||||||
}
|
}
|
||||||
|
|
||||||
static el_status_t bk_char(void)
|
static el_status_t bk_char(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i = 0;
|
||||||
|
|
||||||
i = 0;
|
|
||||||
do {
|
do {
|
||||||
if (rl_point == 0)
|
if (rl_point == 0)
|
||||||
break;
|
break;
|
||||||
@@ -749,9 +800,8 @@ static el_status_t bk_char(void)
|
|||||||
|
|
||||||
static el_status_t bk_del_char(void)
|
static el_status_t bk_del_char(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i = 0;
|
||||||
|
|
||||||
i = 0;
|
|
||||||
do {
|
do {
|
||||||
if (rl_point == 0)
|
if (rl_point == 0)
|
||||||
break;
|
break;
|
||||||
@@ -775,6 +825,7 @@ static el_status_t kill_line(void)
|
|||||||
right(CSmove);
|
right(CSmove);
|
||||||
delete_string(Repeat - rl_point - 1);
|
delete_string(Repeat - rl_point - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CSmove;
|
return CSmove;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -782,6 +833,7 @@ static el_status_t kill_line(void)
|
|||||||
rl_line_buffer[rl_point] = '\0';
|
rl_line_buffer[rl_point] = '\0';
|
||||||
ceol();
|
ceol();
|
||||||
rl_end = rl_point;
|
rl_end = rl_point;
|
||||||
|
|
||||||
return CSstay;
|
return CSstay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,6 +848,7 @@ static el_status_t insert_char(int c)
|
|||||||
if (Repeat == NO_ARG || Repeat < 2) {
|
if (Repeat == NO_ARG || Repeat < 2) {
|
||||||
buff[0] = c;
|
buff[0] = c;
|
||||||
buff[1] = '\0';
|
buff[1] = '\0';
|
||||||
|
|
||||||
return insert_string(buff);
|
return insert_string(buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -819,6 +872,7 @@ static el_status_t beg_line(void)
|
|||||||
rl_point = 0;
|
rl_point = 0;
|
||||||
return CSmove;
|
return CSmove;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CSstay;
|
return CSstay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -828,6 +882,7 @@ static el_status_t end_line(void)
|
|||||||
rl_point = rl_end;
|
rl_point = rl_end;
|
||||||
return CSmove;
|
return CSmove;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CSstay;
|
return CSstay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -841,6 +896,31 @@ el_status_t el_del_char(void)
|
|||||||
return del_char();
|
return del_char();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static el_status_t fd_word(void)
|
||||||
|
{
|
||||||
|
return do_forward(CSmove);
|
||||||
|
}
|
||||||
|
|
||||||
|
static el_status_t bk_word(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
do {
|
||||||
|
for (p = &rl_line_buffer[rl_point]; p > rl_line_buffer && !is_alpha_num(p[-1]); p--)
|
||||||
|
left(CSmove);
|
||||||
|
|
||||||
|
for (; p > rl_line_buffer && !isblank(p[-1]) && is_alpha_num(p[-1]); p--)
|
||||||
|
left(CSmove);
|
||||||
|
|
||||||
|
if (rl_point == 0)
|
||||||
|
break;
|
||||||
|
} while (++i < Repeat);
|
||||||
|
|
||||||
|
return CSstay;
|
||||||
|
}
|
||||||
|
|
||||||
static el_status_t meta(void)
|
static el_status_t meta(void)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
@@ -854,6 +934,20 @@ static el_status_t meta(void)
|
|||||||
if (c == '[' || c == 'O') {
|
if (c == '[' || c == 'O') {
|
||||||
switch (tty_get()) {
|
switch (tty_get()) {
|
||||||
case EOF: return CSeof;
|
case EOF: return CSeof;
|
||||||
|
case '1':
|
||||||
|
{
|
||||||
|
char seq[4] = { 0 };
|
||||||
|
|
||||||
|
for (c = 0; 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 */
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case '2': tty_get(); return CSstay; /* Insert */
|
case '2': tty_get(); return CSstay; /* Insert */
|
||||||
case '3': tty_get(); return del_char(); /* Delete */
|
case '3': tty_get(); return del_char(); /* Delete */
|
||||||
case '5': tty_get(); return CSstay; /* PgUp */
|
case '5': tty_get(); return CSstay; /* PgUp */
|
||||||
@@ -876,11 +970,13 @@ static el_status_t meta(void)
|
|||||||
for (Repeat = c - '0'; (c = tty_get()) != EOF && isdigit(c); )
|
for (Repeat = c - '0'; (c = tty_get()) != EOF && isdigit(c); )
|
||||||
Repeat = Repeat * 10 + c - '0';
|
Repeat = Repeat * 10 + c - '0';
|
||||||
tty_push(c);
|
tty_push(c);
|
||||||
|
|
||||||
return CSstay;
|
return CSstay;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isupper(c))
|
if (isupper(c))
|
||||||
return do_macro(c);
|
return do_macro(c);
|
||||||
|
|
||||||
for (kp = MetaMap; kp->Function; kp++) {
|
for (kp = MetaMap; kp->Function; kp++) {
|
||||||
if (kp->Key == c)
|
if (kp->Key == c)
|
||||||
return kp->Function();
|
return kp->Function();
|
||||||
@@ -947,12 +1043,14 @@ static el_status_t tty_special(int c)
|
|||||||
|
|
||||||
if (c == rl_erase || c == DEL)
|
if (c == rl_erase || c == DEL)
|
||||||
return bk_del_char();
|
return bk_del_char();
|
||||||
|
|
||||||
if (c == rl_kill) {
|
if (c == rl_kill) {
|
||||||
if (rl_point != 0) {
|
if (rl_point != 0) {
|
||||||
rl_point = 0;
|
rl_point = 0;
|
||||||
reposition();
|
reposition();
|
||||||
}
|
}
|
||||||
Repeat = NO_ARG;
|
Repeat = NO_ARG;
|
||||||
|
|
||||||
return kill_line();
|
return kill_line();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -964,16 +1062,15 @@ static el_status_t tty_special(int c)
|
|||||||
return CSdispatch;
|
return CSdispatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *editinput(void)
|
static char *editinput(int complete)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
Repeat = NO_ARG;
|
do {
|
||||||
old_point = rl_point = rl_mark = rl_end = 0;
|
c = tty_get();
|
||||||
rl_line_buffer[0] = '\0';
|
if (c == EOF)
|
||||||
|
break;
|
||||||
|
|
||||||
el_intr_pending = -1;
|
|
||||||
while ((c = tty_get()) != EOF) {
|
|
||||||
switch (tty_special(c)) {
|
switch (tty_special(c)) {
|
||||||
case CSdone:
|
case CSdone:
|
||||||
return rl_line_buffer;
|
return rl_line_buffer;
|
||||||
@@ -1012,7 +1109,8 @@ static char *editinput(void)
|
|||||||
case CSstay:
|
case CSstay:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} while (complete);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1031,11 +1129,11 @@ static void hist_add(const char *p)
|
|||||||
if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0)
|
if (H.Pos && strcmp(p, H.Lines[H.Pos - 1]) == 0)
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
if (H.Size && strcmp(p, H.Lines[H.Size - 1]) == 0)
|
|
||||||
|
s = strdup(p);
|
||||||
|
if (s == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((s = strdup(p)) == NULL)
|
|
||||||
return;
|
|
||||||
if (H.Size < el_hist_size) {
|
if (H.Size < el_hist_size) {
|
||||||
H.Lines[H.Size++] = s;
|
H.Lines[H.Size++] = s;
|
||||||
} else {
|
} else {
|
||||||
@@ -1071,11 +1169,13 @@ static char *read_redirected(void)
|
|||||||
|
|
||||||
p += oldpos; /* Continue where we left off... */
|
p += oldpos; /* Continue where we left off... */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read(el_infd, p, 1) <= 0) {
|
if (read(el_infd, p, 1) <= 0) {
|
||||||
/* Ignore "incomplete" lines at EOF, just like we do for a tty. */
|
/* Ignore "incomplete" lines at EOF, just like we do for a tty. */
|
||||||
free(line);
|
free(line);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*p == '\n')
|
if (*p == '\n')
|
||||||
break;
|
break;
|
||||||
p++;
|
p++;
|
||||||
@@ -1145,6 +1245,34 @@ void rl_initialize(void)
|
|||||||
if (el_outfd < 0) el_outfd = EL_STDOUT;
|
if (el_outfd < 0) el_outfd = EL_STDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rl_uninitialize(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Uninitialize the history */
|
||||||
|
if (H.Lines) {
|
||||||
|
for (i = 0; i < el_hist_size; i++) {
|
||||||
|
if (H.Lines[i])
|
||||||
|
free(H.Lines[i]);
|
||||||
|
H.Lines[i] = NULL;
|
||||||
|
}
|
||||||
|
free(H.Lines);
|
||||||
|
H.Lines = NULL;
|
||||||
|
}
|
||||||
|
H.Size = 0;
|
||||||
|
H.Pos = 0;
|
||||||
|
|
||||||
|
if (old_search)
|
||||||
|
free(old_search);
|
||||||
|
old_search = NULL;
|
||||||
|
|
||||||
|
/* Uninitialize the line buffer */
|
||||||
|
if (rl_line_buffer)
|
||||||
|
free(rl_line_buffer);
|
||||||
|
rl_line_buffer = NULL;
|
||||||
|
Length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *rl_saved_prompt = NULL;
|
static const char *rl_saved_prompt = NULL;
|
||||||
void rl_save_prompt(void)
|
void rl_save_prompt(void)
|
||||||
{
|
{
|
||||||
@@ -1173,23 +1301,15 @@ void rl_forced_update_display()
|
|||||||
tty_flush();
|
tty_flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
char *readline(const char *prompt)
|
static int el_prep(const char *prompt)
|
||||||
{
|
{
|
||||||
char *line;
|
|
||||||
|
|
||||||
/* Unless called by the user already. */
|
|
||||||
rl_initialize();
|
rl_initialize();
|
||||||
|
|
||||||
if (!isatty(0)) {
|
|
||||||
tty_flush();
|
|
||||||
return read_redirected();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rl_line_buffer) {
|
if (!rl_line_buffer) {
|
||||||
Length = MEM_INC;
|
Length = MEM_INC;
|
||||||
rl_line_buffer = malloc(sizeof(char) * Length);
|
rl_line_buffer = malloc(sizeof(char) * Length);
|
||||||
if (!rl_line_buffer)
|
if (!rl_line_buffer)
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tty_info();
|
tty_info();
|
||||||
@@ -1198,11 +1318,12 @@ char *readline(const char *prompt)
|
|||||||
ScreenSize = SCREEN_INC;
|
ScreenSize = SCREEN_INC;
|
||||||
Screen = malloc(sizeof(char) * ScreenSize);
|
Screen = malloc(sizeof(char) * ScreenSize);
|
||||||
if (!Screen)
|
if (!Screen)
|
||||||
return NULL;
|
return -1;
|
||||||
|
|
||||||
rl_prompt = prompt ? prompt : NILSTR;
|
rl_prompt = prompt ? prompt : NILSTR;
|
||||||
if (el_no_echo) {
|
if (el_no_echo) {
|
||||||
int old = el_no_echo;
|
int old = el_no_echo;
|
||||||
|
|
||||||
el_no_echo = 0;
|
el_no_echo = 0;
|
||||||
tty_puts(rl_prompt);
|
tty_puts(rl_prompt);
|
||||||
tty_flush();
|
tty_flush();
|
||||||
@@ -1211,7 +1332,16 @@ char *readline(const char *prompt)
|
|||||||
tty_puts(rl_prompt);
|
tty_puts(rl_prompt);
|
||||||
}
|
}
|
||||||
|
|
||||||
line = editinput();
|
Repeat = NO_ARG;
|
||||||
|
old_point = rl_point = rl_mark = rl_end = 0;
|
||||||
|
rl_line_buffer[0] = '\0';
|
||||||
|
el_intr_pending = -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *el_deprep(char *line)
|
||||||
|
{
|
||||||
if (line) {
|
if (line) {
|
||||||
line = strdup(line);
|
line = strdup(line);
|
||||||
tty_puts(NEWLINE);
|
tty_puts(NEWLINE);
|
||||||
@@ -1219,8 +1349,13 @@ char *readline(const char *prompt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
rl_deprep_term_function();
|
rl_deprep_term_function();
|
||||||
|
if (Screen) {
|
||||||
free(Screen);
|
free(Screen);
|
||||||
|
Screen = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
free(H.Lines[--H.Size]);
|
free(H.Lines[--H.Size]);
|
||||||
|
H.Lines[H.Size] = NULL;
|
||||||
|
|
||||||
/* Add to history, unless no-echo or no-history mode ... */
|
/* Add to history, unless no-echo or no-history mode ... */
|
||||||
if (!el_no_echo && !el_no_hist) {
|
if (!el_no_echo && !el_no_hist) {
|
||||||
@@ -1229,16 +1364,109 @@ char *readline(const char *prompt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (el_intr_pending > 0) {
|
if (el_intr_pending > 0) {
|
||||||
int s = el_intr_pending;
|
int signo = el_intr_pending;
|
||||||
|
|
||||||
el_intr_pending = 0;
|
el_intr_pending = 0;
|
||||||
kill(getpid(), s);
|
kill(getpid(), signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Even though readline() itself adds history automatically, the user can also add
|
void rl_callback_handler_install(const char *prompt, rl_vcpfunc_t *lhandler)
|
||||||
* lines. This is for compat with GNU Readline. */
|
{
|
||||||
|
if (!lhandler)
|
||||||
|
return;
|
||||||
|
line_handler = lhandler;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Any error from el_prep() is handled by the lhandler callbck as
|
||||||
|
* soon as the user calls rl_callback_read_char().
|
||||||
|
*/
|
||||||
|
el_prep(prompt);
|
||||||
|
tty_flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reads one character at a time, when a complete line has been received
|
||||||
|
* the lhandler from rl_callback_handler_install() is called with the
|
||||||
|
* line as argument.
|
||||||
|
*
|
||||||
|
* If the callback returns the terminal is prepped for reading a new
|
||||||
|
* line.
|
||||||
|
*
|
||||||
|
* If any error occurs, either in the _install() phase, or while reading
|
||||||
|
* one character, this function restores the terminal and calls lhandler
|
||||||
|
* with a NULL argument.
|
||||||
|
*/
|
||||||
|
void rl_callback_read_char(void)
|
||||||
|
{
|
||||||
|
char *line;
|
||||||
|
|
||||||
|
if (!line_handler) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if rl_callback_handler_install() failed
|
||||||
|
* This is the only point where we can tell user
|
||||||
|
*/
|
||||||
|
if (!Screen || !rl_line_buffer) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
line_handler(el_deprep(NULL));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
line = editinput(0);
|
||||||
|
if (line) {
|
||||||
|
char *l;
|
||||||
|
|
||||||
|
if (Searching) {
|
||||||
|
h_search_end(line);
|
||||||
|
tty_flush();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = el_deprep(line);
|
||||||
|
line_handler(l);
|
||||||
|
|
||||||
|
if (el_prep(rl_prompt))
|
||||||
|
line_handler(NULL);
|
||||||
|
}
|
||||||
|
tty_flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rl_callback_handler_remove(void)
|
||||||
|
{
|
||||||
|
if (!line_handler)
|
||||||
|
return;
|
||||||
|
|
||||||
|
el_deprep(NULL);
|
||||||
|
line_handler = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *readline(const char *prompt)
|
||||||
|
{
|
||||||
|
/* Unless called by the user already. */
|
||||||
|
rl_initialize();
|
||||||
|
|
||||||
|
if (!isatty(el_infd)) {
|
||||||
|
tty_flush();
|
||||||
|
|
||||||
|
return read_redirected();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el_prep(prompt))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return el_deprep(editinput(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Even though readline() itself adds history automatically, the user
|
||||||
|
* can also add lines. This is for compatibility with GNU Readline.
|
||||||
|
*/
|
||||||
void add_history(const char *p)
|
void add_history(const char *p)
|
||||||
{
|
{
|
||||||
if (p == NULL || *p == '\0')
|
if (p == NULL || *p == '\0')
|
||||||
@@ -1260,12 +1488,12 @@ int read_history(const char *filename)
|
|||||||
while (H.Size < el_hist_size) {
|
while (H.Size < el_hist_size) {
|
||||||
if (!fgets(buf, SCREEN_INC, fp))
|
if (!fgets(buf, SCREEN_INC, fp))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
buf[strlen(buf) - 1] = 0; /* Remove '\n' */
|
buf[strlen(buf) - 1] = 0; /* Remove '\n' */
|
||||||
add_history(buf);
|
add_history(buf);
|
||||||
}
|
}
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
return 0;
|
return fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return errno;
|
return errno;
|
||||||
@@ -1283,9 +1511,7 @@ int write_history(const char *filename)
|
|||||||
while (i < H.Size)
|
while (i < H.Size)
|
||||||
fprintf(fp, "%s\n", H.Lines[i++]);
|
fprintf(fp, "%s\n", H.Lines[i++]);
|
||||||
|
|
||||||
fclose(fp);
|
return fclose(fp);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return errno;
|
return errno;
|
||||||
@@ -1434,6 +1660,7 @@ static el_status_t transpose(void)
|
|||||||
rl_line_buffer[rl_point++] = c;
|
rl_line_buffer[rl_point++] = c;
|
||||||
tty_show(c);
|
tty_show(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CSstay;
|
return CSstay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1462,6 +1689,7 @@ static el_status_t exchange(void)
|
|||||||
rl_point = c;
|
rl_point = c;
|
||||||
return CSmove;
|
return CSmove;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CSstay;
|
return CSstay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1469,6 +1697,7 @@ static el_status_t yank(void)
|
|||||||
{
|
{
|
||||||
if (Yanked && *Yanked)
|
if (Yanked && *Yanked)
|
||||||
return insert_string(Yanked);
|
return insert_string(Yanked);
|
||||||
|
|
||||||
return CSstay;
|
return CSstay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1487,23 +1716,20 @@ static el_status_t copy_region(void)
|
|||||||
|
|
||||||
static el_status_t move_to_char(void)
|
static el_status_t move_to_char(void)
|
||||||
{
|
{
|
||||||
int c;
|
int i, c;
|
||||||
int i;
|
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
if ((c = tty_get()) == EOF)
|
if ((c = tty_get()) == EOF)
|
||||||
return CSeof;
|
return CSeof;
|
||||||
for (i = rl_point + 1, p = &rl_line_buffer[i]; i < rl_end; i++, p++)
|
|
||||||
|
for (i = rl_point + 1, p = &rl_line_buffer[i]; i < rl_end; i++, p++) {
|
||||||
if (*p == c) {
|
if (*p == c) {
|
||||||
rl_point = i;
|
rl_point = i;
|
||||||
return CSmove;
|
return CSmove;
|
||||||
}
|
}
|
||||||
return CSstay;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static el_status_t fd_word(void)
|
return CSstay;
|
||||||
{
|
|
||||||
return do_forward(CSmove);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static el_status_t fd_kill_word(void)
|
static el_status_t fd_kill_word(void)
|
||||||
@@ -1512,29 +1738,10 @@ static el_status_t fd_kill_word(void)
|
|||||||
|
|
||||||
do_forward(CSstay);
|
do_forward(CSstay);
|
||||||
if (old_point != rl_point) {
|
if (old_point != rl_point) {
|
||||||
i = rl_point - old_point;
|
i = rl_point - old_point - 1;
|
||||||
rl_point = old_point;
|
rl_point = old_point;
|
||||||
return delete_string(i);
|
return delete_string(i);
|
||||||
}
|
}
|
||||||
return CSstay;
|
|
||||||
}
|
|
||||||
|
|
||||||
static el_status_t bk_word(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
do {
|
|
||||||
for (p = &rl_line_buffer[rl_point]; p > rl_line_buffer && !is_alpha_num(p[-1]); p--)
|
|
||||||
left(CSmove);
|
|
||||||
|
|
||||||
for (; p > rl_line_buffer && !isblank(p[-1]) && is_alpha_num(p[-1]); p--)
|
|
||||||
left(CSmove);
|
|
||||||
|
|
||||||
if (rl_point == 0)
|
|
||||||
break;
|
|
||||||
} while (++i < Repeat);
|
|
||||||
|
|
||||||
return CSstay;
|
return CSstay;
|
||||||
}
|
}
|
||||||
@@ -1563,13 +1770,17 @@ static int argify(char *line, char ***avp)
|
|||||||
|
|
||||||
for (c = line; isspace(*c); c++)
|
for (c = line; isspace(*c); c++)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (*c == '\n' || *c == '\0')
|
if (*c == '\n' || *c == '\0')
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
|
for (ac = 0, p[ac++] = c; *c && *c != '\n'; ) {
|
||||||
if (isspace(*c)) {
|
if (!isspace(*c)) {
|
||||||
*c++ = '\0';
|
c++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
*c++ = '\0';
|
||||||
if (*c && *c != '\n') {
|
if (*c && *c != '\n') {
|
||||||
if (ac + 1 == i) {
|
if (ac + 1 == i) {
|
||||||
arg = malloc(sizeof(char *) * (i + MEM_INC));
|
arg = malloc(sizeof(char *) * (i + MEM_INC));
|
||||||
@@ -1585,9 +1796,6 @@ static int argify(char *line, char ***avp)
|
|||||||
}
|
}
|
||||||
p[ac++] = c;
|
p[ac++] = c;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*c = '\0';
|
*c = '\0';
|
||||||
@@ -1735,8 +1943,7 @@ el_status_t el_bind_key_in_metamap(int key, el_keymap_func_t function)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* c-file-style: "k&r"
|
||||||
* c-file-style: "ellemtel"
|
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/* Internal header file for editline library.
|
/* Internal header file for editline library.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved.
|
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is not subject to any license of the American Telephone
|
* This software is not subject to any license of the American Telephone
|
||||||
* and Telegraph Company or of the Regents of the University of California.
|
* and Telegraph Company or of the Regents of the University of California.
|
||||||
@@ -19,8 +20,8 @@
|
|||||||
* 4. This notice may not be removed or altered.
|
* 4. This notice may not be removed or altered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PRIVATE_EDITLINE_H__
|
#ifndef EDITLINE_PRIVATE_H_
|
||||||
#define __PRIVATE_EDITLINE_H__
|
#define EDITLINE_PRIVATE_H_
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -95,4 +96,4 @@ extern char *strdup(const char *s);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../include/editline.h"
|
#include "../include/editline.h"
|
||||||
#endif /* __PRIVATE_EDITLINE_H__ */
|
#endif /* EDITLINE_PRIVATE_H_ */
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/* Editline system header file for OS-9 (on 68k).
|
/* Editline system header file for OS-9 (on 68k).
|
||||||
*
|
*
|
||||||
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved.
|
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is not subject to any license of the American Telephone
|
* This software is not subject to any license of the American Telephone
|
||||||
* and Telegraph Company or of the Regents of the University of California.
|
* and Telegraph Company or of the Regents of the University of California.
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/* OS-9 (on 68k) system-dependant routines for editline library.
|
/* OS-9 (on 68k) system-dependant routines for editline library.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved.
|
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is not subject to any license of the American Telephone
|
* This software is not subject to any license of the American Telephone
|
||||||
* and Telegraph Company or of the Regents of the University of California.
|
* and Telegraph Company or of the Regents of the University of California.
|
||||||
@@ -57,8 +58,7 @@ void rl_add_slash(char *path, char *p)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* c-file-style: "k&r"
|
||||||
* c-file-style: "ellemtel"
|
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/* Unix system-dependant routines for editline library.
|
/* Unix system-dependant routines for editline library.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved.
|
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is not subject to any license of the American Telephone
|
* This software is not subject to any license of the American Telephone
|
||||||
* and Telegraph Company or of the Regents of the University of California.
|
* and Telegraph Company or of the Regents of the University of California.
|
||||||
@@ -87,6 +88,7 @@ void rl_ttyset(int Reset)
|
|||||||
if (!Reset) {
|
if (!Reset) {
|
||||||
if (-1 == getattr(0, &old))
|
if (-1 == getattr(0, &old))
|
||||||
perror("Failed tcgetattr()");
|
perror("Failed tcgetattr()");
|
||||||
|
|
||||||
rl_erase = old.c_cc[VERASE];
|
rl_erase = old.c_cc[VERASE];
|
||||||
rl_kill = old.c_cc[VKILL];
|
rl_kill = old.c_cc[VKILL];
|
||||||
rl_eof = old.c_cc[VEOF];
|
rl_eof = old.c_cc[VEOF];
|
||||||
@@ -124,6 +126,7 @@ void rl_ttyset(int Reset)
|
|||||||
if (!Reset) {
|
if (!Reset) {
|
||||||
if (-1 == ioctl_wrap(0, TCGETA, &old))
|
if (-1 == ioctl_wrap(0, TCGETA, &old))
|
||||||
perror("Failed ioctl(TCGETA)");
|
perror("Failed ioctl(TCGETA)");
|
||||||
|
|
||||||
rl_erase = old.c_cc[VERASE];
|
rl_erase = old.c_cc[VERASE];
|
||||||
rl_kill = old.c_cc[VKILL];
|
rl_kill = old.c_cc[VKILL];
|
||||||
rl_eof = old.c_cc[VEOF];
|
rl_eof = old.c_cc[VEOF];
|
||||||
@@ -167,11 +170,13 @@ void rl_ttyset(int Reset)
|
|||||||
if (!Reset) {
|
if (!Reset) {
|
||||||
if (-1 == ioctl_wrap(0, TIOCGETP, &old_sgttyb))
|
if (-1 == ioctl_wrap(0, TIOCGETP, &old_sgttyb))
|
||||||
perror("Failed TIOCGETP");
|
perror("Failed TIOCGETP");
|
||||||
|
|
||||||
rl_erase = old_sgttyb.sg_erase;
|
rl_erase = old_sgttyb.sg_erase;
|
||||||
rl_kill = old_sgttyb.sg_kill;
|
rl_kill = old_sgttyb.sg_kill;
|
||||||
|
|
||||||
if (-1 == ioctl_wrap(0, TIOCGETC, &old_tchars))
|
if (-1 == ioctl_wrap(0, TIOCGETC, &old_tchars))
|
||||||
perror("Failed TIOCGETC");
|
perror("Failed TIOCGETC");
|
||||||
|
|
||||||
rl_eof = old_tchars.t_eofc;
|
rl_eof = old_tchars.t_eofc;
|
||||||
rl_intr = old_tchars.t_intrc;
|
rl_intr = old_tchars.t_intrc;
|
||||||
rl_quit = old_tchars.t_quitc;
|
rl_quit = old_tchars.t_quitc;
|
||||||
@@ -179,6 +184,7 @@ void rl_ttyset(int Reset)
|
|||||||
#ifdef CONFIG_SIGSTOP
|
#ifdef CONFIG_SIGSTOP
|
||||||
if (-1 == ioctl_wrap(0, TIOCGLTC, &old_ltchars))
|
if (-1 == ioctl_wrap(0, TIOCGLTC, &old_ltchars))
|
||||||
perror("Failed TIOCGLTC");
|
perror("Failed TIOCGLTC");
|
||||||
|
|
||||||
rl_susp = old_ltchars.t_suspc;
|
rl_susp = old_ltchars.t_suspc;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -189,8 +195,10 @@ void rl_ttyset(int Reset)
|
|||||||
new_sgttyb.sg_flags &= ~PASS8;
|
new_sgttyb.sg_flags &= ~PASS8;
|
||||||
else
|
else
|
||||||
new_sgttyb.sg_flags |= PASS8;
|
new_sgttyb.sg_flags |= PASS8;
|
||||||
|
|
||||||
if (-1 == ioctl_wrap(0, TIOCSETP, &new_sgttyb))
|
if (-1 == ioctl_wrap(0, TIOCSETP, &new_sgttyb))
|
||||||
perror("Failed TIOCSETP");
|
perror("Failed TIOCSETP");
|
||||||
|
|
||||||
new_tchars = old_tchars;
|
new_tchars = old_tchars;
|
||||||
new_tchars.t_intrc = -1;
|
new_tchars.t_intrc = -1;
|
||||||
new_tchars.t_quitc = -1;
|
new_tchars.t_quitc = -1;
|
||||||
@@ -199,6 +207,7 @@ void rl_ttyset(int Reset)
|
|||||||
} else {
|
} else {
|
||||||
if (-1 == ioctl_wrap(0, TIOCSETP, &old_sgttyb))
|
if (-1 == ioctl_wrap(0, TIOCSETP, &old_sgttyb))
|
||||||
perror("Failed TIOCSETP");
|
perror("Failed TIOCSETP");
|
||||||
|
|
||||||
if (-1 == ioctl_wrap(0, TIOCSETC, &old_tchars))
|
if (-1 == ioctl_wrap(0, TIOCSETC, &old_tchars))
|
||||||
perror("Failed TIOCSETC");
|
perror("Failed TIOCSETC");
|
||||||
}
|
}
|
||||||
@@ -209,14 +218,18 @@ void rl_ttyset(int Reset)
|
|||||||
|
|
||||||
#ifndef HAVE_STRDUP
|
#ifndef HAVE_STRDUP
|
||||||
/* Return an allocated copy of a string. */
|
/* Return an allocated copy of a string. */
|
||||||
char *strdup(const char *p)
|
char *strdup(const char *s)
|
||||||
{
|
{
|
||||||
char *new = malloc(sizeof(char) * strlen(p));
|
size_t len;
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
if (new) {
|
if (!s)
|
||||||
strcpy(new, p);
|
return NULL;
|
||||||
return new;
|
|
||||||
}
|
len = strlen(s) + 1;
|
||||||
|
ptr = malloc(len);
|
||||||
|
if (ptr)
|
||||||
|
return memcpy(ptr, s, len);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -232,8 +245,7 @@ void rl_add_slash(char *path, char *p)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* indent-tabs-mode: t
|
* c-file-style: "k&r"
|
||||||
* c-file-style: "ellemtel"
|
|
||||||
* c-basic-offset: 4
|
* c-basic-offset: 4
|
||||||
* End:
|
* End:
|
||||||
*/
|
*/
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/* Editline system header file for Unix.
|
/* Editline system header file for Unix.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz. All rights reserved.
|
* Copyright (c) 1992, 1993 Simmule Turner and Rich Salz
|
||||||
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is not subject to any license of the American Telephone
|
* This software is not subject to any license of the American Telephone
|
||||||
* and Telegraph Company or of the Regents of the University of California.
|
* and Telegraph Company or of the Regents of the University of California.
|
||||||
@@ -19,8 +20,8 @@
|
|||||||
* 4. This notice may not be removed or altered.
|
* 4. This notice may not be removed or altered.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __EDITLINE_UNIX_H__
|
#ifndef EDITLINE_UNIX_H_
|
||||||
#define __EDITLINE_UNIX_H__
|
#define EDITLINE_UNIX_H_
|
||||||
|
|
||||||
#define CRLF "\r\n"
|
#define CRLF "\r\n"
|
||||||
#define FORWARD STATIC
|
#define FORWARD STATIC
|
||||||
@@ -32,4 +33,4 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
typedef struct dirent DIRENTRY;
|
typedef struct dirent DIRENTRY;
|
||||||
|
|
||||||
#endif /* __EDITLINE_UNIX_H__ */
|
#endif /* EDITLINE_UNIX_H_ */
|
||||||
|
Reference in New Issue
Block a user