ncsubproc: launch processes, make pipes

link to LWN article in History section of README.md.
pull/531/head
nick black 4 years ago
parent ee15d4c1f4
commit 04f90fa1ea
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -534,6 +534,7 @@ target_include_directories(notcurses-tester
target_link_libraries(notcurses-tester
PRIVATE
notcurses
"${TERMINFO_LIBRARIES}"
)
target_compile_options(notcurses-tester
PRIVATE

@ -15,7 +15,7 @@ via notcurses@googlegroups.com.
I wrote a coherent [guidebook](https://nick-black.com/htp-notcurses.pdf), which
is available for free download, or [paperback purchase](https://amazon.com/dp/B086PNVNC9).
notcurses is available in the Arch [AUR](https://aur.archlinux.org/packages/notcurses/).
Notcurses is available in the Arch [AUR](https://aur.archlinux.org/packages/notcurses/).
Packages for Debian Unstable and Ubuntu Focal are available from [DSSCAW](https://www.dsscaw.com/apt.html).
[![Build Status](https://drone.dsscaw.com:4443/api/badges/dankamongmen/notcurses/status.svg)](https://drone.dsscaw.com:4443/dankamongmen/notcurses)
@ -51,30 +51,30 @@ Packages for Debian Unstable and Ubuntu Focal are available from [DSSCAW](https:
* **What it is**: a library facilitating complex TUIs on modern terminal
emulators, supporting vivid colors and Unicode to the maximum degree
possible. Many tasks delegated to Curses can be achieved using notcurses
possible. Many tasks delegated to Curses can be achieved using Notcurses
(and vice versa).
* **What it is not**: a source-compatible X/Open Curses implementation, nor a
replacement for NCURSES on existing systems, nor a widely-ported and -tested
bedrock of free software, nor a battle-proven, veteran library.
notcurses abandons the X/Open Curses API bundled as part of the Single UNIX
Notcurses abandons the X/Open Curses API bundled as part of the Single UNIX
Specification. The latter shows its age, and seems not capable of making use of
terminal functionality such as unindexed 24-bit color ("TrueColor", not to be
confused with the 8-bit indexed 24-bit "extended color" of NCURSES).
For some necessary background, consult Thomas E. Dickey's
superb and authoritative [NCURSES FAQ](https://invisible-island.net/ncurses/ncurses.faq.html#xterm_16MegaColors).
As such, notcurses is not a drop-in Curses replacement. It is almost certainly
As such, Notcurses is not a drop-in Curses replacement. It is almost certainly
less portable, and definitely tested on less hardware. Sorry about that.
Ultimately, I hope to properly support all terminals *supporting the features
necessary for complex TUIs*. I would argue that teletypes etc. are
fundamentally unsuitable. Most operating systems seem reasonable targets, but I
only have Linux and FreeBSD available for testing.
Whenever possible, notcurses makes use of the Terminfo library shipped with
Whenever possible, Notcurses makes use of the Terminfo library shipped with
NCURSES, benefiting greatly from its portability and thoroughness.
notcurses opens up advanced functionality for the interactive user on
Notcurses opens up advanced functionality for the interactive user on
workstations, phones, laptops, and tablets, at the expense of e.g.
some industrial and retail terminals.
@ -103,7 +103,7 @@ Why use this non-standard library?
Much of the above can be had with NCURSES, but they're not what NCURSES was
*designed* for. The most fundamental advantage in my mind, though, is
that notcurses is of the multithreaded era. On the other hand, if you're
that Notcurses is of the multithreaded era. On the other hand, if you're
targeting industrial or critical applications, or wish to benefit from the
time-tested reliability and portability of Curses, you should by all means use
that fine library.
@ -139,20 +139,20 @@ be found on the `notcurses-demo(1)` man page.
A full API reference [is available](https://nick-black.com/notcurses/). Manual
pages ought have been installed along with notcurses.
A program wishing to use notcurses will need to link it, ideally using the
A program wishing to use Notcurses will need to link it, ideally using the
output of `pkg-config --libs notcurses`. It is advised to compile with the
output of `pkg-config --cflags notcurses`. If using CMake, a support file is
provided, and can be accessed as `notcurses`.
Before calling into notcurses—and usually as one of the first calls of the
Before calling into Notcurses—and usually as one of the first calls of the
program—be sure to call `setlocale(3)` with an appropriate UTF-8 locale. It is
usually appropriate to use `setlocale(LC_ALL, "")`, relying on the user to
properly set the `LANG` environment variable. notcurses will refuse to start if
properly set the `LANG` environment variable. Notcurses will refuse to start if
`nl_langinfo(3)` doesn't indicate `ANSI_X3.4-1968` or `UTF-8`. In addition, it
is wise to mask most signals early in the program, before any threads are
spawned (this is particularly critical for `SIGWINCH`).
notcurses requires an available `terminfo(5)` definition appropriate for the
Notcurses requires an available `terminfo(5)` definition appropriate for the
terminal. It is usually appropriate to pass `NULL` in the `termtype` field of a
`notcurses_options` struct, relying on the user to properly set the `TERM`
environment variable. This variable is usually set by the terminal itself. It
@ -163,14 +163,14 @@ Each terminal can be prepared via a call to `notcurses_init()`, which is
supplied a struct of type `notcurses_options`:
```c
// Get a human-readable string describing the running notcurses version.
// Get a human-readable string describing the running Notcurses version.
const char* notcurses_version(void);
struct cell; // a coordinate on an ncplane: an EGC plus styling
struct ncplane; // a drawable notcurses surface, composed of cells
struct notcurses; // notcurses state for a given terminal, composed of ncplanes
struct ncplane; // a drawable Notcurses surface, composed of cells
struct notcurses; // Notcurses state for a given terminal, composed of ncplanes
// These log levels consciously map cleanly to those of libav; notcurses itself
// These log levels consciously map cleanly to those of libav; Notcurses itself
// does not use this full granularity. The log level does not affect the opening
// and closing banners, which can be disabled via the notcurses_option struct's
// 'suppress_banner'. Note that if stderr is connected to the same terminal on
@ -2650,17 +2650,19 @@ up someday **FIXME**.
### History
* 2020-04-19: notcurses is [accepted into Debian](https://bugs.debian.org/950492).
* 2020-04-12: notcurses [1.3.0 "hypnotize"](https://github.com/dankamongmen/notcurses/releases/tag/v1.3.0).
* 2020-02-17: notcurses [1.2.0 "check the résumé, my record's impeccable"](https://github.com/dankamongmen/notcurses/releases/tag/v1.2.0).
* 2019-01-19: notcurses [1.1.0 "all the hustlas they love it just to see one of us make it"](https://github.com/dankamongmen/notcurses/releases/tag/v1.1.0).
* 2020-04-19: Notcurses is [accepted into Debian](https://bugs.debian.org/950492).
* 2020-04-12: Notcurses [1.3.0 "hypnotize"](https://github.com/dankamongmen/notcurses/releases/tag/v1.3.0).
* 2020-04-08: The Notcurses book [is published](https://amazon.com/dp/B086PNVNC9).
* 2020-03-23: Notcurses is featured on [Linux World News](https://lwn.net/Articles/815811/).
* 2020-02-17: Notcurses [1.2.0 "check the résumé, my record's impeccable"](https://github.com/dankamongmen/notcurses/releases/tag/v1.2.0).
* 2019-01-19: Notcurses [1.1.0 "all the hustlas they love it just to see one of us make it"](https://github.com/dankamongmen/notcurses/releases/tag/v1.1.0).
Much better video support, pulsing planes, palette256.
* 2019-01-04: notcurses [1.0.0 "track team, crack fiend, dying to geek"](https://github.com/dankamongmen/notcurses/releases/tag/v1.0.0)
* 2019-01-04: Notcurses [1.0.0 "track team, crack fiend, dying to geek"](https://github.com/dankamongmen/notcurses/releases/tag/v1.0.0)
is released, six days ahead of schedule. 147 issues closed. 702 commits.
* 2019-12-18: notcurses [0.9.0 "You dig in! You dig out! You get out!"](https://github.com/dankamongmen/notcurses/releases/tag/v0.9.0),
* 2019-12-18: Notcurses [0.9.0 "You dig in! You dig out! You get out!"](https://github.com/dankamongmen/notcurses/releases/tag/v0.9.0),
and also the first contributor besides myself (@grendello). Last major
pre-GA release.
* 2019-12-05: notcurses [0.4.0 "TRAP MUSIC ALL NIGHT LONG"](https://github.com/dankamongmen/notcurses/releases/tag/v0.4.0),
* 2019-12-05: Notcurses [0.4.0 "TRAP MUSIC ALL NIGHT LONG"](https://github.com/dankamongmen/notcurses/releases/tag/v0.4.0),
the first generally usable notcurses. I prepare a [demo](https://www.youtube.com/watch?v=eEv2YRyiEVM),
and release it on YouTube.
* November 2019: I begin work on [Outcurses](https://github.com/dankamongmen/ncreels).
@ -2673,7 +2675,7 @@ up someday **FIXME**.
I get into contact with Thomas E. Dickey and confirm that what I'm hoping
to do doesn't really fit in with the codified Curses API.
* 2019-11-16: I make the [first commit](https://github.com/dankamongmen/notcurses/commit/635d7039d79e4f94ba645e8cb601e3a6d82a6b30)
to notcurses.
to Notcurses.
* September 2019: I extracted fade routines from Growlight and Omphalos, and
offered them to NCURSES as extensions. They are not accepted, which is
understandable. I mention that I intend to extract ncreels, and offer to
@ -2690,7 +2692,8 @@ up someday **FIXME**.
engineering history. He exemplifies documentation excellence and
conservative, thoughtful stewardship. The free software community owes
Mr. Dickey a great debt.
* Robert Edmonds provided tremendous assistance Debianizing the package.
* Robert Edmonds provided tremendous assistance Debianizing the package,
and David Cantrell did likewise for Fedora. Both are hella engineers.
* Justine Tunney, one of my first friends at Google NYC, was always present
with support, and pointed out the useful memstream functionality of
POSIX, eliminating the need for me to cons up something similar.

@ -1,3 +1,4 @@
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include "internal.h"
@ -24,6 +25,7 @@ ncfdplane_thread(void* vncfp){
break;
}
}
// FIXME need to continue reading on pipe/socket
if(r <= 0){
ncfp->donecb(ncfp, r == 0 ? 0 : errno, ncfp->curry);
}
@ -85,7 +87,16 @@ ncsubproc* ncsubproc_createv(ncplane* n, const ncsubproc_options* opts,
int fd = -1;
ncsubproc* ret = malloc(sizeof(*ret));
if(ret){
// FIXME launch process, create ncfdplane with pipe
// FIXME create ncfdplane with pipe
ret->pid = fork();
if(ret->pid == 0){
execv(bin, arg);
fprintf(stderr, "Error execv()ing %s\n", bin);
exit(EXIT_FAILURE);
}else if(ret->pid < 0){
free(ret);
return NULL;
}
if((ret->nfp = ncfdplane_create(n, &opts->popts, fd, cbfxn, donecbfxn)) == NULL){
// FIXME kill process
free(ret);
@ -103,17 +114,49 @@ ncsubproc* ncsubproc_createvp(ncplane* n, const ncsubproc_options* opts,
}
int fd = -1;
ncsubproc* ret = malloc(sizeof(*ret));
if(ret){
// FIXME launch process, create ncfdplane with pipe
if((ret->nfp = ncfdplane_create(n, &opts->popts, fd, cbfxn, donecbfxn)) == NULL){
// FIXME kill process
free(ret);
return NULL;
}
if(ret == NULL){
return NULL;
}
int fds[2];
if(pipe2(fds, O_CLOEXEC)){
free(ret);
return NULL;
}
// FIXME move pipe to stdio fds
ret->pid = fork();
if(ret->pid == 0){
execvp(bin, arg);
fprintf(stderr, "Error execv()ing %s\n", bin);
exit(EXIT_FAILURE);
}else if(ret->pid < 0){
free(ret);
return NULL;
}
if((ret->nfp = ncfdplane_create(n, &opts->popts, fd, cbfxn, donecbfxn)) == NULL){
// FIXME kill process
free(ret);
return NULL;
}
return ret;
}
static pid_t
launch_pipe_process(int* pipe){
int pipes[2];
if(pipe2(pipes, O_CLOEXEC)){
return -1;
}
pid_t p = fork();
if(p == 0){
if(dup2(pipes[1], STDOUT_FILENO) < 0 || dup2(pipes[1], STDERR_FILENO) < 0){
return -1;
}
}else{
*pipe = pipes[0];
}
return p;
}
ncsubproc* ncsubproc_createvpe(ncplane* n, const ncsubproc_options* opts,
const char* bin, char* const arg[], char* const env[],
ncfdplane_callback cbfxn, ncfdplane_done_cb donecbfxn){
@ -123,7 +166,15 @@ ncsubproc* ncsubproc_createvpe(ncplane* n, const ncsubproc_options* opts,
int fd = -1;
ncsubproc* ret = malloc(sizeof(*ret));
if(ret){
// FIXME launch process, create ncfdplane with pipe
ret->pid = launch_pipe_process(&fd);
if(ret->pid == 0){
execvpe(bin, arg, env);
fprintf(stderr, "Error execv()ing %s\n", bin);
exit(EXIT_FAILURE);
}else if(ret->pid < 0){
free(ret);
return NULL;
}
if((ret->nfp = ncfdplane_create(n, &opts->popts, fd, cbfxn, donecbfxn)) == NULL){
// FIXME kill process
free(ret);

@ -45,6 +45,9 @@ int main(int argc, char** argv){
notcurses_options opts = {};
opts.inhibit_alternate_screen = true;
struct notcurses* nc = notcurses_init(&opts, stdout);
if(nc == NULL){
return EXIT_FAILURE;
}
struct ncplane* n = notcurses_stdplane(nc);
int ret = -1;
ncsubproc_options nopts = {};

@ -64,7 +64,7 @@ TEST_CASE("FdsAndSubprocs") {
// destroy the ncfdplane outside of its own context
SUBCASE("FdPlaneDestroyOffline") {
REQUIRE(!outofline_cancelled);
outofline_cancelled = false;
ncfdplane_options opts{};
int fd = open("/etc/sysctl.conf", O_RDONLY|O_CLOEXEC);
REQUIRE(0 <= fd);
@ -82,7 +82,7 @@ TEST_CASE("FdsAndSubprocs") {
// destroy the ncfdplane within its own context, i.e. from the eof callback
SUBCASE("FdPlaneDestroyInline") {
REQUIRE(!inline_cancelled);
inline_cancelled = false;
ncfdplane_options opts{};
opts.curry = n_;
int fd = open("/etc/sysctl.conf", O_RDONLY|O_CLOEXEC);
@ -100,7 +100,7 @@ TEST_CASE("FdsAndSubprocs") {
SUBCASE("SubprocDestroyOffline") {
char * const argv[] = { strdup("/bin/cat"), strdup("/etc/sysctl.conf"), NULL, };
REQUIRE(!outofline_cancelled);
outofline_cancelled = false;
ncsubproc_options opts{};
auto ncsubp = ncsubproc_createvp(n_, &opts, argv[0], argv, testfdcb, testfdeof);
REQUIRE(ncsubp);

Loading…
Cancel
Save