Initial import

This commit is contained in:
Justine Tunney
2020-06-15 07:18:57 -07:00
commit c91b3c5006
14915 changed files with 590219 additions and 0 deletions

248
third_party/editline/ChangeLog.md vendored Normal file
View File

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

18
third_party/editline/LICENSE vendored Normal file
View File

@@ -0,0 +1,18 @@
Copyright 1992,1993 Simmule Turner and Rich Salz
All rights reserved.
This software is not subject to any license of the American Telephone
and Telegraph Company or of the Regents of the University of California.
Permission is granted to anyone to use this software for any purpose on
any computer system, and to alter it and redistribute it freely, subject
to the following restrictions:
1. The authors are not responsible for the consequences of use of this
software, no matter how awful, even if they arise from flaws in it.
2. The origin of this software must not be misrepresented, either by
explicit claim or by omission. Since few users ever read sources,
credits must appear in the documentation.
3. Altered versions must be plainly marked as such, and must not be
misrepresented as being the original software. Since few users
ever read sources, credits must appear in the documentation.
4. This notice may not be removed or altered.

362
third_party/editline/complete.c vendored Normal file
View File

@@ -0,0 +1,362 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/alg/alg.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h"
#include "libc/fmt/fmt.h"
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "third_party/editline/editline.h"
#include "third_party/editline/internal.h"
asm(".ident\t\"\\n\\n\
Cosmopolitan Linenoise (BSD-like license)\\n\
Copyright 2019 Justine Alexandra Roberts Tunney\\n\
Copyright 1992,1993 Simmule Turner and Rich Salz\\n\
All rights reserved.\\n\
\\n\
This software is not subject to any license of the American Telephone\\n\
and Telegraph Company or of the Regents of the University of California.\\n\
\\n\
Permission is granted to anyone to use this software for any purpose on\\n\
any computer system, and to alter it and redistribute it freely, subject\\n\
to the following restrictions:\\n\
1. The authors are not responsible for the consequences of use of this\\n\
software, no matter how awful, even if they arise from flaws in it.\\n\
2. The origin of this software must not be misrepresented, either by\\n\
explicit claim or by omission. Since few users ever read sources,\\n\
credits must appear in the documentation.\\n\
3. Altered versions must be plainly marked as such, and must not be\\n\
misrepresented as being the original software. Since few users\\n\
ever read sources, credits must appear in the documentation.\\n\
4. This notice may not be removed or altered.\"");
asm(".include \"libc/disclaimer.inc\"");
#define MAX_TOTAL_MATCHES (256 << sizeof(char *))
int rl_attempted_completion_over = 0;
rl_completion_func_t *rl_attempted_completion_function = NULL;
rl_compentry_func_t *rl_completion_entry_function = NULL;
/* Wrap strcmp() for qsort() -- weird construct to pass -Wcast-qual */
static int compare(const void *p1, const void *p2) {
char *const *v1 = (char *const *)p1;
char *const *v2 = (char *const *)p2;
return strcmp(*v1, *v2);
}
/* Fill in *avp with an array of names that match file, up to its length.
* Ignore . and .. . */
static int FindMatches(char *dir, char *file, char ***avp) {
char **av;
char **word;
char *p;
DIR *dp;
struct dirent *ep;
size_t ac;
size_t len;
size_t choices;
size_t total;
if ((dp = opendir(dir)) == NULL) return 0;
av = NULL;
ac = 0;
len = strlen(file);
choices = 0;
total = 0;
while ((ep = readdir(dp)) != NULL) {
p = ep->d_name;
if (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')))
continue;
if (len && strncmp(p, file, len) != 0) continue;
choices++;
if ((total += strlen(p)) > MAX_TOTAL_MATCHES) {
/* This is a bit too much. */
while (ac > 0) free(av[--ac]);
continue;
}
if ((ac % MEM_INC) == 0) {
word = malloc(sizeof(char *) * (ac + MEM_INC));
if (!word) {
total = 0;
break;
}
if (ac) {
memcpy(word, av, ac * sizeof(char *));
free(av);
}
*avp = av = word;
}
if ((av[ac] = strdup(p)) == NULL) {
if (ac == 0) free(av);
total = 0;
break;
}
ac++;
}
/* Clean up and return. */
closedir(dp);
if (total > MAX_TOTAL_MATCHES) {
char many[sizeof(total) * 3];
p = many + sizeof(many);
*--p = '\0';
while (choices > 0) {
*--p = '0' + choices % 10;
choices /= 10;
}
while (p > many + sizeof(many) - 8) *--p = ' ';
if ((p = strdup(p)) != NULL) av[ac++] = p;
if ((p = strdup("choices")) != NULL) av[ac++] = p;
} else {
if (ac) qsort(av, ac, sizeof(char *), compare);
}
return ac;
}
/* Split a pathname into allocated directory and trailing filename parts. */
static int SplitPath(const char *path, char **dirpart, char **filepart) {
static char DOT[] = ".";
char *dpart;
char *fpart;
if ((fpart = strrchr(path, '/')) == NULL) {
if ((dpart = strdup(DOT)) == NULL) return -1;
if ((fpart = strdup(path)) == NULL) {
free(dpart);
return -1;
}
} else {
if ((dpart = strdup(path)) == NULL) return -1;
dpart[fpart - path + 1] = '\0';
if ((fpart = strdup(fpart + 1)) == NULL) {
free(dpart);
return -1;
}
}
*dirpart = dpart;
*filepart = fpart;
return 0;
}
static rl_complete_func_t *el_complete_func = NULL;
/* For compatibility with the Heimdal project. */
rl_complete_func_t *rl_set_complete_func(rl_complete_func_t *func) {
rl_complete_func_t *old = el_complete_func;
el_complete_func = func;
return old;
}
/* Attempt to complete the pathname, returning an allocated copy.
* Fill in *match if we completed it, or set it to 0 if ambiguous. */
char *el_filename_complete(char *pathname, int *match) {
char **av;
char *dir;
char *file;
char *path;
char *p;
size_t ac;
size_t end;
size_t i;
size_t j;
size_t len;
if (SplitPath((const char *)pathname, &dir, &file) < 0) return NULL;
if ((ac = FindMatches(dir, file, &av)) == 0) {
free(dir);
free(file);
return NULL;
}
p = NULL;
len = strlen(file);
if (ac == 1) {
/* Exactly one match -- finish it off. */
*match = 1;
j = strlen(av[0]) - len + 2;
p = malloc(sizeof(char) * (j + 1));
if (p) {
memcpy(p, av[0] + len, j);
len = strlen(dir) + strlen(av[0]) + 2;
path = malloc(sizeof(char) * len);
if (path) {
snprintf(path, len, "%s/%s", dir, av[0]);
rl_add_slash(path, p);
free(path);
}
}
} else {
*match = 0;
if (len) {
/* Find largest matching substring. */
for (i = len, end = strlen(av[0]); i < end; i++) {
for (j = 1; j < ac; j++) {
if (av[0][i] != av[j][i]) goto breakout;
}
}
breakout:
if (i > len) {
j = i - len + 1;
p = malloc(sizeof(char) * j);
if (p) {
memcpy(p, av[0] + len, j);
p[j - 1] = '\0';
}
}
}
}
/* Clean up and return. */
free(dir);
free(file);
for (i = 0; i < ac; i++) free(av[i]);
free(av);
return p;
}
char *rl_filename_completion_function(const char *text, int state) {
char *dir;
char *file;
static char **av;
static size_t i, ac;
if (!state) {
if (SplitPath(text, &dir, &file) < 0) return NULL;
ac = FindMatches(dir, file, &av);
free(dir);
free(file);
if (!ac) return NULL;
i = 0;
}
if (i < ac) return av[i++];
do {
free(av[--i]);
} while (i > 0);
return NULL;
}
/* Similar to el_find_word(), but used by GNU Readline API */
static char *rl_find_token(size_t *len) {
char *ptr;
int pos;
for (pos = rl_point; pos < rl_end; pos++) {
if (isspace(rl_line_buffer[pos])) {
if (pos > 0) pos--;
break;
}
}
ptr = &rl_line_buffer[pos];
while (pos >= 0 && !isspace(rl_line_buffer[pos])) {
if (pos == 0) break;
pos--;
}
if (ptr != &rl_line_buffer[pos]) {
*len = (size_t)(ptr - &rl_line_buffer[pos]);
return &rl_line_buffer[pos];
}
return NULL;
}
/*
* "uses an application-supplied generator function to generate the list
* of possible matches, and then returns the array of these matches. The
* caller should place the address of its generator function in
* rl_completion_entry_function"
*/
char **rl_completion_matches(const char *token,
rl_compentry_func_t *generator) {
int state = 0, num = 0;
char **array, *entry;
if (!generator) {
generator = rl_completion_entry_function;
if (!generator) generator = rl_filename_completion_function;
}
if (!generator) return NULL;
array = malloc(512 * sizeof(char *));
if (!array) return NULL;
while (num < 511 && (entry = generator(token, state))) {
state = 1;
array[num++] = entry;
}
array[num] = NULL;
if (!num) {
free(array);
return NULL;
}
return array;
}
static char *complete(char *token, int *match) {
size_t len = 0;
char *word, **words = NULL;
int start, end;
word = rl_find_token(&len);
if (!word) goto fallback;
start = word - rl_line_buffer;
end = start + len;
word = strndup(word, len);
if (!word) goto fallback;
rl_attempted_completion_over = 0;
words = rl_attempted_completion_function(word, start, end);
if (!rl_attempted_completion_over && !words)
words = rl_completion_matches(word, NULL);
if (words) {
int i = 0;
free(word);
word = NULL;
if (words[0]) word = strdup(words[0] + len);
while (words[i]) free(words[i++]);
free(words);
if (word) return word;
}
fallback:
return el_filename_complete(token, match);
}
/*
* First check for editline specific custom completion function, then
* for any GNU Readline compat, then fallback to filename completion.
*/
char *rl_complete(char *token, int *match) {
if (el_complete_func) return el_complete_func(token, match);
if (rl_attempted_completion_function) return complete(token, match);
return el_filename_complete(token, match);
}
static rl_list_possib_func_t *el_list_possib_func = NULL;
/* For compatibility with the Heimdal project. */
rl_list_possib_func_t *rl_set_list_possib_func(rl_list_possib_func_t *func) {
rl_list_possib_func_t *old = el_list_possib_func;
el_list_possib_func = func;
return old;
}
/* Default possible completions. */
int el_filename_list_possib(char *pathname, char ***av) {
char *dir;
char *file;
int ac;
if (SplitPath(pathname, &dir, &file) < 0) return 0;
ac = FindMatches(dir, file, av);
free(dir);
free(file);
return ac;
}
/* Return all possible completions. */
int rl_list_possib(char *token, char ***av) {
if (el_list_possib_func) return el_list_possib_func(token, av);
return el_filename_list_possib(token, av);
}

274
third_party/editline/editline.3 vendored Normal file
View File

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

1557
third_party/editline/editline.c vendored Normal file

File diff suppressed because it is too large Load Diff

91
third_party/editline/editline.h vendored Normal file
View File

@@ -0,0 +1,91 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_EDITLINE_EDITLINE_H_
#define COSMOPOLITAN_THIRD_PARTY_EDITLINE_EDITLINE_H_
#include "libc/stdio/stdio.h"
#define CTL(x) ((x)&0x1F)
#define ISCTL(x) ((x) && (x) < ' ')
#define UNCTL(x) ((x) + 64)
#define META(x) ((x) | 0x80)
#define ISMETA(x) ((x)&0x80)
#define UNMETA(x) ((x)&0x7F)
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
typedef enum {
CSdone = 0, /* OK */
CSeof, /* Error, or EOF */
CSmove,
CSdispatch,
CSstay,
CSsignal
} el_status_t;
typedef int rl_list_possib_func_t(char *, char ***);
typedef el_status_t el_keymap_func_t(void);
typedef int rl_hook_func_t(void);
typedef int rl_getc_func_t(void);
typedef void rl_voidfunc_t(void);
typedef void rl_vintfunc_t(int);
typedef void rl_vcpfunc_t(char *);
compatfn typedef char *rl_complete_func_t(char *, int *);
compatfn typedef char *rl_compentry_func_t(const char *, int);
compatfn typedef char **rl_completion_func_t(const char *, int, int);
extern int rl_point;
extern int rl_mark;
extern int rl_end;
extern int rl_inhibit_complete;
extern char *rl_line_buffer;
extern const char *rl_readline_name;
extern FILE *rl_instream; /* The stdio stream from which input is read. Defaults
to stdin if NULL - Not supported yet! */
extern FILE *rl_outstream; /* The stdio stream to which output is flushed.
Defaults to stdout if NULL - Not supported yet! */
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_hist_size; /* size of history scrollback buffer, default: 15 */
extern int rl_meta_chars; /* Display 8-bit chars "as-is" or as `M-x'? Toggle
with M-m. (Default:0 - "as-is") */
extern rl_completion_func_t *rl_attempted_completion_function;
char **rl_completion_matches(const char *, rl_compentry_func_t *);
char *el_find_word(void);
char *readline(const char *);
char *rl_complete(char *, int *);
char *rl_filename_completion_function(const char *, int);
const char *el_next_hist(void);
const char *el_prev_hist(void);
el_status_t el_bind_key(int, el_keymap_func_t);
el_status_t el_bind_key_in_metamap(int, el_keymap_func_t);
el_status_t el_del_char(void);
el_status_t el_ring_bell(void);
int read_history(const char *);
int rl_getc(void);
int rl_insert_text(const char *);
int rl_list_possib(char *, char ***);
int rl_refresh_line(int, int);
int write_history(const char *);
rl_complete_func_t *rl_set_complete_func(rl_complete_func_t *);
rl_getc_func_t *rl_set_getc_func(rl_getc_func_t *);
rl_list_possib_func_t *rl_set_list_possib_func(rl_list_possib_func_t *);
void add_history(const char *);
void el_print_columns(int, char **);
void rl_callback_handler_install(const char *, rl_vcpfunc_t *);
void rl_callback_handler_remove(void);
void rl_callback_read_char(void);
void rl_clear_message(void);
void rl_deprep_terminal(void);
void rl_forced_update_display(void);
void rl_initialize(void);
void rl_prep_terminal(int);
void rl_reset_terminal(const char *);
void rl_restore_prompt(void);
void rl_save_prompt(void);
void rl_set_prompt(const char *);
void rl_uninitialize(void);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_EDITLINE_EDITLINE_H_ */

57
third_party/editline/editline.mk vendored Normal file
View File

@@ -0,0 +1,57 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += THIRD_PARTY_EDITLINE
THIRD_PARTY_EDITLINE_ARTIFACTS += THIRD_PARTY_EDITLINE_A
THIRD_PARTY_EDITLINE = $(THIRD_PARTY_EDITLINE_A_DEPS) $(THIRD_PARTY_EDITLINE_A)
THIRD_PARTY_EDITLINE_A = o/$(MODE)/third_party/editline/editline.a
THIRD_PARTY_EDITLINE_A_FILES := $(wildcard third_party/editline/*)
THIRD_PARTY_EDITLINE_A_HDRS = $(filter %.h,$(THIRD_PARTY_EDITLINE_A_FILES))
THIRD_PARTY_EDITLINE_A_SRCS = $(filter %.c,$(THIRD_PARTY_EDITLINE_A_FILES))
THIRD_PARTY_EDITLINE_A_OBJS = \
$(THIRD_PARTY_EDITLINE_A_SRCS:%=o/$(MODE)/%.zip.o) \
$(THIRD_PARTY_EDITLINE_A_SRCS:%.c=o/$(MODE)/%.o)
THIRD_PARTY_EDITLINE_A_CHECKS = \
$(THIRD_PARTY_EDITLINE_A).pkg
THIRD_PARTY_EDITLINE_A_DIRECTDEPS = \
LIBC_ALG \
LIBC_CALLS \
LIBC_CALLS_HEFTY \
LIBC_FMT \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_STDIO \
LIBC_STR \
LIBC_STUBS \
LIBC_SYSV
THIRD_PARTY_EDITLINE_A_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_EDITLINE_A_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_EDITLINE_A): \
third_party/editline/ \
$(THIRD_PARTY_EDITLINE_A).pkg \
$(THIRD_PARTY_EDITLINE_A_OBJS)
$(THIRD_PARTY_EDITLINE_A).pkg: \
$(THIRD_PARTY_EDITLINE_A_OBJS) \
$(foreach x,$(THIRD_PARTY_EDITLINE_A_DIRECTDEPS),$($(x)_A).pkg)
THIRD_PARTY_EDITLINE_LIBS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)))
THIRD_PARTY_EDITLINE_SRCS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_SRCS))
THIRD_PARTY_EDITLINE_HDRS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_HDRS))
THIRD_PARTY_EDITLINE_BINS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_BINS))
THIRD_PARTY_EDITLINE_CHECKS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_CHECKS))
THIRD_PARTY_EDITLINE_OBJS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_OBJS))
THIRD_PARTY_EDITLINE_TESTS = $(foreach x,$(THIRD_PARTY_EDITLINE_ARTIFACTS),$($(x)_TESTS))
$(THIRD_PARTY_EDITLINE_OBJS): $(BUILD_FILES) third_party/editline/editline.mk
.PHONY: o/$(MODE)/third_party/editline
o/$(MODE)/third_party/editline: \
$(THIRD_PARTY_EDITLINE) \
$(THIRD_PARTY_EDITLINE_CHECKS)

21
third_party/editline/internal.h vendored Normal file
View File

@@ -0,0 +1,21 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_EDITLINE_INTERNAL_H_
#define COSMOPOLITAN_THIRD_PARTY_EDITLINE_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define MEM_INC 64
#define SCREEN_INC 256
extern int rl_eof;
extern int rl_erase;
extern int rl_intr;
extern int rl_kill;
extern int rl_quit;
extern int rl_susp;
void rl_ttyset(int);
void rl_add_slash(char *, char *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_EDITLINE_INTERNAL_H_ */

112
third_party/editline/sysunix.c vendored Normal file
View File

@@ -0,0 +1,112 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/termios.h"
#include "libc/errno.h"
#include "libc/log/log.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/termios.h"
#include "third_party/editline/editline.h"
#include "third_party/editline/internal.h"
asm(".ident\t\"\\n\\n\
Cosmopolitan Linenoise (BSD-like license)\\n\
Copyright 2019 Justine Alexandra Roberts Tunney\\n\
Copyright 1992,1993 Simmule Turner and Rich Salz\\n\
All rights reserved.\\n\
\\n\
This software is not subject to any license of the American Telephone\\n\
and Telegraph Company or of the Regents of the University of California.\\n\
\\n\
Permission is granted to anyone to use this software for any purpose on\\n\
any computer system, and to alter it and redistribute it freely, subject\\n\
to the following restrictions:\\n\
1. The authors are not responsible for the consequences of use of this\\n\
software, no matter how awful, even if they arise from flaws in it.\\n\
2. The origin of this software must not be misrepresented, either by\\n\
explicit claim or by omission. Since few users ever read sources,\\n\
credits must appear in the documentation.\\n\
3. Altered versions must be plainly marked as such, and must not be\\n\
misrepresented as being the original software. Since few users\\n\
ever read sources, credits must appear in the documentation.\\n\
4. This notice may not be removed or altered.\"");
asm(".include \"libc/disclaimer.inc\"");
/* Wrapper for tcgetattr */
static int getattr(int fd, struct termios *arg) {
int result, retries = 3;
while (-1 == (result = tcgetattr(fd, arg)) && retries > 0) {
retries--;
if (EINTR == errno) continue;
break;
}
return result;
}
/* Wrapper for tcgetattr */
static int setattr(int fd, int opt, const struct termios *arg) {
int result, retries = 3;
while (-1 == (result = tcsetattr(fd, opt, arg)) && retries > 0) {
retries--;
if (EINTR == errno) continue;
break;
}
return result;
}
void rl_ttyset(int Reset) {
static struct termios old;
struct termios new;
if (!Reset) {
if (-1 == getattr(0, &old)) {
perror("Failed tcgetattr()");
}
rl_erase = old.c_cc[VERASE];
rl_kill = old.c_cc[VKILL];
rl_eof = old.c_cc[VEOF];
rl_intr = old.c_cc[VINTR];
rl_quit = old.c_cc[VQUIT];
#ifdef CONFIG_SIGSTOP
rl_susp = old.c_cc[VSUSP];
#endif
new = old;
new.c_lflag &= ~(ECHO | ICANON | ISIG);
new.c_iflag &= ~INPCK;
if (rl_meta_chars)
new.c_iflag |= ISTRIP;
else
new.c_iflag &= ~ISTRIP;
new.c_cc[VMIN] = 1;
new.c_cc[VTIME] = 0;
if (-1 == setattr(0, TCSADRAIN, &new)) {
perror("Failed tcsetattr(TCSADRAIN)");
}
} else {
if (-1 == setattr(0, TCSADRAIN, &old)) {
perror("Failed tcsetattr(TCSADRAIN)");
}
}
}
void rl_add_slash(char *path, char *p) {
struct stat Sb;
if (stat(path, &Sb) >= 0) strcat(p, S_ISDIR(Sb.st_mode) ? "/" : " ");
}