diff --git a/INSTALL.md b/INSTALL.md index a29148a..a99e50c 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -12,7 +12,7 @@ this notice are preserved. This file is offered as-is, without any warranty. This is the recommended way to use this library. -Copy [ctlseqs.h](src/ctlseqs.h) and [ctlseqs.c](src/ctlseqs.c) to your project and build it alongside with other code. Requires an ISO C99 and POSIX.1-2008 compliant C implementation. +Copy [ctlseqs.h](src/ctlseqs.h) and [ctlseqs.c](src/ctlseqs.c) to your project and build it alongside with other code. Requires an ISO C99 and POSIX.1-2001 compliant C implementation. ## Build and Install From Source diff --git a/configure.ac b/configure.ac index 12aacdf..d770e38 100644 --- a/configure.ac +++ b/configure.ac @@ -41,7 +41,7 @@ AC_TYPE_SIZE_T AC_TYPE_SSIZE_T # Checks for library functions. -AC_CHECK_FUNCS([dprintf memset strtoul]) +AC_CHECK_FUNCS([memset strtoul]) # Specify libtool library version. m4_define([CTLSEQS_LT_CURRENT], [0]) @@ -49,8 +49,5 @@ m4_define([CTLSEQS_LT_REVISION], [0]) m4_define([CTLSEQS_LT_AGE], [0]) AC_SUBST([CTLSEQS_LT_VERSION], [CTLSEQS_LT_CURRENT:CTLSEQS_LT_REVISION:CTLSEQS_LT_AGE]) -# Assume that POSIX.1-2008 is supported. -AC_DEFINE([_POSIX_C_SOURCE], [200809L], [Feature test macro for POSIX.1-2008]) - AC_CONFIG_FILES([Makefile doc/Makefile man/Makefile src/Makefile tests/Makefile examples/Makefile]) AC_OUTPUT diff --git a/examples/sixdraw.c b/examples/sixdraw.c index 1b39340..385aac7 100644 --- a/examples/sixdraw.c +++ b/examples/sixdraw.c @@ -63,6 +63,8 @@ struct sixdraw_ctx { struct termios termios; union ctlseqs_value result[64]; char const *prog_name; + FILE* out_file; + FILE* err_file; struct ctlseqs_matcher *matcher; struct ctlseqs_reader *reader; bool has_termios; @@ -90,7 +92,7 @@ print_error(struct sixdraw_ctx const *ctx, char const *format, ...) va_start(args, format); vsnprintf(msg, 1024, format, args); va_end(args); - dprintf(ctx->out_fd, "%s: [error] %s.\n", ctx->prog_name, msg); + fprintf(ctx->err_file, "%s: [error] %s.\n", ctx->prog_name, msg); } static void @@ -101,20 +103,20 @@ terminate(struct sixdraw_ctx *ctx) // Restore cursor status. if (ctx->hide_cursor) { - dprintf(ctx->out_fd, CTLSEQS_DECSET("%d"), DECTCEM); + fprintf(ctx->out_file, CTLSEQS_DECSET("%d"), DECTCEM); } // Restore normal screen buffer. if (ctx->alt_scrbuf) { - dprintf(ctx->out_fd, CTLSEQS_DECRST("%d"), ALT_SCRBUF); + fprintf(ctx->out_file, CTLSEQS_DECRST("%d"), ALT_SCRBUF); } // Restore original mouse modes. if (ctx->btnev_tracking) { - dprintf(ctx->out_fd, CTLSEQS_DECRST("%d"), BTN_EVENT_TRACKING); + fprintf(ctx->out_file, CTLSEQS_DECRST("%d"), BTN_EVENT_TRACKING); } if (ctx->sgr_pixelmode) { - dprintf(ctx->out_fd, CTLSEQS_DECRST("%d"), SGR_MOUSE_PIXELMODE); + fprintf(ctx->out_file, CTLSEQS_DECRST("%d"), SGR_MOUSE_PIXELMODE); } // Restore original terminal modes. @@ -148,7 +150,7 @@ decrqm(struct sixdraw_ctx *ctx, unsigned mode, char const *name) { ssize_t retval; union ctlseqs_value *result = ctx->result; - dprintf(ctx->out_fd, CTLSEQS_DECRQM("%d"), mode); + fprintf(ctx->out_file, CTLSEQS_DECRQM("%d"), mode); do { retval = ctlseqs_read(ctx->reader, ctx->matcher, ctx->timeout); } while (retval == CTLSEQS_PARTIAL); @@ -173,7 +175,7 @@ print_sixel_dot(struct sixdraw_ctx *ctx, unsigned x, unsigned y) // Move cursor. unsigned row = y / ctx->ch_height + 1; unsigned col = x / ctx->ch_width + 1; - dprintf(ctx->out_fd, CTLSEQS_CUP("%d", "%d"), row, col); + fprintf(ctx->out_file, CTLSEQS_CUP("%d", "%d"), row, col); // Build sixel sequence. row = y % ctx->ch_height; @@ -182,13 +184,7 @@ print_sixel_dot(struct sixdraw_ctx *ctx, unsigned x, unsigned y) seq_size += sprintf(sixel_seq + seq_size, "%.*s!%u?%c" CTLSEQS_ST, row / 6, "------------------------", col, (1 << row % 6) + 0x3F); - // Output sixel sequence. - for (ssize_t nbytes; seq_size > 0; seq_size -= nbytes) { - nbytes = write(ctx->out_fd, sixel_seq, seq_size); - if (nbytes < 0) { - break; - } - } + fwrite(sixel_seq, seq_size, 1, ctx->out_file); } static bool @@ -196,6 +192,8 @@ init(struct sixdraw_ctx *ctx, int argc, char **argv) { *ctx = (struct sixdraw_ctx) { .prog_name = argc > 0 ? argv[0] : "sixdraw", + .out_file = stdout, + .err_file = stderr, .in_fd = STDIN_FILENO, .out_fd = STDOUT_FILENO, .timeout = DEFAULT_TIMEOUT_MILLIS, @@ -281,7 +279,7 @@ prepare(struct sixdraw_ctx *ctx) } ctx->has_termios = true; - // Set STDIN flags to nonblocking. + // Set STDIN flags to nonblocking, and disable output buffering. int flags = fcntl(ctx->in_fd, F_GETFL); if (flags == -1) { print_error(ctx, "failed to get file status flags"); @@ -291,6 +289,10 @@ prepare(struct sixdraw_ctx *ctx) print_error(ctx, "failed to set file status flags"); return false; } + if (setvbuf(stdout, NULL, _IONBF, 0) != 0) { + print_error(ctx, "failed to disable output buffering"); + return false; + } // Get initial terminal window size. if (!get_winsize(ctx)) { @@ -298,7 +300,7 @@ prepare(struct sixdraw_ctx *ctx) } // Check terminal support for sixel graphics and DEC locator. - dprintf(ctx->out_fd, CTLSEQS_PRIMARY_DA()); + fprintf(ctx->out_file, CTLSEQS_PRIMARY_DA()); ssize_t retval; do { retval = ctlseqs_read(ctx->reader, ctx->matcher, ctx->timeout); @@ -325,16 +327,7 @@ prepare(struct sixdraw_ctx *ctx) } ctx->hide_cursor = result[1].num == DECRQM_SET; if (ctx->hide_cursor) { - dprintf(ctx->out_fd, CTLSEQS_DECRST("%d"), DECTCEM); - } - - // Switch to alternate screen buffer. - if (!decrqm(ctx, ALT_SCRBUF, "screen buffer")) { - return false; - } - ctx->alt_scrbuf = result[1].num == DECRQM_RST; - if (ctx->alt_scrbuf) { - dprintf(ctx->out_fd, CTLSEQS_DECSET("%d"), ALT_SCRBUF); + fprintf(ctx->out_file, CTLSEQS_DECRST("%d"), DECTCEM); } // Enable button event tracking mode. @@ -343,7 +336,7 @@ prepare(struct sixdraw_ctx *ctx) } ctx->btnev_tracking = result[1].num == DECRQM_RST; if (ctx->btnev_tracking) { - dprintf(ctx->out_fd, CTLSEQS_DECSET("%d"), BTN_EVENT_TRACKING); + fprintf(ctx->out_file, CTLSEQS_DECSET("%d"), BTN_EVENT_TRACKING); } // Enable SGR mouse pixel mode. @@ -352,7 +345,16 @@ prepare(struct sixdraw_ctx *ctx) } ctx->sgr_pixelmode = result[1].num == DECRQM_RST; if (ctx->sgr_pixelmode) { - dprintf(ctx->out_fd, CTLSEQS_DECSET("%d"), SGR_MOUSE_PIXELMODE); + fprintf(ctx->out_file, CTLSEQS_DECSET("%d"), SGR_MOUSE_PIXELMODE); + } + + // Switch to alternate screen buffer. + if (!decrqm(ctx, ALT_SCRBUF, "screen buffer")) { + return false; + } + ctx->alt_scrbuf = result[1].num == DECRQM_RST; + if (ctx->alt_scrbuf) { + fprintf(ctx->out_file, CTLSEQS_DECSET("%d"), ALT_SCRBUF); } // Build the immutable part of sixel sequence. @@ -367,9 +369,9 @@ prepare(struct sixdraw_ctx *ctx) static bool draw(struct sixdraw_ctx *ctx) { - dprintf(ctx->out_fd, CTLSEQS_CUP("%d", "1") "Canvas size: %ux%u. Line color: #%06X.", + fprintf(ctx->out_file, CTLSEQS_CUP("%d", "1") "Canvas size: %ux%u. Line color: #%06X.", ctx->rows - 1, ctx->canvas_width, ctx->canvas_height, ctx->line_color); - dprintf(ctx->out_fd, CTLSEQS_CUP("%d", "1") "Usage: Draw with mouse. Press Ctrl+C to exit.", ctx->rows); + fprintf(ctx->out_file, CTLSEQS_CUP("%d", "1") "Usage: Draw with mouse. Press Ctrl+C to exit.", ctx->rows); union ctlseqs_value *result = ctx->result; while (true) { diff --git a/tests/tcsgrep.c b/tests/tcsgrep.c index f26047d..bfff391 100644 --- a/tests/tcsgrep.c +++ b/tests/tcsgrep.c @@ -73,7 +73,7 @@ struct tcsgrep_ctx { static inline void print_error(struct tcsgrep_ctx const *ctx, char const *msg) { - dprintf(STDERR_FILENO, "%s: [error] %s.\n", ctx->prog_name, msg); + fprintf(stderr, "%s: [error] %s.\n", ctx->prog_name, msg); } static inline bool