diff --git a/CMakeLists.txt b/CMakeLists.txt index 412e7d4e8..3785dd223 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,8 +128,8 @@ add_compile_options(-fno-signed-zeros -fno-trapping-math -fassociative-math) add_compile_options(-fno-math-errno -freciprocal-math -funsafe-math-optimizations) add_compile_options(-fexceptions -fstrict-aliasing) if(${USE_ASAN}) -add_compile_options(-fsanitize=undefined) -add_link_options(-fsanitize=undefined) +add_compile_options(-fsanitize=address) +add_link_options(-fsanitize=address) endif() endif() diff --git a/NEWS.md b/NEWS.md index d07c9b8f6..f3f36901a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,8 +12,11 @@ rearrangements of Notcurses. deprecated functionality, ABI3 ought require small changes, if any. * 2.4.9 (not yet released) + * Added `ncnmetric()`, which uses `snprintf()` internally. `ncmetric()` + was reimplemented as a trivial wrapper around `ncnmetric()`. * `qprefix()`, `bprefix()`, and `iprefix()` have been renamed `ncqprefix()`, `ncbprefix()`, and `nciprefix()`, respectively. + The former forms have been deprecated, and will be removed in abi3. * `notcurses_mice_enable()` and `notcurses_mouse_disable()` replace `notcurses_mouse_enable()` and `notcurses_mouse_disable()`, which have been deprecated, and will be removed in ABI3. diff --git a/USAGE.md b/USAGE.md index a9e6ebcbf..4ddfc8007 100644 --- a/USAGE.md +++ b/USAGE.md @@ -451,7 +451,7 @@ are available for direct mode: // Read a (heap-allocated) newline-delimited chunk of text. Returns NULL on // failure. The NCDIRECT_OPTION_INHIBIT_CBREAK flag ought not be used together // with this function, or the line-editing keybindings cannot be honored. -API char* ncdirect_readline(struct ncdirect* nc, const char* prompt); +char* ncdirect_readline(struct ncdirect* nc, const char* prompt); int ncdirect_fg_rgb(struct ncdirect* nc, unsigned rgb); int ncdirect_bg_rgb(struct ncdirect* nc, unsigned rgb); @@ -1674,8 +1674,8 @@ int ncplane_gradient2x1(struct ncplane* n, int y, int x, unsigned ylen, // remaining to the right and below, respectively. It is an error for any // coordinate to be outside the plane. Returns the number of cells set, // or -1 on failure. -API int ncplane_format(struct ncplane* n, int y, int x, unsigned ylen, - unsigned xlen, uint16_t stylemask); +int ncplane_format(struct ncplane* n, int y, int x, unsigned ylen, + unsigned xlen, uint16_t stylemask); // Set the given channels throughout the specified region, keeping content and // channels unchanged. The upper left corner is at 'x', 'y', and -1 may be @@ -1684,9 +1684,9 @@ API int ncplane_format(struct ncplane* n, int y, int x, unsigned ylen, // remaining to the right and below, respectively. It is an error for any // coordinate to be outside the plane. Returns the number of cells set, // or -1 on failure. -API int ncplane_stain(struct ncplane* n, int y, int x, unsigned ylen, - unsigned xlen, uint64_t ul, uint64_t ur, - uint64_t ll, uint64_t lr); +int ncplane_stain(struct ncplane* n, int y, int x, unsigned ylen, + unsigned xlen, uint64_t ul, uint64_t ur, + uint64_t ll, uint64_t lr); ``` My 14 year-old self would never forgive me if we didn't have sweet palette diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 2edd80f30..d4eb69c7b 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -1807,7 +1807,7 @@ API void ncplane_center_abs(const struct ncplane* n, int* RESTRICT y, // Only glyphs from the specified ncblitset may be present. If 'pxdimy' and/or // 'pxdimx' are non-NULL, they will be filled in with the total pixel geometry. API ALLOC uint32_t* ncplane_as_rgba(const struct ncplane* n, ncblitter_e blit, - unsigned begy, unsigned begx, + int begy, int begx, unsigned leny, unsigned lenx, unsigned* pxdimy, unsigned* pxdimx) __attribute__ ((nonnull (1))); @@ -2869,7 +2869,7 @@ API ALLOC struct ncvisual* ncvisual_from_palidx(const void* data, int rows, // Lengths of 0 are interpreted to mean "all available remaining area". API ALLOC struct ncvisual* ncvisual_from_plane(const struct ncplane* n, ncblitter_e blit, - unsigned begy, unsigned begx, + int begy, int begx, unsigned leny, unsigned lenx) __attribute__ ((nonnull (1))); @@ -3366,6 +3366,12 @@ API const char* ncmetric(uintmax_t val, uintmax_t decimal, char* buf, int omitdec, uintmax_t mult, int uprefix) __attribute__ ((nonnull (3))); +// uses snprintf() internally with the argument 's' as its bound +API const char* ncnmetric(uintmax_t val, size_t s, uintmax_t decimal, + char* buf, int omitdec, uintmax_t mult, + int uprefix) + __attribute__ ((nonnull (4))); + // The number of columns is one fewer, as the STRLEN expressions must leave // an extra byte open in case 'µ' (U+00B5, 0xC2 0xB5) shows up. PREFIXCOLUMNS // is the maximum number of columns used by a mult == 1000 (standard) @@ -3672,17 +3678,17 @@ API ALLOC struct ncmenu* ncmenu_create(struct ncplane* n, const ncmenu_options* API int ncmenu_unroll(struct ncmenu* n, int sectionidx); // Roll up any unrolled menu section, and hide the menu if using hiding. -API int ncmenu_rollup(struct ncmenu* n); +API int ncmenu_rollup(struct ncmenu* n) __attribute__ ((nonnull (1))); // Unroll the previous/next section (relative to current unrolled). If no // section is unrolled, the first section will be unrolled. -API int ncmenu_nextsection(struct ncmenu* n); -API int ncmenu_prevsection(struct ncmenu* n); +API int ncmenu_nextsection(struct ncmenu* n) __attribute__ ((nonnull (1))); +API int ncmenu_prevsection(struct ncmenu* n) __attribute__ ((nonnull (1))); // Move to the previous/next item within the currently unrolled section. If no // section is unrolled, the first section will be unrolled. -API int ncmenu_nextitem(struct ncmenu* n); -API int ncmenu_previtem(struct ncmenu* n); +API int ncmenu_nextitem(struct ncmenu* n) __attribute__ ((nonnull (1))); +API int ncmenu_previtem(struct ncmenu* n) __attribute__ ((nonnull (1))); // Disable or enable a menu item. Returns 0 if the item was found. API int ncmenu_item_set_status(struct ncmenu* n, const char* section, @@ -4286,6 +4292,23 @@ API int ncplane_highgradient_sized(struct ncplane* n, uint32_t ul, uint32_t ur, uint32_t ll, uint32_t lr, int ylen, int xlen) __attribute__ ((deprecated)); +__attribute__ ((deprecated)) static inline const char* +qprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){ + return ncmetric(val, decimal, buf, omitdec, 1000, '\0'); +} + +// Mibi, kebi, gibibytes sans 'i' suffix. Use IPREFIXSTRLEN + 1. +__attribute__ ((deprecated)) static inline const char* +iprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){ + return ncmetric(val, decimal, buf, omitdec, 1024, '\0'); +} + +// Mibi, kebi, gibibytes. Use BPREFIXSTRLEN + 1 and BPREFIXCOLUMNS. +__attribute__ ((deprecated)) static inline const char* +bprefix(uintmax_t val, uintmax_t decimal, char* buf, int omitdec){ + return ncmetric(val, decimal, buf, omitdec, 1024, 'i'); +} + #undef API #undef ALLOC diff --git a/src/demo/hud.c b/src/demo/hud.c index b7ac2980e..2d1b908dd 100644 --- a/src/demo/hud.c +++ b/src/demo/hud.c @@ -392,13 +392,13 @@ hud_print_finished(elem* list){ if(ncplane_printf_yx(hud, line, 1, "%d", e->frames) < 0){ return -1; } - char buf[PREFIXCOLUMNS]; - ncmetric(e->totalns, NANOSECS_IN_SEC, buf, 0, 1000, '\0'); - for(size_t x = 6 ; x < 14 - strlen(buf) ; ++x){ + char buf[PREFIXCOLUMNS + 2]; + ncnmetric(e->totalns, sizeof(buf), NANOSECS_IN_SEC, buf, 0, 1000, '\0'); + for(int x = 6 ; x < 14 - ncstrwidth(buf) ; ++x){ nccell ci = CELL_TRIVIAL_INITIALIZER; ncplane_putc_yx(hud, 1, x, &ci); } - if(ncplane_printf_yx(hud, line, 14 - strlen(buf), "%ss", buf) < 0){ + if(ncplane_printf_yx(hud, line, 14 - ncstrwidth(buf), "%ss", buf) < 0){ return -1; } if(ncplane_putstr_yx(hud, line, 16, e->name) < 0){ @@ -612,13 +612,14 @@ int demo_render(struct notcurses* nc){ if(ncplane_printf_yx(hud, 1, 1, "%d", elems->frames) < 0){ return -1; } - char buf[PREFIXCOLUMNS]; - ncmetric(ns, NANOSECS_IN_SEC, buf, 0, 1000, '\0'); - for(size_t x = 6 ; x < 14 - strlen(buf) ; ++x){ + char buf[PREFIXCOLUMNS + 2]; + ncnmetric(ns, sizeof(buf), NANOSECS_IN_SEC, buf, 0, 1000, '\0'); + for(int x = 6 ; x < 14 - ncstrwidth(buf) ; ++x){ nccell ci = CELL_TRIVIAL_INITIALIZER; ncplane_putc_yx(hud, 1, x, &ci); } - if(ncplane_printf_yx(hud, 1, 14 - strlen(buf), "%ss", buf) < 0){ +//fprintf(stderr, "[%s] %zu %d\n", buf, strlen(buf), ncstrwidth(buf)); + if(ncplane_printf_yx(hud, 1, 14 - ncstrwidth(buf), "%ss", buf) < 0){ return -1; } if(ncplane_putstr_yx(hud, 1, 16, elems->name) < 0){ diff --git a/src/demo/intro.c b/src/demo/intro.c index 38819ccf5..487b847d5 100644 --- a/src/demo/intro.c +++ b/src/demo/intro.c @@ -124,7 +124,7 @@ int intro(struct notcurses* nc){ if(!notcurses_canutf8(nc)){ return 0; } - int rows, cols; + unsigned rows, cols; struct ncplane* ncp = notcurses_stddim_yx(nc, &rows, &cols); uint32_t ccul, ccur, ccll, cclr; ccul = ccur = ccll = cclr = 0; diff --git a/src/demo/luigi.c b/src/demo/luigi.c index ec13d2639..7a6bcdb11 100644 --- a/src/demo/luigi.c +++ b/src/demo/luigi.c @@ -146,7 +146,7 @@ int luigi_demo(struct notcurses* nc){ if(!notcurses_canopen_images(nc)){ return 0; } - int rows, cols; + unsigned rows, cols; char* map = find_data("megaman2.bmp"); struct ncvisual* nv = ncvisual_from_file(map); free(map); @@ -166,7 +166,7 @@ int luigi_demo(struct notcurses* nc){ const int height = 32; int yoff = rows * 4 / 5 - height + 1; // tuned struct ncplane* lns[3]; - int i; + unsigned i; struct ncplane* lastseen = NULL; for(i = 0 ; i < 3 ; ++i){ struct ncplane_options nopts = { diff --git a/src/demo/whiteout.c b/src/demo/whiteout.c index 451020324..88955a140 100644 --- a/src/demo/whiteout.c +++ b/src/demo/whiteout.c @@ -509,14 +509,14 @@ int witherworm_demo(struct notcurses* nc){ } int ulen = 0; int r; - //if(wcwidth(wcs) <= maxx - x){ + if(wcwidth(wcs) <= (int)maxx - x){ if((r = ncplane_putegc(n, &(*s)[idx], &ulen)) <= 0){ if(ulen < 0){ return -1; }else if(ulen == 0){ break; // FIXME work around missing unicode } - //} + } }else{ if((r = ncplane_putchar(n, '#')) < 1){ return -1; diff --git a/src/lib/fill.c b/src/lib/fill.c index fe124cb0c..6a935c093 100644 --- a/src/lib/fill.c +++ b/src/lib/fill.c @@ -20,50 +20,58 @@ void ncplane_greyscale(ncplane *n){ // success. so a return of 0 means there's no work to be done here, and N means // we did some work here, filling everything we could reach. out-of-plane is 0. static int -ncplane_polyfill_recurse(ncplane* n, unsigned y, unsigned x, const nccell* c, const char* filltarg){ - if(y >= (unsigned)n->leny || x >= (unsigned)n->lenx){ - return 0; // not fillable +ncplane_polyfill_inner(ncplane* n, unsigned y, unsigned x, const nccell* c, const char* filltarg){ + struct topolyfill* stack = NULL; + if(create_polyfill_op(y, x, &stack) == NULL){ + return -1; } - nccell* cur = &n->fb[nfbcellidx(n, y, x)]; - const char* glust = nccell_extended_gcluster(n, cur); + int ret = 0; + do{ + struct topolyfill* s = stack; + stack = stack->next; + y = s->y; + x = s->x; + nccell* cur = &n->fb[nfbcellidx(n, y, x)]; + const char* glust = nccell_extended_gcluster(n, cur); //fprintf(stderr, "checking %d/%d (%s) for [%s]\n", y, x, glust, filltarg); - if(strcmp(glust, filltarg)){ - return 0; - } - if(nccell_duplicate(n, cur, c) < 0){ - return -1; - } - int r, ret = 1; + if(strcmp(glust, filltarg) == 0){ + ++ret; + if(nccell_duplicate(n, cur, c) < 0){ + // FIXME need free stack! + return -1; + } //fprintf(stderr, "blooming from %d/%d ret: %d\n", y, x, ret); - if(y){ - if((r = ncplane_polyfill_recurse(n, y - 1, x, c, filltarg)) < 0){ - return -1; + if(y){ + if(create_polyfill_op(y - 1, x, &stack) == NULL){ + return -1; + } + } + if(y + 1 < n->leny){ + if(create_polyfill_op(y + 1, x, &stack) == NULL){ + return -1; + } + } + if(x){ + if(create_polyfill_op(y, x - 1, &stack) == NULL){ + return -1; + } + } + if(x + 1 < n->lenx){ + if(create_polyfill_op(y, x + 1, &stack) == NULL){ + return -1; + } + } } - ret += r; - } - if((r = ncplane_polyfill_recurse(n, y + 1, x, c, filltarg)) < 0){ - return -1; - } - ret += r; - if(x){ - if((r = ncplane_polyfill_recurse(n, y, x - 1, c, filltarg)) < 0){ - return -1; - } - ret += r; - } - if((r = ncplane_polyfill_recurse(n, y, x + 1, c, filltarg)) < 0){ - return -1; - } - ret += r; + free(s); + }while(stack); return ret; } // at the initial step only, invalid ystart, xstart is an error, so explicitly check. int ncplane_polyfill_yx(ncplane* n, int ystart, int xstart, const nccell* c){ - int ret = -1; if(ystart < 0){ if(ystart != -1){ - logerror("invalid ystart: %d\n", ystart); + logerror("invalid y: %d\n", ystart); return -1; } ystart = n->y; @@ -71,7 +79,7 @@ int ncplane_polyfill_yx(ncplane* n, int ystart, int xstart, const nccell* c){ unsigned y = ystart; if(xstart < 0){ if(xstart != -1){ - logerror("invalid xstart: %d\n", xstart); + logerror("invalid x: %d\n", xstart); return -1; } xstart = n->x; @@ -88,11 +96,12 @@ int ncplane_polyfill_yx(ncplane* n, int ystart, int xstart, const nccell* c){ if(strcmp(fillegc, targ) == 0){ return 0; } + int ret = -1; // we need an external copy of this, since we'll be writing to it on - // the first call into ncplane_polyfill_recurse() + // the first call into ncplane_polyfill_inner() char* targcopy = strdup(targ); if(targcopy){ - ret = ncplane_polyfill_recurse(n, y, x, c, targcopy); + ret = ncplane_polyfill_inner(n, y, x, c, targcopy); free(targcopy); } return ret; @@ -141,69 +150,6 @@ bool check_gradient_args(uint64_t ul, uint64_t ur, uint64_t bl, uint64_t br){ return false; } -// takes a signed starting coordinate (where -1 indicates the cursor's -// position), and an unsigned vector (where 0 indicates "everything -// remaining", i.e. to the right and below). returns 0 iff everything -// is valid and on the plane, filling in 'ystart'/'xstart' with the -// (non-negative) starting coordinates and 'ylen'/'xlen with the -// (positive) dimensions of the affected area. -static int -check_geometry_args(const ncplane* n, int y, int x, - unsigned* ylen, unsigned* xlen, - unsigned* ystart, unsigned* xstart){ - // handle the special -1 case for y/x, and reject other negatives - if(y < 0){ - if(y != -1){ - logerror("invalid y: %d\n", y); - return -1; - } - y = n->y; - } - if(x < 0){ - if(x != -1){ - logerror("invalid x: %d\n", x); - return -1; - } - x = n->x; - } - // y and x are both now definitely positive, but might be off-plane. - // lock in y and x as ystart and xstart for unsigned comparisons. - *ystart = y; - *xstart = x; - unsigned ymax, xmax; - ncplane_dim_yx(n, &ymax, &xmax); - if(*ystart >= ymax || *xstart >= xmax){ - logerror("invalid starting coordinates: %u/%u\n", *ystart, *xstart); - return -1; - } - // handle the special 0 case for ylen/xlen - if(*ylen == 0){ - *ylen = ymax - *ystart; - } - if(*xlen == 0){ - *xlen = xmax - *xstart; - } - // ensure ylen/xlen are on-plane - if(*ylen > ymax){ - logerror("ylen > dimy %u > %u\n", *ylen, ymax); - return -1; - } - if(*xlen > xmax){ - logerror("xlen > dimx %u > %u\n", *xlen, xmax); - return -1; - } - // ensure x + xlen and y + ylen are on-plane, without overflow - if(ymax - *ylen < *ystart){ - logerror("y + ylen > ymax %u + %u > %u\n", *ystart, *ylen, ymax); - return -1; - } - if(xmax - *xlen < *xstart){ - logerror("x + xlen > xmax %u + %u > %u\n", *xstart, *xlen, xmax); - return -1; - } - return 0; -} - // calculate both channels of a gradient at a particular point, knowing that // we're using double halfblocks, into `c`->channels. static inline void @@ -248,7 +194,7 @@ int ncplane_gradient2x1(ncplane* n, int y, int x, unsigned ylen, unsigned xlen, if(pool_blit_direct(&n->pool, targc, "▀", strlen("▀"), 1) <= 0){ return -1; } - calc_highgradient(targc, ul, ur, ll, lr, yy - ystart, xx - xstart, ylen, xlen); + calc_highgradient(targc, ul, ur, ll, lr, yy - ystart, xx - xstart, ylen * 2, xlen); ++total; } } diff --git a/src/lib/internal.h b/src/lib/internal.h index 2bf17bee5..587360c3b 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -1448,6 +1448,69 @@ int drop_signals(void* nc); int block_signals(sigset_t* old_blocked_signals); int unblock_signals(const sigset_t* old_blocked_signals); +// takes a signed starting coordinate (where -1 indicates the cursor's +// position), and an unsigned vector (where 0 indicates "everything +// remaining", i.e. to the right and below). returns 0 iff everything +// is valid and on the plane, filling in 'ystart'/'xstart' with the +// (non-negative) starting coordinates and 'ylen'/'xlen with the +// (positive) dimensions of the affected area. +static inline int +check_geometry_args(const ncplane* n, int y, int x, + unsigned* ylen, unsigned* xlen, + unsigned* ystart, unsigned* xstart){ + // handle the special -1 case for y/x, and reject other negatives + if(y < 0){ + if(y != -1){ + logerror("invalid y: %d\n", y); + return -1; + } + y = n->y; + } + if(x < 0){ + if(x != -1){ + logerror("invalid x: %d\n", x); + return -1; + } + x = n->x; + } + // y and x are both now definitely positive, but might be off-plane. + // lock in y and x as ystart and xstart for unsigned comparisons. + *ystart = y; + *xstart = x; + unsigned ymax, xmax; + ncplane_dim_yx(n, &ymax, &xmax); + if(*ystart >= ymax || *xstart >= xmax){ + logerror("invalid starting coordinates: %u/%u\n", *ystart, *xstart); + return -1; + } + // handle the special 0 case for ylen/xlen + if(*ylen == 0){ + *ylen = ymax - *ystart; + } + if(*xlen == 0){ + *xlen = xmax - *xstart; + } + // ensure ylen/xlen are on-plane + if(*ylen > ymax){ + logerror("ylen > dimy %u > %u\n", *ylen, ymax); + return -1; + } + if(*xlen > xmax){ + logerror("xlen > dimx %u > %u\n", *xlen, xmax); + return -1; + } + // ensure x + xlen and y + ylen are on-plane, without overflow + if(ymax - *ylen < *ystart){ + logerror("y + ylen > ymax %u + %u > %u\n", *ystart, *ylen, ymax); + return -1; + } + if(xmax - *xlen < *xstart){ + logerror("x + xlen > xmax %u + %u > %u\n", *xstart, *xlen, xmax); + return -1; + } + return 0; +} + void ncvisual_printbanner(fbuf* f); // alpha comes to us 0--255, but we have only 3 alpha values to map them to @@ -1615,6 +1678,27 @@ resize_bitmap(const uint32_t* bmap, int srows, int scols, size_t sstride, return ret; } +// a neighbor on which to polyfill. by the time we get to it, it might or +// might not have been filled in. if so, discard immediately. otherwise, +// check self, and if valid, push all neighbors. +struct topolyfill { + int y, x; + struct topolyfill* next; +}; + +static inline struct topolyfill* +create_polyfill_op(int y, int x, struct topolyfill** stck){ + // cast for the benefit of c++ callers + struct topolyfill* n = (struct topolyfill*)malloc(sizeof(*n)); + if(n){ + n->y = y; + n->x = x; + n->next = *stck; + *stck = n; + } + return n; +} + // implemented by a multimedia backend (ffmpeg or oiio), and installed // prior to calling notcurses_core_init() (by notcurses_init()). typedef struct ncvisual_implementation { diff --git a/src/lib/metric.c b/src/lib/metric.c index 38585e780..9a8e9d8ad 100644 --- a/src/lib/metric.c +++ b/src/lib/metric.c @@ -22,8 +22,9 @@ detect_utf8(void){ } } -const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec, - uintmax_t mult, int uprefix){ +const char* ncnmetric(uintmax_t val, size_t s, uintmax_t decimal, + char* buf, int omitdec, uintmax_t mult, + int uprefix){ // FIXME this is global to the process...ick :/ fesetround(FE_TONEAREST); pthread_once(&utf8_detector, detect_utf8); @@ -70,15 +71,17 @@ const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec, // 1,024). That can overflow with large 64-bit values, but we can first // divide both sides by mult, and then scale by 100. if(omitdec && (val % dv) == 0){ - sprintfed = sprintf(buf, "%" PRIu64 "%lc", (uint64_t)(val / dv), + sprintfed = snprintf(buf, s, "%" PRIu64 "%lc", (uint64_t)(val / dv), (wint_t)prefixes[consumed - 1]); }else{ - sprintfed = sprintf(buf, "%.2f%lc", (double)val / dv, + sprintfed = snprintf(buf, s, "%.2f%lc", (double)val / dv, (wint_t)prefixes[consumed - 1]); } if(uprefix){ - buf[sprintfed] = uprefix; - buf[sprintfed + 1] = '\0'; + if((size_t)sprintfed < s){ + buf[sprintfed] = uprefix; + buf[++sprintfed] = '\0'; + } } return buf; } @@ -86,22 +89,29 @@ const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec, // val / decimal < dv (or we ran out of prefixes) if(omitdec && val % decimal == 0){ if(consumed){ - sprintfed = sprintf(buf, "%" PRIu64 "%lc", (uint64_t)(val / decimal), + sprintfed = snprintf(buf, s, "%" PRIu64 "%lc", (uint64_t)(val / decimal), (wint_t)subprefixes[consumed - 1]); }else{ - sprintfed = sprintf(buf, "%" PRIu64, (uint64_t)(val / decimal)); + sprintfed = snprintf(buf, s, "%" PRIu64, (uint64_t)(val / decimal)); } }else{ if(consumed){ - sprintfed = sprintf(buf, "%.2f%lc", (double)val / decimal, + sprintfed = snprintf(buf, s, "%.2f%lc", (double)val / decimal, (wint_t)subprefixes[consumed - 1]); }else{ - sprintfed = sprintf(buf, "%.2f", (double)val / decimal); + sprintfed = snprintf(buf, s, "%.2f", (double)val / decimal); } } if(consumed && uprefix){ - buf[sprintfed] = uprefix; - buf[sprintfed + 1] = '\0'; + if((size_t)sprintfed < s){ + buf[sprintfed] = uprefix; + buf[++sprintfed] = '\0'; + } } return buf; } + +const char *ncmetric(uintmax_t val, uintmax_t decimal, char *buf, int omitdec, + uintmax_t mult, int uprefix){ + return ncnmetric(val, SIZE_MAX, decimal, buf, omitdec, mult, uprefix); +} diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 7e0f4e422..13fa4f926 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -1994,6 +1994,7 @@ int ncplane_vline_interp(ncplane* n, const nccell* c, unsigned len, return ret; } +// we must have at least 2x2, or it's an error int ncplane_box(ncplane* n, const nccell* ul, const nccell* ur, const nccell* ll, const nccell* lr, const nccell* hl, const nccell* vl, unsigned ystop, unsigned xstop, @@ -2845,23 +2846,11 @@ is_bg_p(int idx, int py, int px, int width){ static inline uint32_t* ncplane_as_rgba_internal(const ncplane* nc, ncblitter_e blit, - unsigned begy, unsigned begx, unsigned leny, - unsigned lenx, unsigned* pxdimy, unsigned* pxdimx){ + int begy, int begx, unsigned leny, unsigned lenx, + unsigned* pxdimy, unsigned* pxdimx){ const notcurses* ncur = ncplane_notcurses_const(nc); - if(begx >= (unsigned)nc->lenx || begy >= (unsigned)nc->leny){ - logerror("invalid origin (%u,%u)\n", begy, begx); - return NULL; - } - if(lenx == 0){ // -1 means "to the end"; use all space available - lenx = nc->lenx - begx; - } - if(leny == 0){ - leny = nc->leny - begy; - } -//fprintf(stderr, "sum: %d/%d avail: %d/%d\n", begy + leny, begx + lenx, nc->leny, nc->lenx); - if(nc->lenx - begx < lenx || nc->leny - begy < leny){ - logerror("invalid specs %u + %u > %d or %u + %u > %d\n", - begx, lenx, nc->lenx, begy, leny, nc->leny); + unsigned ystart, xstart; + if(check_geometry_args(nc, begy, begx, &leny, &lenx, &ystart, &xstart)){ return NULL; } if(blit == NCBLIT_PIXEL){ // FIXME extend this to support sprixels @@ -2887,8 +2876,8 @@ ncplane_as_rgba_internal(const ncplane* nc, ncblitter_e blit, uint32_t* ret = malloc(sizeof(*ret) * lenx * bset->width * leny * bset->height); //fprintf(stderr, "GEOM: %d/%d %d/%d ret: %p\n", bset->height, bset->width, *pxdimy, *pxdimx, ret); if(ret){ - for(unsigned y = begy, targy = 0 ; y < begy + leny ; ++y, targy += bset->height){ - for(unsigned x = begx, targx = 0 ; x < begx + lenx ; ++x, targx += bset->width){ + for(unsigned y = ystart, targy = 0 ; y < ystart + leny ; ++y, targy += bset->height){ + for(unsigned x = xstart, targx = 0 ; x < xstart + lenx ; ++x, targx += bset->width){ uint16_t stylemask; uint64_t channels; char* c = ncplane_at_yx(nc, y, x, &stylemask, &channels); @@ -2941,7 +2930,7 @@ ncplane_as_rgba_internal(const ncplane* nc, ncblitter_e blit, } uint32_t* ncplane_as_rgba(const ncplane* nc, ncblitter_e blit, - unsigned begy, unsigned begx, unsigned leny, + int begy, int begx, unsigned leny, unsigned lenx, unsigned* pxdimy, unsigned* pxdimx){ unsigned px, py; if(!pxdimy){ @@ -2955,39 +2944,15 @@ uint32_t* ncplane_as_rgba(const ncplane* nc, ncblitter_e blit, // return a heap-allocated copy of the contents char* ncplane_contents(ncplane* nc, int begy, int begx, unsigned leny, unsigned lenx){ - if(begy < 0){ - if(begy != -1){ - logerror("invalid y coordinate: %d\n", begy); - } - begy = nc->y; - } - if(begx < 0){ - if(begx != -1){ - logerror("invalid x coordinate: %d\n", begx); - } - begx = nc->x; - } - if((unsigned)begx >= nc->lenx || (unsigned)begy >= nc->leny){ - logerror("beginning coordinates (%d/%d) exceeded area (%u/%u)\n", - begy, begx, nc->leny, nc->lenx); - return NULL; - } - if(lenx == 0){ // 0 means "to the end"; use all space available - lenx = nc->lenx - begx; - } - if(leny == 0){ - leny = nc->leny - begy; - } - if(nc->lenx - begx < lenx || nc->leny - begy < leny){ - logerror("ending coordinates (%u/%u) exceeded lengths (%u/%u)\n", - begy + leny, begx + lenx, nc->leny, nc->lenx); + unsigned ystart, xstart; + if(check_geometry_args(nc, begy, begx, &leny, &lenx, &ystart, &xstart)){ return NULL; } size_t retlen = 1; char* ret = malloc(retlen); if(ret){ - for(unsigned y = begy, targy = 0 ; y < begy + leny ; ++y, targy += 2){ - for(unsigned x = begx, targx = 0 ; x < begx + lenx ; ++x, ++targx){ + for(unsigned y = ystart, targy = 0 ; y < ystart + leny ; ++y, targy += 2){ + for(unsigned x = xstart, targx = 0 ; x < xstart + lenx ; ++x, ++targx){ nccell ncl = CELL_TRIVIAL_INITIALIZER; // we need ncplane_at_yx_cell() here instead of ncplane_at_yx(), // because we should only have one copy of each wide EGC. diff --git a/src/lib/reader.c b/src/lib/reader.c index cda56647f..3b1e2416f 100644 --- a/src/lib/reader.c +++ b/src/lib/reader.c @@ -61,10 +61,10 @@ ncreader_redraw(ncreader* n){ assert(n->xproject >= 0); assert(n->textarea->lenx >= n->ncp->lenx); assert(n->textarea->leny >= n->ncp->leny); - for(int y = 0 ; y < n->ncp->leny ; ++y){ - const int texty = y; - for(int x = 0 ; x < n->ncp->lenx ; ++x){ - const int textx = x + n->xproject; + for(unsigned y = 0 ; y < n->ncp->leny ; ++y){ + const unsigned texty = y; + for(unsigned x = 0 ; x < n->ncp->lenx ; ++x){ + const unsigned textx = x + n->xproject; const nccell* src = &n->textarea->fb[nfbcellidx(n->textarea, texty, textx)]; nccell* dst = &n->ncp->fb[nfbcellidx(n->ncp, y, x)]; //fprintf(stderr, "projecting %d/%d [%s] to %d/%d [%s]\n", texty, textx, cell_extended_gcluster(n->textarea, src), y, x, cell_extended_gcluster(n->ncp, dst)); @@ -121,9 +121,9 @@ int ncreader_move_left(ncreader* n){ // row. if on the right side of the viewarea, but not the right side of the // textarea, pans right. returns 0 if a move was made. int ncreader_move_right(ncreader* n){ - int viewx = n->ncp->x; - int textx = n->textarea->x; - int y = n->ncp->y; + unsigned textx = n->textarea->x; + unsigned y = n->ncp->y; + unsigned viewx = n->ncp->x; //fprintf(stderr, "moving right: tcurs: %dx%d vcurs: %dx%d xproj: %d\n", y, textx, y, viewx, n->xproject); if(textx >= n->textarea->lenx - 1){ // are we on the last column of the textarea? if so, we must also be on @@ -171,7 +171,7 @@ int ncreader_move_up(ncreader* n){ // try to move down. does not move past the bottom of the textarea. // returns 0 if a move was made. int ncreader_move_down(ncreader* n){ - int y = n->ncp->y; + unsigned y = n->ncp->y; if(y >= n->textarea->leny - 1){ // are we on the last row of the textarea? if so, we can't move. return -1; @@ -190,14 +190,14 @@ int ncreader_write_egc(ncreader* n, const char* egc){ logerror("Fed illegal UTF-8 [%s]\n", egc); return -1; } - if(n->textarea->x >= n->textarea->lenx - cols){ + if(n->textarea->x >= (int)n->textarea->lenx - cols){ if(n->horscroll){ if(ncplane_resize_simple(n->textarea, n->textarea->leny, n->textarea->lenx + cols)){ return -1; } ++n->xproject; } - }else if(n->ncp->x >= n->ncp->lenx){ + }else if((unsigned)n->ncp->x >= n->ncp->lenx){ ++n->xproject; } // use ncplane_putegc on both planes because it'll get cursor movement right @@ -207,12 +207,12 @@ int ncreader_write_egc(ncreader* n, const char* egc){ if(ncplane_putegc(n->ncp, egc, NULL) < 0){ return -1; } - if(n->textarea->x >= n->textarea->lenx - cols){ + if(n->textarea->x >= (int)n->textarea->lenx - cols){ if(!n->horscroll){ n->textarea->x = n->textarea->lenx - cols; } } - if(n->ncp->x >= n->ncp->lenx - cols){ + if(n->ncp->x >= (int)n->ncp->lenx - cols){ n->ncp->x = n->ncp->lenx - cols; } ncreader_redraw(n); @@ -275,7 +275,7 @@ ncreader_ctrl_input(ncreader* n, const ncinput* ni){ } break; case 'E': // cursor to end of line - while(n->textarea->x < ncplane_dim_x(n->textarea) - 1){ + while(n->textarea->x < (int)ncplane_dim_x(n->textarea) - 1){ if(ncreader_move_right(n)){ break; } @@ -320,7 +320,7 @@ ncreader_alt_input(ncreader* n, const ncinput* ni){ } break; case 'f': // forward one word (past end cell) - while(n->textarea->x < ncplane_dim_x(n->textarea) - 1){ + while(n->textarea->x < (int)ncplane_dim_x(n->textarea) - 1){ if(ncreader_move_right(n)){ break; } diff --git a/src/lib/reel.c b/src/lib/reel.c index 2b40a1a3f..a4ab71cdd 100644 --- a/src/lib/reel.c +++ b/src/lib/reel.c @@ -186,7 +186,10 @@ tablet_geom(const ncreel* nr, nctablet* t, int* begx, int* begy, //fprintf(stderr, "jigsawing %p with %d/%d dir %d\n", t, frontiertop, frontierbottom, direction); *begy = 0; *begx = 0; - ncplane_dim_yx(nr->p, leny, lenx); + unsigned uleny, ulenx; + ncplane_dim_yx(nr->p, &uleny, &ulenx); + *leny = uleny; + *lenx = ulenx; if(frontiertop < 0){ if(direction == DIRECTION_UP){ return -1; @@ -501,14 +504,15 @@ tighten_reel_down(ncreel* r, int ybot){ if(cur->p == NULL){ break; } - int cury, curx, ylen; + int cury, curx; + unsigned ylen; ncplane_yx(cur->p, &cury, &curx); ncplane_dim_yx(cur->p, &ylen, NULL); - if(cury <= ybot - ylen - 1){ + if(cury <= ybot - (int)ylen - 1){ break; } //fprintf(stderr, "tightening %p down to %d from %d\n", cur, ybot - ylen, cury); - cury = ybot - ylen; + cury = ybot - (int)ylen; ncplane_move_yx(cur->p, cury, curx); ybot = cury - 1; if((cur = cur->prev) == r->tablets){ @@ -580,7 +584,7 @@ tighten_reel(ncreel* r){ const int ybot = rylen - 1 + !!(r->ropts.bordermask & NCBOXMASK_BOTTOM); // FIXME want to tighten down whenever we're at the bottom, and the reel // is full, not just in this case (this can leave a gap of more than 1 row) - if(yoff + ylen + 1 >= ybot){ + if(yoff + (int)ylen + 1 >= ybot){ if(tighten_reel_down(r, ybot)){ return -1; } diff --git a/src/lib/selector.c b/src/lib/selector.c index 8eaf5227b..b52975228 100644 --- a/src/lib/selector.c +++ b/src/lib/selector.c @@ -19,16 +19,16 @@ typedef struct ncselector { unsigned selected; // index of selection unsigned startdisp; // index of first option displayed unsigned maxdisplay; // max number of items to display, 0 -> no limit - int longop; // columns occupied by longest option - int longdesc; // columns occupied by longest description + unsigned longop; // columns occupied by longest option + unsigned longdesc; // columns occupied by longest description struct ncselector_int* items; // list of items and descriptions, heap-copied unsigned itemcount; // number of pairs in 'items' char* title; // can be NULL, in which case there's no riser - int titlecols; // columns occupied by title + unsigned titlecols; // columns occupied by title char* secondary; // can be NULL - int secondarycols; // columns occupied by secondary + unsigned secondarycols; // columns occupied by secondary char* footer; // can be NULL - int footercols; // columns occupied by footer + unsigned footercols; // columns occupied by footer uint64_t opchannels; // option channels uint64_t descchannels; // description channels uint64_t titlechannels; // title channels @@ -42,15 +42,15 @@ typedef struct ncmultiselector { unsigned current; // index of highlighted item unsigned startdisp; // index of first option displayed unsigned maxdisplay; // max number of items to display, 0 -> no limit - int longitem; // columns occupied by longest item + unsigned longitem; // columns occupied by longest item struct ncmselector_int* items; // items, descriptions, and statuses, heap-copied unsigned itemcount; // number of pairs in 'items' char* title; // can be NULL, in which case there's no riser unsigned titlecols; // columns occupied by title char* secondary; // can be NULL - int secondarycols; // columns occupied by secondary + unsigned secondarycols; // columns occupied by secondary char* footer; // can be NULL - int footercols; // columns occupied by footer + unsigned footercols; // columns occupied by footer uint64_t opchannels; // option channels uint64_t descchannels; // description channels uint64_t titlechannels; // title channels @@ -62,7 +62,7 @@ typedef struct ncmultiselector { // ideal body width given the ncselector's items and secondary/footer static int ncselector_body_width(const ncselector* n){ - int cols = 0; + unsigned cols = 0; // the body is the maximum of // * longop + longdesc + 5 // * secondary + 2 @@ -162,7 +162,7 @@ ncselector_draw(ncselector* n){ // Top line of body (background and possibly up arrow) ++yoff; ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1); - for(int i = xoff + 1 ; i < dimx - 1 ; ++i){ + for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){ nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell ncplane_putc(n->ncp, &transc); } @@ -181,12 +181,12 @@ ncselector_draw(ncselector* n){ n->uarrowy = yoff; unsigned printidx = n->startdisp; unsigned printed = 0; - for(yoff += 1 ; yoff < dimy - 2 ; ++yoff){ + for(yoff += 1 ; yoff < (int)dimy - 2 ; ++yoff){ if(n->maxdisplay && printed == n->maxdisplay){ break; } ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1); - for(int i = xoff + 1 ; i < dimx - 1 ; ++i){ + for(int i = xoff + 1 ; i < (int)dimx - 1 ; ++i){ nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell ncplane_putc(n->ncp, &transc); } @@ -207,7 +207,7 @@ ncselector_draw(ncselector* n){ } // Bottom line of body (background and possibly down arrow) ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1); - for(int i = xoff + 1 ; i < dimx - 1 ; ++i){ + for(int i = xoff + 1 ; i < (int)dimx - 1 ; ++i){ nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell ncplane_putc(n->ncp, &transc); } @@ -225,8 +225,8 @@ ncselector_draw(ncselector* n){ // calculate the necessary dimensions based off properties of the selector static void -ncselector_dim_yx(const ncselector* n, int* ncdimy, int* ncdimx){ - int rows = 0, cols = 0; // desired dimensions +ncselector_dim_yx(const ncselector* n, unsigned* ncdimy, unsigned* ncdimx){ + unsigned rows = 0, cols = 0; // desired dimensions const ncplane* parent = ncplane_parent(n->ncp); unsigned dimy, dimx; // dimensions of containing plane ncplane_dim_yx(parent, &dimy, &dimx); @@ -305,13 +305,21 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){ } for(ns->itemcount = 0 ; ns->itemcount < itemcount ; ++ns->itemcount){ const struct ncselector_item* src = &opts->items[ns->itemcount]; - int cols = ncstrwidth(src->option); + int unsafe = ncstrwidth(src->option); + if(unsafe < 0){ + goto freeitems; + } + unsigned cols = unsafe; ns->items[ns->itemcount].opcolumns = cols; if(cols > ns->longop){ ns->longop = cols; } const char *desc = src->desc ? src->desc : ""; - cols = ncstrwidth(desc); + unsafe = ncstrwidth(desc); + if(unsafe < 0){ + goto freeitems; + } + cols = unsafe; ns->items[ns->itemcount].desccolumns = cols; if(cols > ns->longdesc){ ns->longdesc = cols; @@ -324,7 +332,7 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){ goto freeitems; } } - int dimy, dimx; + unsigned dimy, dimx; ns->ncp = n; ncselector_dim_yx(ns, &dimy, &dimx); if(ncplane_resize_simple(n, dimy, dimx)){ @@ -347,7 +355,7 @@ freeitems: } int ncselector_additem(ncselector* n, const struct ncselector_item* item){ - int origdimy, origdimx; + unsigned origdimy, origdimx; ncselector_dim_yx(n, &origdimy, &origdimx); size_t newsize = sizeof(*n->items) * (n->itemcount + 1); struct ncselector_int* items = realloc(n->items, newsize); @@ -358,7 +366,11 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){ n->items[n->itemcount].option = strdup(item->option); const char *desc = item->desc ? item->desc : ""; n->items[n->itemcount].desc = strdup(desc); - int cols = ncstrwidth(item->option); + int usafecols = ncstrwidth(item->option); + if(usafecols < 0){ + return -1; + } + unsigned cols = usafecols; n->items[n->itemcount].opcolumns = cols; if(cols > n->longop){ n->longop = cols; @@ -369,7 +381,7 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){ n->longdesc = cols; } ++n->itemcount; - int dimy, dimx; + unsigned dimy, dimx; ncselector_dim_yx(n, &dimy, &dimx); if(origdimx < dimx || origdimy < dimy){ // resize if too small ncplane_resize_simple(n->ncp, dimy, dimx); @@ -378,7 +390,7 @@ int ncselector_additem(ncselector* n, const struct ncselector_item* item){ } int ncselector_delitem(ncselector* n, const char* item){ - int origdimy, origdimx; + unsigned origdimy, origdimx; ncselector_dim_yx(n, &origdimy, &origdimx); bool found = false; int maxop = 0, maxdesc = 0; @@ -410,7 +422,7 @@ int ncselector_delitem(ncselector* n, const char* item){ if(found){ n->longop = maxop; n->longdesc = maxdesc; - int dimy, dimx; + unsigned dimy, dimx; ncselector_dim_yx(n, &dimy, &dimx); if(origdimx > dimx || origdimy > dimy){ // resize if too big ncplane_resize_simple(n->ncp, dimy, dimx); @@ -560,9 +572,9 @@ ncplane* ncmultiselector_plane(ncmultiselector* n){ } // ideal body width given the ncselector's items and secondary/footer -static int +static unsigned ncmultiselector_body_width(const ncmultiselector* n){ - int cols = 0; + unsigned cols = 0; // the body is the maximum of // * longop + longdesc + 5 // * secondary + 2 @@ -589,7 +601,7 @@ ncmultiselector_draw(ncmultiselector* n){ // if we have a title, we'll draw a riser. the riser is two rows tall, and // exactly four columns longer than the title, and aligned to the right. we // draw a rounded box. the body will blow part or all of the bottom away. - int yoff = 0; + unsigned yoff = 0; if(n->title){ size_t riserwidth = n->titlecols + 4; int offx = ncplane_halign(n->ncp, NCALIGN_RIGHT, riserwidth); @@ -649,7 +661,7 @@ ncmultiselector_draw(ncmultiselector* n){ // Top line of body (background and possibly up arrow) ++yoff; ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1); - for(int i = xoff + 1 ; i < dimx - 1 ; ++i){ + for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){ nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell ncplane_putc(n->ncp, &transc); } @@ -670,7 +682,7 @@ ncmultiselector_draw(ncmultiselector* n){ break; } ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1); - for(int i = xoff + 1 ; i < dimx - 1 ; ++i){ + for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){ nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell ncplane_putc(n->ncp, &transc); } @@ -700,7 +712,7 @@ ncmultiselector_draw(ncmultiselector* n){ } // Bottom line of body (background and possibly down arrow) ncplane_cursor_move_yx(n->ncp, yoff, xoff + 1); - for(int i = xoff + 1 ; i < dimx - 1 ; ++i){ + for(unsigned i = xoff + 1 ; i < dimx - 1 ; ++i){ nccell transc = CELL_TRIVIAL_INITIALIZER; // fall back to base cell ncplane_putc(n->ncp, &transc); } @@ -899,11 +911,19 @@ ncmultiselector* ncmultiselector_create(ncplane* n, const ncmultiselector_option } for(ns->itemcount = 0 ; ns->itemcount < itemcount ; ++ns->itemcount){ const struct ncmselector_item* src = &opts->items[ns->itemcount]; - int cols = ncstrwidth(src->option); + int unsafe = ncstrwidth(src->option); + if(unsafe < 0){ + goto freeitems; + } + unsigned cols = unsafe; if(cols > ns->longitem){ ns->longitem = cols; } - int cols2 = ncstrwidth(src->desc); + unsafe = ncstrwidth(src->desc); + if(unsafe < 0){ + goto freeitems; + } + unsigned cols2 = unsafe; if(cols + cols2 > ns->longitem){ ns->longitem = cols + cols2; } diff --git a/src/lib/visual.c b/src/lib/visual.c index 0e5db8a0d..28f2544fe 100644 --- a/src/lib/visual.c +++ b/src/lib/visual.c @@ -1193,7 +1193,7 @@ ncplane* ncvisual_render(notcurses* nc, ncvisual* ncv, const struct ncvisual_opt } ncvisual* ncvisual_from_plane(const ncplane* n, ncblitter_e blit, - unsigned begy, unsigned begx, + int begy, int begx, unsigned leny, unsigned lenx){ unsigned py, px; uint32_t* rgba = ncplane_as_rgba(n, blit, begy, begx, leny, lenx, &py, &px); @@ -1269,26 +1269,6 @@ int ncvisual_at_yx(const ncvisual* n, unsigned y, unsigned x, uint32_t* pixel){ return 0; } -// a neighbor on which to polyfill. by the time we get to it, it might or -// might not have been filled in. if so, discard immediately. otherwise, -// check self, and if valid, push all neighbors. -struct topolyfill { - int y, x; - struct topolyfill* next; -}; - -static inline struct topolyfill* -create_polyfill_op(int y, int x, struct topolyfill** stack){ - struct topolyfill* n = malloc(sizeof(*n)); - if(n){ - n->y = y; - n->x = x; - n->next = *stack; - *stack = n; - } - return n; -} - // originally i wrote this recursively, at which point it promptly began // exploding once i multithreaded the [yield] demo. hence the clumsy stack // and hand-rolled iteration. alas, poor yorick! @@ -1314,6 +1294,7 @@ ncvisual_polyfill_core(ncvisual* n, unsigned y, unsigned x, uint32_t rgba, uint3 *pixel = rgba; if(y){ if(create_polyfill_op(y - 1, x, &stack) == NULL){ + // FIXME need free stack! return -1; } } diff --git a/src/poc/ncwidth.c b/src/poc/ncwidth.c index e90249fe3..fa665d363 100644 --- a/src/poc/ncwidth.c +++ b/src/poc/ncwidth.c @@ -74,13 +74,14 @@ int main(int argc, char **argv){ totalb += conv; add_wchar(&wbuf, &bufsize, &used, w); } - int y, x, newy, newx; putchar('\n'); + unsigned y, x; ncdirect_cursor_yx(n, &y, &x); printf("%s", *argv); fflush(stdout); + unsigned newy, newx; ncdirect_cursor_yx(n, &newy, &newx); - int realcols = (newx - x) + ncdirect_dim_x(n) * (newy - y); + unsigned realcols = (newx - x) + ncdirect_dim_x(n) * (newy - y); printf("\n iterated wcwidth: %d total bytes: %llu wcswidth: %d true width: %d\n\n", totalcols, (unsigned long long)totalb, wcswidth(wbuf, used), realcols); ncdirect_cursor_yx(n, &y, &x); @@ -123,7 +124,7 @@ int main(int argc, char **argv){ } ncdirect_set_fg_default(n); ncdirect_set_bg_default(n); - for(int z = 0 ; z < realcols && z < ncdirect_dim_x(n) ; ++z){ + for(unsigned z = 0 ; z < realcols && z < ncdirect_dim_x(n) ; ++z){ putchar('0' + z % 10); } if(realcols < ncdirect_dim_x(n)){ diff --git a/src/poc/rtl.c b/src/poc/rtl.c index 3f09d9a88..a702d063d 100644 --- a/src/poc/rtl.c +++ b/src/poc/rtl.c @@ -10,7 +10,7 @@ int main(void){ if(!nc){ return EXIT_FAILURE; } - int dimy, dimx; + unsigned dimy, dimx; struct ncplane* n = notcurses_stddim_yx(nc, &dimy, &dimx); ncplane_printf_yx(n, dimy / 2 - 2, 0, "ࡢ‎ࡣ‎ࡤ‎ࡥ‎ࡦ‎ࡧ‎ࡨ‎ࡩ‎ࡪ‎ࢠ‎ࢡ‎ࢢ‎ࢣ‎ࢤ‎ࢥ‎ࢦ‎ࢧ‎ࢨ‎ࢩ‎ࢪ‎ࢫ‎ࢬ‎ࢭ‎ࢮ‎ࢯ‎ࢰ‎ࢱ‎ࢲ‎ࢳ‎ࢴ‎ࢶ‎ࢷ‎ࢸ‎ࢹ‎ࢺ‎ࢻ‎ࢼ‎ࢽ‎࣢ः"); ncplane_printf_yx(n, dimy / 2 - 1, 0, "࠲‎࠳‎࠴‎࠵‎࠶‎࠷‎࠸‎࠹‎࠺‎࠻‎࠼‎࠽‎࠾‎ࡀ‎ࡁ‎ࡂ‎ࡃ‎ࡄ‎ࡅ‎ࡆ‎ࡇ‎ࡈ‎ࡉ‎ࡊ‎ࡋ‎ࡌ‎ࡍ‎ࡎ‎ࡏ‎ࡐ‎ࡑ‎ࡒ‎ࡓ‎ࡔ‎ࡕ‎ࡖ‎ࡗ‎ࡘ‎࡞‎ࡡ"); diff --git a/src/poc/statepixel.c b/src/poc/statepixel.c index 9d71efdf8..35150e292 100644 --- a/src/poc/statepixel.c +++ b/src/poc/statepixel.c @@ -7,7 +7,7 @@ static int across_row(struct notcurses* nc, int y, struct ncplane* n, struct ncplane* t, const struct timespec* ds){ - for(int x = 0 ; x < ncplane_dim_x(n) ; ++x){ + for(unsigned x = 0 ; x < ncplane_dim_x(n) ; ++x){ if(ncplane_move_yx(t, y, x)){ return -1; } @@ -21,7 +21,7 @@ across_row(struct notcurses* nc, int y, struct ncplane* n, struct ncplane* t, static int across_bmap(struct notcurses* nc, struct ncplane* n, struct ncplane* t, const struct timespec* ds){ - for(int y = 0 ; y < ncplane_dim_y(n) - 1 ; ++y){ + for(unsigned y = 0 ; y < ncplane_dim_y(n) - 1 ; ++y){ if(across_row(nc, y, n, t, ds)){ return -1; } diff --git a/src/tests/fills.cpp b/src/tests/fills.cpp index d42844fd5..c6b2fc87f 100644 --- a/src/tests/fills.cpp +++ b/src/tests/fills.cpp @@ -577,7 +577,9 @@ TEST_CASE("Fills") { const char* qr = "a very simple qr code"; unsigned dimy, dimx; ncplane_dim_yx(n_, &dimy, &dimx); - CHECK(0 < ncplane_qrcode(n_, &dimy, &dimx, qr, strlen(qr))); + int sdimy = dimy; + int sdimx = dimx; + CHECK(0 < ncplane_qrcode(n_, &sdimy, &sdimx, qr, strlen(qr))); CHECK(0 == notcurses_render(nc_)); } #endif