From 37f077a653f43e93137a1ed4c882223b8d0583c7 Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 4 Nov 2021 02:09:07 -0400 Subject: [PATCH] normalize lenghts for line-drawing functions #1696 --- NEWS.md | 4 ++- USAGE.md | 24 ++++++++-------- doc/man/man3/notcurses_direct.3.md | 4 +-- doc/man/man3/notcurses_lines.3.md | 12 +++++--- include/notcurses/direct.h | 14 +++++----- include/notcurses/notcurses.h | 20 +++++++------ src/lib/direct.c | 44 ++++++++++++++++------------- src/lib/notcurses.c | 45 ++++++++++++++++++------------ 8 files changed, 95 insertions(+), 72 deletions(-) diff --git a/NEWS.md b/NEWS.md index 6375c5406..fd7ec25b7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -16,7 +16,9 @@ rearrangements of Notcurses. functions. Lengths are now `unsigned` as opposed to `int`. Where -1 was being used to indicate "everything", 0 is now required. This affects `ncplane_as_rgba()`, `ncplane_contents()`, and `ncvisual_from_plane()`, - which all used -1. + which all used -1. A length of zero passed to line-drawing functions is + now an error. Several line-drawing functions now reliably return errors + as opposed to short successes. * `ncvisual_geom()` has been introduced, using the `ncvgeom` struct introduced for direct mode. This allows complete statement of geometry for an `ncvisual`. It replaces `ncvisual_blitter_geom()`, which has been diff --git a/USAGE.md b/USAGE.md index ade0f10a6..19324847c 100644 --- a/USAGE.md +++ b/USAGE.md @@ -526,10 +526,11 @@ int ncdirect_putegc(struct ncdirect* nc, uint64_t channels, // horizontal line, |len| cannot exceed the screen width minus the cursor's // offset. For a vertical line, it may be as long as you'd like; the screen // will scroll as necessary. All lines start at the current cursor position. -int ncdirect_hline_interp(struct ncdirect* n, const char* egc, int len, - uint64_t h1, uint64_t h2); -int ncdirect_vline_interp(struct ncdirect* n, const char* egc, int len, - uint64_t h1, uint64_t h2); +// A length of 0 is an error, resulting in a return of -1. +int ncdirect_hline_interp(struct ncdirect* n, const char* egc, + unsigned len, uint64_t h1, uint64_t h2); +int ncdirect_vline_interp(struct ncdirect* n, const char* egc, + unsigned len, uint64_t h1, uint64_t h2); // Draw a box with its upper-left corner at the current cursor position, having // dimensions |ylen|x|xlen|. See ncplane_box() for more information. The @@ -1499,21 +1500,20 @@ on both sides. Boxes allow fairly detailed specification of how they're drawn. // current cursor position. The cursor will end at the cell following the last // cell output (even, perhaps counter-intuitively, when drawing vertical // lines), just as if ncplane_putc() was called at that spot. Return the -// number of cells drawn on success. On error, return the negative number of -// cells drawn. -int ncplane_hline_interp(struct ncplane* n, const nccell* c, int len, - uint64_t c1, uint64_t c2); +// number of cells drawn on success. A length of 0 is an error. +int ncplane_hline_interp(struct ncplane* n, const nccell* c, + unsigned len, uint64_t c1, uint64_t c2); static inline int -ncplane_hline(struct ncplane* n, const nccell* c, int len){ +ncplane_hline(struct ncplane* n, const nccell* c, unsigned len){ return ncplane_hline_interp(n, c, len, c->channels, c->channels); } -int ncplane_vline_interp(struct ncplane* n, const nccell* c, int len, - uint64_t c1, uint64_t c2); +int ncplane_vline_interp(struct ncplane* n, const nccell* c, + unsigned len, uint64_t c1, uint64_t c2); static inline int -ncplane_vline(struct ncplane* n, const nccell* c, int len){ +ncplane_vline(struct ncplane* n, const nccell* c, unsigned len){ return ncplane_vline_interp(n, c, len, c->channels, c->channels); } diff --git a/doc/man/man3/notcurses_direct.3.md b/doc/man/man3/notcurses_direct.3.md index d98f765f1..784d27cea 100644 --- a/doc/man/man3/notcurses_direct.3.md +++ b/doc/man/man3/notcurses_direct.3.md @@ -78,9 +78,9 @@ notcurses_direct - minimal notcurses instances for styling text **const char* ncdirect_detected_terminal(const struct ncdirect* ***n***);** -**int ncdirect_hline_interp(struct ncdirect* ***n***, const char* ***egc***, int ***len***, uint64_t ***h1***, uint64_t ***h2***);** +**int ncdirect_hline_interp(struct ncdirect* ***n***, const char* ***egc***, unsigned ***len***, uint64_t ***h1***, uint64_t ***h2***);** -**int ncdirect_vline_interp(struct ncdirect* ***n***, const char* ***egc***, int ***len***, uint64_t ***h1***, uint64_t ***h2***);** +**int ncdirect_vline_interp(struct ncdirect* ***n***, const char* ***egc***, unsigned ***len***, uint64_t ***h1***, uint64_t ***h2***);** **int ncdirect_box(struct ncdirect* ***n***, uint64_t ***ul***, uint64_t ***ur***, uint64_t ***ll***, uint64_t ***lr***, const wchar_t* ***wchars***, int ***ylen***, int ***xlen***, unsigned ***ctlword***);** diff --git a/doc/man/man3/notcurses_lines.3.md b/doc/man/man3/notcurses_lines.3.md index ba500201d..8eeca69b6 100644 --- a/doc/man/man3/notcurses_lines.3.md +++ b/doc/man/man3/notcurses_lines.3.md @@ -10,13 +10,13 @@ notcurses_lines - operations on lines and boxes **#include ** -**int ncplane_hline_interp(struct ncplane* ***n***, const nccell* ***c***, int ***len***, uint64_t ***c1***, uint64_t ***c2***);** +**int ncplane_hline_interp(struct ncplane* ***n***, const nccell* ***c***, unsigned ***len***, uint64_t ***c1***, uint64_t ***c2***);** -**static inline int ncplane_hline(struct ncplane* ***n***, const nccell* ***c***, int ***len***);** +**static inline int ncplane_hline(struct ncplane* ***n***, const nccell* ***c***, unsigned ***len***);** -**int ncplane_vline_interp(struct ncplane* ***n***, const nccell* ***c***, int ***len***, uint64_t ***c1***, uint64_t ***c2***);** +**int ncplane_vline_interp(struct ncplane* ***n***, const nccell* ***c***, unsigned ***len***, uint64_t ***c1***, uint64_t ***c2***);** -**static inline int ncplane_vline(struct ncplane* ***n***, const nccell* ***c***, int ***len***);** +**static inline int ncplane_vline(struct ncplane* ***n***, const nccell* ***c***, unsigned ***len***);** ```c #define NCBOXMASK_TOP 0x0001 @@ -78,6 +78,10 @@ Box- and line-drawing is unaffected by a plane's scrolling status. **ncplane_format** returns -1 if either **ystop** or **xstop** is less than the current equivalent position, otherwise 0. +**ncplane_hline_interp**, **ncplane_hline**, **ncplane_vline_interp**, and +**ncplane_vline** all return the number of glyphs drawn on success, or -1 +on failure. Passing a length of 0 is an error. + # SEE ALSO **notcurses(3)**, diff --git a/include/notcurses/direct.h b/include/notcurses/direct.h index c3766d7c9..c3363d057 100644 --- a/include/notcurses/direct.h +++ b/include/notcurses/direct.h @@ -263,13 +263,13 @@ API const nccapabilities* ncdirect_capabilities(const struct ncdirect* n) // horizontal line, |len| cannot exceed the screen width minus the cursor's // offset. For a vertical line, it may be as long as you'd like; the screen // will scroll as necessary. All lines start at the current cursor position. -API int ncdirect_hline_interp(struct ncdirect* n, const char* egc, int len, - uint64_t h1, uint64_t h2) - __attribute__ ((nonnull (1))); +API int ncdirect_hline_interp(struct ncdirect* n, const char* egc, + unsigned len, uint64_t h1, uint64_t h2) + __attribute__ ((nonnull (1, 2))); -API int ncdirect_vline_interp(struct ncdirect* n, const char* egc, int len, - uint64_t h1, uint64_t h2) - __attribute__ ((nonnull (1))); +API int ncdirect_vline_interp(struct ncdirect* n, const char* egc, + unsigned len, uint64_t h1, uint64_t h2) + __attribute__ ((nonnull (1, 2))); // Draw a box with its upper-left corner at the current cursor position, having // dimensions |ylen|x|xlen|. See ncplane_box() for more information. The @@ -278,7 +278,7 @@ API int ncdirect_vline_interp(struct ncdirect* n, const char* egc, int len, API int ncdirect_box(struct ncdirect* n, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr, const wchar_t* wchars, int ylen, int xlen, unsigned ctlword) - __attribute__ ((nonnull (1))); + __attribute__ ((nonnull (1, 6))); __attribute__ ((nonnull (1))) static inline int ncdirect_light_box(struct ncdirect* n, uint64_t ul, uint64_t ur, diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 6293f730b..1ab7417f5 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -2156,20 +2156,22 @@ API int ncplane_puttext(struct ncplane* n, int y, ncalign_e align, // cell output (even, perhaps counter-intuitively, when drawing vertical // lines), just as if ncplane_putc() was called at that spot. Return the // number of cells drawn on success. On error, return the negative number of -// cells drawn. -API int ncplane_hline_interp(struct ncplane* n, const nccell* c, int len, - uint64_t c1, uint64_t c2); +// cells drawn. A length of 0 is an error, resulting in a return of -1. +API int ncplane_hline_interp(struct ncplane* n, const nccell* c, + unsigned len, uint64_t c1, uint64_t c2) + __attribute__ ((nonnull (1, 2))); -static inline int -ncplane_hline(struct ncplane* n, const nccell* c, int len){ +__attribute__ ((nonnull (1, 2))) static inline int +ncplane_hline(struct ncplane* n, const nccell* c, unsigned len){ return ncplane_hline_interp(n, c, len, c->channels, c->channels); } -API int ncplane_vline_interp(struct ncplane* n, const nccell* c, int len, - uint64_t c1, uint64_t c2); +API int ncplane_vline_interp(struct ncplane* n, const nccell* c, + unsigned len, uint64_t c1, uint64_t c2) + __attribute__ ((nonnull (1, 2))); -static inline int -ncplane_vline(struct ncplane* n, const nccell* c, int len){ +__attribute__ ((nonnull (1, 2))) static inline int +ncplane_vline(struct ncplane* n, const nccell* c, unsigned len){ return ncplane_vline_interp(n, c, len, c->channels, c->channels); } diff --git a/src/lib/direct.c b/src/lib/direct.c index 9419a697f..644e9cbab 100644 --- a/src/lib/direct.c +++ b/src/lib/direct.c @@ -1242,8 +1242,11 @@ int ncdirect_set_bg_default(ncdirect* nc){ return 0; } -int ncdirect_hline_interp(ncdirect* n, const char* egc, int len, +int ncdirect_hline_interp(ncdirect* n, const char* egc, unsigned len, uint64_t c1, uint64_t c2){ + if(len == 0){ + return -1; + } unsigned ur, ug, ub; int r1, g1, b1, r2, g2, b2; int br1, bg1, bb1, br2, bg2, bb2; @@ -1261,7 +1264,7 @@ int ncdirect_hline_interp(ncdirect* n, const char* egc, int len, int deltbr = br2 - br1; int deltbg = bg2 - bg1; int deltbb = bb2 - bb1; - int ret; + unsigned ret; bool fgdef = false, bgdef = false; if(ncchannels_fg_default_p(c1) && ncchannels_fg_default_p(c2)){ if(ncdirect_set_fg_default(n)){ @@ -1276,12 +1279,12 @@ int ncdirect_hline_interp(ncdirect* n, const char* egc, int len, bgdef = true; } for(ret = 0 ; ret < len ; ++ret){ - int r = (deltr * ret) / len + r1; - int g = (deltg * ret) / len + g1; - int b = (deltb * ret) / len + b1; - int br = (deltbr * ret) / len + br1; - int bg = (deltbg * ret) / len + bg1; - int bb = (deltbb * ret) / len + bb1; + int r = (deltr * (int)ret) / (int)len + r1; + int g = (deltg * (int)ret) / (int)len + g1; + int b = (deltb * (int)ret) / (int)len + b1; + int br = (deltbr * (int)ret) / (int)len + br1; + int bg = (deltbg * (int)ret) / (int)len + bg1; + int bb = (deltbb * (int)ret) / (int)len + bb1; if(!fgdef){ ncdirect_set_fg_rgb8(n, r, g, b); } @@ -1289,14 +1292,17 @@ int ncdirect_hline_interp(ncdirect* n, const char* egc, int len, ncdirect_set_bg_rgb8(n, br, bg, bb); } if(fprintf(n->ttyfp, "%s", egc) < 0){ - break; + return -1; } } return ret; } -int ncdirect_vline_interp(ncdirect* n, const char* egc, int len, +int ncdirect_vline_interp(ncdirect* n, const char* egc, unsigned len, uint64_t c1, uint64_t c2){ + if(len == 0){ + return -1; + } unsigned ur, ug, ub; int r1, g1, b1, r2, g2, b2; int br1, bg1, bb1, br2, bg2, bb2; @@ -1308,13 +1314,13 @@ int ncdirect_vline_interp(ncdirect* n, const char* egc, int len, br1 = ur; bg1 = ug; bb1 = ub; ncchannels_bg_rgb8(c2, &ur, &ug, &ub); br2 = ur; bg2 = ug; bb2 = ub; - int deltr = (r2 - r1) / (len + 1); - int deltg = (g2 - g1) / (len + 1); - int deltb = (b2 - b1) / (len + 1); - int deltbr = (br2 - br1) / (len + 1); - int deltbg = (bg2 - bg1) / (len + 1); - int deltbb = (bb2 - bb1) / (len + 1); - int ret; + int deltr = (r2 - r1) / ((int)len + 1); + int deltg = (g2 - g1) / ((int)len + 1); + int deltb = (b2 - b1) / ((int)len + 1); + int deltbr = (br2 - br1) / ((int)len + 1); + int deltbg = (bg2 - bg1) / ((int)len + 1); + int deltbb = (bb2 - bb1) / ((int)len + 1); + unsigned ret; bool fgdef = false, bgdef = false; if(ncchannels_fg_default_p(c1) && ncchannels_fg_default_p(c2)){ if(ncdirect_set_fg_default(n)){ @@ -1343,11 +1349,11 @@ int ncdirect_vline_interp(ncdirect* n, const char* egc, int len, ncchannels_set_bg_rgb8(&channels, br1, bg1, bb1); } if(ncdirect_putstr(n, channels, egc) <= 0){ - break; + return -1; } if(len - ret > 1){ if(ncdirect_cursor_down(n, 1) || ncdirect_cursor_left(n, 1)){ - break; + return -1; } } } diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index b81131e38..4d2c4304c 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -1877,8 +1877,12 @@ int ncplane_vprintf_stained(struct ncplane* n, const char* format, va_list ap){ return ret; } -int ncplane_hline_interp(ncplane* n, const nccell* c, int len, +int ncplane_hline_interp(ncplane* n, const nccell* c, unsigned len, uint64_t c1, uint64_t c2){ + if(len <= 0){ + logerror("passed invalid length %u\n", len); + return -1; + } unsigned ur, ug, ub; int r1, g1, b1, r2, g2, b2; int br1, bg1, bb1, br2, bg2, bb2; @@ -1896,7 +1900,7 @@ int ncplane_hline_interp(ncplane* n, const nccell* c, int len, int deltbr = br2 - br1; int deltbg = bg2 - bg1; int deltbb = bb2 - bb1; - int ret; + unsigned ret; nccell dupc = CELL_TRIVIAL_INITIALIZER; if(nccell_duplicate(n, &dupc, c) < 0){ return -1; @@ -1909,12 +1913,12 @@ int ncplane_hline_interp(ncplane* n, const nccell* c, int len, bgdef = true; } for(ret = 0 ; ret < len ; ++ret){ - int r = (deltr * ret) / len + r1; - int g = (deltg * ret) / len + g1; - int b = (deltb * ret) / len + b1; - int br = (deltbr * ret) / len + br1; - int bg = (deltbg * ret) / len + bg1; - int bb = (deltbb * ret) / len + bb1; + int r = (deltr * (int)ret) / (int)len + r1; + int g = (deltg * (int)ret) / (int)len + g1; + int b = (deltb * (int)ret) / (int)len + b1; + int br = (deltbr * (int)ret) / (int)len + br1; + int bg = (deltbg * (int)ret) / (int)len + bg1; + int bb = (deltbb * (int)ret) / (int)len + bb1; if(!fgdef){ nccell_set_fg_rgb8(&dupc, r, g, b); } @@ -1922,15 +1926,19 @@ int ncplane_hline_interp(ncplane* n, const nccell* c, int len, nccell_set_bg_rgb8(&dupc, br, bg, bb); } if(ncplane_putc(n, &dupc) <= 0){ - break; + return -1; } } nccell_release(n, &dupc); return ret; } -int ncplane_vline_interp(ncplane* n, const nccell* c, int len, +int ncplane_vline_interp(ncplane* n, const nccell* c, unsigned len, uint64_t c1, uint64_t c2){ + if(len <= 0){ + logerror("passed invalid length %u\n", len); + return -1; + } unsigned ur, ug, ub; int r1, g1, b1, r2, g2, b2; int br1, bg1, bb1, br2, bg2, bb2; @@ -1942,13 +1950,14 @@ int ncplane_vline_interp(ncplane* n, const nccell* c, int len, br1 = ur; bg1 = ug; bb1 = ub; ncchannels_bg_rgb8(c2, &ur, &ug, &ub); br2 = ur; bg2 = ug; bb2 = ub; - int deltr = (r2 - r1) / (len + 1); - int deltg = (g2 - g1) / (len + 1); - int deltb = (b2 - b1) / (len + 1); - int deltbr = (br2 - br1) / (len + 1); - int deltbg = (bg2 - bg1) / (len + 1); - int deltbb = (bb2 - bb1) / (len + 1); - int ret, ypos, xpos; + int deltr = (r2 - r1) / ((int)len + 1); + int deltg = (g2 - g1) / ((int)len + 1); + int deltb = (b2 - b1) / ((int)len + 1); + int deltbr = (br2 - br1) / ((int)len + 1); + int deltbg = (bg2 - bg1) / ((int)len + 1); + int deltbb = (bb2 - bb1) / ((int)len + 1); + int ypos, xpos; + unsigned ret; ncplane_cursor_yx(n, &ypos, &xpos); nccell dupc = CELL_TRIVIAL_INITIALIZER; if(nccell_duplicate(n, &dupc, c) < 0){ @@ -1978,7 +1987,7 @@ int ncplane_vline_interp(ncplane* n, const nccell* c, int len, nccell_set_bg_rgb8(&dupc, br1, bg1, bb1); } if(ncplane_putc(n, &dupc) <= 0){ - break; + return -1; } } nccell_release(n, &dupc);