diff --git a/csi.c b/csi.c index 14d41c12..e833d2a7 100644 --- a/csi.c +++ b/csi.c @@ -23,6 +23,7 @@ #include "version.h" #include "vt.h" #include "xmalloc.h" +#include "xsnprintf.h" #define UNHANDLED() LOG_DBG("unhandled: %s", csi_as_string(term, final, -1)) #define UNHANDLED_SGR(idx) LOG_DBG("unhandled: %s", csi_as_string(term, 'm', idx)) @@ -1204,9 +1205,9 @@ csi_dispatch(struct terminal *term, uint8_t final) if (x >= 0 && y >= 0) { char reply[64]; - snprintf(reply, sizeof(reply), "\033[3;%d;%dt", + size_t n = xsnprintf(reply, sizeof(reply), "\033[3;%d;%dt", x / term->scale, y / term->scale); - term_to_slave(term, reply, strlen(reply)); + term_to_slave(term, reply, n); } break; } @@ -1235,9 +1236,9 @@ csi_dispatch(struct terminal *term, uint8_t final) if (width >= 0 && height >= 0) { char reply[64]; - snprintf(reply, sizeof(reply), "\033[4;%d;%dt", + size_t n = xsnprintf(reply, sizeof(reply), "\033[4;%d;%dt", height / term->scale, width / term->scale); - term_to_slave(term, reply, strlen(reply)); + term_to_slave(term, reply, n); } break; } @@ -1245,10 +1246,10 @@ csi_dispatch(struct terminal *term, uint8_t final) case 15: /* report screen size in pixels */ tll_foreach(term->window->on_outputs, it) { char reply[64]; - snprintf(reply, sizeof(reply), "\033[5;%d;%dt", + size_t n = xsnprintf(reply, sizeof(reply), "\033[5;%d;%dt", it->item->dim.px_scaled.height, it->item->dim.px_scaled.width); - term_to_slave(term, reply, strlen(reply)); + term_to_slave(term, reply, n); break; } @@ -1258,28 +1259,28 @@ csi_dispatch(struct terminal *term, uint8_t final) case 16: { /* report cell size in pixels */ char reply[64]; - snprintf(reply, sizeof(reply), "\033[6;%d;%dt", + size_t n = xsnprintf(reply, sizeof(reply), "\033[6;%d;%dt", term->cell_height / term->scale, term->cell_width / term->scale); - term_to_slave(term, reply, strlen(reply)); + term_to_slave(term, reply, n); break; } case 18: { /* text area size in chars */ char reply[64]; - snprintf(reply, sizeof(reply), "\033[8;%d;%dt", + size_t n = xsnprintf(reply, sizeof(reply), "\033[8;%d;%dt", term->rows, term->cols); - term_to_slave(term, reply, strlen(reply)); + term_to_slave(term, reply, n); break; } case 19: { /* report screen size in chars */ tll_foreach(term->window->on_outputs, it) { char reply[64]; - snprintf(reply, sizeof(reply), "\033[9;%d;%dt", + size_t n = xsnprintf(reply, sizeof(reply), "\033[9;%d;%dt", it->item->dim.px_real.height / term->cell_height / term->scale, it->item->dim.px_real.width / term->cell_width / term->scale); - term_to_slave(term, reply, strlen(reply)); + term_to_slave(term, reply, n); break; } @@ -1341,9 +1342,9 @@ csi_dispatch(struct terminal *term, uint8_t final) * terminfo says the receiver of the reply should * decrement, hence we must add 1 */ char reply[64]; - snprintf(reply, sizeof(reply), "\x1b[%d;%dR", + size_t n = xsnprintf(reply, sizeof(reply), "\x1b[%d;%dR", row + 1, term->grid->cursor.point.col + 1); - term_to_slave(term, reply, strlen(reply)); + term_to_slave(term, reply, n); break; } @@ -1468,10 +1469,10 @@ csi_dispatch(struct terminal *term, uint8_t final) static_assert(FOOT_PATCH < 100, "Patch version must not exceed 99"); char reply[64]; - snprintf(reply, sizeof(reply), "\033[>1;%02u%02u%02u;0c", + size_t n = xsnprintf(reply, sizeof(reply), "\033[>1;%02u%02u%02u;0c", FOOT_MAJOR, FOOT_MINOR, FOOT_PATCH); - term_to_slave(term, reply, strlen(reply)); + term_to_slave(term, reply, n); break; case 'm': @@ -1625,8 +1626,8 @@ csi_dispatch(struct terminal *term, uint8_t final) value = 0; char reply[32]; - snprintf(reply, sizeof(reply), "\033[?%u;%u$y", param, value); - term_to_slave(term, reply, strlen(reply)); + size_t n = xsnprintf(reply, sizeof(reply), "\033[?%u;%u$y", param, value); + term_to_slave(term, reply, n); break; } diff --git a/input.c b/input.c index 33127afd..ffbd7b34 100644 --- a/input.c +++ b/input.c @@ -37,6 +37,7 @@ #include "util.h" #include "vt.h" #include "xmalloc.h" +#include "xsnprintf.h" struct pipe_context { char *text; @@ -974,8 +975,8 @@ key_press_release(struct seat *seat, struct terminal *term, uint32_t serial, assert(modify_param != 0); char reply[1024]; - snprintf(reply, sizeof(reply), "\x1b[27;%d;%d~", modify_param, sym); - term_to_slave(term, reply, strlen(reply)); + size_t n = xsnprintf(reply, sizeof(reply), "\x1b[27;%d;%d~", modify_param, sym); + term_to_slave(term, reply, n); } else { diff --git a/main.c b/main.c index 592e5dfb..ea2d4a27 100644 --- a/main.c +++ b/main.c @@ -31,6 +31,7 @@ #include "util.h" #include "version.h" #include "xmalloc.h" +#include "xsnprintf.h" static volatile sig_atomic_t aborted = 0; @@ -127,9 +128,9 @@ print_pid(const char *pid_file, bool *unlink_at_exit) if (pid_fd >= 0) { char pid[32]; - snprintf(pid, sizeof(pid), "%u\n", getpid()); + size_t n = xsnprintf(pid, sizeof(pid), "%u\n", getpid()); - ssize_t bytes = write(pid_fd, pid, strlen(pid)); + ssize_t bytes = write(pid_fd, pid, n); close(pid_fd); if (bytes < 0) { diff --git a/meson.build b/meson.build index dc76f041..2d96d62c 100644 --- a/meson.build +++ b/meson.build @@ -112,6 +112,7 @@ misc = static_library( 'misc.c', 'misc.h', 'uri.c', 'uri.h', 'xmalloc.c', 'xmalloc.h', + 'xsnprintf.c', 'xsnprintf.h', ) vtlib = static_library( diff --git a/osc.c b/osc.c index d24a4603..0e658ce6 100644 --- a/osc.c +++ b/osc.c @@ -17,6 +17,7 @@ #include "uri.h" #include "vt.h" #include "xmalloc.h" +#include "xsnprintf.h" #define UNHANDLED() LOG_DBG("unhandled: OSC: %.*s", (int)term->vt.osc.idx, term->vt.osc.data) @@ -522,9 +523,9 @@ osc_dispatch(struct terminal *term) uint8_t b = (color >> 0) & 0xff; char reply[32]; - snprintf(reply, sizeof(reply), "\033]4;%u;rgb:%02x/%02x/%02x\033\\", + size_t n = xsnprintf(reply, sizeof(reply), "\033]4;%u;rgb:%02x/%02x/%02x\033\\", idx, r, g, b); - term_to_slave(term, reply, strlen(reply)); + term_to_slave(term, reply, n); } else { @@ -568,11 +569,11 @@ osc_dispatch(struct terminal *term) * E.g. for color 0xdcdccc we reply "\033]10;rgb:dc/dc/cc\033\\" */ char reply[32]; - snprintf( + size_t n = xsnprintf( reply, sizeof(reply), "\033]%u;rgb:%02x/%02x/%02x\033\\", param, r, g, b); - term_to_slave(term, reply, strlen(reply)); + term_to_slave(term, reply, n); break; } @@ -602,8 +603,8 @@ osc_dispatch(struct terminal *term) uint8_t b = (term->cursor_color.cursor >> 0) & 0xff; char reply[32]; - snprintf(reply, sizeof(reply), "\033]12;rgb:%02x/%02x/%02x\033\\", r, g, b); - term_to_slave(term, reply, strlen(reply)); + size_t n = xsnprintf(reply, sizeof(reply), "\033]12;rgb:%02x/%02x/%02x\033\\", r, g, b); + term_to_slave(term, reply, n); break; } diff --git a/sixel.c b/sixel.c index cfca4d4a..96d2aba2 100644 --- a/sixel.c +++ b/sixel.c @@ -10,6 +10,7 @@ #include "hsl.h" #include "util.h" #include "xmalloc.h" +#include "xsnprintf.h" static size_t count; @@ -1101,8 +1102,8 @@ void sixel_colors_report_current(struct terminal *term) { char reply[24]; - snprintf(reply, sizeof(reply), "\033[?1;0;%uS", term->sixel.palette_size); - term_to_slave(term, reply, strlen(reply)); + size_t n = xsnprintf(reply, sizeof(reply), "\033[?1;0;%uS", term->sixel.palette_size); + term_to_slave(term, reply, n); LOG_DBG("query response for current color count: %u", term->sixel.palette_size); } @@ -1135,8 +1136,8 @@ void sixel_colors_report_max(struct terminal *term) { char reply[24]; - snprintf(reply, sizeof(reply), "\033[?1;0;%uS", SIXEL_MAX_COLORS); - term_to_slave(term, reply, strlen(reply)); + size_t n = xsnprintf(reply, sizeof(reply), "\033[?1;0;%uS", SIXEL_MAX_COLORS); + term_to_slave(term, reply, n); LOG_DBG("query response for max color count: %u", SIXEL_MAX_COLORS); } @@ -1144,10 +1145,10 @@ void sixel_geometry_report_current(struct terminal *term) { char reply[64]; - snprintf(reply, sizeof(reply), "\033[?2;0;%u;%uS", + size_t n = xsnprintf(reply, sizeof(reply), "\033[?2;0;%u;%uS", min(term->cols * term->cell_width, term->sixel.max_width), min(term->rows * term->cell_height, term->sixel.max_height)); - term_to_slave(term, reply, strlen(reply)); + term_to_slave(term, reply, n); LOG_DBG("query response for current sixel geometry: %ux%u", term->sixel.max_width, term->sixel.max_height); @@ -1178,8 +1179,8 @@ sixel_geometry_report_max(struct terminal *term) unsigned max_height = term->rows * term->cell_height; char reply[64]; - snprintf(reply, sizeof(reply), "\033[?2;0;%u;%uS", max_width, max_height); - term_to_slave(term, reply, strlen(reply)); + size_t n = xsnprintf(reply, sizeof(reply), "\033[?2;0;%u;%uS", max_width, max_height); + term_to_slave(term, reply, n); LOG_DBG("query response for max sixel geometry: %ux%u", max_width, max_height); diff --git a/xsnprintf.c b/xsnprintf.c new file mode 100644 index 00000000..e8e8d25d --- /dev/null +++ b/xsnprintf.c @@ -0,0 +1,36 @@ +#include "xsnprintf.h" + +#include +#include +#include + +size_t +xvsnprintf(char *buf, size_t n, const char *format, va_list ap) +{ + assert(n <= INT_MAX); + int len = vsnprintf(buf, n, format, ap); + + /* + * ISO C11 ยง7.21.6.5 states: + * "The snprintf function returns the number of characters that + * would have been written had n been sufficiently large, not + * counting the terminating null character, or a negative value + * if an encoding error occurred. Thus, the null-terminated output + * has been completely written if and only if the returned value + * is nonnegative and less than n." + */ + assert(len >= 0); + assert(len < (int)n); + + return (size_t)len; +} + +size_t +xsnprintf(char *buf, size_t n, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + size_t len = xvsnprintf(buf, n, format, ap); + va_end(ap); + return len; +} diff --git a/xsnprintf.h b/xsnprintf.h new file mode 100644 index 00000000..c745ef3e --- /dev/null +++ b/xsnprintf.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include +#include "macros.h" + +size_t xsnprintf(char *buf, size_t len, const char *fmt, ...) PRINTF(3) NONNULL_ARGS; +size_t xvsnprintf(char *buf, size_t len, const char *fmt, va_list ap) VPRINTF(3) NONNULL_ARGS;