Skip to content

Commit

Permalink
ncdirect: open an fd for the controlling terminal
Browse files Browse the repository at this point in the history
Use ctermid(3) to identify the controlling terminal device.
When one exists, open(2) it up, and retain this file descriptor
across the life of the ncdirect context. Allow a failure, since
not everything requires such an fd. This will be used for tty-
specific activity such as ioctl()s and escape sequences
involving terminal replies (such as get absolute cursor
position). #752
  • Loading branch information
dankamongmen committed Jul 2, 2020
1 parent cda4253 commit 93ff1d7
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 57 deletions.
88 changes: 71 additions & 17 deletions src/lib/direct.cpp
@@ -1,3 +1,5 @@
#include <ncurses.h> // needed for some definitions, see terminfo(3ncurses)
#include <fcntl.h>
#include <errno.h>
#include <cstring>
#include <unistd.h>
Expand Down Expand Up @@ -335,23 +337,6 @@ nc_err_e ncdirect_render_image(ncdirect* n, const char* file, ncblitter_e blitte
return NCERR_SUCCESS;
}

int ncdirect_stop(ncdirect* nc){
int ret = 0;
if(nc){
if(nc->tcache.op && term_emit("op", nc->tcache.op, nc->ttyfp, true)){
ret = -1;
}
if(nc->tcache.sgr0 && term_emit("sgr0", nc->tcache.sgr0, nc->ttyfp, true)){
ret = -1;
}
if(nc->tcache.oc && term_emit("oc", nc->tcache.oc, nc->ttyfp, true)){
ret = -1;
}
free(nc);
}
return ret;
}

int ncdirect_fg_palindex(ncdirect* nc, int pidx){
return term_emit("setaf", tiparm(nc->tcache.setaf, pidx), nc->ttyfp, false);
}
Expand Down Expand Up @@ -403,3 +388,72 @@ int ncdirect_printf_aligned(ncdirect* n, int y, ncalign_e align, const char* fmt
va_end(va);
return ret;
}

int get_controlling_tty(void){
char cbuf[L_ctermid + 1];
if(ctermid(cbuf) == NULL){
return -1;
}
return open(cbuf, O_RDWR | O_CLOEXEC);
}

ncdirect* ncdirect_init(const char* termtype, FILE* outfp){
if(outfp == NULL){
outfp = stdout;
}
auto ret = new ncdirect{};
if(ret == NULL){
return ret;
}
ret->ttyfp = outfp;
memset(&ret->palette, 0, sizeof(ret->palette));
int ttyfd = fileno(ret->ttyfp);
if(ttyfd < 0){
fprintf(stderr, "No file descriptor was available in outfp %p\n", outfp);
delete(ret);
return NULL;
}
int termerr;
if(setupterm(termtype, ttyfd, &termerr) != OK){
fprintf(stderr, "Terminfo error %d (see terminfo(3ncurses))\n", termerr);
delete(ret);
return NULL;
}
if(interrogate_terminfo(&ret->tcache)){
delete(ret);
return NULL;
}
// we don't need a controlling tty for everything we do; allow a failure here
ret->ctermfd = get_controlling_tty();
ret->fgdefault = ret->bgdefault = true;
ret->fgrgb = ret->bgrgb = 0;
ncdirect_styles_set(ret, 0);
const char* encoding = nl_langinfo(CODESET);
if(encoding && strcmp(encoding, "UTF-8") == 0){
ret->utf8 = true;
}else if(encoding && strcmp(encoding, "ANSI_X3.4-1968") == 0){
ret->utf8 = false;
}
return ret;
}

int ncdirect_stop(ncdirect* nc){
int ret = 0;
if(nc){
if(nc->tcache.op && term_emit("op", nc->tcache.op, nc->ttyfp, true)){
ret = -1;
}
if(nc->tcache.sgr0 && term_emit("sgr0", nc->tcache.sgr0, nc->ttyfp, true)){
ret = -1;
}
if(nc->tcache.oc && term_emit("oc", nc->tcache.oc, nc->ttyfp, true)){
ret = -1;
}
if(nc->ctermfd >= 0){
ret |= close(nc->ctermfd);
}
delete(nc);
}
return ret;
}

8 changes: 6 additions & 2 deletions src/lib/internal.h
Expand Up @@ -268,9 +268,10 @@ typedef struct tinfo {
typedef struct ncdirect {
int attrword; // current styles
palette256 palette; // 256-indexed palette can be used instead of/with RGB
FILE* ttyfp; // FILE* for controlling tty
FILE* ttyfp; // FILE* for output tty
int ctermfd; // fd for controlling terminal
tinfo tcache; // terminfo cache
uint16_t fgrgb, bgrgb; // last RGB values of foreground/background
unsigned fgrgb, bgrgb; // last RGB values of foreground/background
bool fgdefault, bgdefault; // are FG/BG currently using default colors?
bool utf8; // are we using utf-8 encoding, as hoped?
} ncdirect;
Expand Down Expand Up @@ -781,6 +782,9 @@ nc_err_e ncvisual_blit(struct ncvisual* ncv, int rows, int cols,

void nclog(const char* fmt, ...);

// get a file descriptor for the controlling tty device, -1 on error
int get_controlling_tty(void);

// logging
#define logerror(nc, fmt, ...) do{ \
if((nc)->loglevel >= NCLOGLEVEL_ERROR){ \
Expand Down
38 changes: 0 additions & 38 deletions src/lib/notcurses.c
Expand Up @@ -631,44 +631,6 @@ ffmpeg_log_level(ncloglevel_e level){
#endif
}

ncdirect* ncdirect_init(const char* termtype, FILE* outfp){
if(outfp == NULL){
outfp = stdout;
}
ncdirect* ret = malloc(sizeof(*ret));
if(ret == NULL){
return ret;
}
ret->ttyfp = outfp;
memset(&ret->palette, 0, sizeof(ret->palette));
int ttyfd = fileno(ret->ttyfp);
if(ttyfd < 0){
fprintf(stderr, "No file descriptor was available in outfp %p\n", outfp);
free(ret);
return NULL;
}
int termerr;
if(setupterm(termtype, ttyfd, &termerr) != OK){
fprintf(stderr, "Terminfo error %d (see terminfo(3ncurses))\n", termerr);
free(ret);
return NULL;
}
if(interrogate_terminfo(&ret->tcache)){
free(ret);
return NULL;
}
ret->fgdefault = ret->bgdefault = true;
ret->fgrgb = ret->bgrgb = 0;
ncdirect_styles_set(ret, 0);
const char* encoding = nl_langinfo(CODESET);
if(encoding && strcmp(encoding, "UTF-8") == 0){
ret->utf8 = true;
}else if(encoding && strcmp(encoding, "ANSI_X3.4-1968") == 0){
ret->utf8 = false;
}
return ret;
}

// unless the suppress_banner flag was set, print some version information and
// (if applicable) warnings to stdout. we are not yet on the alternate screen.
static void
Expand Down

0 comments on commit 93ff1d7

Please sign in to comment.