start merging in the fauxmemstream branch #1977

pull/1978/head
nick black 3 years ago
parent cac96c1a61
commit 24d7d6d995
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -27,7 +27,7 @@ Only applies to multiframe media such as video and animated images. Not supporte
the "press any key to continue" prompt will not be displayed. **seconds** may
be any non-negative number.
**-l** ***loglevel***: Log between everything (loglevel 8) and nothing (loglevel 0) to stderr.
**-l** ***loglevel***: Log between everything (loglevel 7) and nothing (loglevel 0) to stderr.
**-s** ***scalemode***: Scaling mode, one of **none**, **hires**, **scale**, **scalehi**, or **stretch**.

@ -57,7 +57,7 @@ terminal, and will refuse to run in anything smaller than 80x24.
**-d** ***delaymult***: Apply a non-negative rational multiplier to the standard delay of 1s.
**-l** ***loglevel***: Log between everything (loglevel 8) and nothing (loglevel 0) to stderr.
**-l** ***loglevel***: Log between everything (loglevel 7) and nothing (loglevel 0) to stderr.
**-f** ***renderfile***: Render each frame to ***renderfile*** in addition to the screen.

@ -824,17 +824,18 @@ nccell_load_egc32(struct ncplane* n, nccell* c, uint32_t egc){
// 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
// which we're rendering, any kind of logging will disrupt the output.
// which we're rendering, any kind of logging will disrupt the output (which is
// undesirable). The "default" zero value is NCLOGLEVEL_PANIC.
typedef enum {
NCLOGLEVEL_SILENT, // default. print nothing once fullscreen service begins
NCLOGLEVEL_PANIC, // print diagnostics immediately related to crashing
NCLOGLEVEL_FATAL, // we're hanging around, but we've had a horrible fault
NCLOGLEVEL_ERROR, // we can't keep doing this, but we can do other things
NCLOGLEVEL_WARNING, // you probably don't want what's happening to happen
NCLOGLEVEL_INFO, // "standard information"
NCLOGLEVEL_VERBOSE, // "detailed information"
NCLOGLEVEL_DEBUG, // this is honestly a bit much
NCLOGLEVEL_TRACE, // there's probably a better way to do what you want
NCLOGLEVEL_SILENT = -1,// default. print nothing once fullscreen service begins
NCLOGLEVEL_PANIC = 0, // print diagnostics related to catastrophic failure
NCLOGLEVEL_FATAL = 1, // we're hanging around, but we've had a horrible fault
NCLOGLEVEL_ERROR = 2, // we can't keep doing this, but we can do other things
NCLOGLEVEL_WARNING = 3,// you probably don't want what's happening to happen
NCLOGLEVEL_INFO = 4, // "standard information"
NCLOGLEVEL_VERBOSE = 5,// "detailed information"
NCLOGLEVEL_DEBUG = 6, // this is honestly a bit much
NCLOGLEVEL_TRACE = 7, // there's probably a better way to do what you want
} ncloglevel_e;
// Bits for notcurses_options->flags.

@ -88,7 +88,7 @@ shuffle_in(struct ncplane** arr, int count, struct ncplane* n){
}
arr = tmp;
// location of new element
int pos = random() % (count + 1);
int pos = rand() % (count + 1);
if(pos < count){
// move everything, starting at our new location, one spot right
memmove(arr + pos + 1, arr + pos, sizeof(*arr) * (count - pos));

@ -424,7 +424,7 @@ tinfo_debug_styles(const notcurses* nc, struct ncplane* n, const char* indent){
tinfo_debug_style(n, "struck", NCSTYLE_STRUCK, ' ');
tinfo_debug_style(n, "ucurl", NCSTYLE_UNDERCURL, ' ');
tinfo_debug_style(n, "uline", NCSTYLE_UNDERLINE, ' ');
tinfo_debug_cap(n, "u7", get_escape(ti, ESCAPE_DSRCPR), ' ');
tinfo_debug_cap(n, "u7", get_escape(ti, ESCAPE_U7), ' ');
tinfo_debug_cap(n, "ccc", ti->caps.can_change_colors, ' ');
tinfo_debug_cap(n, "rgb", ti->caps.rgb, ' ');
finish_line(n);

@ -255,7 +255,7 @@ cursor_yx_get(int ttyfd, const char* u7, int* y, int* x){
int ncdirect_cursor_move_yx(ncdirect* n, int y, int x){
const char* hpa = get_escape(&n->tcache, ESCAPE_HPA);
const char* vpa = get_escape(&n->tcache, ESCAPE_VPA);
const char* u7 = get_escape(&n->tcache, ESCAPE_DSRCPR);
const char* u7 = get_escape(&n->tcache, ESCAPE_U7);
if(y == -1){ // keep row the same, horizontal move only
if(hpa){
return term_emit(tiparm(hpa, x), n->ttyfp, false);
@ -410,7 +410,7 @@ int ncdirect_cursor_yx(ncdirect* n, int* y, int* x){
if(n->ctermfd < 0){
return -1;
}
const char* u7 = get_escape(&n->tcache, ESCAPE_DSRCPR);
const char* u7 = get_escape(&n->tcache, ESCAPE_U7);
if(u7 == NULL){
fprintf(stderr, "Terminal doesn't support cursor reporting\n");
return -1;
@ -1411,7 +1411,7 @@ const nccapabilities* ncdirect_capabilities(const ncdirect* n){
}
bool ncdirect_canget_cursor(const ncdirect* n){
if(get_escape(&n->tcache, ESCAPE_DSRCPR) == NULL){
if(get_escape(&n->tcache, ESCAPE_U7) == NULL){
return false;
}
if(n->ctermfd < 0){

@ -0,0 +1,267 @@
#ifndef NOTCURSES_FBUF
#define NOTCURSES_FBUF
#ifdef __cplusplus
extern "C" {
#endif
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include "compat/compat.h"
// a growable buffer into which one can perform formatted i/o, like the
// ten thousand that came before it, and the ten trillion which shall
// come after. uses mmap (with huge pages, if possible) on unix and
// virtualalloc on windows. it can grow arbitrarily large. it does
// *not* maintain a NUL terminator, and can hold binary data.
// on Windows, we're using VirtualAlloc(). on BSD, we're using realloc().
// on Linux, we're using mmap()+mremap().
typedef struct fbuf {
uint64_t size;
uint64_t used;
char* buf;
} fbuf;
// header-only so that we can test it from notcurses-tester
static inline char*
fbuf_at(fbuf* f, uint64_t at){
if(at > f->used){
return NULL;
}
return f->buf + at;
}
#ifdef MAP_POPULATE
#ifdef MAP_UNINITIALIZED
#define MAPFLAGS (MAP_POPULATE | MAP_UNINITIALIZED)
#else
#define MAPFLAGS MAP_POPULATE
#endif
#else
#ifdef MAP_UNINITIALIZED
#define MAPFLAGS MAP_UNINITIALIZED
#else
#define MAPFLAGS 0
#endif
#endif
// ensure there is sufficient room to add |n| bytes to |f|. if necessary,
// enlarge the buffer, which might move it (invalidating any references
// therein). the amount added is based on the current size (and |n|). we
// never grow larger than SIZE_MAX / 2.
static inline int
fbuf_grow(fbuf* f, size_t n){
assert(NULL != f->buf);
assert(0 != f->size);
size_t size = f->size;
if(size - f->used >= n){
return 0; // we have enough space
}
while(SIZE_MAX / 2 >= size){
size *= 2;
if(size - f->used < n){
continue;
}
void* tmp;
#ifdef __linux__
tmp = mremap(f->buf, f->size, size, MREMAP_MAYMOVE);
if(tmp == MAP_FAILED){
return -1;
}
#else
tmp = realloc(f->buf, f->size);
if(tmp == NULL){
return -1;
}
#endif
f->buf = (char*)tmp; // cast for c++ callers
f->size = size;
return 0;
}
// n (or our current buffer) is too large
return -1;
}
// prepare (a significant amount of) initial space for the fbuf.
// pass 1 for |small| if it ought be...small.
static inline int
fbuf_initgrow(fbuf* f, unsigned small){
assert(NULL == f->buf);
assert(0 == f->used);
assert(0 == f->size);
// we start with 2MiB, the huge page size on all of x86+PAE,
// ARMv7+LPAE, ARMv8, and x86-64.
// FIXME use GetLargePageMinimum() and sysconf
size_t size = small ? (4096 > BUFSIZ ? 4096 : BUFSIZ) : 0x200000lu;
#if defined(__linux__)
static bool hugepages_failed = false; // FIXME atomic
if(!hugepages_failed && !small){
// mmap(2): hugetlb results in automatic stretch out to cover hugepage
f->buf = (char*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_HUGETLB |
MAP_PRIVATE | MAP_ANONYMOUS | MAPFLAGS , -1, 0);
if(f->buf == MAP_FAILED){
hugepages_failed = true;
f->buf = NULL;
}
}
if(f->buf == NULL){ // try again without MAP_HUGETLB
f->buf = (char*)mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAPFLAGS , -1, 0);
}
if(f->buf == MAP_FAILED){
f->buf = NULL;
return -1;
}
#else
f->buf = (char*)malloc(size);
if(f->buf == NULL){
return -1;
}
#endif
f->size = size;
return 0;
}
#undef MAPFLAGS
// prepare f with a small initial buffer.
static inline int
fbuf_init_small(fbuf* f){
f->used = 0;
f->size = 0;
f->buf = NULL;
return fbuf_initgrow(f, 1);
}
// prepare f with a large initial buffer.
static inline int
fbuf_init(fbuf* f){
f->used = 0;
f->size = 0;
f->buf = NULL;
return fbuf_initgrow(f, 0);
}
// reset usage, but don't shrink the buffer or anything
static inline void
fbuf_reset(fbuf* f){
f->used = 0;
}
static inline int
fbuf_putc(fbuf* f, char c){
if(fbuf_grow(f, 1)){
return -1;
}
*fbuf_at(f, f->used++) = c;
return 1;
}
static inline int
fbuf_putn(fbuf* f, const char* s, size_t len){
if(fbuf_grow(f, len)){
return -1;
}
memcpy(f->buf + f->used, s, len);
f->used += len;
return len;
}
static inline int
fbuf_puts(fbuf* f, const char* s){
size_t slen = strlen(s);
return fbuf_putn(f, s, slen);
}
static inline int
fbuf_putint(fbuf* f, int n){
if(fbuf_grow(f, 10)){ // 32-bit int might require up to 10 digits
return -1;
}
uint64_t r = snprintf(f->buf + f->used, f->size - f->used, "%d", n);
if(r > f->size - f->used){
assert(r <= f->size - f->used);
return -1; // FIXME grow?
}
f->used += r;
return r;
}
// FIXME eliminate this, ideally
__attribute__ ((format (printf, 2, 3)))
static inline int
fbuf_printf(fbuf* f, const char* fmt, ...){
if(fbuf_grow(f, BUFSIZ) < 0){
return -1;
}
va_list va;
va_start(va, fmt);
int r = vsnprintf(f->buf + f->used, f->size - f->used, fmt, va);
va_end(va);
if((size_t)r >= f->size - f->used){
return -1;
}
assert(r >= 0);
f->used += r;
return r;
}
// emit an escape; obviously you can't flush here
static inline int
fbuf_emit(fbuf* f, const char* esc){
if(!esc){
return -1;
}
if(fbuf_puts(f, esc) < 0){
//logerror("error emitting escape (%s)\n", strerror(errno));
return -1;
}
return 0;
}
// releases the resources held by f. f itself is not freed.
static inline void
fbuf_free(fbuf* f){
if(f){
// logdebug("Releasing from %" PRIu32 "B (%" PRIu32 "B)\n", f->size, f->used);
if(f->buf){
#if __linux__
if(munmap(f->buf, f->size)){
//logwarn("Error unmapping alloc (%s)\n", strerror(errno));
}
#else
free(f->buf);
#endif
f->buf = NULL;
}
f->size = 0;
f->used = 0;
}
}
// attempt to write the contents of |f| to the FILE |fp|, if there are any
// contents, and free the fbuf either way. if |flushfp| is set, fflush(fp).
static inline int
fbuf_finalize(fbuf* f, FILE* fp, bool flushfp){
int ret = 0;
if(f->used){
if(fwrite(f->buf, f->used, 1, fp) != 1){
ret = -1;
}
}
if(flushfp && ret == 0 && fflush(fp) == EOF){
ret = -1;
}
fbuf_free(f);
return ret;
}
#ifdef __cplusplus
}
#endif
#endif

@ -33,6 +33,7 @@ typedef enum {
TERMINAL_ITERM, // XTVERSION == 'iTerm2 [ver]'
TERMINAL_TERMINOLOGY, // TDA: "~~TY"
TERMINAL_APPLE, // Terminal.App, determined by TERM_PROGRAM + macOS
TERMINAL_MSTERMINAL, // Microsoft Windows Terminal
} queried_terminals_e;
// sets up the input layer, building a trie of escape sequences and their

@ -261,41 +261,6 @@ compare_versions(const char* restrict v1, const char* restrict v2){
return 0;
}
// tlen -- size of escape table. tused -- used bytes in same.
// returns -1 if the starting location is >= 65535. otherwise,
// copies tstr into the table, and sets up 1-biased index.
static int
grow_esc_table(tinfo* ti, const char* tstr, escape_e esc,
size_t* tlen, size_t* tused){
// the actual table can grow past 64KB, but we can't start there, as
// we only have 16-bit indices.
if(*tused >= 65535){
fprintf(stderr, "Can't add escape %d to full table\n", esc);
return -1;
}
if(get_escape(ti, esc)){
fprintf(stderr, "Already defined escape %d (%s)\n",
esc, get_escape(ti, esc));
return -1;
}
size_t slen = strlen(tstr) + 1; // count the nul term
if(*tlen - *tused < slen){
// guaranteed to give us enough space to add tstr (and then some)
size_t newsize = *tlen + 4020 + slen; // don't pull two pages ideally
char* tmp = realloc(ti->esctable, newsize);
if(tmp == NULL){
return -1;
}
ti->esctable = tmp;
*tlen = newsize;
}
// we now are guaranteed sufficient space to copy tstr
memcpy(ti->esctable + *tused, tstr, slen);
ti->escindices[esc] = *tused + 1; // one-bias
*tused += slen;
return 0;
}
// Tertiary Device Attributes, necessary to identify VTE.
// https://vt100.net/docs/vt510-rm/DA3.html
// Replies with DCS ! | ... ST
@ -408,11 +373,11 @@ init_terminfo_esc(tinfo* ti, const char* name, escape_e idx,
// terminal supports it, hah.
static int
add_u7_escape(tinfo* ti, size_t* tablelen, size_t* tableused){
const char* u7 = get_escape(ti, ESCAPE_DSRCPR);
const char* u7 = get_escape(ti, ESCAPE_U7);
if(u7){
return 0; // already present
}
if(grow_esc_table(ti, DSRCPR, ESCAPE_DSRCPR, tablelen, tableused)){
if(grow_esc_table(ti, DSRCPR, ESCAPE_U7, tablelen, tableused)){
return -1;
}
return 0;
@ -777,7 +742,7 @@ int interrogate_terminfo(tinfo* ti, int fd, const char* termname, unsigned utf8,
{ ESCAPE_CLEAR, "clear", },
{ ESCAPE_OC, "oc", },
{ ESCAPE_RMKX, "rmkx", },
{ ESCAPE_DSRCPR, "u7", },
{ ESCAPE_U7, "u7", },
{ ESCAPE_MAX, NULL, },
};
size_t tablelen = 0;
@ -942,7 +907,7 @@ locate_cursor_simple(int fd, const char* u7, int* cursor_y, int* cursor_x){
// is valid, we can just camp there. otherwise, we need dance with potential
// user input looking at infd.
int locate_cursor(tinfo* ti, int* cursor_y, int* cursor_x){
const char* u7 = get_escape(ti, ESCAPE_DSRCPR);
const char* u7 = get_escape(ti, ESCAPE_U7);
if(u7 == NULL){
logwarn("No support in terminfo\n");
return -1;

@ -29,42 +29,42 @@ struct ncsharedstats;
// indexes into the table of fixed-width (16-bit) indices
typedef enum {
ESCAPE_CUP, // "cup" move cursor to absolute x, y position
ESCAPE_HPA, // "hpa" move cursor to absolute horizontal position
ESCAPE_VPA, // "vpa" move cursor to absolute vertical position
ESCAPE_SETAF, // "setaf" set foreground color
ESCAPE_SETAB, // "setab" set background color
ESCAPE_OP, // "op" set foreground and background color to defaults
ESCAPE_FGOP, // set foreground only to default
ESCAPE_BGOP, // set background only to default
ESCAPE_SGR0, // "sgr0" turn off all styles
ESCAPE_CIVIS, // "civis" make the cursor invisiable
ESCAPE_CNORM, // "cnorm" restore the cursor to normal
ESCAPE_OC, // "oc" restore original colors
ESCAPE_SITM, // "sitm" start italics
ESCAPE_RITM, // "ritm" end italics
ESCAPE_CUU, // "cuu" move n cells up
ESCAPE_CUB, // "cub" move n cells back (left)
ESCAPE_CUF, // "cuf" move n cells forward (right)
ESCAPE_BOLD, // "bold" enter bold mode
ESCAPE_NOBOLD, // disable bold (ANSI but not terminfo, SGR 22)
ESCAPE_CUD, // "cud" move n cells down
ESCAPE_SMKX, // "smkx" keypad_xmit (keypad transmit mode)
ESCAPE_RMKX, // "rmkx" keypad_local
ESCAPE_SMCUP, // "smcup" enter alternate screen
ESCAPE_RMCUP, // "rmcup" leave alternate screen
ESCAPE_SMXX, // "smxx" start struckout
ESCAPE_SMUL, // "smul" start underline
ESCAPE_RMUL, // "rmul" end underline
ESCAPE_SMULX, // "Smulx" deparameterized: start extended underline
ESCAPE_SMULNOX, // "Smulx" deparameterized: kill underline
ESCAPE_RMXX, // "rmxx" end struckout
ESCAPE_SC, // "sc" push the cursor onto the stack
ESCAPE_RC, // "rc" pop the cursor off the stack
ESCAPE_CLEAR, // "clear" clear screen and home cursor
ESCAPE_INITC, // "initc" set up palette entry
ESCAPE_GETM, // "getm" get mouse events
ESCAPE_DSRCPR, // "u7" cursor position report
ESCAPE_CUP, // "cup" move cursor to absolute x, y position
ESCAPE_HPA, // "hpa" move cursor to absolute horizontal position
ESCAPE_VPA, // "vpa" move cursor to absolute vertical position
ESCAPE_SETAF, // "setaf" set foreground color
ESCAPE_SETAB, // "setab" set background color
ESCAPE_OP, // "op" set foreground and background color to defaults
ESCAPE_FGOP, // set foreground only to default
ESCAPE_BGOP, // set background only to default
ESCAPE_SGR0, // "sgr0" turn off all styles
ESCAPE_CIVIS, // "civis" make the cursor invisiable
ESCAPE_CNORM, // "cnorm" restore the cursor to normal
ESCAPE_OC, // "oc" restore original colors
ESCAPE_SITM, // "sitm" start italics
ESCAPE_RITM, // "ritm" end italics
ESCAPE_CUU, // "cuu" move n cells up
ESCAPE_CUB, // "cub" move n cells back (left)
ESCAPE_CUF, // "cuf" move n cells forward (right)
ESCAPE_BOLD, // "bold" enter bold mode
ESCAPE_NOBOLD, // disable bold (ANSI but not terminfo, SGR 22)
ESCAPE_CUD, // "cud" move n cells down
ESCAPE_SMKX, // "smkx" keypad_xmit (keypad transmit mode)
ESCAPE_RMKX, // "rmkx" keypad_local
ESCAPE_SMCUP, // "smcup" enter alternate screen
ESCAPE_RMCUP, // "rmcup" leave alternate screen
ESCAPE_SMXX, // "smxx" start struckout
ESCAPE_SMUL, // "smul" start underline
ESCAPE_RMUL, // "rmul" end underline
ESCAPE_SMULX, // "Smulx" deparameterized: start extended underline
ESCAPE_SMULNOX, // "Smulx" deparameterized: kill underline
ESCAPE_RMXX, // "rmxx" end struckout
ESCAPE_SC, // "sc" push the cursor onto the stack
ESCAPE_RC, // "rc" pop the cursor off the stack
ESCAPE_CLEAR, // "clear" clear screen and home cursor
ESCAPE_INITC, // "initc" set up palette entry
ESCAPE_GETM, // "getm" get mouse events
ESCAPE_U7, // "u7" cursor position report
// Application synchronized updates, not present in terminfo
// (https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec)
ESCAPE_BSUM, // Begin Synchronized Update Mode
@ -231,6 +231,41 @@ char* termdesc_longterm(const tinfo* ti);
int locate_cursor(tinfo* ti, int* cursor_y, int* cursor_x);
// tlen -- size of escape table. tused -- used bytes in same.
// returns -1 if the starting location is >= 65535. otherwise,
// copies tstr into the table, and sets up 1-biased index.
static inline int
grow_esc_table(tinfo* ti, const char* tstr, escape_e esc,
size_t* tlen, size_t* tused){
// the actual table can grow past 64KB, but we can't start there, as
// we only have 16-bit indices.
if(*tused >= 65535){
fprintf(stderr, "Can't add escape %d to full table\n", esc);
return -1;
}
if(get_escape(ti, esc)){
fprintf(stderr, "Already defined escape %d (%s)\n",
esc, get_escape(ti, esc));
return -1;
}
size_t slen = strlen(tstr) + 1; // count the nul term
if(*tlen - *tused < slen){
// guaranteed to give us enough space to add tstr (and then some)
size_t newsize = *tlen + 4020 + slen; // don't pull two pages ideally
char* tmp = (char*)realloc(ti->esctable, newsize); // cast for c++
if(tmp == NULL){
return -1;
}
ti->esctable = tmp;
*tlen = newsize;
}
// we now are guaranteed sufficient space to copy tstr
memcpy(ti->esctable + *tused, tstr, slen);
ti->escindices[esc] = *tused + 1; // one-bias
*tused += slen;
return 0;
}
#ifdef __cplusplus
}
#endif

@ -0,0 +1,37 @@
#include "termdesc.h"
#include "internal.h"
#include "windows.h"
// ti has been memset to all zeroes. windows configuration is static.
int prepare_windows_terminal(tinfo* ti, size_t* tablelen, size_t* tableused){
const struct wtermdesc {
escape_e esc;
const char* tinfo;
} wterms[] = {
{ ESCAPE_CUP, "\x1b[%i%p1%d;%p2%dH", },
{ ESCAPE_RMKX, "\x1b[?1l", },
{ ESCAPE_SMKX, "\x1b[?1h", },
{ ESCAPE_VPA, "\x1b[%i%p1%dd", },
{ ESCAPE_HPA, "\x1b[%i%p1%dG", },
{ ESCAPE_SC, "\x1b[s", },
{ ESCAPE_RC, "\x1b[u", },
{ ESCAPE_CLEAR, "\x1b[2J", },
{ ESCAPE_SMCUP, "\x1b[?1049h", },
{ ESCAPE_RMCUP, "\x1b[?1049l", },
{ ESCAPE_SETAF, "\x1b[38;5;%i%p1%dm", },
{ ESCAPE_SETAB, "\x1b[48;5;%i%p1%dm", },
{ ESCAPE_OP, "\x1b[39;49m", },
{ ESCAPE_CIVIS, "\x1b[?25l", },
{ ESCAPE_CNORM, "\x1b[?25h", },
{ ESCAPE_U7, "\x1b[6n", },
{ ESCAPE_MAX, NULL, }
}, *w;
for(w = wterms ; w->tinfo; ++w){
if(grow_esc_table(ti, w->tinfo, w->esc, tablelen, tableused)){
return -1;
}
}
ti->caps.rgb = true;
ti->caps.colors = 256;
return 0;
}

@ -0,0 +1,18 @@
#ifndef NOTCURSES_WINDOWS
#define NOTCURSES_WINDOWS
#ifdef __cplusplus
extern "C" {
#endif
struct tinfo;
// ti has been memset to all zeroes. windows configuration is static.
int prepare_windows_terminal(struct tinfo* ti, size_t* tablelen,
size_t* tableused);
#ifdef __cplusplus
}
#endif
#endif

@ -27,7 +27,7 @@ void usage(std::ostream& o, const char* name, int exitcode){
o << " -k: use direct mode (cannot be used with -L or -d)\n";
o << " -L: loop frames\n";
o << " -t seconds: delay t seconds after each file\n";
o << " -l loglevel: integer between 0 and 8, goes to stderr'\n";
o << " -l loglevel: integer between 0 and 7, goes to stderr'\n";
o << " -s scaling: one of 'none', 'hires', 'scale', 'scalehi', or 'stretch'\n";
o << " -b blitter: one of 'ascii', 'half', 'quad', 'sex', 'braille', or 'pixel'\n";
o << " -m margins: margin, or 4 comma-separated margins\n";
@ -259,11 +259,11 @@ auto handle_opts(int argc, char** argv, notcurses_options& opts, bool* quiet,
int ll;
ss >> ll;
if(ll < NCLogLevel::Silent || ll > NCLogLevel::Trace){
std::cerr << "Invalid log level [" << optarg << "] (wanted [0..8])\n";
std::cerr << "Invalid log level [" << optarg << "] (wanted [-1..7])\n";
usage(std::cerr, argv[0], EXIT_FAILURE);
}
if(ll == 0 && strcmp(optarg, "0")){
std::cerr << "Invalid log level [" << optarg << "] (wanted [0..8])\n";
std::cerr << "Invalid log level [" << optarg << "] (wanted [-1..7])\n";
usage(std::cerr, argv[0], EXIT_FAILURE);
}
opts.loglevel = static_cast<ncloglevel_e>(ll);
@ -486,11 +486,6 @@ auto main(int argc, char** argv) -> int {
std::cerr << "Couldn't set locale based off LANG\n";
return EXIT_FAILURE;
}
sigset_t sigmask;
// ensure SIGWINCH is delivered only to a thread doing input
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGWINCH);
pthread_sigmask(SIG_BLOCK, &sigmask, NULL);
float timescale, displaytime;
ncscale_e scalemode;
notcurses_options ncopts{};

@ -6,6 +6,9 @@ int main(void){
.flags = NCOPTION_NO_ALTERNATE_SCREEN | NCOPTION_SUPPRESS_BANNERS,
};
struct notcurses* nc = notcurses_core_init(&nops, NULL);
if(nc == NULL){
return EXIT_FAILURE;
}
struct ncplane* n = notcurses_stdplane(nc);
const int y = 10;
ncplane_putstr_aligned(n, y + 0, NCALIGN_CENTER, "Pack my box with five dozen liquor jugs.");

@ -0,0 +1,84 @@
#include "main.h"
#include "fbuf.h"
TEST_CASE("Fbuf") {
auto nc_ = testing_notcurses();
if(!nc_){
return;
}
int dimy, dimx;
struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx);
REQUIRE(n_);
REQUIRE(0 == ncplane_cursor_move_yx(n_, 0, 0));
// check that upon successful initialization, we have some space
SUBCASE("FbufInit") {
fbuf f{};
CHECK(0 == fbuf_init(&f));
CHECK(0 < f.size);
CHECK(0 == f.used);
CHECK(nullptr != f.buf);
fbuf_free(&f);
}
// fill the fbuf a character at a time
SUBCASE("FbufPutcCover") {
fbuf f{};
CHECK(0 == fbuf_init(&f));
CHECK(0 < f.size);
CHECK(0 == f.used);
CHECK(nullptr != f.buf);
auto oldsize = f.size;
for(size_t s = 0 ; s < oldsize ; ++s){
CHECK(1 == fbuf_putc(&f, 'X'));
}
CHECK(f.used == oldsize);
CHECK(oldsize <= f.size);
fbuf_free(&f);
}
// fill the fbuf with one large write
SUBCASE("FbufPutsCover") {
fbuf f{};
CHECK(0 == fbuf_init(&f));
CHECK(0 < f.size);
CHECK(0 == f.used);
CHECK(nullptr != f.buf);
auto oldsize = f.size;
auto erp = new char[oldsize + 1];
memset(erp, 'X', oldsize);
erp[oldsize] = '\0';
CHECK(oldsize == fbuf_puts(&f, erp));
delete[] erp;
CHECK(f.used == oldsize);
CHECK(oldsize <= f.size);
fbuf_free(&f);
}
// fill the fbuf with random writes
SUBCASE("FbufPutsCover") {
fbuf f{};
CHECK(0 == fbuf_init(&f));
CHECK(0 < f.size);
CHECK(0 == f.used);
CHECK(nullptr != f.buf);
auto oldsize = f.size;
auto erp = new char[oldsize + 1];
size_t used = 0;
while(used < oldsize){
size_t oldused = f.used;
size_t towrite = rand() % (oldsize - used) + 1;
memset(erp, rand() % 26 + 'A', towrite);
erp[towrite] = '\0';
CHECK(towrite == fbuf_puts(&f, erp));
CHECK(f.used == oldused + towrite);
used += towrite;
}
delete[] erp;
CHECK(f.used == oldsize);
CHECK(oldsize <= f.size);
fbuf_free(&f);
}
CHECK(0 == notcurses_stop(nc_));
}
Loading…
Cancel
Save